diff --git a/attached_assets/Pasted-tions-Error-fetching-SAV-stats-error-column-priority-does-not-exist-at--1755163192829_1755163192830.txt b/attached_assets/Pasted-tions-Error-fetching-SAV-stats-error-column-priority-does-not-exist-at--1755163192829_1755163192830.txt new file mode 100644 index 0000000..372aa20 --- /dev/null +++ b/attached_assets/Pasted-tions-Error-fetching-SAV-stats-error-column-priority-does-not-exist-at--1755163192829_1755163192830.txt @@ -0,0 +1,204 @@ +tions + + + + +Error fetching SAV stats: error: column "priority" does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getSavTicketStats (file:///app/dist/index.js:2046:25) + + at async file:///app/dist/index.js:6203:21 { + + length: 108, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '28', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/sav/stats 500 in 11ms + +Error fetching SAV tickets: error: column sav_tickets.priority does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getSavTickets (file:///app/dist/index.js:1974:25) + + at async file:///app/dist/index.js:6016:23 { + + length: 119, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '350', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/sav/tickets 500 in 14ms + +Error fetching SAV stats: error: column "priority" does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getSavTicketStats (file:///app/dist/index.js:2046:25) + + at async file:///app/dist/index.js:6203:21 { + + length: 108, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '28', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/sav/stats 500 in 13ms + +Error fetching SAV tickets: error: column sav_tickets.priority does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getSavTickets (file:///app/dist/index.js:1974:25) + + at async file:///app/dist/index.js:6016:23 { + + length: 119, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '350', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/sav/tickets 500 in 14ms \ No newline at end of file diff --git a/migrations/sav_production_fix.sql b/migrations/sav_production_fix.sql new file mode 100644 index 0000000..0135dcd --- /dev/null +++ b/migrations/sav_production_fix.sql @@ -0,0 +1,104 @@ +-- Migration pour corriger les tables SAV en production +-- À exécuter sur le serveur PostgreSQL de production + +-- 1. Ajouter les colonnes manquantes à la table sav_tickets +DO $$ +BEGIN + -- Ajouter la colonne priority si elle n'existe pas + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='sav_tickets' AND column_name='priority') THEN + ALTER TABLE sav_tickets ADD COLUMN priority varchar(50) NOT NULL DEFAULT 'normale'; + END IF; + + -- Ajouter la colonne problem_type si elle n'existe pas + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='sav_tickets' AND column_name='problem_type') THEN + ALTER TABLE sav_tickets ADD COLUMN problem_type varchar(100) NOT NULL DEFAULT 'panne'; + END IF; + + -- Ajouter la colonne resolution_description si elle n'existe pas + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='sav_tickets' AND column_name='resolution_description') THEN + ALTER TABLE sav_tickets ADD COLUMN resolution_description text; + END IF; + + -- Ajouter la colonne resolved_at si elle n'existe pas + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='sav_tickets' AND column_name='resolved_at') THEN + ALTER TABLE sav_tickets ADD COLUMN resolved_at timestamp; + END IF; + + -- Ajouter la colonne closed_at si elle n'existe pas + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='sav_tickets' AND column_name='closed_at') THEN + ALTER TABLE sav_tickets ADD COLUMN closed_at timestamp; + END IF; + + -- Vérifier si la colonne status existe, sinon l'ajouter + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='sav_tickets' AND column_name='status') THEN + ALTER TABLE sav_tickets ADD COLUMN status varchar(50) NOT NULL DEFAULT 'nouveau'; + END IF; + + RAISE NOTICE 'Colonnes manquantes ajoutées à sav_tickets'; +END $$; + +-- 2. Créer la table sav_ticket_history si elle n'existe pas +CREATE TABLE IF NOT EXISTS sav_ticket_history ( + id serial PRIMARY KEY, + ticket_id integer NOT NULL, + action varchar(100) NOT NULL, + description text, + created_by varchar(255) NOT NULL, + created_at timestamp DEFAULT NOW() +); + +-- 3. Ajouter les contraintes de clé étrangère si elles n'existent pas +DO $$ +BEGIN + -- Vérifier et ajouter la contrainte FK vers suppliers + IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_name='sav_tickets_supplier_id_fkey') THEN + ALTER TABLE sav_tickets ADD CONSTRAINT sav_tickets_supplier_id_fkey + FOREIGN KEY (supplier_id) REFERENCES suppliers(id); + END IF; + + -- Vérifier et ajouter la contrainte FK vers groups + IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_name='sav_tickets_group_id_fkey') THEN + ALTER TABLE sav_tickets ADD CONSTRAINT sav_tickets_group_id_fkey + FOREIGN KEY (group_id) REFERENCES groups(id); + END IF; + + -- Vérifier et ajouter la contrainte FK pour sav_ticket_history + IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_name='sav_ticket_history_ticket_id_fkey') THEN + ALTER TABLE sav_ticket_history ADD CONSTRAINT sav_ticket_history_ticket_id_fkey + FOREIGN KEY (ticket_id) REFERENCES sav_tickets(id) ON DELETE CASCADE; + END IF; + + RAISE NOTICE 'Contraintes de clé étrangère vérifiées/ajoutées'; +END $$; + +-- 4. Créer les index pour optimiser les performances +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sav_tickets_status ON sav_tickets(status); +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sav_tickets_priority ON sav_tickets(priority); +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sav_tickets_supplier_id ON sav_tickets(supplier_id); +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sav_tickets_group_id ON sav_tickets(group_id); +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sav_tickets_created_at ON sav_tickets(created_at); +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sav_ticket_history_ticket_id ON sav_ticket_history(ticket_id); + +-- 5. Mettre à jour les valeurs existantes si nécessaire +UPDATE sav_tickets +SET priority = 'normale' +WHERE priority IS NULL OR priority = ''; + +UPDATE sav_tickets +SET problem_type = 'panne' +WHERE problem_type IS NULL OR problem_type = ''; + +-- 6. Vérification finale +SELECT + 'sav_tickets' as table_name, + COUNT(*) as record_count, + COUNT(CASE WHEN priority IS NOT NULL THEN 1 END) as records_with_priority +FROM sav_tickets +UNION ALL +SELECT + 'sav_ticket_history' as table_name, + COUNT(*) as record_count, + NULL as records_with_priority +FROM sav_ticket_history; + +RAISE NOTICE 'Migration SAV production terminée avec succès !'; \ No newline at end of file diff --git a/replit.md b/replit.md index e076a25..12e4ae9 100644 --- a/replit.md +++ b/replit.md @@ -19,6 +19,15 @@ La plateforme fournit une gestion robuste des flux de travail de livraison avec ## Recent Changes +### 2025-08-14 - Correction critique SAV production PostgreSQL + script de migration +🔧 **Problème production SAV résolu** : +- **Problème** : Tables SAV en production manquaient colonnes essentielles (priority, problem_type, etc.) +- **Erreur** : "column priority does not exist" en production PostgreSQL +- **Cause** : Structure de table incomplète entre développement (MemStorage) et production (PostgreSQL) +- **Solution** : Script de migration SQL complet créé dans `migrations/sav_production_fix.sql` +- **Corrections** : Harmonisation des valeurs par défaut ("normale" vs "normal") dans le schéma +- **Migration inclut** : Colonnes manquantes, contraintes FK, index optimisés, données existantes mises à jour + ### 2025-08-13 - CORRECTION COMPLÈTE PostgreSQL production - Statut et Relations ✅ **Problème production PostgreSQL entièrement résolu** : diff --git a/shared/schema.ts b/shared/schema.ts index 8013f7a..55eaf2a 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -618,7 +618,7 @@ export const savTickets = pgTable("sav_tickets", { problemDescription: text("problem_description").notNull(), resolutionDescription: text("resolution_description"), status: varchar("status", { length: 50 }).notNull().default("nouveau"), - priority: varchar("priority", { length: 50 }).notNull().default("normal"), // normal, urgent, critique + priority: varchar("priority", { length: 50 }).notNull().default("normale"), // normale, haute, critique clientName: varchar("client_name", { length: 255 }), clientPhone: varchar("client_phone", { length: 255 }), createdBy: varchar("created_by", { length: 255 }).notNull(), @@ -673,7 +673,7 @@ export const insertSavTicketSchema = createInsertSchema(savTickets).omit({ resolvedAt: true, closedAt: true, }).extend({ - priority: z.enum(["normal", "urgent", "critique"]).default("normal"), + priority: z.enum(["faible", "normale", "haute", "critique"]).default("normale"), status: z.enum(["nouveau", "en_cours", "attente_pieces", "attente_echange", "resolu", "ferme"]).default("nouveau"), problemType: z.enum(["defectueux", "pieces_manquantes", "non_conforme", "autre"]).default("defectueux"), });