Checkpoint: Checkpoint saved: Ajout d'une page "Paramètres de réception" complète pour configurer les différentes méthodes d'import de factures.

Nouvelles fonctionnalités :
 Table importSettings dans la base de données (7 tables au total)
 Routes tRPC pour gérer les paramètres de réception (get, update)
 Page "Paramètres de réception" accessible via le menu de navigation

Configuration disponible :
1. **Import manuel** : Activation/désactivation de l'upload manuel de fichiers PDF via l'interface

2. **Import automatique depuis dossier** :
   - Activation/désactivation
   - Configuration du chemin du dossier source à surveiller
   - Fréquence de lecture du dossier (en minutes)

3. **Import par email** :
   - Activation/désactivation
   - Configuration du compte email (adresse + mot de passe)
   - Serveur IMAP (host + port)
   - Fréquence de lecture des emails (en minutes)

Interface utilisateur :
- 3 cartes distinctes avec icônes (Upload, FolderOpen, Mail)
- Switches pour activer/désactiver chaque méthode
- Champs de configuration qui apparaissent uniquement si la méthode est activée
- Bouton "Enregistrer les paramètres" avec feedback visuel
- Notifications toast pour confirmer la sauvegarde ou signaler les erreurs

Architecture :
- Schéma de base de données : table importSettings avec 14 colonnes
- Backend : Fonctions db.ts (getImportSettingsByUser, upsertImportSettings)
- Routes tRPC : importSettings.get et importSettings.update
- Frontend : Page ImportSettings.tsx avec gestion d'état React
- Navigation : Nouveau lien "Paramètres de réception" dans le menu latéral

La page est maintenant accessible via /import-settings et permet aux utilisateurs de configurer toutes les méthodes d'importation de factures de manière centralisée.
This commit is contained in:
Manus
2026-02-10 12:05:23 -05:00
parent 4690b16c9f
commit 35efbf632d
10 changed files with 1418 additions and 2 deletions

View File

@@ -0,0 +1,18 @@
CREATE TABLE `importSettings` (
`id` int AUTO_INCREMENT NOT NULL,
`userId` int NOT NULL,
`manualImportEnabled` int NOT NULL DEFAULT 1,
`autoImportEnabled` int NOT NULL DEFAULT 0,
`autoImportSourcePath` text,
`autoImportFrequency` int NOT NULL DEFAULT 60,
`emailImportEnabled` int NOT NULL DEFAULT 0,
`emailImportAddress` varchar(320),
`emailImportPassword` text,
`emailImportHost` varchar(255),
`emailImportPort` int DEFAULT 993,
`emailImportFrequency` int NOT NULL DEFAULT 30,
`createdAt` timestamp NOT NULL DEFAULT (now()),
`updatedAt` timestamp NOT NULL DEFAULT (now()) ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT `importSettings_id` PRIMARY KEY(`id`),
CONSTRAINT `importSettings_userId_unique` UNIQUE(`userId`)
);

View File

