Checkpoint: Le score de qualité est désormais recalculé et persisté par le serveur après chaque modification manuelle de facture. Il s’appuie sur les champs obligatoires configurés pour le propriétaire de la facture, conserve un référentiel par défaut en l’absence de configuration et accepte explicitement un compte ayant rendu tous ses champs optionnels. Le calcul local non persisté de la page détail est supprimé. 64 tests, TypeScript et build validés.
This commit is contained in:
42
shared/invoiceQuality.ts
Normal file
42
shared/invoiceQuality.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/** 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);
|
||||
}
|
||||
Reference in New Issue
Block a user