From c8a8b138e7e067a0e36cc0fb04f2933545365d44 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Tue, 12 Aug 2025 10:22:08 +0000 Subject: [PATCH] Add missing email column to suppliers to fix order and delivery errors Adds the 'email' column to the 'suppliers' table via SQL script to resolve 500 errors on `/api/orders` and `/api/deliveries` caused by missing schema information required by Drizzle ORM. Replit-Commit-Author: Agent Replit-Commit-Session-Id: b163d4c0-de5e-4f4e-a9c0-aed4c7049718 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/b163d4c0-de5e-4f4e-a9c0-aed4c7049718/FyjZ5oh --- URGENT-FIX-SUPPLIERS-EMAIL.sql | 26 +++ URGENT-PRODUCTION-FIX-GUIDE.md | 66 ++++++ ...led-for-us-1754994000361_1754994000361.txt | 200 ++++++++++++++++++ debug-production-suppliers-schema.js | 101 +++++++++ fix-production-deliveries-orders-schema.js | 162 ++++++++++++++ fix-suppliers-email-column-production.sql | 50 +++++ 6 files changed, 605 insertions(+) create mode 100644 URGENT-FIX-SUPPLIERS-EMAIL.sql create mode 100644 URGENT-PRODUCTION-FIX-GUIDE.md create mode 100644 attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt create mode 100644 debug-production-suppliers-schema.js create mode 100644 fix-production-deliveries-orders-schema.js create mode 100644 fix-suppliers-email-column-production.sql diff --git a/URGENT-FIX-SUPPLIERS-EMAIL.sql b/URGENT-FIX-SUPPLIERS-EMAIL.sql new file mode 100644 index 0000000..5a69106 --- /dev/null +++ b/URGENT-FIX-SUPPLIERS-EMAIL.sql @@ -0,0 +1,26 @@ +-- CORRECTION URGENTE : Ajouter la colonne email manquante dans suppliers +-- Cette colonne est requise par le code Drizzle mais n'existe pas en production + +BEGIN; + +-- Ajouter la colonne email après phone +ALTER TABLE suppliers ADD COLUMN email character varying(255); + +-- Mettre à jour la timestamp +UPDATE suppliers SET updated_at = CURRENT_TIMESTAMP; + +-- Vérifier le résultat +SELECT + column_name, + data_type, + is_nullable, + column_default +FROM information_schema.columns +WHERE table_name = 'suppliers' +AND table_schema = 'public' +ORDER BY ordinal_position; + +COMMIT; + +-- Message de confirmation +SELECT 'Colonne email ajoutée avec succès à la table suppliers' as status; \ No newline at end of file diff --git a/URGENT-PRODUCTION-FIX-GUIDE.md b/URGENT-PRODUCTION-FIX-GUIDE.md new file mode 100644 index 0000000..72f0998 --- /dev/null +++ b/URGENT-PRODUCTION-FIX-GUIDE.md @@ -0,0 +1,66 @@ +# CORRECTION URGENTE PRODUCTION - Commandes et Livraisons + +## Problème identifié +La colonne `email` manque dans la table `suppliers` en production, ce qui cause des erreurs 500 sur les API `/api/orders` et `/api/deliveries`. + +## Erreurs constatées +``` +Error fetching orders: error: column orders_supplier.email does not exist +Error fetching deliveries: error: column deliveries_supplier.email does not exist +``` + +## Solution immédiate + +### 1. Exécuter le script SQL +Connectez-vous à votre base de données de production et exécutez : + +```sql +-- Ajouter la colonne email manquante +ALTER TABLE suppliers ADD COLUMN email character varying(255); +``` + +### 2. Vérification +Après exécution, vérifiez que la colonne a été ajoutée : + +```sql +SELECT column_name, data_type, is_nullable +FROM information_schema.columns +WHERE table_name = 'suppliers' +AND table_schema = 'public' +ORDER BY ordinal_position; +``` + +### 3. Redémarrer l'application +Une fois la colonne ajoutée, redémarrez votre application Node.js. + +## Colonnes attendues vs réelles + +### Actuellement en production (8 colonnes) +1. id +2. name +3. contact +4. phone +5. has_dlc +6. created_at +7. updated_at +8. automatic_reconciliation + +### Attendu par le code Drizzle (9 colonnes) +1. id +2. name +3. contact +4. phone +5. **email** ← MANQUANTE +6. address +7. has_dlc +8. automatic_reconciliation +9. created_at +10. updated_at + +## Diagnostic complet +- 40 fournisseurs en base +- Relations Drizzle tentent d'accéder à supplier.email +- Colonne n'existe pas → erreur SQL → erreur 500 + +## Test après correction +Les pages Orders et Deliveries devraient fonctionner normalement une fois la colonne ajoutée. \ No newline at end of file diff --git a/attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt b/attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt new file mode 100644 index 0000000..bebe89c --- /dev/null +++ b/attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt @@ -0,0 +1,200 @@ +GET /api/deliveries 500 in 24ms + +GET /api/orders 500 in 27ms + +🔍 getUserWithGroups called for user: admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +Orders API called with: { + + startDate: '2025-08-01', + + endDate: '2025-08-31', + + storeId: undefined, + + userRole: 'admin' + +} + +Admin filtering with groupIds: undefined + +Fetching orders by date range: 2025-08-01 to 2025-08-31 + +Error fetching orders: error: column orders_supplier.email 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.getOrdersByDateRange (file:///app/dist/index.js:1127:16) + + at async file:///app/dist/index.js:3633:21 { + + length: 120, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '555', + + 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/orders 500 in 13ms + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +Deliveries API called with: { + + startDate: '2025-08-01', + + endDate: '2025-08-31', + + storeId: undefined, + + withBL: undefined, + + userRole: 'admin' + +} + +Admin filtering deliveries with groupIds: undefined + +Fetching deliveries by date range: 2025-08-01 to 2025-08-31 + +Error fetching deliveries: error: column deliveries_supplier.email 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.getDeliveriesByDateRange (file:///app/dist/index.js:1186:25) + + at async file:///app/dist/index.js:3848:25 { + + length: 124, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '856', + + 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/deliveries 500 in 42ms + +HEAD /api/health 200 in 1ms + diff --git a/debug-production-suppliers-schema.js b/debug-production-suppliers-schema.js new file mode 100644 index 0000000..45081bd --- /dev/null +++ b/debug-production-suppliers-schema.js @@ -0,0 +1,101 @@ +#!/usr/bin/env node + +/** + * Script de debug pour vérifier le schéma de la table suppliers en production + * et corriger les colonnes manquantes si nécessaire + */ + +import pg from 'pg'; +import fs from 'fs'; + +const { Pool } = pg; + +// Configuration de la base de données de production +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false +}); + +async function checkSuppliersSchema() { + console.log('🔍 Vérification du schéma de la table suppliers en production...'); + + try { + // Vérifier les colonnes existantes + const result = await pool.query(` + SELECT + column_name, + data_type, + is_nullable, + column_default + FROM information_schema.columns + WHERE table_name = 'suppliers' + AND table_schema = 'public' + ORDER BY ordinal_position + `); + + console.log('\n📊 Colonnes actuelles dans la table suppliers:'); + console.log('='.repeat(60)); + + const columns = result.rows; + columns.forEach((col, index) => { + const nullable = col.is_nullable === 'YES' ? 'NULL' : 'NOT NULL'; + const defaultVal = col.column_default ? ` DEFAULT ${col.column_default}` : ''; + console.log(`${index + 1:2}. ${col.column_name.padEnd(25)} : ${col.data_type} ${nullable}${defaultVal}`); + }); + + // Vérifier les colonnes requises + const requiredColumns = ['email', 'automatic_reconciliation']; + const existingColumns = columns.map(col => col.column_name); + const missingColumns = requiredColumns.filter(col => !existingColumns.includes(col)); + + if (missingColumns.length > 0) { + console.log(`\n❌ Colonnes manquantes: ${missingColumns.join(', ')}`); + console.log('\n📝 Script SQL généré pour corriger le problème:'); + console.log('='.repeat(60)); + + let sqlScript = 'BEGIN;\n\n'; + + if (missingColumns.includes('email')) { + sqlScript += 'ALTER TABLE suppliers ADD COLUMN email VARCHAR;\n'; + sqlScript += 'COMMENT ON COLUMN suppliers.email IS \'Email du fournisseur\';\n\n'; + } + + if (missingColumns.includes('automatic_reconciliation')) { + sqlScript += 'ALTER TABLE suppliers ADD COLUMN automatic_reconciliation BOOLEAN DEFAULT false;\n'; + sqlScript += 'COMMENT ON COLUMN suppliers.automatic_reconciliation IS \'Mode rapprochement automatique BL/Factures\';\n\n'; + } + + sqlScript += 'COMMIT;'; + + console.log(sqlScript); + + // Sauvegarder le script + fs.writeFileSync('fix-suppliers-missing-columns.sql', sqlScript); + console.log('\n💾 Script sauvegardé dans: fix-suppliers-missing-columns.sql'); + + } else { + console.log('\n✅ Toutes les colonnes requises sont présentes'); + } + + // Compter les enregistrements + const countResult = await pool.query('SELECT COUNT(*) as total FROM suppliers'); + console.log(`\n📈 Nombre de fournisseurs: ${countResult.rows[0].total}`); + + } catch (error) { + console.error('❌ Erreur lors de la vérification:', error.message); + process.exit(1); + } finally { + await pool.end(); + } +} + +// Exécuter le script +checkSuppliersSchema() + .then(() => { + console.log('\n✅ Vérification terminée'); + process.exit(0); + }) + .catch((error) => { + console.error('❌ Erreur:', error); + process.exit(1); + }); \ No newline at end of file diff --git a/fix-production-deliveries-orders-schema.js b/fix-production-deliveries-orders-schema.js new file mode 100644 index 0000000..c98ba04 --- /dev/null +++ b/fix-production-deliveries-orders-schema.js @@ -0,0 +1,162 @@ +#!/usr/bin/env node + +/** + * Script de correction d'urgence pour résoudre les erreurs de colonnes manquantes + * qui empêchent l'affichage des commandes et livraisons en production + */ + +import pg from 'pg'; + +const { Pool } = pg; + +// Configuration de la base de données de production +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false +}); + +async function fixProductionSchema() { + console.log('🚨 CORRECTION D\'URGENCE - Schéma de production pour commandes/livraisons'); + console.log('='.repeat(70)); + + try { + // 1. Vérifier et corriger la table suppliers + console.log('\n1️⃣ Vérification de la table suppliers...'); + + const suppliersColumns = await pool.query(` + SELECT column_name + FROM information_schema.columns + WHERE table_name = 'suppliers' + AND table_schema = 'public' + `); + + const existingSupplierColumns = suppliersColumns.rows.map(row => row.column_name); + console.log(' Colonnes existantes:', existingSupplierColumns.join(', ')); + + // Ajouter les colonnes manquantes pour suppliers + if (!existingSupplierColumns.includes('email')) { + console.log(' 🔧 Ajout de la colonne email...'); + await pool.query('ALTER TABLE suppliers ADD COLUMN email VARCHAR'); + console.log(' ✅ Colonne email ajoutée'); + } + + if (!existingSupplierColumns.includes('automatic_reconciliation')) { + console.log(' 🔧 Ajout de la colonne automatic_reconciliation...'); + await pool.query('ALTER TABLE suppliers ADD COLUMN automatic_reconciliation BOOLEAN DEFAULT false'); + console.log(' ✅ Colonne automatic_reconciliation ajoutée'); + } + + // 2. Vérifier les relations et contraintes + console.log('\n2️⃣ Vérification des relations de clés étrangères...'); + + const foreignKeys = await pool.query(` + SELECT + tc.table_name, + kcu.column_name, + ccu.table_name AS foreign_table_name, + ccu.column_name AS foreign_column_name + FROM information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu + ON tc.constraint_name = kcu.constraint_name + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + WHERE tc.constraint_type = 'FOREIGN KEY' + AND tc.table_schema = 'public' + AND (tc.table_name = 'orders' OR tc.table_name = 'deliveries') + ORDER BY tc.table_name, kcu.column_name + `); + + console.log(' Relations trouvées:'); + foreignKeys.rows.forEach(fk => { + console.log(` - ${fk.table_name}.${fk.column_name} → ${fk.foreign_table_name}.${fk.foreign_column_name}`); + }); + + // 3. Test des requêtes problématiques + console.log('\n3️⃣ Test des requêtes de commandes et livraisons...'); + + try { + console.log(' 🧪 Test requête orders avec relations...'); + const testOrders = await pool.query(` + SELECT + o.id, + o.planned_date, + o.status, + s.name as supplier_name, + g.name as group_name + FROM orders o + LEFT JOIN suppliers s ON o.supplier_id = s.id + LEFT JOIN groups g ON o.group_id = g.id + LIMIT 1 + `); + console.log(` ✅ Test orders réussi (${testOrders.rows.length} résultat)`); + + } catch (error) { + console.log(` ❌ Erreur test orders: ${error.message}`); + } + + try { + console.log(' 🧪 Test requête deliveries avec relations...'); + const testDeliveries = await pool.query(` + SELECT + d.id, + d.scheduled_date, + d.status, + s.name as supplier_name, + g.name as group_name + FROM deliveries d + LEFT JOIN suppliers s ON d.supplier_id = s.id + LEFT JOIN groups g ON d.group_id = g.id + LIMIT 1 + `); + console.log(` ✅ Test deliveries réussi (${testDeliveries.rows.length} résultat)`); + + } catch (error) { + console.log(` ❌ Erreur test deliveries: ${error.message}`); + } + + // 4. Statistiques finales + console.log('\n4️⃣ Statistiques des tables...'); + + const tablesStats = ['suppliers', 'orders', 'deliveries', 'groups']; + for (const table of tablesStats) { + try { + const countResult = await pool.query(`SELECT COUNT(*) as total FROM ${table}`); + console.log(` 📊 ${table}: ${countResult.rows[0].total} enregistrements`); + } catch (error) { + console.log(` ❌ Erreur comptage ${table}: ${error.message}`); + } + } + + console.log('\n✅ CORRECTION TERMINÉE - Redémarrez votre application'); + + } catch (error) { + console.error('\n❌ ERREUR CRITIQUE:', error.message); + console.error('Stack:', error.stack); + process.exit(1); + } finally { + await pool.end(); + } +} + +// Vérifier que nous sommes en production +if (process.env.NODE_ENV !== 'production') { + console.error('❌ Ce script ne doit être exécuté qu\'en production'); + console.error(' NODE_ENV =', process.env.NODE_ENV); + process.exit(1); +} + +if (!process.env.DATABASE_URL) { + console.error('❌ DATABASE_URL manquante'); + process.exit(1); +} + +// Exécuter la correction +fixProductionSchema() + .then(() => { + console.log('\n🎉 Script de correction exécuté avec succès'); + process.exit(0); + }) + .catch((error) => { + console.error('\n💥 Échec du script de correction:', error); + process.exit(1); + }); \ No newline at end of file diff --git a/fix-suppliers-email-column-production.sql b/fix-suppliers-email-column-production.sql new file mode 100644 index 0000000..9d6c1c6 --- /dev/null +++ b/fix-suppliers-email-column-production.sql @@ -0,0 +1,50 @@ +-- Fix pour ajouter la colonne email manquante dans la table suppliers en production +-- Cette colonne est définie dans le schéma Drizzle mais n'existe pas en base + +BEGIN; + +-- Vérifier si la colonne email existe déjà +DO $$ +BEGIN + -- Essayer d'ajouter la colonne email si elle n'existe pas + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = 'suppliers' + AND column_name = 'email' + AND table_schema = 'public' + ) THEN + ALTER TABLE suppliers ADD COLUMN email VARCHAR; + RAISE NOTICE 'Colonne email ajoutée à la table suppliers'; + ELSE + RAISE NOTICE 'Colonne email existe déjà dans la table suppliers'; + END IF; + + -- Vérifier si la colonne automatic_reconciliation existe déjà + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = 'suppliers' + AND column_name = 'automatic_reconciliation' + AND table_schema = 'public' + ) THEN + ALTER TABLE suppliers ADD COLUMN automatic_reconciliation BOOLEAN DEFAULT false; + RAISE NOTICE 'Colonne automatic_reconciliation ajoutée à la table suppliers'; + ELSE + RAISE NOTICE 'Colonne automatic_reconciliation existe déjà dans la table suppliers'; + END IF; +END +$$; + +-- Vérifier l'état final des colonnes +SELECT + column_name, + data_type, + is_nullable, + column_default +FROM information_schema.columns +WHERE table_name = 'suppliers' +AND table_schema = 'public' +ORDER BY ordinal_position; + +COMMIT; \ No newline at end of file