User shared their actual published service-rate card. Bundle 9's seeded
numbers were placeholders that no longer match. Realigned the rate card,
added the LIFT & ELEVATING SERVICE class, added the in-shop labour
rate path, added the delivery / pickup charge model, added rush as a
proper tier (distinct from after-hours), and added 30-min increment
rounding on top of the existing 1-hour minimum.
EQUIPMENT CLASS
fusion.repair.product.category gets a new x_fc_equipment_class
selection: 'standard' vs 'lift_elevating'. The published card splits
pricing into two service classes - lift_elevating has higher rates
($160 callout vs $95, $110/h vs $85).
Categories marked lift_elevating in seed:
stairlift, porch_lift, lift_chair (new)
New 'Lift Chair' category seeded (power recliner / lift chair).
CALLOUT RATE CARD
fusion.repair.callout.rate gets:
- equipment_class field (standard / lift_elevating)
- in_shop_labor_rate field (separate $75 vs $85 on-site)
- 'rush' tier value (was missing - rush was implicit via emergency
surcharge from Bundle 8; now a proper tier matching the printed
rate card row 'Rush Service Calls $120')
Re-seeded with the PUBLISHED Westin rate card (exact values):
STANDARD SERVICE
regular $95 callout / $85/h on-site / $75/h in-shop
rush $120 callout / $85/h / $75/h
after_hours $140 callout / $85/h / $75/h
weekend $180 callout / $85/h / $75/h (extension)
holiday $220 callout / $85/h / $75/h (extension)
LIFT & ELEVATING SERVICE
regular $160 callout / $110/h on-site / $110/h in-shop
rush $200 callout / $110/h / $110/h (extension)
after_hours $240 callout / $110/h / $110/h (extension)
weekend $300 callout / $110/h / $110/h (extension)
holiday $360 callout / $110/h / $110/h (extension)
Travel: $0.70 per km, BOTH WAYS, past 25 km, per technician
(matches the per-card '$0.70 per km x 2-way' footnote).
get_for_tier(tier, equipment_class) now resolves with a fallback:
tries (tier, lift_elevating) first, falls back to (tier, standard)
if no lift-specific row exists - so an admin can leave standard rows
as the catch-all and only customise lift for the exceptions.
DELIVERY / PICKUP RATE CARD
New fusion.repair.delivery.charge model + seed of all 7 items from
the printed card:
Local Service Area (within Brampton) ........ $35
Outside Local Area .......................... $60
Rush Pickups / Delivery ..................... $60 + $0.70/km x 2-way
Lift Chair Delivery and Set-Up .............. $120
Hospital Bed Delivery and Set-Up ............ $120
Stairlift Delivery and Set-Up ............... $300
Stairlift Removal ........................... $300
quote_rush(distance_km) helper for the office's delivery scheduling.
New menu: Configuration > Delivery / Pickup Charges.
PRICING ENGINE UPDATES (repair.order._compute_callout_quote)
- Class-aware rate lookup (uses category.equipment_class).
- In-shop mode (x_fc_in_shop=True): skips callout fee + extra-tech +
travel; charges in_shop_labor_rate * hours * techs only. Per the
rate-card footnote 'In-Shop Labour Rate'.
- 30-min increment rounding ON TOP of the 1-hour floor:
billable_h = max(ceil(actual * 2) / 2, min_hours)
-> 20-min work bills 1.0 h
-> 75-min work bills 1.5 h
-> 95-min work bills 2.0 h
- Improved breakdown text shows the rate-card row name + class +
pro-ration math so the client can see how the total was computed.
NEW FIELDS
repair.order:
x_fc_in_shop (Boolean) - flip to switch the quote engine to
in-shop mode.
x_fc_callout_tier now includes 'rush' as a value (was missing).
visit-report wizard:
callout_in_shop related field - tech can flip the mode on-site if
the work was actually done in-store after pickup.
MIGRATION SCRIPT
migrations/19.0.2.1.0/post-migration.py runs once on existing
installs:
1. Updates stairlift / porch_lift / lift_chair categories
equipment_class -> lift_elevating
2. Wipes the 4 Bundle 9 rate-card xml_ids so the new noupdate=1
seed creates them with the correct printed values.
Fresh installs get the right values directly from the seed XML.
Admin-created custom rate rows (no xml_id) are NEVER touched.
VERIFIED END-TO-END (0 bugs across 28 checks)
Rate card matches printed values exactly:
regular/standard = $95/$85h/$75h PASS
rush/standard = $120/$85h/$75h PASS
after_hours/standard = $140/$85h/$75h PASS
regular/lift = $160/$110h/$110h PASS
Six end-to-end quote scenarios:
A. Standard 12km 20-min -> $180 ($95 + 1h*$85)
B. Lift 12km 20-min -> $270 ($160 + 1h*$110)
C. Rush 30km 1.2h -> $254.50
($120 + ceil(2.4)/2=1.5h * $85 + 5km*2*$0.70 = $7)
D. After-hours lift 2-tech 35km 2.6h -> $928.00
($240 + ceil(5.2)/2=3.0h * $110 * 2 + 10km*2*$0.70*2)
E. In-shop standard 2h -> $150 (2h * $75 in-shop, no callout)
F. In-shop lift 1.5h -> $165 (1.5h * $110 in-shop)
Seven delivery rates loaded with correct amounts; rush 40km calc
= $81 ($60 base + 15km*2*$0.70).
Stairlift / Porch Lift / Lift Chair categories correctly marked
lift_elevating; rest stay standard.
Bumped to 19.0.2.1.0.
Co-authored-by: Cursor <cursoragent@cursor.com>
7.0 KiB
7.0 KiB
| 1 | id | name | model_id:id | group_id:id | perm_read | perm_write | perm_create | perm_unlink |
|---|---|---|---|---|---|---|---|---|
| 2 | access_repair_product_category_user | Repair Category User Read | model_fusion_repair_product_category | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 3 | access_repair_product_category_manager | Repair Category Manager Full | model_fusion_repair_product_category | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 4 | access_repair_intake_template_user | Intake Template User Read | model_fusion_repair_intake_template | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 5 | access_repair_intake_template_manager | Intake Template Manager Full | model_fusion_repair_intake_template | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 6 | access_repair_intake_question_user | Intake Question User Read | model_fusion_repair_intake_question | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 7 | access_repair_intake_question_manager | Intake Question Manager Full | model_fusion_repair_intake_question | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 8 | access_repair_intake_answer_user | Intake Answer User Full | model_fusion_repair_intake_answer | group_fusion_repairs_user | 1 | 1 | 1 | 0 |
| 9 | access_repair_intake_answer_manager | Intake Answer Manager Full | model_fusion_repair_intake_answer | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 10 | access_repair_intake_answer_tech_portal | Intake Answer Technician Read | model_fusion_repair_intake_answer | fusion_tasks.group_field_technician | 1 | 0 | 0 | 0 |
| 11 | access_repair_intake_wizard_user | Intake Wizard User Full | model_fusion_repair_intake_wizard | group_fusion_repairs_user | 1 | 1 | 1 | 1 |
| 12 | access_repair_intake_wizard_equipment_user | Intake Wizard Equipment User Full | model_fusion_repair_intake_wizard_equipment | group_fusion_repairs_user | 1 | 1 | 1 | 1 |
| 13 | access_repair_service_catalog_user | Catalogue User Read | model_fusion_repair_service_catalog | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 14 | access_repair_service_catalog_manager | Catalogue Manager Full | model_fusion_repair_service_catalog | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 15 | access_repair_warranty_user | Warranty User Read | model_fusion_repair_warranty_coverage | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 16 | access_repair_warranty_manager | Warranty Manager Full | model_fusion_repair_warranty_coverage | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 17 | access_repair_visit_report_wizard_user | Visit Report Wizard User | model_fusion_repair_visit_report_wizard | group_fusion_repairs_user | 1 | 1 | 1 | 1 |
| 18 | access_repair_visit_report_wizard_line_user | Visit Report Line User | model_fusion_repair_visit_report_wizard_line | group_fusion_repairs_user | 1 | 1 | 1 | 1 |
| 19 | access_repair_maintenance_user | Maintenance Contract User Read | model_fusion_repair_maintenance_contract | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 20 | access_repair_maintenance_dispatcher | Maintenance Contract Dispatcher | model_fusion_repair_maintenance_contract | group_fusion_repairs_dispatcher | 1 | 1 | 1 | 0 |
| 21 | access_repair_maintenance_manager | Maintenance Contract Manager Full | model_fusion_repair_maintenance_contract | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 22 | access_repair_order_repairs_user | Repair Order Repairs User Read/Write | repair.model_repair_order | group_fusion_repairs_user | 1 | 1 | 1 | 0 |
| 23 | access_repair_order_repairs_manager | Repair Order Repairs Manager Full | repair.model_repair_order | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 24 | access_technician_task_repairs_user | Technician Task Repairs User Schedule | fusion_tasks.model_fusion_technician_task | group_fusion_repairs_user | 1 | 1 | 1 | 0 |
| 25 | access_technician_task_repairs_manager | Technician Task Repairs Manager Full | fusion_tasks.model_fusion_technician_task | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 26 | access_repair_self_check_rule_user | Self-Check Rule User Read | model_fusion_repair_self_check_rule | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 27 | access_repair_self_check_rule_manager | Self-Check Rule Manager Full | model_fusion_repair_self_check_rule | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 28 | access_qr_sticker_wizard_user | QR Sticker Wizard User Full | model_fusion_repair_qr_sticker_wizard | group_fusion_repairs_user | 1 | 1 | 1 | 1 |
| 29 | access_repair_inspection_user | Inspection Cert User Read | model_fusion_repair_inspection_certificate | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 30 | access_repair_inspection_dispatcher | Inspection Cert Dispatcher | model_fusion_repair_inspection_certificate | group_fusion_repairs_dispatcher | 1 | 1 | 1 | 0 |
| 31 | access_repair_inspection_manager | Inspection Cert Manager Full | model_fusion_repair_inspection_certificate | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 32 | access_repair_inspection_technician | Inspection Cert Field Tech Read-Only | model_fusion_repair_inspection_certificate | fusion_tasks.group_field_technician | 1 | 0 | 0 | 0 |
| 33 | access_service_plan_sub_user | Service Plan Sub User Read | model_fusion_repair_service_plan_subscription | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 34 | access_service_plan_sub_dispatcher | Service Plan Sub Dispatcher | model_fusion_repair_service_plan_subscription | group_fusion_repairs_dispatcher | 1 | 1 | 1 | 0 |
| 35 | access_service_plan_sub_manager | Service Plan Sub Manager Full | model_fusion_repair_service_plan_subscription | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 36 | access_service_plan_burn_user | Service Plan Burn User Read | model_fusion_repair_service_plan_burn | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 37 | access_service_plan_burn_manager | Service Plan Burn Manager Full | model_fusion_repair_service_plan_burn | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 38 | access_emergency_charge_user | Emergency Charge User Read | model_fusion_repair_emergency_charge | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 39 | access_emergency_charge_manager | Emergency Charge Manager Full | model_fusion_repair_emergency_charge | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 40 | access_part_order_user | Part Order User Read | model_fusion_repair_part_order | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 41 | access_part_order_dispatcher | Part Order Dispatcher | model_fusion_repair_part_order | group_fusion_repairs_dispatcher | 1 | 1 | 1 | 0 |
| 42 | access_part_order_manager | Part Order Manager Full | model_fusion_repair_part_order | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 43 | access_part_order_technician | Part Order Field Tech Create | model_fusion_repair_part_order | fusion_tasks.group_field_technician | 1 | 1 | 1 | 0 |
| 44 | access_visit_report_partline_user | Visit Report Part Line User Full | model_fusion_repair_visit_report_wizard_partline | group_fusion_repairs_user | 1 | 1 | 1 | 1 |
| 45 | access_visit_report_partline_tech | Visit Report Part Line Field Tech Full | model_fusion_repair_visit_report_wizard_partline | fusion_tasks.group_field_technician | 1 | 1 | 1 | 1 |
| 46 | access_callout_rate_user | Callout Rate User Read | model_fusion_repair_callout_rate | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 47 | access_callout_rate_manager | Callout Rate Manager Full | model_fusion_repair_callout_rate | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 48 | access_delivery_charge_user | Delivery Charge User Read | model_fusion_repair_delivery_charge | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 49 | access_delivery_charge_manager | Delivery Charge Manager Full | model_fusion_repair_delivery_charge | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 50 | access_labor_warranty_user | Labor Warranty User Read | model_fusion_repair_labor_warranty | group_fusion_repairs_user | 1 | 0 | 0 | 0 |
| 51 | access_labor_warranty_sales_rep | Labor Warranty Sales Rep Write | model_fusion_repair_labor_warranty | group_fusion_repairs_sales_rep | 1 | 1 | 0 | 0 |
| 52 | access_labor_warranty_manager | Labor Warranty Manager Full | model_fusion_repair_labor_warranty | group_fusion_repairs_manager | 1 | 1 | 1 | 1 |
| 53 | access_labor_warranty_technician | Labor Warranty Field Tech Read | model_fusion_repair_labor_warranty | fusion_tasks.group_field_technician | 1 | 1 | 0 | 0 |