Biashara ERP Enterprise Suite
← All guides

POS till authorization

Supervisor approvals for refunds, discounts, credit sales, cart edits, and owner-only payment methods.

POS till authorization

This document describes how cashier-sensitive POS actions are gated behind tenant administrator approval (owner, branch manager, or supervisor), and how that design reduces employee misuse.

Problem

Cashiers need fast checkout, but several actions carry financial or compliance risk if used without oversight:

  • Refunds and returns
  • Issuing customer invoices from the cart
  • Line discounts and line notes
  • Selling on account (credit)
  • Owner-restricted payment methods
  • Cart corrections (remove line, decrease quantity, clear cart, discard held sale)

Previously, only cart edits had a partial supervisor flow (owner-only dashboard approval). Refunds, invoices, and discounts relied on static role permissions that cashiers could not hold—but nothing stopped a cashier from attempting them in the UI, and server enforcement was inconsistent.

Design principles

  1. Server is authoritative — UI prompts are for UX; every sensitive endpoint re-checks authorization. A cashier cannot bypass approval by calling the API directly.
  2. Cashier-only gating — Supervisors and owners with the right permissions perform actions without a temporary grant.
  3. Time-limited grants — After approval, the cashier receives a short-lived cache grant (15 minutes for most actions; 25 minutes for cart-edit bucket).
  4. Two approval channels — Remote (dashboard) or physical (supervisor at counter with password). Fingerprint hardware can replace password verification in a future release using the same audit hook.
  5. Full audit trail — Requests and approvals are recorded as PosEvent entries (SUPERVISOR_REQUESTED, SUPERVISOR_APPROVED).

Protected actions

Action key What it covers
clear_cart Empty the active cart
remove_line Remove a cart line
decrease_qty Lower quantity on a line
discard_hold Delete a parked / held sale
refund_return Open or post sale returns
issue_invoice Create/issue invoice from POS cart
line_discount Line-level discount % or notes
sell_on_credit On-account payment method
owner_payment_method Payment methods flagged owner-only

Cart-edit actions share one grant bucket (cart_edit) so one approval unlocks all cart corrections for the window.

Roles and permissions

  • pos_till_approve — Assigned to owner, branch_manager, and supervisor. Allows listing pending requests and approving/dismissing them.
  • Approvers can also authorize at the counter by entering their own login password (verified with Hash::check).

Cashiers do not receive refund, discount, credit, or till-approve permissions.

Cashier experience (POS)

When a cashier triggers a protected action:

  1. The Administrator authorization dialog opens.
  2. At counter — Cashier selects a supervisor; supervisor enters their password. On success, a grant is stored in cache.
  3. Dashboard request — A PosSupervisorRequest row is created; administrators see it on the dashboard widget Till authorization requests.

The cashier can tap Check if approved to poll grant status after a remote approval.

Sensitive entry points wired in the UI:

  • Cart remove / qty down / clear
  • Footer Refund (F8)
  • Invoice from cart
  • Line details (discount / notes)
  • On-account and owner-only payment methods
  • Manager panel (F7) request buttons

Administrator experience (dashboard)

Users with pos_till_approve see pending requests with human-readable labels (e.g. “Refund / return”, “Issue invoice from cart”). Approve calls PosTillAuthorizationService::grant() for the specific action (or cart-edit bucket). Dismiss closes the request without granting access.

JSON API (for integrations or mobile supervisor apps):

  • GET /pos/supervisor-requests/pending
  • POST to each row’s approve_url or dismiss_url with session auth + CSRF

At-counter API (cashier session):

  • GET /pos/till-authorization/approvers
  • GET /pos/till-authorization/grants
  • POST /pos/till-authorization/verify-at-counter

Server enforcement

Endpoint / validator Check
SaleReturnController::create/store refund_return grant or refund_sales permission
PosCheckoutInvoiceController issue_invoice grant (cashiers)
StoreSaleRequest Grants for line discount, credit, owner payment methods
ParkedSaleController::destroy discard_hold grant or non-cashier
Cart edit unlock (existing) cart_edit bucket

Misuse prevention

Risk Mitigation
Cashier issues unauthorised refund Return routes return 403 without grant; UI requires approval first
Cashier discounts friends’ purchases Line discount blocked in StoreSaleRequest without grant; supervisor password logged on at-counter approval
Credit sales without approval On-account payment blocked client- and server-side without sell_on_credit grant
Invoice fraud before payment Invoice API requires grant for cashiers
Cart manipulation to hide theft Cart edits need approval; one destructive edit consumes cart grant (existing behaviour)
Supervisor collusion All approvals logged with approver user id, cashier id, action, and mode (dashboard vs at_counter)
Stale wide-open access Grants expire automatically (15–25 minutes); not persisted in DB
Cross-tenant approval Organization id matched on requests, approvers, and verify-at-counter

Fingerprint (future)

The at-counter flow is intentionally password-based today so it works on any device. The verifyAtCounter path records mode: at_counter in PosEvent; a biometric driver can call the same grant() + audit sequence after hardware verification without changing cashier or dashboard flows.

Key files

  • app/Support/Pos/PosTillAuthorizationAction.php — action constants and labels
  • app/Services/Pos/PosTillAuthorizationService.php — grants, verification, approver lists
  • app/Http/Controllers/PosSupervisorRequestController.php — dashboard requests
  • app/Http/Controllers/PosTillAuthorizationController.php — at-counter verify + grant polling
  • resources/js/pos-till-authorization.js — POS dialog and client orchestration
  • resources/views/dashboard/widgets/supervisor_requests.blade.php — dashboard widget
  • config/rbac.phppos_till_approve permission

Testing

Run:

php artisan test --filter=SupervisorPendingApiTest

Extend coverage for supervisor approver role and at-counter verification as the suite grows.

Ready to run your business on one platform?

14-day trial on entry tier · CRM & mass SMS · Industry-specific modules · Your own workspace subdomain