Aller au contenu principal

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.