Workflow: Sales Agent Commission
Modules involved: Invoices · Payments · Commission (Policy · Applicable Staff · Hierarchy · Receipt) · Sales Agent · Goals · DataPulse
Who uses it: Sales Manager · Sales Agents · Finance Administrator
Typical duration: Instantaneous after invoice payment (automatic trigger) + monthly cycle for commission payout
Overview
The Commission module automatically calculates the commission owed to a sales agent the moment an invoice is paid. No manual action is required for the actual calculation — everything is triggered by the after_payment_added hook. The full workflow covers: commission policy configuration, assigning agents to policies, automatic calculation upon payment, viewing accumulated commissions, and actual payout through issuing a Commission Receipt.
Note: Commission is calculated only on standard CRM invoices (
tblinvoices). Invoices from the Sales Agent module (sa_sale_invoices) do not trigger commission.
Flow diagram
[CONFIGURATION — once only]
│
├── Commission Policy (type 1–5, date range, percentage/scale)
├── Applicable Staff → assign agent to policy
├── Hierarchy (optional) → coordinator receives % of agent's commission
└── General options → calculate_after_days · payment_trigger_mode
│
↓
[INVOICING]
│
├── Invoice created → sale_agent set on invoice (or on client/group)
└── Invoice status: Draft → Sent
│
↓
[INVOICE PAYMENT — automatic trigger]
│
├── Payment recorded → after_payment_added hook fires
├── System checks: invoice age ≥ calculate_after_days?
├── System checks: payment_trigger_mode?
│ 'partial_allowed' (default) → any payment > 0 generates commission
│ 'full_only' → commission only if sum of payments = invoice total
├── System checks: invoice eligible? (not voided, valid status)
└── System resolves agent: sale_agent on invoice → customer_admin of client
→ commission_salesadmin_group (client group → agent)
│
↓
[COMMISSION GENERATED]
│
├── Row created in tblcommission: staffid, invoice_id, amount, paid=0
├── Types 1–4: calculated immediately per invoice
└── Type 5 (monthly/margin): calculated by cron on commission_month_close_day
│
↓
[APPROVAL / VIEWING]
│
├── Manager → /admin/commission → sees commissions with paid=0
├── Agent → sees their own commissions (permission commission_manage → view)
└── Reports: commission_chart · staff_monthly_dashboard
│
↓
[COMMISSION PAYOUT]
│
├── Manager creates Commission Receipt: selects unpaid commissions
├── Receipt can be converted to Expense (for accounting records)
└── Selected commissions → paid=1 in tblcommission
│
↓
[COMMISSION PAID ✓]
Step by step
1. Initial configuration (admin)
1a. Commission policy
Where: /admin/commission → Commission Policy → New Policy
There are 5 policy types (commission_policy_type):
| Type | Name | How it works |
|---|---|---|
1 |
Ladder — invoice total | Different percentages on value tiers of the total invoice |
2 |
Flat percentage | Fixed percentage applied to invoice total (or profit, if amount_to_calculate=1) |
3 |
Per-product with quantity tiers | Different percentages per product based on quantity |
4 |
Ladder per product | Scale on individual product values |
5 |
Monthly margin (staff monthly) | Calculated at month end based on net margin; requires staff_margin_settings JSON |
Essential fields when creating:
| Field | Required | Notes |
|---|---|---|
name |
Yes | Descriptive name for the policy |
policy_scope |
Yes | vendor (for vendors/clients) or staff (for employees) |
from_date / to_date |
Yes | Policy validity range |
commission_type |
Yes | percentage or fixed amount |
payment_trigger_mode |
Yes | partial_allowed (default) or full_only |
calculate_after_days |
No | Days to wait after payment before calculating commission (0 = immediately) |
amount_to_calculate |
No | 0 = invoice total, 1 = profit (difference from product cost) |
commission_tax_mode |
No | without_tax (default) or with_tax |
Important: If
calculate_after_daysis negative, the system automatically uses 14 days.
1b. Assigning an agent to a policy
Where: /admin/commission → Applicable Staff → Add
Links an employee (staffid) to a policy (commission_policy_id) through the tblcommission_applicable_staff table. An agent can be assigned to multiple policies with different dates.
For vendor/client type commissions: Applicable Client (set is_client=1 and commission_receiver_vendor_id on the client record).
1c. Commission hierarchy (optional)
Where: /admin/commission → Settings → Hierarchy
Allows a coordinator to receive a percentage of the commission of the agent under their supervision:
| Field | Description |
|---|---|
salesman |
staffid of sales agent |
coordinator |
staffid of coordinator/manager |
percent |
% of agent's commission received by the coordinator |
1d. General options
Where: /admin/commission → Settings → Commission General
| Option | Default value | Description |
|---|---|---|
commission_payment_trigger_mode |
partial_allowed |
Global (can be overridden per policy) |
commission_calculate_after_days |
0 |
Global waiting days |
commission_cron_interval_minutes |
1440 (24h) |
Backup cron for commissions missed by hook |
commission_month_close_day |
1 |
Day of month on which type-5 is calculated (for previous month) |
2. Resolving the agent on an invoice
When an invoice is paid, the system determines the agent in this order:
invoices.sale_agent— agent set directly on the invoicetblcustomer_admins.staff_id— the client's account admin (ifsale_agentis empty)tblcommission_salesadmin_group— client group → agent mapping (if the first two are empty)
Gotcha: If none of the three is configured, no commission is generated and no alert appears. Always verify that invoices have
sale_agentset or that clients have a customer admin.
3. Automatic calculation upon payment
When a payment is recorded (/admin/invoices/:id → Add Payment or via API), the after_payment_added hook calls Commission_model::add_commission($payment_id).
System checks performed (if any fail, commission is NOT generated):
| Check | Detail |
|---|---|
| Invoice age | Invoice date + calculate_after_days ≤ today |
| Invoice status | Status must NOT be in [5=cancelled, 6=draft, 7=credit note, 8=internal] |
| Voiding | Invoice does not have an associated credit note |
| Trigger mode | If full_only: sum of all payments = invoice total |
Fallback cron: Every commission_cron_interval_minutes minutes, a job checks invoices with payments that missed the hook and generates missing commissions.
Manual regeneration (admin):
- On invoice: Regenerate Commission button
- Bulk:
/admin/commission→ Recalculate (requirescommission → createpermission)
4. Type 5 commissions — Monthly margin
Different from types 1–4: calculation is not done per payment, but monthly via cron.
On day commission_month_close_day of the month (default day 1), run_staff_monthly_commissions() calculates for the previous month:
- Aggregates all paid invoices from that month per agent
- Calculates net margin (
sales_net,avg_margin,avg_discount) - Applies tiers from
staff_margin_settingsJSON - Writes to
tblcommission_staff_monthly(status:draft) - Writes per-invoice details to
tblcommission_staff_monthly_detail
5. Viewing and approving commissions
Where: /admin/commission
| Section | Who sees it | What it shows |
|---|---|---|
| Commission List | Admin + commission_manage → view |
All commissions with paid=0 |
| Staff Monthly Dashboard | Admin + commission_manage → view |
Monthly summary per agent, draft status |
| Commission Chart | Admin + commission_manage → view |
Commission trend charts |
| Agent (own) | Staff with commission_manage → view |
Their own commissions only |
6. Commission payout
Where: /admin/commission → Commission Receipts → New Receipt
Steps:
- Select unpaid commissions (
paid=0) to include in the payout - Fill in:
amount,paymentmode,date,note,transactionid - Save → system marks all selected
tblcommissionentries withpaid=1 - Optional: check Convert to Expense to automatically generate an expense in the Expenses module (for accounting records)
Required permissions: commission_receipt → create + commission_receipt → view
Required permissions
| Role / Permission | Access |
|---|---|
| Admin | Full access to all functions |
commission_manage → view |
View commissions, charts, monthly reports |
commission → create |
Bulk recalculation |
commission → view_setting |
Access to Settings |
commission_receipt → view/create/edit/delete |
Manage payment receipts |
commission_applicable_client → view/create/delete |
Manage applicable clients |
Gotchas
| Problem | Cause | Solution |
|---|---|---|
| Commission not generated after payment | sale_agent missing on invoice, expired policy, or calculate_after_days not met |
Check sale_agent field on invoice + policy dates + after_days setting |
full_only does not generate on partial payment |
Correct behavior — commission only appears on full payment | Switch to partial_allowed if you want commission on each installment |
| Commission generated twice | Both cron and hook ran | System checks for an existing row in tblcommission per invoice_id+staffid before insert — duplicate is blocked |
| Agent does not appear in Applicable Staff dropdown | User does not have active Staff role | Verify that the user is an active Staff member in the system |
| Type-5 not calculated | commission_month_close_day has not passed or cron has not run |
Check the day setting and verify CRM cron is active (/admin/misc/cron_jobs) |
Module references
- Commission — reports
- Invoices — the
sale_agentfield - Payments — payment trigger
- Sales Agent — discount programs (separate from commission)
- Goals — targets per agent
- DataPulse — team performance dashboard