# Inventory and Import Shipments module: install notes

Builds on the DMS core package (branches, users, RBAC, settings, audit log, document sequences).
Needs PHP 8.2+ with the `bcmath` extension, Laravel 11/12, Tailwind v4, Alpine (already set up in core).

## 1. Copy files
Copy `app/`, `config/`, `database/`, `resources/`, `routes/inventory.php`, `tests/` into the app.
These files REPLACE core versions (same names): `config/navigation.php`, `database/seeders/DatabaseSeeder.php`,
`app/Http/Controllers/DashboardController.php`, `resources/views/dashboard.blade.php`.
Merge (do not overwrite) `routes/console.php`.

## 2. Wire up
```php
// end of routes/web.php
require __DIR__.'/inventory.php';
```
```bash
composer require bacon/bacon-qr-code picqer/php-barcode-generator
php artisan migrate
php artisan db:seed --class=InventoryPermissionSeeder
php artisan db:seed --class=InventorySettingsSeeder
php artisan db:seed --class=VehicleCatalogSeeder
php artisan test --filter=InventoryTest
```
Server cron for the scheduler: `* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1`

## 3. Before first use
- **Exchange rates.** Foreign-currency costs need a rate. Either type the rate on the form, or add rows to `exchange_rates`
  (an admin screen for this is not built yet).
- **Users.** New permissions: `vehicles.reverse_sale`, `vehicles.manage_costs`, `shipments.view|manage|manage_charges`.
  Defaults: Branch Manager gets all; Finance gets shipment charges and vehicle costs; Workshop Supervisor gets vehicle costs;
  Sales Executive sees vehicles but not costs. Adjust in `InventoryPermissionSeeder`.
- **Settings** (per company, overridable per branch): `stock.aging_warn_days` (60), `stock.aging_alert_days` (90), `stock.reservation_hours` (72).

## How it fits together
- Status rules live in `App\Enums\VehicleStatus`; every change goes through `VehicleStatusService` (locks the row, writes history, audited).
- Landed cost = sum of `vehicle_costs.amount_kes`. `vehicles.landed_cost` is a cached copy. Shipment charges are spread over
  the shipment's vehicles by `ShipmentCostAllocator` (equally or by purchase price); re-running it replaces earlier allocations.
- The aging clock starts when a vehicle first enters stock and stops at sale. `stock:check-aging` notifies branch managers
  (database notification) and does not repeat for the same vehicle within 7 days.
- Labels: QR opens `/yard/{stock_id}` (sign-in and branch isolation still apply); the Code 128 barcode holds the stock ID for scanners.

## Known gaps (next steps)
Vehicle photo and document uploads, inter-branch transfer, an exchange-rate admin screen, a notification bell in the top bar,
and workshop refurbishment posting costs back to `vehicle_costs`.
Not run in the authoring environment (no PHP available): run the migrations and tests before relying on it.
