Shoppy Max is a Laravel 12 application for inventory, order operations, reseller management, courier settlement, and reporting.
It includes role-based access control, product variants, stock-safe purchase/order flows, waybill generation, imports/exports, and print/PDF outputs across multiple modules.
- Overview
- Core Capabilities
- Tech Stack
- System Requirements
- Quick Start (SQLite)
- Alternative Database Setup
- Running the App
- Seed Data and Default Credentials
- Environment Configuration
- Operational Business Rules
- Imports, Exports, and Documents
- Main Route Map
- Useful Commands
- Testing and Quality
- Troubleshooting
- Security and Production Checklist
- Project Structure
- License
This system manages:
- Contacts: customers, suppliers, resellers, direct resellers, cities
- Product catalog: categories, sub-categories, units, products, variants, pricing
- Inventory movement: purchases, GRN intake, unit-level stock tracking, and orders
- Orders: create/edit/view/print/PDF, call list, waybill queue, waybill Excel export queue, plus packing and return flows that exist in part but should still be treated as work-in-progress operational areas
- Finance flows: reseller targets/payments/dues, courier payments, bank accounts
- Reports: province sales, profit/loss, stock, packet count, product sales, user sales
Authentication is provided by Laravel Breeze, and permissions are handled by Spatie Permission.
- Full CRUD for operational masters and transactions
- Product variants with:
- unit + unit value
- unique SKU
- selling price + limit price
- stock quantity and alert quantity
- Product import with preview validation:
- auto SKU generation
- category/sub-category/unit validation
- same product name is case-insensitive
- conflict checks before final import
- Order workflow with:
- customer auto-create/update by mobile
- delivery status lifecycle
- call status tracking
- payment entries and derived payment status
- order structure locking after intake progresses, with manual edit/cancel/delete blocked once waybill printing starts
- packing pages with unit-level barcode scans, persisted scan progress, and quantity-accurate completion checks
- note: packing core flow exists, but it is still a work-in-progress operational area and broader hardening / full browser QA are still pending
- note: the
returnedstate exists in backend accounting/inventory logic, but returns are still a work-in-progress operational area until the dedicated post-dispatch return screen/action exists
- Purchase workflow with:
- forward-only moderation (
pending -> checking -> verified -> complete) - GRN checking by barcode scan
- stock release only after full GRN completion
- immutable purchase date and purchasing ID after creation
- forward-only moderation (
- Unit-level inventory traceability:
- purchase labels generated per PCS quantity
- orders allocate real inventory units
- delivered/cancel/return flows update tracked units
- Waybill workflow:
- queue based on
call_status = confirm - print generates waybill numbers
- printed orders leave the pending waybill queue
- printed orders enter a courier-specific Excel export queue
- Excel export defaults to not-yet-downloaded rows and can optionally include already-downloaded rows
- queue based on
- Courier receive and courier payment reconciliation
- Reseller commission/penalty logic (reseller-only, not direct reseller)
- PDF/print/export support across modules
- PHP 8.2+
- Laravel 12
- SQLite (default) or MySQL/PostgreSQL
- Blade + Alpine.js + Tailwind CSS + Flowbite
- SweetAlert2
- Spatie Permission
- DomPDF (
barryvdh/laravel-dompdf) - Laravel Excel (
maatwebsite/excel) - Cloudinary Laravel SDK (image upload integration)
- Vite for asset bundling
- PHP
^8.2 - Composer
- Node.js + npm
- SQLite (default) or another supported DB
# From the project root
cd shoppy-max
composer install
npm install
cp .env.example .env
php artisan key:generateCreate SQLite DB file:
mkdir -p database
touch database/database.sqliteSet in .env:
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/shoppy-max/database/database.sqliteRun migrations and seed demo data:
php artisan migrate:fresh --seedCreate frontend assets:
npm run buildStart app:
php artisan serveOpen:
http://127.0.0.1:8000/loginhttp://127.0.0.1:8000/shop(public product page)
For MySQL/PostgreSQL, update .env DB values, then:
php artisan migrate:fresh --seedDevelopment (all-in-one with server, queue listener, logs, and Vite):
composer run devOr run manually in separate terminals:
php artisan serve
php artisan queue:work
npm run devSeeders used:
RolesAndPermissionsSeederDemoSystemSeeder
Default users:
- Super Admin
- Email:
admin@shoppy-max.com - Password:
password - Role:
super admin
- Email:
- Manager
- Email:
manager@shoppy-max.com - Password:
password - Role:
admin
- Email:
Seed data includes:
- Units, categories, sub-categories
- Cities (with district/province)
- Couriers + rate sets
- Bank accounts
- Suppliers
- Resellers and direct resellers
- Products/variants
- Demo purchases/orders/payments/targets/logs
- Inventory units and barcode-traceable demo stock
- Courier payment examples with linked settled orders
- Eligible courier-receive examples for testing receive flow
APP_ENV,APP_DEBUG,APP_URLAPP_TIMEZONE(recommended to set explicitly, e.g.Asia/Colombo)
DB_CONNECTION=sqliteSESSION_DRIVER=databaseQUEUE_CONNECTION=databaseCACHE_STORE=database
If using database-backed drivers, ensure migrations are run.
- Local filesystem default:
FILESYSTEM_DISK=local - Product image uploads use Cloudinary integration in controllers.
- Configure
CLOUDINARY_URLor related Cloudinary env vars for image upload support.
- Configure
These are current implemented behaviors.
- Product and variant creation starts stock at
0. - Purchases create inventory-unit records immediately, but stock does not become available until the purchase is fully completed through GRN.
- Orders allocate real inventory units, not only aggregate stock counts.
- Stock decreases when units are allocated to active orders.
- Delivered orders mark units as delivered.
- Cancelling, returning, or deleting orders releases units appropriately.
- Use the inventory-unit reconciliation commands if aggregate stock drifts from tracked units.
Purchase statuses:
pendingcheckingverifiedcomplete
Rules:
- New purchases start at
pending. - Moderation is forward-only:
pending -> checking -> verified -> complete
- Purchase date and purchasing ID are locked after creation.
- GRN is scanner-driven from the verified stage.
- Partial GRN scans update progress only.
- Stock becomes available only when the final GRN scan completes the whole purchase.
- Once GRN receiving starts, purchase structure is locked.
- Completed purchases are locked from structural edits and deletion.
order_numberis unique and generated daily (ORD-YYYYMMDD-####).- Soft-deleted orders still reserve their order numbers.
- Once an order moves beyond early intake, core order details lock:
- only payment entries and notes remain editable.
Supported statuses:
- Internal order status (system-managed):
pending,hold,confirm,cancel - Call status:
pending,confirm,hold,cancel - Delivery status:
pendingwaybill_printedpicked_from_rackpackeddispatcheddeliveredreturnedcancel
Cancellation behavior:
- Cancelling order auto-sets call status to
cancel - Cancelling order auto-sets delivery status to
cancel
When creating/updating orders:
- customer is upserted by
mobile - customer address + location fields are saved:
countrycitydistrictprovince
- Order remains
pendingwhen discount exists or method isOnline Payment. - Payment status auto-resolves to
paidwhen:- delivery status is
delivered, or - online payment is fully paid.
- delivery status is
- Only dispatched orders can move to
delivered.
- Commission applies only for
resellertype accounts (not direct reseller). - Commission is suppressed for cancelled/returned orders.
- Returned reseller orders can apply reseller return fee penalty and adjust due amounts.
Orders are eligible for courier receive only when:
call_status = confirmpayment_method = CODdelivery_status = dispatched- waybill number exists
- courier matches the receive screen
- order is not already linked to a courier payment
Settlement values:
- System delivery charge: order delivery charge at placement time
- Real delivery charge: what the courier actually charged
- Courier commission: system delivery charge minus real delivery charge
- Received amount: order total minus real delivery charge
Behavior:
- Receiving courier payment marks linked orders as delivered.
- Editing a courier payment can add/remove linked orders.
- Removing an order from a courier payment reverts that order to
dispatched, clears settlement-specific values, and restores COD payment state to pending. - Whole courier payment deletion is disabled; correction is done through edit/unlink flow.
Orders are eligible for waybill print only when:
call_status = confirmdelivery_status = pending- waybill number is empty
Printing waybill:
- assigns waybill number
- updates delivery status to
waybill_printed - stamps
waybill_printed_at
Waybill Excel export:
- is grouped by courier
- includes orders with saved printed waybill IDs
- defaults to pending-download rows only
- can include previously downloaded rows with the explicit filter
- marks newly exported rows as downloaded without blocking later re-export
- Template download available
- Preview validates rows before final import
- SKU auto-generated in import path
- Duplicate/conflicting data validation applied
- Template + preview + final store flow available
Available across relevant modules:
- contact exports (Excel/PDF)
- product export
- purchase PDF and barcode print
- order print/PDF/bulk PDF ZIP
- reseller payment invoice downloads
Important entry points:
- Auth:
/login - Dashboard:
/dashboard - Public shop:
/shop - Contacts:
/customers/suppliers/resellers/direct-resellers/cities
- Products:
/admin/products - Orders:
/orders/orders/create/orders/call-list/orders/waybill
- Purchases:
/purchases - Purchase moderation:
/purchases/moderation - Couriers:
/couriers/receive-courier/courier-payments
- Bank Accounts:
/bank-accounts - Reseller ops:
/reseller-targets/reseller-payments/reseller-dues
- Reports:
/reports - User Logs (coming soon):
/user-logs
Setup helper:
composer run setupMigrate:
php artisan migrate
php artisan migrate:fresh --seedInventory reconciliation:
php artisan inventory-units:backfill
php artisan inventory-units:sync-stockCache and optimize:
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan optimizeClear caches:
php artisan optimize:clear
php artisan route:clear
php artisan view:clearRun tests:
php artisan testRun formatter:
./vendor/bin/pintNote:
- The automated test suite is currently light and does not cover the main operational workflows.
- After changing purchases, GRN, orders, courier settlement, or stock logic, manual workflow
verification is still required even if
php artisan testpasses. - The default Laravel sample test
Tests\Feature\ExampleTestexpects/to return200. - In this app,
/redirects to login, so that sample test can fail with302unless adjusted.
Cause:
- Orders are soft-deleted, and old order numbers still exist.
Current behavior:
- Generator now includes soft-deleted orders, preventing reuse collisions.
- Ensure Cloudinary env config is valid when uploading images.
- If Cloudinary is not configured, avoid image upload until configured.
- Run:
php artisan migrate:fresh --seed
- Run:
php artisan inventory-units:sync-stock
- Run only on a dataset that does not already have inventory units:
php artisan inventory-units:backfill
- Run migrations (database drivers are used by default):
php artisan migrate
Before production:
- Set
APP_ENV=production,APP_DEBUG=false - Set strong unique credentials and rotate seeded defaults
- Configure real database credentials
- Set
APP_URLcorrectly - Configure queue worker as a managed process
- Configure backup/monitoring/log rotation
- Configure Cloudinary credentials (if image uploads are required)
- Build frontend assets with
npm run build - Cache config/routes/views
app/
Http/Controllers/ Business workflows and CRUD endpoints
Models/ Domain models
database/
migrations/ Schema evolution
seeders/ Roles/permissions + demo data
resources/
views/ Blade UI (admin + operational screens)
routes/
web.php Main app routes
api.php API routes (city lookup, auth user)
This project is proprietary software owned by Codezela Technologies.
See the full license terms in LICENSE.