60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
/** Champ requis configuré pour le calcul du score de qualité d’une facture. */
|
||
export type QualityFieldConfig = {
|
||
fieldName: string;
|
||
isRequired: number;
|
||
};
|
||
|
||
/** Référentiel utilisé tant qu’un compte ne possède pas encore sa configuration en base. */
|
||
export const DEFAULT_REQUIRED_INVOICE_FIELDS = [
|
||
"supplierName",
|
||
"invoiceNumber",
|
||
"invoiceDate",
|
||
"totalAmount",
|
||
] as const;
|
||
|
||
function hasValue(value: unknown): boolean {
|
||
if (value === null || value === undefined) return false;
|
||
if (typeof value === "string") return value.trim().length > 0;
|
||
if (value instanceof Date) return Number.isFinite(value.getTime());
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Recalcule le score selon les champs obligatoires configurés pour le compte.
|
||
* Les champs optionnels n'affectent jamais le résultat. Le calcul est purement
|
||
* déterministe afin d'être identique après import et après une correction manuelle.
|
||
*/
|
||
export function calculateInvoiceQualityScore(
|
||
invoice: Record<string, unknown>,
|
||
fieldsConfiguration: readonly QualityFieldConfig[],
|
||
): number {
|
||
const configuredRequiredFields = fieldsConfiguration
|
||
.filter((field) => field.isRequired === 1)
|
||
.map((field) => field.fieldName);
|
||
const requiredFields = fieldsConfiguration.length > 0
|
||
? configuredRequiredFields
|
||
: DEFAULT_REQUIRED_INVOICE_FIELDS;
|
||
|
||
if (requiredFields.length === 0) return 100;
|
||
|
||
const completedFields = requiredFields.filter((fieldName) => hasValue(invoice[fieldName])).length;
|
||
return Math.round((completedFields / requiredFields.length) * 100);
|
||
}
|
||
|
||
/**
|
||
* Prépare une extraction IA pour la persistance. Le score brut du modèle est
|
||
* volontairement remplacé par le calcul déterministe commun à tous les flux.
|
||
*/
|
||
export function withCalculatedInvoiceQuality<T extends object>(
|
||
invoice: T,
|
||
fieldsConfiguration: readonly QualityFieldConfig[],
|
||
): T & { qualityScore: number } {
|
||
return {
|
||
...invoice,
|
||
qualityScore: calculateInvoiceQualityScore(
|
||
invoice as Record<string, unknown>,
|
||
fieldsConfiguration,
|
||
),
|
||
};
|
||
}
|