Checkpoint: Système de gestion des automatismes pour remplissage automatique des factures
Nouvelle fonctionnalité majeure : ✅ Page "Automatismes" complète pour gérer les règles de remplissage automatique ✅ Système de règles conditionnelles SI...ALORS pour automatiser le remplissage des champs métier ✅ Support de conditions multiples avec logique AND/OR ✅ Application automatique des règles lors de l'import de factures ✅ Gestion de la priorité des règles (ordre d'exécution) ✅ Activation/désactivation des règles individuelles Architecture technique : - drizzle/schema.ts : Table automationRules avec conditions JSON et actions JSON - server/db.ts : Fonctions CRUD complètes pour les règles (create, update, delete, list) - server/routers.ts : Routes tRPC pour gérer les automatismes - server/automationEngine.ts : Moteur d'évaluation et d'application des règles - client/src/pages/AutomationRules.tsx : Interface complète de gestion des règles - Migration 0009_regular_warhawk.sql appliquée avec succès Fonctionnement des règles : 1. **Conditions (SI)** : Définissez des critères basés sur les champs de la facture - Champs disponibles : Fournisseur, N° Facture, Montant, Date, N° Commande, N° Bon de livraison - Opérateurs : contient, égal à, commence par, finit par, >, <, >=, <= - Logique : AND (toutes les conditions) ou OR (au moins une condition) 2. **Actions (ALORS)** : Définissez les champs à remplir automatiquement - Type d'achat (CAPEX/OPEX) - Service concerné (depuis la liste des services) - Ventilation comptable (depuis la liste des ventilations) 3. **Priorité** : Les règles sont appliquées dans l'ordre de priorité - Une règle de priorité supérieure ne peut pas être écrasée par une règle de priorité inférieure 4. **Application automatique** : Les règles s'appliquent automatiquement lors de l'import de factures Exemples d'utilisation : - SI Fournisseur contient "Microsoft" ET Montant > 1000 ALORS Type d'achat = CAPEX, Service = DSI - SI Fournisseur contient "EDF" ALORS Type d'achat = OPEX, Ventilation = TOUS - SI N° Facture commence par "AB" ALORS Service = Administration Interface utilisateur : - Liste des règles avec nom, conditions, actions et statut - Formulaire de création/édition avec interface intuitive - Boutons d'activation/désactivation rapide - Suppression avec confirmation - Affichage lisible des conditions et actions Cette fonctionnalité permet de gagner un temps considérable en automatisant le remplissage des champs métier selon des règles métier prédéfinies.
This commit is contained in:
@@ -36,6 +36,11 @@ import {
|
||||
createAccountingAllocation,
|
||||
deleteAccountingAllocation,
|
||||
initializeDefaultLists,
|
||||
getAutomationRulesByUser,
|
||||
getAutomationRuleById,
|
||||
createAutomationRule,
|
||||
updateAutomationRule,
|
||||
deleteAutomationRule,
|
||||
} from "./db";
|
||||
import { loginLocal, hashPassword, getAzureAuthUrl, isAzureAdConfigured, generateToken } from "./auth";
|
||||
import { extractInvoicesWithMistral, generateMetadataJSON } from "./invoiceExtractor";
|
||||
@@ -220,7 +225,7 @@ export const appRouter = router({
|
||||
);
|
||||
|
||||
// Create invoice record
|
||||
await createInvoice({
|
||||
const newInvoice = await createInvoice({
|
||||
userId,
|
||||
sourceFileId: sourceFile.id,
|
||||
invoiceIndexInFile: i + 1,
|
||||
@@ -242,6 +247,20 @@ export const appRouter = router({
|
||||
status: "completed",
|
||||
});
|
||||
|
||||
// Apply automation rules to the newly created invoice
|
||||
try {
|
||||
const { applyAutomationRules } = await import("./automationEngine");
|
||||
const automationUpdates = await applyAutomationRules(userId, newInvoice);
|
||||
|
||||
// If automation rules suggest updates, apply them
|
||||
if (Object.keys(automationUpdates).length > 0) {
|
||||
await updateInvoice(newInvoice.id, automationUpdates);
|
||||
}
|
||||
} catch (autoError) {
|
||||
console.error("[Automation] Error applying rules:", autoError);
|
||||
// Don't fail the import if automation fails
|
||||
}
|
||||
|
||||
importedCount++;
|
||||
} catch (error: any) {
|
||||
errorsCount++;
|
||||
@@ -753,6 +772,63 @@ export const appRouter = router({
|
||||
return { success: true };
|
||||
}),
|
||||
}),
|
||||
|
||||
// ============= AUTOMATION RULES ROUTES =============
|
||||
automationRules: router({
|
||||
list: protectedProcedure.query(async ({ ctx }) => {
|
||||
return await getAutomationRulesByUser(ctx.user.id);
|
||||
}),
|
||||
|
||||
getById: protectedProcedure
|
||||
.input(z.object({
|
||||
id: z.number(),
|
||||
}))
|
||||
.query(async ({ input }) => {
|
||||
return await getAutomationRuleById(input.id);
|
||||
}),
|
||||
|
||||
create: protectedProcedure
|
||||
.input(z.object({
|
||||
name: z.string().min(1),
|
||||
isActive: z.number().min(0).max(1).optional(),
|
||||
priority: z.number().optional(),
|
||||
conditions: z.string(), // JSON string
|
||||
conditionsLogic: z.enum(["AND", "OR"]).optional(),
|
||||
actions: z.string(), // JSON string
|
||||
}))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const rule = await createAutomationRule({
|
||||
userId: ctx.user.id,
|
||||
...input,
|
||||
});
|
||||
return rule;
|
||||
}),
|
||||
|
||||
update: protectedProcedure
|
||||
.input(z.object({
|
||||
id: z.number(),
|
||||
name: z.string().min(1).optional(),
|
||||
isActive: z.number().min(0).max(1).optional(),
|
||||
priority: z.number().optional(),
|
||||
conditions: z.string().optional(),
|
||||
conditionsLogic: z.enum(["AND", "OR"]).optional(),
|
||||
actions: z.string().optional(),
|
||||
}))
|
||||
.mutation(async ({ input }) => {
|
||||
const { id, ...data } = input;
|
||||
const updated = await updateAutomationRule(id, data);
|
||||
return updated;
|
||||
}),
|
||||
|
||||
delete: protectedProcedure
|
||||
.input(z.object({
|
||||
id: z.number(),
|
||||
}))
|
||||
.mutation(async ({ input }) => {
|
||||
await deleteAutomationRule(input.id);
|
||||
return { success: true };
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
|
||||
Reference in New Issue
Block a user