Vasyka
954ba8f059
Stage 12 — Online Store: public catalog + cart + orders
...
Schema:
- online_orders (token-tracked, status workflow, delivery method/fee)
- online_order_items (price snapshot, fulfilled flag)
- part_cross_refs (OEM/equivalent codes for search)
- parts.is_published (shop visibility)
Storefront (ShopController, tenant subdomain, /shop):
- Catalog with search across name/article/brand/cross-refs, category +
in-stock filters, live stock, white-label themed layout
- Part detail page with cross-ref codes
- VIN search → VinDecoder → guided catalog search
- Session cart (per-tenant key), guest checkout, order confirmation page
- Respects settings.shop.enabled (404 when off); tenant-guarded
Part::searchPublished matches cross-ref articles via whereHas.
Order notifications (ShopOrderNotifier, best-effort):
- Staff: Web Push to active users
- Customer: Telegram if phone matches a linked client
Filament (tenant):
- OnlineOrderResource under "Magazin" nav group, status workflow,
items relation, "Onorează" action issues stock via WarehouseService (FIFO)
- PartResource: is_published toggle + column + bulk publish/unpublish +
CrossRefsRelationManager
- Settings: shop section (enable, delivery methods, fee, free-over)
- Landing page: shop button when enabled
Tests (6 new):
- catalog 404 when disabled; lists published only; cross-ref search;
order placement (token + items + total); fulfill issues stock;
cross-tenant token isolation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-28 05:27:51 +00:00
Vasyka
e48ef1b755
Stage 7+14 — Mechanic Board + Scan Center
...
Mechanic Workflow (Stage 7):
- /app/mechanic Filament page filtered to master_id = auth user
- Kanban 4 columns (in_work / awaiting_parts / ready / recent), each card
shows WO#, plate, client, complaint summary, photo presence
- 2 KPI tiles (active now / closed today)
- Mobile-responsive grid (auto-fit, minmax 260px)
WarehouseService:
- issueNow(WorkOrderPart) — consume reservations immediately scoped to one
line, without closing the WO (mechanic physically takes part now)
- returnPart(WorkOrderPart, qty?, notes?) — refund to stock as new batch
at original buy_price, writes `return` event, capped at consumed total
WO PartsRelationManager:
- "Eliberează" action — visible when active reservation exists
- "Restituire" action — visible when consumed reservation exists, with qty
modal + notes
Scan Center (Stage 14):
- PartResource "QR" action — per-part SVG QR with payload PART:<article|id>
- BulkAction "Tipărește etichete QR" → /parts/labels?ids=N,M (HTML A4 sheet,
3-col grid, print CSS hides toolbar)
- /app/scan Filament page using html5-qrcode 2.3.8 (CDN), auto-picks back
camera, decodes → Livewire dispatches scanner-decoded → resolveAndRedirect
- Lookup matches PART:N prefix, parts.article, parts.barcode, or numeric id
- Manual input fallback for browsers without camera
Tests (6 new):
- WarehouseIssueReturnTest (3): issueNow consumes immediately; returnPart
creates positive batch + return event; over-return is capped
- ScannerLookupTest (3): PART: prefix lookup, raw barcode lookup, unknown miss
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 21:39:39 +00:00
Vasyka
1ff888131f
Stage 16 — AI Layer: VIN decoder + diagnostic / parts / price helpers
...
VinDecoder (deterministic, no API):
- ISO 3779/3780 parsing: WMI manufacturer (~60 brands), year (cyclical with
post-2010 disambiguation via position 7), region, plant, NA checksum
- Strip non-VIN chars, accept dashes/spaces, reject I/O/Q per spec
AiAssistantService:
- Refactored provider HTTP into postClaude/postOpenAI/postGemini so both
chat history and one-shot calls share the same transport
- singleShot(system, userPrompt, provider?) for fire-and-forget calls
- 4 specialized helpers with tight prompts:
- suggestDiagnosis(WO) — diagnostician based on complaint + VIN info
- suggestParts(WO, task) — OEM parts list for an operation
- suggestPrice(Part) — markup recommendation with justification
- vinRecommendations(vin, mileage) — scheduled maintenance from decoded VIN
- monthlyUsage() — token spend MTD by provider
Filament:
- VehicleResource: "Decode VIN" + "AI: recomandări" actions
- WorkOrderResource Edit: "AI: sugerează diagnostic" header action
- PartResource: "AI: preț recomandat" action
- Shared views: filament.tenant.ai-reply, filament.tenant.vin-decode
- AiAssistant page shows monthly token usage banner
Tests (13 new):
- 8 VinDecoder unit tests with real VIN samples (Honda 2003, VW 1999, Audi
2014, Dacia, unknown WMI, lowercase/dashes, forbidden chars)
- 5 AiHelpers feature tests with Http::fake covering all providers + no-key
fallback + token usage aggregation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 20:24:09 +00:00
Vasyka
a2026f640a
Stage 6 — Purchase System: partial receipt + supplier analytics
...
Schema:
- purchase_items.qty_received (backfilled from `received` boolean)
- purchases.warehouse_id (target warehouse FK)
- supplier_part_prices (price history per supplier/part with purchase ref)
- New status `partial` between ordered and received
Purchase ↔ Warehouse integration:
- Purchase::receiveItem(item, qty, warehouse?) — routes through
WarehouseService::receive: creates batch + receipt event + supplier price row
- Purchase::receiveAllRemaining(warehouse?) — receives all outstanding lines
- Purchase::recomputeStatus() — auto: ordered → partial → received
Old flat markReceived() removed — every receipt now writes batches + ledger.
Filament:
- Purchase list: progress %, partial badge, warehouse picker on form
- ItemsRelationManager: per-line "Recepționează" with qty + warehouse modal,
qty_received shown as "X.XX / Y.YY" with colour
- PartResource: new PriceHistoryRelationManager (supplier price history)
- SupplierResource: derived columns onTimeRate / avgDeliveryDays / spend(90d)
+ "Rerating" action
Analytics:
- App\Services\Warehouse\SupplierAnalytics (onTimeRate, avgDeliveryDays,
spend, count, computedRating)
- `suppliers:rate` artisan command + weekly schedule (Mon 04:00)
- Computed rating: 70% on-time + 20% volume + 10% speed bonus
Tests (6 new, all pass):
- Partial receipt of 3/10 → status=partial + 1 batch + 1 price row
- receiveAllRemaining → status=received with received_at set
- Over-receive throws InvalidArgumentException
- Two partial receipts (4+6) → 2 batches FIFO + status=received
- onTimeRate 50% with 1 on-time + 1 late
- computedRating null when <2 deliveries
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 19:37:12 +00:00
Vasyka
426156fe45
Stage 5.1 — Warehouse ERP: batches + FIFO + reservations + multi-warehouse
...
Schema:
- warehouses (multi-warehouse, code unique per company, is_default)
- part_batches (lot per receipt, qty_in/qty_remaining, buy_price, FIFO-indexed)
- warehouse_events (immutable ledger: opening/receipt/issue/transfer/adjustment/write_off)
- part_reservations (per-WO allocations from specific batches, active/consumed/released)
- companies.default_warehouse_id + parts.qty_reserved
Backfill: 1 default warehouse + 1 opening batch per existing part per company.
WarehouseService:
- receive / issue (FIFO) / reserve / release / consume / transfer / adjust
- DB::transaction + lockForUpdate on batch rows
- InsufficientStockException with requested + available context
- Auto-syncs parts.qty as aggregate cache (source of truth = sum(qty_remaining))
WO integration:
- WorkOrderPart created/updated → reserve from FIFO batches
- WorkOrderPart deleted → release
- WorkOrder status=done → consume reservations into issue events
- WorkOrder status=cancelled → release reservations
Filament:
- WarehouseResource (CRUD)
- BatchesRelationManager on PartResource (FIFO list with qty_remaining + cost)
- "Recepție" action on parts list → calls WarehouseService::receive
- qty_reserved column added on parts list
Tests (8 new, all pass):
- receipt creates batch + event
- FIFO order verified across 3 batches with different received_at
- InsufficientStockException on over-issue
- Reservations block other reservations but don't deplete on-hand
- WO done consumes; WO cancelled releases
- Batches tenant-isolated
- Transfer between warehouses with weighted-avg cost
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 19:29:19 +00:00
Vasyka
d5680f78dc
fix: column names in globalSearch (leads.source, vehicles.make, parts.article, WO.complaint)
2026-05-08 11:12:16 +00:00
Vasyka
0399262514
Deploy 3: Onboarding wizard + empty states + docs operationale
...
- 3-step onboarding wizard at /app/onboarding (auto-redirected via
RequireOnboarding middleware on first login per tenant)
- Empty states with icon + heading + description on Client, Vehicle,
WorkOrder, Lead, Part lists
- Docs: operations/{api,i18n,2fa,monitoring}.md, stack/reverb.md
- Updated 00-index.md and journal.md with status of all 15 items
2026-05-07 20:16:03 +00:00
Vasyka
d1e0695930
Deploy 1: i18n + Notifications + Global Search + Tests
...
- SetLocale middleware (ro/ru/en, session-first, user-persisted)
- Lang switcher in topbar (Filament render hook USER_MENU_BEFORE)
- POST /locale/{lang} route persists to user.locale + session
- Database notifications enabled on tenant panel (30s polling)
- GlobalSearch (Cmd+K / Ctrl+K) on Client, Vehicle, WorkOrder, Lead, Part
- Tests: TenantIsolation (4), AuthFlow (2), WorkOrderCalc (3), MarkupRule (3)
2026-05-07 18:22:48 +00:00
Vasyka
7264dccffa
Faza 3.3: Depozit — Furnizori + Catalog piese + Achiziții
...
Schema:
- suppliers: name, contact, phone/email/website, pay_terms, delivery_days,
rating (1-5), discount_pct, categories (JSON), is_active, notes
- parts: name, article (UNIQUE per tenant), brand, category, qty/unit/min_qty,
buy_price/sell_price, location (rack/bin), barcode, preferred_supplier_id,
is_active. Index pe (company_id, category) și (company_id, is_active).
- purchases: număr unique per tenant + an, supplier_id, status workflow
(draft/ordered/received/cancelled), order/expected/received/paid_at, total
- purchase_items: name, article, qty, unit, buy_price, total auto, received bool;
link opțional la part_id
- wo_parts + part_id: linkare opțională la catalog (alter migration)
Modele cu logică:
- Part::adjustStock($delta) — modifică qty cu validare ≥ 0
- Part::isLow() / isOut() helpers
- Purchase::markReceived() — atomic: marchează items ca received + creste qty
pe pieces din catalog (DB::transaction)
- WorkOrderPart::updating event — la trecerea status='installed' decrementează
stoc auto. La revenire (ex: storno) incrementează la loc.
- PurchaseItem::saving — total = qty * buy_price; recalc parent total
Filament resources (group Depozit):
- SupplierResource: form 3 secțiuni, rating ★★★★★, TagsInput pentru categorii
- PartResource: form 4 secțiuni, badge nav cu nr. piese sub stoc minim,
filtre low_stock + out_of_stock, coloană qty colorată după stoc
- PurchaseResource: form antet + RelationManager Items.
Action 'Recepționează' care apelează markReceived() — un click = stoc actualizat
WorkOrder PartsRelationManager updated:
- Selector din catalog (Part::active) cu stoc afișat
- Auto-fill name/article/brand/unit/buy_price/sell_price din piesa selectată
- Helper text: la status='installed' se scade din stoc
Widget low-stock:
- TableWidget pe dashboard tenant, listează piesele cu qty <= min_qty
- Span full, sortat după qty (cele mai critice sus)
Seed:
- 2 furnizori (AutoParts Moldova SRL ★5, Inter Cars Moldova ★4)
- 5 piese demo: Ulei Shell, Filtru Mann, Plăcuțe Brembo, Antigel (qty=0!), Bujii NGK
- 1 achiziție recepționată (P-26-0001) cu 2 articole linked la catalog
Total Filament tenant routes: 63 (de la 31).
2026-05-06 21:58:30 +00:00