Skip to content

Sale Customers

Location: dg_smart_pos_api/modules/SaleCustomers. Owns a standalone, lightweight customer directory captured at the point of sale: a SaleCustomer is keyed by name (unique per store), can be auto-created silently when a cashier types a name that doesn’t match an existing one, and is deliberately separate from the base customers table (debtors/suppliers) and from Repair’s own RepairCustomer.

Gated per store by the maintain_customer_data system config, enforced by the system.config:maintain_customer_data route middleware on the whole route group, confirmed in modules/SaleCustomers/Routes/sale_customers.php. App\Services\SaleService and Modules\Sales\Services\Api\SalesService both check the same flag directly before calling into this module; when it’s off, sale write paths skip customer linking entirely rather than calling in for a no-op.

  • SaleCustomer - name, store (FK to stores, unique together with name), phone, soft-deletable. email and shipping_address are declared $fillable on the model (shipping_address cast to array), but neither column exists in the module’s migration; only id, name, store, phone, timestamps, deleted_at, and deleted_by are actually created. No current controller code sets either field, so this is unused rather than actively broken, but don’t assume they can be written to yet.

SaleCustomerController::index/store/update/destroy is plain CRUD scoped to a store, with name required unique per store (sale_customers_store_name_unique) and phone validated against a Kenyan local-format regex (a leading 0 followed by 9 digits).

SaleCustomerLinkingService::resolve() is the entry point sale write paths call when maintain_customer_data is on: given a typed customer_id, name, and phone, it resolves to a saved SaleCustomer, first by ID, then by a case-insensitive trimmed name match, then by creating a new row. Creation races are handled explicitly: a unique-constraint violation on (store, name) falls back to re-fetching and linking to whichever concurrent request won.

All under auth:sanctum + system.config:maintain_customer_data, prefix store/{store}/sale-customers (note: not the {module}/stores/{store} + REST convention most other modules use), registered via modules/SaleCustomers/Routes/sale_customers.php (required once from routes/tenant.php):

Method Path Controller method
GET all index
POST add store
PUT {customer}/edit update
DELETE {customer}/delete destroy
  • Sales - sale write paths call SaleCustomerLinkingService
  • Repair - separate customer directory, don’t conflate the two