Skip to main content

ERP-7 β€” Insurance LOB Custom Doctypes

Overview​

Three custom ERPNext doctypes model the insurance contract lifecycle on top of the standard CRM and billing modules:

DoctypeTypeRole
Insurance ProductReference dataCatalogue of insurance products (LOB, pricing, TSCA)
Insurance PolicySubmittableIssued contract β€” links Customer, Product, CRM Opportunity, Sales Invoice
Insurance ClaimSubmittableFiled sinistre β€” linked to a Policy, tracks amounts and status

Two custom fields are added to Opportunity to close the CRM β†’ contract loop.


Insurance Product​

Autoname: field:product_code β€” the code is the unique identifier.

Fields​

FieldTypeNotes
product_codeData (unique)Internal code: IARD-AUTO-RC, IARD-HAB-MRH, PREV-IND-01
product_nameDataCommercial name
risk_typeSelectLOB aligned with CRM risk_type options
is_activeCheckGates availability in CRM and Policy form
base_premiumCurrencyAnnual base premium (€)
tsca_rateFloatTSCA rate: 9 / 13 / 33 β€” see art. 991 CGI
companyLink β†’ CompanyIssuing company
itemLink β†’ ItemERPNext Item used on Sales Invoice line
descriptionText EditorCommercial pitch
coverage_detailsText EditorCovered guarantees
exclusionsText EditorExclusion clauses

Seeded products​

CodeLOBBase premiumTSCA
IARD-AUTO-RCIARD - Automobile350 €/yr13 %
IARD-HAB-MRHIARD - MRH180 €/yr9 %
PREV-IND-01PrΓ©voyance Individuelle420 €/yr9 %

Insurance Policy​

Autoname: naming_series: β†’ INS-POL-.YYYY.-.####
Submittable: submit = issue the policy, cancel+amend = endorsement.

Fields​

FieldTypeNotes
naming_seriesSelectSeries: INS-POL-.YYYY.-.####
customerLink β†’ CustomerPolicyholder
insurance_productLink β†’ Insurance ProductProduct
statusSelectEn attente / En cours / Suspendu / RΓ©siliΓ© / ExpirΓ©
companyLink β†’ Company
effective_dateDateStart of coverage
expiry_dateDateEnd of coverage
renewal_dateDateNext renewal date
payment_frequencySelectAnnuel / Semestriel / Trimestriel / Mensuel
risk_typeSelectLOB (auto-fill from Product)
insured_nameDataIf the insured β‰  policyholder
premium_amountCurrencyAnnual premium amount
currencyLink β†’ CurrencyDefault EUR
opportunityLink β†’ OpportunityOriginating CRM opportunity
sales_invoiceLink β†’ Sales InvoicePremium invoice
sepa_mandate_refData (read-only)Copied from Customer.sepa_mandate_id at issuance
notesTextFree notes

Policy lifecycle​

[Saved β€” En attente]
β”‚ submit
β–Ό
[Submitted β€” En cours]
β”‚ manual status change
β”œβ”€β”€β†’ Suspendu (non-payment, art. L113-3)
β”œβ”€β”€β†’ RΓ©siliΓ© (cancelled by insurer or insured)
└──→ ExpirΓ© (expiry_date reached)

Endorsements (avenants) use the standard ERPNext Cancel + Amend pattern β€” each amendment creates a new version with an incremented revision suffix.


Insurance Claim​

Autoname: naming_series: β†’ INS-CLM-.YYYY.-.####
Submittable: submit = official claim filing.

Fields​

FieldTypeNotes
naming_seriesSelectSeries: INS-CLM-.YYYY.-.####
policyLink β†’ Insurance PolicyParent policy
customerLink β†’ CustomerAuto-fetched from policy.customer
statusSelectDΓ©clarΓ© β†’ En cours β†’ ExpertisΓ© β†’ AcceptΓ© / RefusΓ© β†’ RΓ©glΓ© β†’ ClΓ΄turΓ©
companyLink β†’ CompanyAuto-fetched from policy.company
incident_dateDateDate of loss event
declaration_dateDateDate claim was filed (defaults to today)
risk_typeSelectAuto-fetched from policy.risk_type
adjuster_nameDataIndependent loss adjuster (expert)
claim_amountCurrencyDeclared loss amount
settlement_amountCurrencySettled/paid amount
currencyLink β†’ CurrencyDefault EUR
descriptionText EditorDescription of the loss event
notesTextInternal notes

Claim status workflow​

DΓ©clarΓ©
└──→ En cours d'instruction
└──→ ExpertisΓ©
β”œβ”€β”€β†’ AcceptΓ© ──→ RΓ©glΓ© ──→ ClΓ΄turΓ©
└──→ RefusΓ© ──→ ClΓ΄turΓ©

CRM Opportunity β€” New Fields​

Two fields added to the Opportunity doctype (collapsible section, inserted after risk_type):

FieldTypeNotes
quoted_productLink β†’ Insurance ProductProduct shown to the prospect
linked_policyLink β†’ Insurance Policy (read-only)Policy created at conversion β€” filled manually or by automation

Full CRM β†’ Contract flow:

Lead (ORIAS, broker_ref, risk_type)
└──→ Opportunity (quoted_product, CRM stages)
└──→ Insurance Policy (opportunity link back)
└──→ Sales Invoice (prime)
└──→ Insurance Claim (sinistres)

Reproduction​

POD=$(kubectl get pod -n erp -l app.kubernetes.io/name=erpnext-gunicorn \
-o jsonpath='{.items[0].metadata.name}')

# Create doctypes + Opportunity fields
kubectl cp scripts/setup_insurance_doctypes.py erp/${POD}:/tmp/
kubectl exec -n erp ${POD} -- bash -c \
"cd /home/frappe/frappe-bench/sites && \
/home/frappe/frappe-bench/env/bin/python /tmp/setup_insurance_doctypes.py"

# Seed the 3 standard products
kubectl cp scripts/setup_insurance_products.py erp/${POD}:/tmp/
kubectl exec -n erp ${POD} -- bash -c \
"cd /home/frappe/frappe-bench/sites && \
/home/frappe/frappe-bench/env/bin/python /tmp/setup_insurance_products.py"

Expected summary output:

=== Summary ===
βœ“ Insurance Product
βœ“ Insurance Policy
βœ“ Insurance Claim
Opportunity custom fields: 4/4

Known gotchas​

Series fieldtype removed in Frappe v16. Use Select with the series pattern as options (e.g. "INS-POL-.YYYY.-.####\n"). Set doc.autoname = "naming_series:" on the DocType. Frappe handles the auto-increment from the Select field at save time.

fetch_from is UI-only. Fields with fetch_from = "policy.customer" auto-populate in the browser form when the Link field changes. They do not populate on programmatic insert β€” always set them explicitly in scripts or API calls.

Custom DocType module must be "Custom". Using any other module name (e.g. "Selling") causes the DocType to appear in a non-existent app namespace and may conflict with standard module permissions.