Root cause of CTR-00008: _createBuiltInInstallChain only created Issue +
Dispatch Jobs. It never created a pending Service Subscription, so when
the chain's terminal job Completed, activateSubscriptionForJob found
nothing matching customer+service_location+status='En attente' to flip.
Result: 4/4 tasks done, no sub activation, no prorated invoice.
Changes:
- contracts.js: after chain creation, create Service Subscription with
status='En attente' (plan_name + service_category inferred from the
contract). Back-link it on Service Contract.service_subscription (a
new custom field — the stock 'subscription' field on Service Contract
points at the built-in ERPNext Subscription doctype, not ours).
- project-templates.js: add test_single (1-step) and test_parallel
(diamond: step0 → step1 ∥ step2) for faster lifecycle testing.
Extract chooseTemplate(contract) with precedence:
contract.install_template → contract_type mapping → fiber_install.
- contracts.js: chain builder now uses chooseTemplate instead of
hardcoded fiber_install, logs the chosen template per contract.
- _inferServiceCategory/_inferPlanName helpers map contract metadata
into the Service Subscription's required fields.
Companion changes on ERPNext (custom fields, no code):
Service Contract.service_subscription Link → Service Subscription
Service Contract.install_template Select (fiber_install,
phone_service, move_service, repair_service, test_single,
test_parallel)
Retroactive repair for CTR-00008 applied directly on prod:
→ SUB-0000100003 (Actif), SINV-2026-700014 (Draft, $9.32 prorata).
Smoke test of test_single path on prod (CTR-00010 synthetic, cleaned up):
template=test_single ✓ sub created ✓ activated on completion ✓
prorated invoice emitted ✓
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>