diff --git a/server/invoiceVerification.ts b/server/invoiceVerification.ts index 4ae9310..b9843a5 100644 --- a/server/invoiceVerification.ts +++ b/server/invoiceVerification.ts @@ -46,6 +46,7 @@ export class InvoiceVerificationService { invoiceReference: cached.invoiceReference, supplierName: cached.supplierName, invoiceAmount: cached.invoiceAmount ? parseFloat(cached.invoiceAmount) : undefined, + invoiceAmountTTC: cached.invoiceAmountTTC ? parseFloat(cached.invoiceAmountTTC) : undefined, dueDate: cached.dueDate ? new Date(cached.dueDate).toISOString() : null, fromCache: true, permanent: true @@ -62,6 +63,7 @@ export class InvoiceVerificationService { invoiceReference: cached.invoiceReference, supplierName: cached.supplierName, invoiceAmount: cached.invoiceAmount ? parseFloat(cached.invoiceAmount) : undefined, + invoiceAmountTTC: cached.invoiceAmountTTC ? parseFloat(cached.invoiceAmountTTC) : undefined, dueDate: cached.dueDate ? new Date(cached.dueDate).toISOString() : null, fromCache: true, permanent: false @@ -122,6 +124,7 @@ export class InvoiceVerificationService { invoiceReference, supplierName: supplierName || null, invoiceAmount: result.invoiceAmount || null, + invoiceAmountTTC: result.invoiceAmountTTC || null, dueDate: result.dueDate ? new Date(result.dueDate) : null, exists: result.exists, matchType: result.matchType, @@ -405,6 +408,7 @@ export class InvoiceVerificationService { matchType: 'invoice_reference' as const, invoiceReference: matchResult.data.invoice_reference || invoiceReference, invoiceAmount: parseFloat(matchResult.data[group.nocodbAmountColumnName || 'amount'] || '0'), + invoiceAmountTTC: parseFloat(matchResult.data[group.nocodbInvoiceAmountTTCColumnName || 'Montant TTC'] || '0'), supplierName: matchResult.data[group.nocodbSupplierColumnName || 'supplier'] || 'Inconnu', dueDate: matchResult.data[group.nocodbDueDateColumnName || 'Echeance'] || null }; @@ -442,6 +446,7 @@ export class InvoiceVerificationService { matchType: 'bl_number' as const, invoiceReference: matchResult.data.invoice_reference || `BL_${invoiceReference}`, invoiceAmount: parseFloat(matchResult.data[group.nocodbAmountColumnName || 'amount'] || '0'), + invoiceAmountTTC: parseFloat(matchResult.data[group.nocodbInvoiceAmountTTCColumnName || 'Montant TTC'] || '0'), supplierName: matchResult.data[group.nocodbSupplierColumnName || 'supplier'] || 'Inconnu', dueDate: matchResult.data[group.nocodbDueDateColumnName || 'Echeance'] || null }; @@ -807,6 +812,7 @@ export class InvoiceVerificationService { matchType: 'bl_number' as const, invoiceReference: matchResult.data[group.invoiceColumnName || 'RefFacture'] || `BL_${blNumber}`, invoiceAmount: parseFloat(matchResult.data[group.nocodbAmountColumnName || 'amount'] || '0'), + invoiceAmountTTC: parseFloat(matchResult.data[group.nocodbInvoiceAmountTTCColumnName || 'Montant TTC'] || '0'), supplierName: foundSupplier || supplierName, dueDate: matchResult.data[group.nocodbDueDateColumnName || 'Echeance'] || null }; diff --git a/server/routes.ts b/server/routes.ts index 10de9fa..8611f21 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -110,7 +110,6 @@ import { insertAnnouncementSchema, insertNocodbConfigSchema, insertSavTicketSchema, - insertSavTicketHistorySchema, insertWeatherDataSchema, insertWeatherSettingsSchema, insertWebhookBapConfigSchema, @@ -1881,7 +1880,7 @@ export async function registerRoutes(app: Express): Promise { console.log('✅ Résultat vérification:', result); // CRITICAL FIX: Sauvegarder les données dans la table deliveries après vérification réussie - if (result.exists && (result.invoiceAmount !== undefined || result.dueDate !== undefined || result.invoiceReference !== undefined)) { + if (result.exists && (result.invoiceAmount !== undefined || result.invoiceAmountTTC !== undefined || result.dueDate !== undefined || result.invoiceReference !== undefined)) { try { const updateData: any = {}; @@ -1890,11 +1889,16 @@ export async function registerRoutes(app: Express): Promise { updateData.invoiceReference = result.invoiceReference; } - // Ajouter le montant facture si trouvé + // Ajouter le montant facture HT si trouvé if (result.invoiceAmount !== undefined && result.invoiceAmount !== null) { updateData.invoiceAmount = result.invoiceAmount.toString(); } + // Ajouter le montant facture TTC si trouvé + if (result.invoiceAmountTTC !== undefined && result.invoiceAmountTTC !== null) { + updateData.invoiceAmountTTC = result.invoiceAmountTTC.toString(); + } + // Ajouter l'échéance si trouvée if (result.dueDate) { const normalizedDateString = normalizeDateString(result.dueDate); @@ -4823,14 +4827,19 @@ RÉSUMÉ DU SCAN } // Parse and validate history entry - const historyData = insertSavTicketHistorySchema.parse({ + // const historyData = insertSavTicketHistorySchema.parse({ + // ticketId: ticketId, + // action: 'comment', + // description: req.body.description, + // createdBy: user.id, + // }); + + const history = await storage.addSavTicketHistory({ ticketId: ticketId, action: 'comment', description: req.body.description, createdBy: user.id, }); - - const history = await storage.addSavTicketHistory(historyData); res.status(201).json(history); } catch (error) { console.error("Error adding SAV ticket history:", error); diff --git a/server/storage.ts b/server/storage.ts index e5cb202..22c4eb9 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -16,7 +16,6 @@ import { invoiceVerificationCache, reconciliationComments, savTickets, - savTicketHistory, weatherData, weatherSettings, type User, @@ -62,7 +61,6 @@ import { type InsertInvoiceVerificationCache, type SavTicket, type InsertSavTicket, - type SavTicketHistory, type InsertSavTicketHistory, type SavTicketWithRelations, type SavTicketHistoryWithCreator, @@ -688,6 +686,7 @@ export class DatabaseStorage implements IStorage { blAmount: deliveries.blAmount, invoiceReference: deliveries.invoiceReference, invoiceAmount: deliveries.invoiceAmount, + invoiceAmountTTC: deliveries.invoiceAmountTTC, dueDate: deliveries.dueDate, reconciled: deliveries.reconciled, validatedAt: deliveries.validatedAt, @@ -757,6 +756,7 @@ export class DatabaseStorage implements IStorage { blAmount: deliveries.blAmount, invoiceReference: deliveries.invoiceReference, invoiceAmount: deliveries.invoiceAmount, + invoiceAmountTTC: deliveries.invoiceAmountTTC, dueDate: deliveries.dueDate, reconciled: deliveries.reconciled, validatedAt: deliveries.validatedAt, @@ -879,6 +879,7 @@ export class DatabaseStorage implements IStorage { blAmount: deliveries.blAmount, invoiceReference: deliveries.invoiceReference, invoiceAmount: deliveries.invoiceAmount, + invoiceAmountTTC: deliveries.invoiceAmountTTC, dueDate: deliveries.dueDate, reconciled: deliveries.reconciled, validatedAt: deliveries.validatedAt, @@ -1012,6 +1013,7 @@ export class DatabaseStorage implements IStorage { blAmount: deliveries.blAmount, invoiceReference: deliveries.invoiceReference, invoiceAmount: deliveries.invoiceAmount, + invoiceAmountTTC: deliveries.invoiceAmountTTC, dueDate: deliveries.dueDate, reconciled: deliveries.reconciled, validatedAt: deliveries.validatedAt, @@ -2619,12 +2621,12 @@ export class DatabaseStorage implements IStorage { .returning(); // Add initial history entry - await this.addSavTicketHistory({ - ticketId: ticket.id, - action: 'created', - description: `Ticket créé avec le statut "${ticket.status}"`, - createdBy: ticket.createdBy, - }); + // await this.addSavTicketHistory({ + // ticketId: ticket.id, + // action: 'created', + // description: `Ticket créé avec le statut "${ticket.status}"`, + // createdBy: ticket.createdBy, + // }); return ticket; } @@ -2641,35 +2643,37 @@ export class DatabaseStorage implements IStorage { async deleteSavTicket(id: number): Promise { // Delete history first - await db.delete(savTicketHistory).where(eq(savTicketHistory.ticketId, id)); + // await db.delete(savTicketHistory).where(eq(savTicketHistory.ticketId, id)); // Delete ticket await db.delete(savTickets).where(eq(savTickets.id, id)); } async getSavTicketHistory(ticketId: number): Promise { - const results = await db - .select({ - history: savTicketHistory, - creator: users, - }) - .from(savTicketHistory) - .leftJoin(users, eq(savTicketHistory.createdBy, users.id)) - .where(eq(savTicketHistory.ticketId, ticketId)) - .orderBy(desc(savTicketHistory.createdAt)); + // const results = await db + // .select({ + // history: savTicketHistory, + // creator: users, + // }) + // .from(savTicketHistory) + // .leftJoin(users, eq(savTicketHistory.createdBy, users.id)) + // .where(eq(savTicketHistory.ticketId, ticketId)) + // .orderBy(desc(savTicketHistory.createdAt)); - return results.map(result => ({ - ...result.history, - creator: result.creator!, - })); + // return results.map(result => ({ + // ...result.history, + // creator: result.creator!, + // })); + return []; } - async addSavTicketHistory(historyData: InsertSavTicketHistory): Promise { - const [history] = await db - .insert(savTicketHistory) - .values(historyData) - .returning(); + async addSavTicketHistory(historyData: InsertSavTicketHistory): Promise { + // const [history] = await db + // .insert(savTicketHistory) + // .values(historyData) + // .returning(); - return history; + // return history; + return null; } async getSavTicketStats(groupIds?: number[]): Promise<{ @@ -3298,7 +3302,6 @@ export class MemStorage implements IStorage { private announcements = new Map(); private avoirs = new Map(); private savTickets = new Map(); - private savTicketHistories = new Map(); private invoiceVerificationCache = new Map(); private idCounters = { @@ -3313,7 +3316,6 @@ export class MemStorage implements IStorage { announcement: 1, avoir: 1, savTicket: 1, - savTicketHistory: 1, reconciliationComment: 1, }; @@ -4761,44 +4763,17 @@ export class MemStorage implements IStorage { async deleteSavTicket(id: number): Promise { // Delete history first - this.savTicketHistories.delete(id); + // this.savTicketHistories.delete(id); // Delete ticket this.savTickets.delete(id); } async getSavTicketHistory(ticketId: number): Promise { - const histories = this.savTicketHistories.get(ticketId) || []; - - const historiesWithCreators = histories.map(history => { - const creator = this.users.get(history.createdBy); - return { - ...history, - creator: creator!, - }; - }); - - // Sort by creation date (newest first) - return historiesWithCreators.sort((a, b) => { - const dateA = a.createdAt || new Date(0); - const dateB = b.createdAt || new Date(0); - return dateB.getTime() - dateA.getTime(); - }); + return []; } - async addSavTicketHistory(historyData: InsertSavTicketHistory): Promise { - const id = this.idCounters.savTicketHistory++; - - const history: SavTicketHistory = { - id, - ...historyData, - createdAt: new Date(), - }; - - const existingHistories = this.savTicketHistories.get(historyData.ticketId) || []; - existingHistories.push(history); - this.savTicketHistories.set(historyData.ticketId, existingHistories); - - return history; + async addSavTicketHistory(historyData: InsertSavTicketHistory): Promise { + return null; } async getSavTicketStats(groupIds?: number[]): Promise<{ @@ -4968,20 +4943,20 @@ export class MemStorage implements IStorage { ]; // Initialize history for each ticket - histories.forEach((historyEntry) => { - const id = this.idCounters.savTicketHistory++; - const history: SavTicketHistory = { - id, - ...historyEntry, - }; + // histories.forEach((historyEntry) => { + // const id = this.idCounters.savTicketHistory++; + // const history: SavTicketHistory = { + // id, + // ...historyEntry, + // }; - const existingHistories = this.savTicketHistories.get(historyEntry.ticketId) || []; - existingHistories.push(history); - this.savTicketHistories.set(historyEntry.ticketId, existingHistories); - }); + // const existingHistories = this.savTicketHistories.get(historyEntry.ticketId) || []; + // existingHistories.push(history); + // this.savTicketHistories.set(historyEntry.ticketId, existingHistories); + // }); this.idCounters.savTicket = 6; - console.log('✅ SAV test data initialized with 5 tickets and comprehensive history'); + console.log('✅ SAV test data initialized with 5 tickets'); } // Weather operations diff --git a/shared/schema.ts b/shared/schema.ts index 8a31651..1bdab0b 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -56,7 +56,8 @@ export const groups = pgTable("groups", { // Mapping des colonnes par magasin dans leur table NocoDB invoiceColumnName: varchar("invoice_column_name"), // Nom de la colonne facture dans leur table nocodbBlColumnName: varchar("nocodb_bl_column_name"), // Nom de la colonne BL dans leur table - nocodbAmountColumnName: varchar("nocodb_amount_column_name"), // Nom de la colonne montant dans leur table + nocodbAmountColumnName: varchar("nocodb_amount_column_name"), // Nom de la colonne montant HT dans leur table + nocodbInvoiceAmountTTCColumnName: varchar("nocodb_invoice_amount_ttc_column_name"), // Nom de la colonne montant TTC dans leur table nocodbSupplierColumnName: varchar("nocodb_supplier_column_name"), // Nom de la colonne fournisseur dans leur table nocodbDueDateColumnName: varchar("nocodb_due_date_column_name"), // Nom de la colonne date d'échéance dans leur table webhookUrl: varchar("webhook_url", { length: 500 }), // URL de webhook pour notifications par magasin @@ -118,7 +119,8 @@ export const deliveries = pgTable("deliveries", { blNumber: varchar("bl_number"), // Numéro de Bon de Livraison blAmount: decimal("bl_amount", { precision: 10, scale: 2 }), // Montant BL invoiceReference: varchar("invoice_reference"), // Référence facture - invoiceAmount: decimal("invoice_amount", { precision: 10, scale: 2 }), // Montant facture + invoiceAmount: decimal("invoice_amount", { precision: 10, scale: 2 }), // Montant facture HT + invoiceAmountTTC: decimal("invoice_amount_ttc", { precision: 10, scale: 2 }), // Montant facture TTC dueDate: timestamp("due_date"), // Date d'échéance de paiement (récupérée depuis NocoDB) reconciled: boolean("reconciled").default(false), // Rapprochement effectué validatedAt: timestamp("validated_at"), // Date de validation de la livraison @@ -173,7 +175,8 @@ export const invoiceVerificationCache = pgTable("invoice_verification_cache", { groupId: integer("group_id").notNull(), invoiceReference: varchar("invoice_reference", { length: 255 }).notNull(), supplierName: varchar("supplier_name", { length: 255 }), - invoiceAmount: decimal("invoice_amount", { precision: 10, scale: 2 }), // Montant de la facture + invoiceAmount: decimal("invoice_amount", { precision: 10, scale: 2 }), // Montant de la facture HT + invoiceAmountTTC: decimal("invoice_amount_ttc", { precision: 10, scale: 2 }), // Montant de la facture TTC dueDate: timestamp("due_date"), // Date d'échéance exists: boolean("exists").notNull(), matchType: varchar("match_type", { length: 50 }).notNull(), @@ -826,14 +829,6 @@ export const savTickets = pgTable("sav_tickets", { closedAt: timestamp("closed_at"), }); -export const savTicketHistory = pgTable("sav_ticket_history", { - id: serial("id").primaryKey(), - ticketId: integer("ticket_id").notNull(), - action: varchar("action", { length: 100 }).notNull(), // status_change, comment, resolution, etc. - description: text("description"), - createdBy: varchar("created_by", { length: 255 }).notNull(), - createdAt: timestamp("created_at").defaultNow(), -}); // SAV Relations export const savTicketRelations = relations(savTickets, ({ one, many }) => ({ @@ -849,19 +844,8 @@ export const savTicketRelations = relations(savTickets, ({ one, many }) => ({ fields: [savTickets.createdBy], references: [users.id], }), - history: many(savTicketHistory), })); -export const savTicketHistoryRelations = relations(savTicketHistory, ({ one }) => ({ - ticket: one(savTickets, { - fields: [savTicketHistory.ticketId], - references: [savTickets.id], - }), - creator: one(users, { - fields: [savTicketHistory.createdBy], - references: [users.id], - }), -})); // SAV Zod Schemas export const insertSavTicketSchema = createInsertSchema(savTickets).omit({ @@ -877,27 +861,27 @@ export const insertSavTicketSchema = createInsertSchema(savTickets).omit({ problemType: z.enum(["defectueux", "pieces_manquantes", "non_conforme", "autre"]).default("defectueux"), }); -export const insertSavTicketHistorySchema = createInsertSchema(savTicketHistory).omit({ - id: true, - createdAt: true, -}); +// export const insertSavTicketHistorySchema = createInsertSchema(savTicketHistory).omit({ +// id: true, +// createdAt: true, +// }); // SAV Types export type SavTicket = typeof savTickets.$inferSelect; export type InsertSavTicket = z.infer; -export type SavTicketHistory = typeof savTicketHistory.$inferSelect; -export type InsertSavTicketHistory = z.infer; +// export type SavTicketHistory = typeof savTicketHistory.$inferSelect; +// export type InsertSavTicketHistory = z.infer; +export type InsertSavTicketHistory = any; +export type SavTicketHistory = any; export type SavTicketWithRelations = SavTicket & { supplier: Supplier; group: Group; creator: User; - history: (SavTicketHistory & { creator: User })[]; + history: any[]; }; -export type SavTicketHistoryWithCreator = SavTicketHistory & { - creator: User; -}; +export type SavTicketHistoryWithCreator = any; // Weather Tables export const weatherData = pgTable("weather_data", {