Repair
Location: dg_smart_pos_api/modules/Repair. Owns the repair-shop job card workflow end to end: intake (from a walk-in customer, or from a device already in shop stock), diagnosis and status tracking, parts consumption from stock, outsourcing to third-party vendors, payments, and collection. It uses its own RepairCustomer model, entirely separate from Sale Customers, and moves stock through RepairStockService, which calls Modules\Inventory\Services\InventoryAdjustmentService, rather than owning stock adjustments itself.
Gated per store by the enable_repair_module system config, enforced by the system.config:enable_repair_module route middleware on the whole route group, confirmed in modules/Repair/Routes/repair.php.
Data model
Section titled “Data model”RepairJobCard- the job itself: source (customer/shop_stock), item details, dates, amounts computed on the model (laborAmount(),partsTotal(),paidTotal(),balance()), currentstatus.RepairJobCardPart- a stock part consumed on a job.RepairJobCardPropertyValue- a value for one of the item type’s custom properties.RepairCustomer- repair-specific clientele (a phone lookup may return several; distinct fromSaleCustomerand from the basecustomerstable).RepairItemType/RepairItemTypeProperty- configurable device categories and their custom fields.RepairVendor- an outsourcing vendor.RepairOutsourcing- a job sent to a vendor.RepairPayment- a payment against a job.RepairStatusHistory- an audit trail row per status transition.RepairJobCounter- backs sequentialjob_numbergeneration (RepairJobNumberService).
Intake
Section titled “Intake”RepairJobCardController::store takes source (customer or shop_stock), either a repair_customer_id or inline customer details (name/phone required together), optional custom property_values, and an optional initial_payment. If source is customer (the default), the request is rejected unless an existing client or a new name+phone is supplied. If source is shop_stock, stock_id is required and RepairJobCardService::create calls RepairStockService::deviceOut, moving the device out of sellable inventory via InventoryAdjustmentService (action RepairOut).
Status transitions
Section titled “Status transitions”RepairJobCardController::transition moves a job through RepairStatus’s explicit transition graph (RepairStatus::allowedTransitions()): received -> diagnosing -> {awaiting_approval, in_repair} -> ... -> {repaired, unrepairable} -> collected, with cancelled reachable from every non-terminal state up through in_repair. repaired and unrepairable can only move on to collected; collected and cancelled are terminal. A job card’s other fields can no longer be edited once its status is terminal (isTerminal()).
Collection
Section titled “Collection”RepairJobCardController::collect is the endpoint that actually closes out a customer job: RepairPartService::collect sells the consumed parts through a real POS sale, records any remaining labor balance as a RepairPayment, and transitions the job to collected, all in one transaction. Waiving an outstanding balance (waive_balance) requires the caller to be an admin, checked inline in the controller by matching role names, rather than through the permission: middleware the rest of the module uses.
Parts and outsourcing
Section titled “Parts and outsourcing”RepairPartController::store draws a part from stock onto a job card; writeOff marks a part unusable without returning it to stock. RepairOutsourcingController sends a job to a RepairVendor and updates it on return.
Route surface
Section titled “Route surface”All under auth:sanctum + system.config:enable_repair_module, prefix repairs/stores/{store}, registered via modules/Repair/Routes/repair.php (required once from routes/tenant.php):
| Method | Path | Controller method | Permission |
|---|---|---|---|
| POST | item-types |
RepairItemTypeController::store |
store:edit-settings |
| PUT | item-types/{itemType} |
RepairItemTypeController::update |
store:edit-settings |
| DELETE | item-types/{itemType} |
RepairItemTypeController::destroy |
store:edit-settings |
| POST | item-types/{itemType}/properties |
RepairPropertyController::store |
store:edit-settings |
| PUT | properties/{property} |
RepairPropertyController::update |
store:edit-settings |
| DELETE | properties/{property} |
RepairPropertyController::destroy |
store:edit-settings |
| POST | vendors |
RepairVendorController::store |
store:edit-settings |
| PUT | vendors/{vendor} |
RepairVendorController::update |
store:edit-settings |
| DELETE | vendors/{vendor} |
RepairVendorController::destroy |
store:edit-settings |
| GET | item-types |
RepairItemTypeController::index |
(none) |
| GET | item-types/{itemType}/properties |
RepairPropertyController::index |
(none) |
| GET | vendors |
RepairVendorController::index |
(none) |
| GET | vendors/{vendor}/summary |
RepairVendorController::summary |
(none) |
| GET | customers |
RepairCustomerController::index |
(none) |
| POST | customers |
RepairCustomerController::store |
(none) |
| PUT | customers/{customer} |
RepairCustomerController::update |
(none) |
| GET | job-cards |
RepairJobCardController::index |
(none) |
| GET | job-cards/stats |
RepairJobCardController::stats |
(none) |
| POST | job-cards |
RepairJobCardController::store |
(none) |
| GET | job-cards/{jobCard} |
RepairJobCardController::show |
(none) |
| PUT | job-cards/{jobCard} |
RepairJobCardController::update |
(none) |
| POST | job-cards/{jobCard}/status |
RepairJobCardController::transition |
(none) |
| POST | job-cards/{jobCard}/collect |
RepairJobCardController::collect |
(none) |
| POST | job-cards/{jobCard}/payments |
RepairPaymentController::store |
(none) |
| DELETE | payments/{payment} |
RepairPaymentController::destroy |
sales:delete |
| POST | job-cards/{jobCard}/parts |
RepairPartController::store |
(none) |
| DELETE | parts/{part} |
RepairPartController::destroy |
(none) |
| POST | parts/{part}/write-off |
RepairPartController::writeOff |
(none) |
| POST | job-cards/{jobCard}/outsourcings |
RepairOutsourcingController::store |
(none) |
| PUT | outsourcings/{outsourcing} |
RepairOutsourcingController::update |
(none) |
“(none)” means only auth:sanctum and the module-enabled gate apply, no permission: middleware wraps that specific route.
Related
Section titled “Related”- Inventory - parts and device stock movements
- Sales -
collectcreates a real POS sale - Sale Customers - separate, unrelated customer directory
- Analytics