États personnalisés

Construire sa propre spécification pas à pas — source, colonnes, colonnes calculées, filtres, période, tri, regroupements et options — avec des exemples complets.

L'idée

Un état personnalisé est une spécification que vous envoyez à preview ou generate (ou que vous enregistrez comme modèle). Elle décrit :

{
  "sourceCode": "RECEIPTS",
  "columns":  [ ... ],
  "filters":  [ ... ],
  "scope":    { ... },
  "grouping": [ ... ],
  "sorting":  { ... },
  "options":  { ... }
}

Vous pouvez partir de zéro (sourceCode + ce que vous voulez) ou partir d'un état du catalogue en donnant definitionCode : tout ce que vous omettez prend alors la valeur de l'état, tout ce que vous donnez la remplace. Le chemin le plus sûr est de lire defaultSpec avec GET /provider/reports/catalog/{code} et de le modifier.

Règles de fusion avec definitionCode : columns vide → colonnes de l'état ; filters absent → filtres de l'état, filters: [] → aucun filtre ; grouping absent → regroupement de l'état, grouping: [] → regroupement désactivé ; sorting absent → tri de l'état.

La source — sourceCode

Une source = une table de données avec son grain. Choisissez-la selon la question posée :

Vous voulez une ligne par…Source
contratCONTRACTS
avenant (tout acte, émis ou non)ENDORSEMENTS
attestationCERTIFICATES
quittance (avenant émis), avec primes, taxes, encaissement et répartitionRECEIPTS
règlement non confirmé (impayé)UNPAID
règlement confirmé (encaissement)COLLECTIONS
part de compagnie sur un avenant (apéritrice, coassureur, Pool)COINSURANCE
séjour d'un véhicule sur un contratFLEET
souscripteurSUBSCRIBERS

La liste des champs de chaque source est dans Sources et champs et dans GET /provider/reports/sources/{code}/fields.

Les colonnes — columns

Chaque colonne est soit un champ natif de la source, soit une colonne calculée par formule.

"columns": [
  { "type": "NATIVE", "fieldName": "receiptRef" },
  { "type": "NATIVE", "fieldName": "subscriberName", "label": "Client" },
  { "type": "NATIVE", "fieldName": "netPremium" },
  { "type": "NATIVE", "fieldName": "totalTaxes" },
  { "type": "CALCULATED", "name": "tauxTaxes", "label": "Taxes / prime nette (%)",
    "definition": "(totalTaxes / netPremium) * 100" }
]
ChampColonne nativeColonne calculée
typeNATIVE (défaut)CALCULATED
fieldNameclé du champ, obligatoire—
name—clé de sortie, obligatoire, unique
definition—formule, obligatoire
labellibellé affiché (défaut : libellé du champ)libellé affiché (défaut : name)

Règles :

  • Si columns est vide, les champs defaultSelected de la source sont utilisés.
  • Les champs required de la source (ex. policyNumber, receiptRef) sont toujours ajoutés en tête, même si vous ne les demandez pas.
  • L'ordre des colonnes dans le fichier est l'ordre de columns.

Formules des colonnes calculées

La formule est une expression arithmétique évaluée ligne par ligne, dont les variables sont les clés des colonnes présentes dans la ligne (natives ou calculées placées avant). Le résultat est un nombre arrondi à 2 décimales.

ÉlémentExemple
Opérateurs+ - * / ^ %
Parenthèses(netPremium + accessories) * 0.1
Fonctions usuellesabs(x), sqrt(x), log(x), exp(x), floor(x), ceil(x), min/max non disponibles : utilisez une colonne native déjà agrégée
Constantes0.6, 100

Points d'attention :

  • Une variable non numérique ou absente vaut 0. Une division par zéro ou une erreur de syntaxe donne une cellule vide (null), jamais une erreur HTTP.
  • Référencez des colonnes que vous avez demandées dans columns : une formule qui cite un champ non sélectionné le voit à 0.
  • En mode récapitulatif, la formule s'applique sur les sommes du groupe (ex. un taux moyen pondéré se calcule naturellement : (commission / netPremium) * 100).
  • Les colonnes calculées ne sont ni filtrables, ni triables, ni groupables.

Exemples :

{ "type": "CALCULATED", "name": "partPool", "label": "Part Pool recalculée (10 %)", "definition": "netPremium * 0.10" }
{ "type": "CALCULATED", "name": "ecartFG", "label": "Écart FG", "definition": "fraisGestion - netPremium * 0.10" }
{ "type": "CALCULATED", "name": "resteDu", "label": "Reste dû", "definition": "totalTtc - amountPaid" }
{ "type": "CALCULATED", "name": "tauxCommission", "label": "Commission (%)", "definition": "(commission / netPremium) * 100" }

