Fix production SAV module issues by adding missing columns and updating schemas

Introduce a SQL migration script to address critical production issues in the SAV module by adding missing columns to the `sav_tickets` table, correcting default values, and ensuring proper foreign key constraints and indexes are in place. This resolves "column does not exist" errors and aligns the production database schema with the development environment.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 31f9bd88-0285-4787-81b3-31ceeea5a08b
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/31f9bd88-0285-4787-81b3-31ceeea5a08b/BuVhk7G
This commit is contained in:
michaelschal committed 2025-08-14 09:21:36 +00:00
1 parent d9c4e091af
commit 45abdc5973
4 files changed
+319 -2

No files matched your search

@@ -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
+104
View File
@@ -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 !';
+9
View File
@@ -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** :
+2 -2
View File
@@ -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"),
});