OmniPOS is a learning project to gain hands-on experience across the full web stack Laravel, Vue.js 3, REST APIs, PHPUnit, third-party integrations and Pinia combined into one real application. A fully working browser-based POS system covering barcode scanning, payments, receipts, inventory and analytics.
| Layer | Technology |
|---|---|
| Backend Framework | Laravel 13 (PHP 8.3) |
| Frontend Framework | Vue.js 3 + Vite |
| Styling | Tailwind CSS v4 |
| State Management | Pinia |
| Database | MariaDB 10.4 |
| Authentication | Laravel Sanctum |
| HTTP Client | Guzzle |
| Barcode Scanner | Html5-QRCode |
| Analytics | Chart.js |
| PDF / Invoice | domPDF |
| Excel Export | Laravel Excel (Maatwebsite) |
| Testing | PHPUnit 12 |
| API Testing | Postman |
| IDE | Cursor (VS Code-based) |
- Camera-based barcode scanning via Html5-QRCode
- Supports EAN-13 (standard retail) and QR Codes
- Async product lookup on scan — beep sound on success
- Register New Product pop-up when barcode is not found
- Scan-to-Fill in Add Product form — barcode auto-populates
- Reactive cart — add, remove, +/− quantity without page refresh
- Hold & Resume queue — save active cart and serve next customer
- Fixed (RM) and percentage (%) discount toggle
- Automatic SST 6% calculation on every cart update
- Live currency conversion via ExchangeRate-API (USD, SGD, IDR, EUR)
- Currency toggle on checkout with converted total shown live
- Payment gateway simulation — test card returns 200 OK or 402 Decline
- API latency and response logging in
api_logstable - 29 REST API endpoints documented in Postman
- A4 invoice mode — branded layout with invoice number, line items and totals
- Thermal mock mode — CSS
@media printforces 80mm width, hides nav - Print button triggers browser print dialog
- QR code digital receipt — unique URL per sale, scannable by phone
- Daily sales export to Excel (.xlsx)
- Low stock watchdog — red indicators for stock below threshold
- Inventory audit log — records Who, When, Why on every stock change
- Manual stock adjustment with reason and notes
- Chart.js peak sales hours — line chart by hour of day
- Chart.js top 5 selling products — bar chart by units sold
- PHPUnit automated tests — verifies stock deduction, audit log, validation
- Insufficient stock returns 422 not 500 — proper error handling
- Strict barcode input validation — symbols and text rejected with 422
- API debug log — latency, status and payload stored per request
omnipos/
├── app/
│ ├── Exports/ # Excel export classes
│ ├── Http/
│ │ └── Controllers/
│ │ └── Api/ # All API controllers
│ └── Models/ # Eloquent models
├── database/
│ └── migrations/ # All 11 table migrations
├── resources/
│ └── js/
│ ├── pages/ # Vue page components
│ ├── stores/ # Pinia state stores
│ ├── router/ # Vue Router config
│ └── app.js # Vue app entry point
├── routes/
│ ├── api.php # All 29 API routes
│ └── web.php # SPA catch-all route
└── tests/
└── Feature/ # PHPUnit feature tests
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/products | List all products |
| POST | /api/products | Create product |
| GET | /api/products/{id} | Get product |
| PUT | /api/products/{id} | Update product |
| DELETE | /api/products/{id} | Delete product |
| GET | /api/products/barcode/{barcode} | Find by barcode |
| GET | /api/categories | List categories |
| POST | /api/categories | Create category |
| GET | /api/sales | List sales |
| POST | /api/sales | Process checkout |
| GET | /api/sales/receipt/{token} | Get receipt by token |
| GET | /api/sales/export/daily | Export sales to Excel |
| GET | /api/inventory | Stock overview |
| GET | /api/inventory/logs | Audit log |
| GET | /api/inventory/low-stock | Low stock items |
| POST | /api/inventory/{id}/adjust | Adjust stock |
| GET | /api/held-carts | List held carts |
| POST | /api/held-carts | Save held cart |
| GET | /api/currency/rates | Live exchange rates |
| POST | /api/payment/process | Payment simulation |
| Table | Purpose |
|---|---|
| users | Staff accounts |
| products | Product catalogue |
| categories | Product categories |
| sales | Sale transactions |
| sale_items | Line items per sale |
| inventory_logs | Stock audit trail |
| held_carts | Saved/paused carts |
| api_logs | External API call log |
| personal_access_tokens | Sanctum auth tokens |
| cache | Laravel cache |
| jobs | Laravel queue |
| Card Number | Result |
|---|---|
| 4111111111111111 | ✅ Approved (200 OK) |
| 5500005555555559 | ✅ Approved (200 OK) |
| 4000000000000002 | ❌ Declined (402) |
| 4000000000009995 | ❌ Declined (402) |
- PHP 8.2+
- Composer
- Node.js 18+
- MySQL or MariaDB
1. Clone the repository
git clone https://github.com/yourusername/omnipos.git
cd omnipos2. Install dependencies
composer install
npm install3. Configure environment
cp .env.example .env
php artisan key:generate4. Set your database credentials in .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=omnipos
DB_USERNAME=root
DB_PASSWORD=5. Run migrations
php artisan migrate6. Start development servers
php artisan serve
npm run dev7. Visit http://localhost:8000
php artisan serve --host=0.0.0.0 --port=8000
npm run dev -- --hostThen open the network URL Vite displays on your phone browser.
php artisan testExpected output:
PASS Tests\Feature\SaleStockDeductionTest
✓ stock deduction works correctly
✓ inventory log is created
✓ sale fails if stock is low
✓ invalid barcode format is rejected
Tests: 4 passed
Import OmniPOS-API.postman_collection.json into Postman to explore and test all endpoints with pre-configured request bodies and headers.
- Designing and building a RESTful API with Laravel from scratch
- Database relationships, migrations and Eloquent ORM
- Vue.js 3 Composition API and reactive state with Pinia
- Integrating third-party APIs (ExchangeRate-API)
- Writing PHPUnit feature tests for real business logic
- CSS
@media printfor thermal and A4 print layouts - Camera-based barcode scanning in the browser
- Building a full SaaS-style application end to end
- Laravel Sanctum login / logout UI
- Multi-user roles (cashier vs manager)
- Real payment gateway (Billplz / iPay88)
- E-invoice compliance (Malaysia MyInvois / LHDN)
- Multi-outlet / multi-branch support
- Customer loyalty points system
- Mobile app using the existing API
- Cloud deployment
Built by dxisoon as a learning project, from zero to a working POS system in one session.