Les filtres — filters

"filters": [
  { "fieldName": "paymentStatus", "operator": "EQUALS",  "values": ["CONFIRMED"] },
  { "fieldName": "netPremium",    "operator": "BETWEEN", "values": ["10000", "100000"] },
  { "fieldName": "companyLabel",  "operator": "CONTAINS", "values": ["wafa"] },
  { "fieldName": "attestationNumber", "operator": "IS_NOT_EMPTY" }
]

Les filtres se cumulent (ET). Le champ doit être filterable.

OpérateurValeursSens
EQUALS / NOT_EQUALS1 (ou plusieurs : devient IN / NOT_IN)égalité
IN / NOT_IN≥ 1appartenance
GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL1comparaison
BETWEENexactement 2 (basse, haute), bornes inclusesintervalle
CONTAINS1contient, insensible à la casse
IS_EMPTY / IS_NOT_EMPTY0null ou vide / renseigné

Les valeurs sont toujours des chaînes, converties selon le type du champ :

Type du champFormat attenduExemple
INTEGERentier"5"
DECIMAL, MONEY, PERCENTdécimal, point"14697.00"
BOOLEANtrue / false"true"
DATEyyyy-MM-dd"2026-10-01"
DATETIMEISO 8601, ou yyyy-MM-dd (= début de journée)"2026-10-01T00:00:00"
ENUMcode de l'énumération"ISSUED", "ACTIVE"
STRINGtexte"COMAR"

Une valeur inconvertible renvoie 400 « Valeur de filtre invalide pour … ».

La période — scope

"scope": {
  "basedOn": "issuedAt",
  "relativeRange": "PREVIOUS_MONTH",
  "timezone": "Africa/Abidjan"
}

ou, en bornes absolues :

"scope": {
  "basedOn": "collectedDate",
  "dateRange": { "from": "2026-10-01T00:00:00", "to": "2026-10-28T23:59:59" }
}
ChampDescription
basedOnAncre : le champ de date qui est borné. Chaque source a ses ancres (ex. RECEIPTS : issuedAt défaut, collectedDate, effectiveDate). Absent = ancre par défaut de la source
relativeRangePériode relative résolue au moment de l'exécution : TODAY, YESTERDAY, CURRENT_WEEK, PREVIOUS_WEEK, CURRENT_MONTH, PREVIOUS_MONTH, CURRENT_QUARTER, PREVIOUS_QUARTER, CURRENT_YEAR, PREVIOUS_YEAR, LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS
dateRange.from, dateRange.toBornes absolues, inclusives. Si dateRange est présent il prime sur relativeRange. Une borne manquante = ouverte
timezoneFuseau de résolution des périodes relatives (défaut Africa/Abidjan)

Sans scope du tout, aucune borne de date n'est appliquée (toute l'historique). Les bornes réellement appliquées sont renvoyées dans resolvedFrom / resolvedTo.

Changer d'ancre change le résultat. « Quittancement du mois d'octobre » basé sur issuedAt (émission) et basé sur collectedDate (encaissement) ne donnent pas le même total. Dans une planification mensuelle, préférez PREVIOUS_MONTH : le mois complet est clos au moment de l'envoi.

Le tri — sorting

"sorting": { "fieldName": "issuedAt", "direction": "DESC" }

Un seul champ, sortable, direction = ASC ou DESC (défaut ASC). Absent = tri par défaut de la source. Avec un regroupement, le tri s'applique à l'intérieur de chaque groupe (les groupes sont triés par leur dimension).

Les regroupements — grouping et options.aggregated

"grouping": ["companyLabel"],
"options":  { "aggregated": true }

Deux modes selon options.aggregated :

