Skip to content

Commission sheets

Commission sheets let the store pay employees a per-product commission when the product sells. A sheet is a named bundle of (1) the scope it applies to, and (2) the products it covers, with a configurable rate per item.

Use it to:

  • Define a “Bảng hoa hồng nhân viên quầy” sheet that pays 5% on every item in the store.
  • Build a region-specific sheet that only applies to a few branches.
  • Set a flat VND amount on a single hot product (e.g. ₫2,000 per Coca Cola sold).

Open More → Commission Setup on the mobile POS workspace, or call the matching NestJS endpoints directly from the vendor-web HR editor (see the API catalog under Vendor commissions).

A sheet has:

FieldWhat it means
NameDisplay title shown in the list.
Scopeall (Toàn hệ thống) or branches (a chosen list of stores).
Branch listFilled in only when scope === 'branches'.
ItemsProducts attached to the sheet — each with its own rate (VND or %).
NoteOptional free-form admin note (Vietnamese product copy OK).
Item countCached count of attached products — surface in the list pill.
  • all (Toàn hệ thống) — applies vendor-wide. Use for store-wide incentives (“5% on every snack for the month”).
  • branches — restricted to the explicit branch list. Use when one region needs a different rate (e.g. the HCM store runs a different promo than the HN store).

You can edit the scope after creation — toggling all ↔ branches clears the branch list (or vice versa) on the next attach.

  1. Open More → Commission Setup on the mobile POS workspace.
  2. Tap the + floating action button in the bottom-right.
  3. Type the sheet name (e.g. “Bảng hoa hồng Q4”).
  4. Pick a scope:
    • Toàn hệ thống — no branch list needed.
    • Chi nhánh — pick one or more branches from the multi-select.
  5. Optionally add a note.
  6. Tap Save. The screen returns to the sheet list with the new sheet at the top.

The new sheet starts with 0 sản phẩm until you attach products.

  1. Open the sheet, then tap Thêm hàng hoá.
  2. The product picker shows every active item from the live catalog (GET /vendor/products). Search by name, SKU, or scan a barcode.
  3. Pick the products. The picker sends the full selection on Save — replacing whatever was attached before (see “Replace-all” below).
  4. Optional: tap Mức hoa hồng mặc định before saving to apply the same rate to every attached row.

The backend wipes the prior item set before inserting the new one. This keeps the mobile UX predictable — the picker always reflects the current selection, never an unintended union of old + new picks.

If you add Coca Cola + Pepsi then reopen and add only Aquafina, the sheet ends up with just Aquafina (not all three).

Each row has its own rate. The unit can be:

  • vnd — flat VND amount per sale. e.g. 2000 means ₫2,000 per item sold.
  • percent — percent of the product price. e.g. 5 means 5% of the displayed price.

Switch the unit by tapping the VND / % toggle next to the input.

The Lợi nhuận tạm tính column shows max(0, price − commission_in_vnd) so you can sanity-check the rate before committing.

Tap a row’s rate input, type a value, and tap away. The change saves immediately and the Lợi nhuận tạm tính recomputes.

Tap the Mức hoa hồng modal trigger at the top of the items screen to apply the same rate to every row on the sheet. Use it after a fresh attach to seed a default rate, or to align all items to a new policy.

The current mobile screens do not yet feed commissions into payroll — the sheet is the definition of the rule, the payroll run is what consumes it. When payroll runs for a given store and period:

  1. The system reads the matching sheets (origin store OR any sheet whose branch list includes the store).
  2. For every sold item, it sums the matching sheet’s rate × quantity sold.
  3. The total becomes the commission_total line on the payslip for that employee.

This integration is in flight; today the sheets surface as a configured catalog of rules that the operator can review and tune.

MethodPathPurpose
GET/api/v1/vendor/commissionsList sheets for the vendor (filter by store, paginated).
POST/api/v1/vendor/commissionsCreate a sheet.
GET/api/v1/vendor/commissions/:id/itemsList attached items on a sheet.
POST/api/v1/vendor/commissions/:id/itemsAttach products (replace-all).
PATCH/api/v1/vendor/commissions/:id/items/:itemIdUpdate one item’s rate.
PATCH/api/v1/vendor/commissions/:id/items/bulkApply the same rate to every item on the sheet.

All routes require the commission vendor module (owner JWTs bypass). Vendor scope is enforced server-side; a cross-vendor id resolves to 404 Not Found so we never leak IDs.

  • id — 13-char Crockford Base32, minted by PublicIdSubscriber on insert.
  • scope — 'all' | 'branches'.
  • commission_unit — 'vnd' | 'percent'.
  • price, commission_value, estimated_profit — DECIMAL(15,0) (VND, no decimals).

See apps/backend/src/database/migrations/2000000000205-CreateVendorCommissionSheetsAndItemsTables.ts for the full DDL.

  • Sheet visible only on the active store — the list filters by activeStoreId. Switch stores in the top bar to see sheets anchored to other branches.
  • Replace-all wipes your picks — reopening the picker and saving a smaller selection removes the products you unchecked. This is intentional; if you meant to add, tap each item again before saving.
  • Branch list is required when scope === 'branches' — the DTO rejects the request with 400 if you forget.
  • % rates round to VND at attach time — 5% of ₫10,000 becomes ₫500 stored in commission_value. Re-compute when prices change.
  • Owner vs employee — the commission module key ships off by default for employees. Grant it via Settings → Roles → Modules if a manager should be able to edit commission sheets.