@@ -0,0 +1,950 @@
{
"version": "5",
"dialect": "mysql",
"id": "1e89df9d-47b6-47da-8afc-6024d8bdc8ba",
"prevId": "5a495536-d69b-4bd9-9618-0644c5a001bd",
"tables": {
"importLogs": {
"name": "importLogs",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"sourceFileId": {
"name": "sourceFileId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fileName": {
"name": "fileName",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"totalInvoicesDetected": {
"name": "totalInvoicesDetected",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"invoicesImported": {
"name": "invoicesImported",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"duplicatesIgnored": {
"name": "duplicatesIgnored",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"errors": {
"name": "errors",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"duplicateDetails": {
"name": "duplicateDetails",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"errorDetails": {
"name": "errorDetails",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"importedAt": {
"name": "importedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"importLogs_id": {
"name": "importLogs_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"importSettings": {
"name": "importSettings",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"manualImportEnabled": {
"name": "manualImportEnabled",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 1
},
"autoImportEnabled": {
"name": "autoImportEnabled",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"autoImportSourcePath": {
"name": "autoImportSourcePath",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"autoImportFrequency": {
"name": "autoImportFrequency",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 60
},
"emailImportEnabled": {
"name": "emailImportEnabled",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"emailImportAddress": {
"name": "emailImportAddress",
"type": "varchar(320)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"emailImportPassword": {
"name": "emailImportPassword",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"emailImportHost": {
"name": "emailImportHost",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"emailImportPort": {
"name": "emailImportPort",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": 993
},
"emailImportFrequency": {
"name": "emailImportFrequency",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 30
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"importSettings_id": {
"name": "importSettings_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"importSettings_userId_unique": {
"name": "importSettings_userId_unique",
"columns": [
"userId"
]
}
},
"checkConstraint": {}
},
"invoices": {
"name": "invoices",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"sourceFileId": {
"name": "sourceFileId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"invoiceIndexInFile": {
"name": "invoiceIndexInFile",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 1
},
"fileName": {
"name": "fileName",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fileKey": {
"name": "fileKey",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fileUrl": {
"name": "fileUrl",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"supplierName": {
"name": "supplierName",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"invoiceNumber": {
"name": "invoiceNumber",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"invoiceDate": {
"name": "invoiceDate",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"deliveryNoteNumber": {
"name": "deliveryNoteNumber",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"orderNumber": {
"name": "orderNumber",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"totalAmount": {
"name": "totalAmount",
"type": "decimal(10,2)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"pageRange": {
"name": "pageRange",
"type": "varchar(20)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"qualityScore": {
"name": "qualityScore",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"metadataFileKey": {
"name": "metadataFileKey",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"metadataFileUrl": {
"name": "metadataFileUrl",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "enum('processing','completed','error')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'processing'"
},
"errorMessage": {
"name": "errorMessage",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"exportStatus": {
"name": "exportStatus",
"type": "enum('not_exported','exported','export_error')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'not_exported'"
},
"manuallyEdited": {
"name": "manuallyEdited",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"exportedAt": {
"name": "exportedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"exportMode": {
"name": "exportMode",
"type": "enum('manual','automatic')",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {
"supplier_invoice_date_unique": {
"name": "supplier_invoice_date_unique",
"columns": [
"supplierName",
"invoiceNumber",
"invoiceDate"
],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"invoices_id": {
"name": "invoices_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"llmLogs": {
"name": "llmLogs",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"sourceFileId": {
"name": "sourceFileId",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"invoiceId": {
"name": "invoiceId",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"promptSent": {
"name": "promptSent",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"rawResponse": {
"name": "rawResponse",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"cleanedResponse": {
"name": "cleanedResponse",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"success": {
"name": "success",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 1
},
"errorMessage": {
"name": "errorMessage",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"processingTimeMs": {
"name": "processingTimeMs",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"pageRange": {
"name": "pageRange",
"type": "varchar(50)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"llmLogs_id": {
"name": "llmLogs_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"sourceFiles": {
"name": "sourceFiles",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fileName": {
"name": "fileName",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fileKey": {
"name": "fileKey",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fileUrl": {
"name": "fileUrl",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"totalInvoicesDetected": {
"name": "totalInvoicesDetected",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"processingStatus": {
"name": "processingStatus",
"type": "enum('processing','completed','error')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'processing'"
},
"processingProgress": {
"name": "processingProgress",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"sourceFiles_id": {
"name": "sourceFiles_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"userSettings": {
"name": "userSettings",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"llmModel": {
"name": "llmModel",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'mistral-large-latest'"
},
"orderNumberFormat": {
"name": "orderNumberFormat",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"invoiceNumberKeywords": {
"name": "invoiceNumberKeywords",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"deliveryNoteKeywords": {
"name": "deliveryNoteKeywords",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"orderNumberKeywords": {
"name": "orderNumberKeywords",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"supplierKeywords": {
"name": "supplierKeywords",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"totalAmountKeywords": {
"name": "totalAmountKeywords",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sftpHost": {
"name": "sftpHost",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sftpPort": {
"name": "sftpPort",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": 22
},
"sftpUsername": {
"name": "sftpUsername",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sftpPassword": {
"name": "sftpPassword",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sftpRemotePath": {
"name": "sftpRemotePath",
"type": "varchar(500)",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'/'"
},
"sftpAutoExport": {
"name": "sftpAutoExport",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"llmLogsRetentionMonths": {
"name": "llmLogsRetentionMonths",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 3
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"userSettings_id": {
"name": "userSettings_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"userSettings_userId_unique": {
"name": "userSettings_userId_unique",
"columns": [
"userId"
]
}
},
"checkConstraint": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"openId": {
"name": "openId",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"azureAdId": {
"name": "azureAdId",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(320)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"passwordHash": {
"name": "passwordHash",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"loginMethod": {
"name": "loginMethod",
"type": "enum('manus','local','azure-ad')",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"role": {
"name": "role",
"type": "enum('user','admin')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'user'"
},
"isActive": {
"name": "isActive",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 1
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
},
"lastSignedIn": {
"name": "lastSignedIn",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"users_id": {
"name": "users_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"users_openId_unique": {
"name": "users_openId_unique",
"columns": [
"openId"
]
},
"users_azureAdId_unique": {
"name": "users_azureAdId_unique",
"columns": [
"azureAdId"
]
},
"users_email_unique": {
"name": "users_email_unique",
"columns": [
"email"
]
}
},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}

View File

@@ -22,6 +22,13 @@
"when": 1767881720296,
"tag": "0002_striped_red_skull",
"breakpoints": true
},
{
"idx": 3,
"version": "5",
"when": 1770742897031,
"tag": "0003_previous_killraven",
"breakpoints": true
}
]
}

View File

@@ -130,6 +130,36 @@ export const userSettings = mysqlTable("userSettings", {
export type UserSettings = typeof userSettings.$inferSelect;
export type InsertUserSettings = typeof userSettings.$inferInsert;
/**
* Import settings table for configuring different import methods
*/
export const importSettings = mysqlTable("importSettings", {
id: int("id").autoincrement().primaryKey(),
userId: int("userId").notNull().unique(), // One settings record per user
// Manual import settings
manualImportEnabled: int("manualImportEnabled").default(1).notNull(), // 0 = disabled, 1 = enabled
// Automatic import from folder settings
autoImportEnabled: int("autoImportEnabled").default(0).notNull(), // 0 = disabled, 1 = enabled
autoImportSourcePath: text("autoImportSourcePath"), // Path to folder to watch
autoImportFrequency: int("autoImportFrequency").default(60).notNull(), // Frequency in minutes (default: 60 = 1 hour)
// Email import settings
emailImportEnabled: int("emailImportEnabled").default(0).notNull(), // 0 = disabled, 1 = enabled
emailImportAddress: varchar("emailImportAddress", { length: 320 }), // Email address to monitor
emailImportPassword: text("emailImportPassword"), // Encrypted password
emailImportHost: varchar("emailImportHost", { length: 255 }), // IMAP server host
emailImportPort: int("emailImportPort").default(993), // IMAP port (default: 993 for SSL)
emailImportFrequency: int("emailImportFrequency").default(30).notNull(), // Frequency in minutes (default: 30)
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type ImportSettings = typeof importSettings.$inferSelect;
export type InsertImportSettings = typeof importSettings.$inferInsert;
/**
* Import logs table for tracking all import operations
*/