ModeaggregatedRésultat
Récapitulatiftrue (défaut dès qu'un grouping est donné)Une ligne par groupe : les dimensions, une colonne rowCount (« Nombre »), puis uniquement les colonnes totalisables (Σ) et les colonnes calculées
Détail groupéfalseToutes les lignes de détail, triées par groupe, avec ruptures et sous-totaux par groupe dans le fichier

Plusieurs dimensions sont possibles (["brokerName", "companyLabel"]). Les champs doivent être groupable. aggregated: true sans grouping renvoie 400.

Les options — options

OptionDéfautEffet
hideSensitiveDatatrueMasque les champs sensibles (téléphone, e-mail, adresse, pièce d'identité) par ••••••
includeTotalstrueLigne de totaux (et sous-totaux) dans le fichier
includeLogotrueLogo en en-tête du PDF
aggregatednullForce le mode récapitulatif (true) ou détail groupé (false) ; sinon déduit de grouping

Le format, le titre, le nom de fichier (génération)

Propres à POST /provider/reports/generate :

ChampDescription
formatPDF, CSV, XLSX. Avec definitionCode, doit appartenir à formats de l'état
titleTitre imprimé en en-tête (défaut : titre de l'état ou du modèle)
fileNameNom de fichier sans extension (défaut généré à partir du titre et de la période)
scopeModeGLOBAL (défaut) ou PER_COMPANY (comptes Pool : un fichier par compagnie)
companyIdComptes Pool : restreindre à une compagnie
recipientsTo, recipientsCcAdresses e-mail qui recevront le fichier en pièce jointe

Exemples complets

A. Quittances encaissées du mois, triées par montant

{
  "sourceCode": "RECEIPTS",
  "columns": [
    { "fieldName": "receiptRef" }, { "fieldName": "companyLabel" }, { "fieldName": "subscriberName" },
    { "fieldName": "netPremium" }, { "fieldName": "totalTtc" }, { "fieldName": "amountPaid" },
    { "fieldName": "collectedDate" }, { "fieldName": "paymentReference" }
  ],
  "filters": [ { "fieldName": "paymentStatus", "operator": "EQUALS", "values": ["CONFIRMED"] } ],
  "scope": { "basedOn": "collectedDate", "relativeRange": "CURRENT_MONTH" },
  "sorting": { "fieldName": "totalTtc", "direction": "DESC" },
  "format": "XLSX",
  "title": "Quittances encaissées — mois en cours"
}

B. Contrôle des frais de gestion Pool par compagnie

Part de prime nette attendue (10 %) comparée aux frais de gestion réellement répartis.

{
  "sourceCode": "RECEIPTS",
  "columns": [
    { "fieldName": "netPremium" },
    { "fieldName": "fraisGestion" },
    { "type": "CALCULATED", "name": "fgAttendu", "label": "FG attendus (10 %)", "definition": "netPremium * 0.10" },
    { "type": "CALCULATED", "name": "ecart", "label": "Écart", "definition": "fraisGestion - netPremium * 0.10" }
  ],
  "grouping": ["companyLabel"],
  "options": { "aggregated": true },
  "scope": { "basedOn": "issuedAt", "dateRange": { "from": "2026-10-01T00:00:00", "to": "2026-10-28T23:59:59" } },
  "format": "XLSX"
}

C. Impayés de plus de 30 jours, par intermédiaire, avec le détail

{
  "definitionCode": "IMPAYES",
  "filters": [ { "fieldName": "daysOverdue", "operator": "GREATER_THAN", "values": ["30"] } ],
  "grouping": ["brokerName"],
  "options": { "aggregated": false, "includeTotals": true },
  "scope": { "basedOn": "dueDate", "relativeRange": "LAST_90_DAYS" },
  "format": "PDF"
}

D. Récapitulatif de production du mois précédent, pour une seule compagnie (compte Pool)

{
  "definitionCode": "RECAP_PROD_COMPAGNIE",
  "scope": { "relativeRange": "PREVIOUS_MONTH" },
  "companyId": "5647d861-5a4b-493e-8043-17fb60958720",
  "format": "PDF"
}

E. Bordereau de cession, un fichier par compagnie (compte Pool)

{
  "definitionCode": "BORDEREAU_CESSION",
  "scope": { "relativeRange": "PREVIOUS_MONTH" },
  "scopeMode": "PER_COMPANY",
  "format": "PDF",
  "recipientsTo": ["reversements@pooltpv.ci"]
}

Check-list avant d'envoyer

  • sourceCode ou definitionCode présent
  • chaque fieldName existe dans la source (…/sources/{code}/fields)
  • les filtres portent sur des champs filterable, avec le bon nombre de valeurs et le bon format
  • les regroupements portent sur des champs groupable
  • le tri porte sur un champ sortable
  • le scope a une ancre connue et une période (sinon toute l'historique)
  • le format est autorisé par l'état et, en PDF, le volume reste sous 25 000 lignes
  • vous avez prévisualisé avec size: 1 pour vérifier total et estimate

On this page