# Test data

```bash
php artisan migrate:fresh --seed          # everything below, about 4 seconds
php artisan db:seed --class=DemoShopsSeeder   # add the demo shops to an existing database (skips ones that exist)
```

Never runs in production: there `db:seed` only creates the permission catalogue (no shops, no known passwords).
All passwords are **`password`**.

| Shop | State | Currency / timezone | Logins | What's inside |
|---|---|---|---|---|
| **Demo Shop** (`demo-shop`) | active | USD / UTC | `owner@` · `cashier@` · `stock@example.com` | 20 categories (parents and sub-categories), 41 products, 6 suppliers, 12 customers, a month of trading |
| **Green Grocer** (`green-grocer`) | active | PKR / Asia/Karachi | `owner2@` · `cashier2@` · `stock2@example.com` | 5 categories, 13 products in kg and other units, 3 suppliers, 5 customers, a smaller history |
| **Pending Boutique** | pending approval | EUR / Paris | `pending@example.com` | empty: log in to see the "awaiting approval" page, approve it as master |
| **Suspended Mart** | suspended | GBP / London | `suspended@example.com` | empty: log in to see the suspension reason |
| Platform admin | | | `master@example.com` | approve / suspend shops, "enter" any shop |

## What the catalogue is built to exercise
- **Stock states:** healthy, low (below alert), out of stock, an untracked service (Home Delivery), an inactive product (Seasonal Gift Box), an archived product (Discontinued Candy).
- **Customers:** some owe money (opening balances), one is near their credit limit (Usman Tariq), two are cash-only (limit 0), one is inactive.
- **Suppliers:** two with an opening balance owed; the rest settled.
- **History (Demo Shop ~45 sales, Green Grocer ~17):** over the last 30 days: cash with change, card, split cash + mobile, credit sales with and without a deposit, a few returns, damages, supplier purchases with part-payments, and customer / supplier payments.

## How it's made (so it stays trustworthy)
- Everything goes through the real services (`StockService`, `LedgerService`, `SaleService`, `PurchaseService`, …), never raw inserts, so stock equals its movement ledger, balances equal their ledgers, invoice numbers have no gaps, and low-stock alerts fire as they would live.
- **Repeatable:** each shop's history comes from a fixed seed, so the same sales appear every time. (Laravel's `->random()`, `->shuffle()` and `inRandomOrder()` ignore seeds, so the builders use `mt_rand()` only.)
- **Safe to re-run:** a shop that already exists (by slug) is skipped.

Code: `database/seeders/` — `DatabaseSeeder`, `DemoShopsSeeder`, `Demo/CatalogData` (the data), `Demo/CatalogueBuilder`, `Demo/ActivityBuilder`.
Guarded by `tests/Feature/DemoSeederTest.php`.
