BDS commission is a two-part flow: admins upload commission rules (Excel) per insurer, month, and department; partner/BDS systems then call an API to calculate payout for a policy using those rules.
In short:
RuleImportController + commission_file_upload.php — import and manage rules.POST getCommission → InsuranceCommissionController::initiateCommissionCalc — read JSON, pick first matching rule, return payout.writable/uploads/commission/rules/{MONYYYY}/{insurer_id}_{department}.json (e.g. SEP2025/5_motor.json).| Part | File |
|---|---|
| Upload list UI | app/Views/commission_file_upload.php |
| Rules editor UI | app/Views/commission_rules_list.php |
| Upload and editor API | app/Controllers/RuleImportController.php |
| Excel parsing | ruleImportService (via Config\Services::ruleImportService()) |
| Payout calculation API | app/Controllers/InsuranceCommissionController.php |
| Upload metadata DB | commission_files (CommissionFilesModel) |
Admin (commission group):
| Route | Handler |
|---|---|
GET/POST commission/list | commissionFileUploadList |
POST commission/upload | upload |
GET commission/sample_file | Sample CSV download |
GET commission/downloadErrorFile | Annotated error Excel |
GET commission/checkSameEntry | Duplicate insurer + month + department check |
GET commission/rules/list/(:id) | ruleList — rules editor page |
POST commission/rules/save/ | saveRule |
POST commission/rules/remove/ | removeRule |
GET commission/checkRuleUsage | Whether rule is used on partner policies |
GET commission/deleteCommissionData/(:id) | Soft-delete file + mark rules deleted |
Runtime API:
POST getCommission
→ InsuranceCommissionController::initiateCommissionCalc
→ filter: CommissionApiFilter
Use the template from the upload screen (Download sample file) or copy from
public/sample_excel/sample_commission.csv. Dev copies also live under
writable/uploads/commission/files/ (e.g. sample_commission.csv,
Sample_commission_file-New.xlsx). After a successful import, see the generated JSON under
writable/uploads/commission/rules/{MONYYYY}/ (example: NOV2025/1_motor.json).
writable/uploads/commission/files/ use legacy headers
(Rule Name, Commission Params(TP:OD:PA)). The importer expects the
S.No layout below (RuleImportService). Wrong headers fail with
“Missing required columns”.
Header text must match exactly (one row per rule, starting row 2). Empty cells are allowed and simply skip that condition.
| Column | Purpose | Example |
|---|---|---|
| S.No | Serial (not used in logic) | 1 |
| Premium Type | Maps to policy_type | OD, TP, COM |
| Vehicle Type | vehicle_type; comma = multiple (IN) | Two Wheeler, Four Wheeler |
| Vehicle Sub Type | vehicle_sub_type | Car, PCV |
| Make / Model | Vehicle make and model | Honda, i10 |
| CC Min / CC Max | Cubic capacity range | 1000, 3000 |
| Fuel Type | Comma-separated fuels | Petrol, Diesel |
| Vehicle Age Min / Max | Vehicle age range (years) | 1, 5 |
| Vehicle Weight Min / Max | Weight range (kg) | 2000, 3000 |
| RTO State / RTO Code | geo_rto_state, geo_rto_city | RJ, 41 |
| Renewal Type | renewal_type | Online, Cash, Card |
| Commission Type | percentage, composite, flat, tiered | percentage |
| Commission Value | % or flat amount (required for percentage / flat) | 15 or 500 |
| Commission Params (TP) | Composite: % on TP premium | 18 |
| Commission Params (OD) | Composite: % on OD premium | 10 |
| Commission Params (PA) | Composite: % on PA premium | 0 or empty |
| Type | Fill in sheet | Becomes in JSON |
|---|---|---|
percentage |
Commission Value = e.g. 10 |
10% of premium |
composite |
Leave Value empty; set TP / OD / PA param columns (percent each) | Split % on tp_premium, od_premium, pa_premium |
flat |
Commission Value = fixed rupee amount e.g. 500 |
Fixed payout on premium |
Template header + rows (public/sample_excel/sample_commission.csv):
S.No,Premium Type,Vehicle Type,...,Commission Type,Commission Value,Commission Params (TP),Commission Params (OD),Commission Params (PA)
1,OD,Car,...,percentage,15,,,
2,TP,Two Wheeler,...,composite,,18,10,
3,COM,PCV,...,percentage,25,,,
4,COM,GCV,...,composite,,,10,
Example A — composite two-wheeler (from writable/.../rules/NOV2025/1_motor.json):
Two Wheeler, CC Min/Max = 100composite, TP = 10, OD = 25Example B — percentage four-wheeler:
Four Wheeler, CC = 1000, Vehicle Age Min/Max = 5percentage, Commission Value = 10Example C — composite TP-only:
TP, Vehicle Type = Four Wheelercomposite, Commission Params (TP) = 10Example D — flat amount:
Two Wheeler,Four Wheeler (comma → matches either)flat, Commission Value = 500Tips:
.csv, .xlsx, .xls, .ods.motor, health; import logic is built for motor columns today.From commission_file_upload.php the user picks insurer, commission month, department (motor / health), and an Excel/CSV file.
checkSameEntry — if a successful upload already exists for the same trio, SweetAlert offers Overwrite or Append (overwrite=1 or 0 on POST).upload — stores file under writable/uploads/commission/files/, inserts commission_files row (pending).ruleImportService->processUpload() — validates Excel rows; on success returns rules array; on failure returns annotated_file for download.rules/{MONYYYY}/{insurer_id}_{department}.json; sets file_status=success and rules_count.file_status=failed; user downloads annotated_{filename} via downloadErrorFile.
For successful uploads, action View Rules opens
commission/rules/list/{file_id} (commission_rules_list.php).
saveRule — create or update a rule (conditions + calculation + name) in the JSON via updateCommissionRules().removeRule — soft-delete one rule (is_deleted=true).checkRuleUsage — warns if partner_policy.commission_applied_rule references the rule.file_id as deleted in JSON, then sets commission_files.is_active=0.Each rule is roughly:
{
"id": "rule_…",
"name": "Rule name",
"department": "motor",
"file_id": 12,
"is_deleted": false,
"conditions": [
{ "field": "vehicle_type", "operator": "==", "value": "car" }
],
"calculation": {
"type": "percentage",
"value": 10,
"on": "premium"
}
}
Calculation types in InsuranceCommissionController: percentage, composite, fixed. Conditions support ==, !=, >, >=, <, <=, between, in.
initiateCommissionCalc() expects POST/JSON including at least:
policy_issue_date — used to pick folder {MON}{YEAR} (e.g. SEP2025)insurer_iddepartment — motor, health, etc.premium, od_premium)Rules with is_deleted: false are loaded; the first matching rule wins (no priority field yet).
/commission/list (logged-in admin).POST getCommission with the same insurer, department, and a policy_issue_date in that commission month.policy_issue_date to resolve the same MONYYYY folder.status and code in the JSON body, not only HTTP status.