From f21d807968ff00a9629a5b9dd7eb34f4b4ab0929 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Sat, 16 Aug 2025 07:27:13 +0000 Subject: [PATCH] Improve store data handling and user authentication for multiple stores Update storage and authentication logic to support multiple stores, including specific configurations for "Magasin 1" and "Magasin 2", and add new development user credentials. Replit-Commit-Author: Agent Replit-Commit-Session-Id: a3de0820-9397-41b2-b000-7931ee9c29de Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/a3de0820-9397-41b2-b000-7931ee9c29de/mKF47ul --- cookies.txt | 2 +- cookies_manager1.txt | 5 + cookies_manager2.txt | 5 + server/localAuth.ts | 10 +- server/storage.ts | 240 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 240 insertions(+), 22 deletions(-) create mode 100644 cookies_manager1.txt create mode 100644 cookies_manager2.txt diff --git a/cookies.txt b/cookies.txt index 0feb356..02f39c6 100644 --- a/cookies.txt +++ b/cookies.txt @@ -2,4 +2,4 @@ # https://curl.se/docs/http-cookies.html # This file was generated by libcurl! Edit at your own risk. -#HttpOnly_localhost FALSE / FALSE 1755334812 connect.sid s%3AIUsQcAbYjJ2Yu9GRwhXwQt22rGvvMGRo.zTBgX64O5zq1nh16Yc0umuKKQnBAy0xAn4BkA5iErOQ +#HttpOnly_localhost FALSE / FALSE 1755415501 connect.sid s%3Akq9rv9dYrk7ObCvKdTPAwZUL7UaWGfqL.x5cl2uDVboBhiWzQE1pp4349NXCs5x%2ByI8OHzfVl8%2Bw diff --git a/cookies_manager1.txt b/cookies_manager1.txt new file mode 100644 index 0000000..14a2b42 --- /dev/null +++ b/cookies_manager1.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_localhost FALSE / FALSE 1755415612 connect.sid s%3ALA_C3VgRvKbgl1oG2suDWpO0NfwuqOpQ.%2B1GRLR0jeREW8LP6YP5YNnQJG0UtzOoYylg2R3Vf4Hg diff --git a/cookies_manager2.txt b/cookies_manager2.txt new file mode 100644 index 0000000..d56163c --- /dev/null +++ b/cookies_manager2.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_localhost FALSE / FALSE 1755415612 connect.sid s%3ARzj7n77KbzyUgygzi1pqOCY7ToJBSeT7.A2HiKInsuth99WAyYy%2Bc2ZnZePEr3rtLet6qccJCXN0 diff --git a/server/localAuth.ts b/server/localAuth.ts index 69f4aa1..34dfab4 100644 --- a/server/localAuth.ts +++ b/server/localAuth.ts @@ -25,11 +25,19 @@ export async function hashPassword(password: string) { async function comparePasswords(supplied: string, stored: string) { console.log('🔐 comparePasswords:', { supplied: 'HIDDEN', stored: stored?.substring(0, 20) + '...', hasFormat: stored?.includes('.') }); - // Simple password comparison for development (admin.salt format) + // Simple password comparison for development users if (stored === 'admin.salt' && supplied === 'admin') { console.log('🔐 Development auth: admin password accepted'); return true; } + if (stored === 'manager1.salt' && supplied === 'manager1') { + console.log('🔐 Development auth: manager1 password accepted'); + return true; + } + if (stored === 'manager2.salt' && supplied === 'manager2') { + console.log('🔐 Development auth: manager2 password accepted'); + return true; + } // Vérifier le format du mot de passe stocké pour production if (!stored || !stored.includes('.')) { diff --git a/server/storage.ts b/server/storage.ts index 8440673..aa044b7 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -1863,6 +1863,7 @@ export class MemStorage implements IStorage { private tasks = new Map(); private savTickets = new Map(); private savTicketHistories = new Map(); + private passwords = new Map(); private idCounters = { group: 1, @@ -1892,13 +1893,14 @@ export class MemStorage implements IStorage { firstName: 'Admin', lastName: 'User', profileImageUrl: null, - password: 'admin', // In real app, this would be hashed + password: 'admin.salt', // Development format with salt role: 'admin', passwordChanged: false, createdAt: new Date(), updatedAt: new Date(), }; this.users.set(adminUser.id, adminUser); + this.passwords.set('admin', { password: 'admin.salt', hasFormat: true }); // Initialize group counter this.idCounters.group = 2; @@ -1907,39 +1909,124 @@ export class MemStorage implements IStorage { this.idCounters.supplier = 2; // Create test groups - const testGroup: Group = { + const testGroup1: Group = { id: 1, - name: 'Magasin Test', + name: 'Magasin 1', color: '#3B82F6', nocodbConfigId: 1, // Référence vers la config NocoDB de test - nocodbTableName: 'invoices', + nocodbTableName: 'invoices_store1', nocodbTableId: 'mrr733dfb8wtt9b', // ID réel de la table NocoDB invoiceColumnName: 'invoice_reference', nocodbBlColumnName: 'bl_number', nocodbAmountColumnName: 'amount', nocodbSupplierColumnName: 'supplier', - webhookUrl: 'https://webhook.test/invoice-upload', + webhookUrl: 'https://webhook.test/invoice-upload-store1', createdAt: new Date(), updatedAt: new Date(), }; - this.groups.set(testGroup.id, testGroup); - this.idCounters.group = 2; + + const testGroup2: Group = { + id: 2, + name: 'Magasin 2', + color: '#10B981', + nocodbConfigId: 1, // Même config NocoDB + nocodbTableName: 'invoices_store2', + nocodbTableId: 'store2table123', // Différent ID de table + invoiceColumnName: 'invoice_reference', + nocodbBlColumnName: 'bl_number', + nocodbAmountColumnName: 'amount', + nocodbSupplierColumnName: 'supplier', + webhookUrl: 'https://webhook.test/invoice-upload-store2', + createdAt: new Date(), + updatedAt: new Date(), + }; + + this.groups.set(testGroup1.id, testGroup1); + this.groups.set(testGroup2.id, testGroup2); + this.idCounters.group = 3; - // Create test supplier - const testSupplier: Supplier = { + // Create test suppliers + const testSupplier1: Supplier = { id: 1, - name: 'Fournisseur Test', - contact: 'test@supplier.com', + name: 'Fournisseur Magasin 1', + contact: 'magasin1@supplier.com', phone: '0123456789', - hasDlc: false, + hasDlc: true, + automaticReconciliation: true, + createdAt: new Date(), + updatedAt: new Date(), + }; + + const testSupplier2: Supplier = { + id: 2, + name: 'Fournisseur Magasin 2', + contact: 'magasin2@supplier.com', + phone: '0987654321', + hasDlc: true, automaticReconciliation: false, createdAt: new Date(), updatedAt: new Date(), }; - this.suppliers.set(testSupplier.id, testSupplier); - this.idCounters.supplier = 2; + + this.suppliers.set(testSupplier1.id, testSupplier1); + this.suppliers.set(testSupplier2.id, testSupplier2); + this.idCounters.supplier = 3; + + // Create additional test users for different stores + const manager1User: User = { + id: 'manager1', + username: 'manager1', + email: 'manager1@magasin1.com', + name: 'Manager Magasin 1', + firstName: 'Manager', + lastName: 'Magasin 1', + profileImageUrl: null, + password: 'manager1.salt', + role: 'manager', + passwordChanged: false, + createdAt: new Date(), + updatedAt: new Date(), + }; + this.users.set(manager1User.id, manager1User); + this.passwords.set('manager1', { password: 'manager1.salt', hasFormat: true }); + + const manager2User: User = { + id: 'manager2', + username: 'manager2', + email: 'manager2@magasin2.com', + name: 'Manager Magasin 2', + firstName: 'Manager', + lastName: 'Magasin 2', + profileImageUrl: null, + password: 'manager2.salt', + role: 'manager', + passwordChanged: false, + createdAt: new Date(), + updatedAt: new Date(), + }; + this.users.set(manager2User.id, manager2User); + this.passwords.set('manager2', { password: 'manager2.salt', hasFormat: true }); + + // Set up user-group associations + this.userGroups.set('admin', [ + { userId: 'admin', groupId: 1 }, + { userId: 'admin', groupId: 2 } + ]); + + this.userGroups.set('manager1', [ + { userId: 'manager1', groupId: 1 } + ]); + + this.userGroups.set('manager2', [ + { userId: 'manager2', groupId: 2 } + ]); console.log('✅ MemStorage initialized with admin user (admin/admin)'); + console.log('🔧 Test users created:', { + admin: 'Access to both stores', + manager1: 'Access to Magasin 1 only', + manager2: 'Access to Magasin 2 only' + }); } // User operations @@ -2014,6 +2101,16 @@ export class MemStorage implements IStorage { async deleteUser(id: string): Promise { this.users.delete(id); this.userGroups.delete(id); + this.passwords.delete(id); + } + + async validatePassword(userId: string, password: string): Promise { + const storedPassword = this.passwords.get(userId); + if (!storedPassword) return false; + + // For development, we use simple string comparison + // In production, this would use bcrypt comparison + return storedPassword.password === password; } // Group operations @@ -2683,7 +2780,9 @@ export class MemStorage implements IStorage { } private initializeExtraTestData() { - // Add test customer orders + console.log('🔧 Initialisation des données de test des commandes clients...'); + + // Add test customer orders for Store 1 (groupId: 1) - Recent dates const testOrder1: CustomerOrder = { id: 1, supplierId: 1, @@ -2702,8 +2801,8 @@ export class MemStorage implements IStorage { isPromotionalPrice: false, customerNotified: false, notes: 'Livraison urgente demandée', - createdAt: new Date('2025-01-15'), - updatedAt: new Date('2025-01-15'), + createdAt: new Date('2025-08-15'), + updatedAt: new Date('2025-08-15'), }; const testOrder2: CustomerOrder = { @@ -2724,13 +2823,114 @@ export class MemStorage implements IStorage { isPromotionalPrice: true, customerNotified: true, notes: null, - createdAt: new Date('2025-01-10'), - updatedAt: new Date('2025-01-12'), + createdAt: new Date('2025-08-10'), + updatedAt: new Date('2025-08-12'), + }; + + // Add test customer orders for Store 2 (groupId: 2) - Recent dates + const testOrder3: CustomerOrder = { + id: 3, + supplierId: 2, + groupId: 2, + createdBy: 'admin', + orderTaker: 'Manager Store 2', + customerName: 'Jean Durand', + customerPhone: '0147258369', + customerEmail: 'jean.durand@email.fr', + productDesignation: 'Canapé 3 places', + productReference: 'CAN-001', + gencode: null, + quantity: 1, + deposit: '300.00' as any, + status: 'Commande passée', + isPromotionalPrice: false, + customerNotified: true, + notes: 'Client préfère livraison matin', + createdAt: new Date('2025-08-14'), + updatedAt: new Date('2025-08-14'), + }; + + const testOrder4: CustomerOrder = { + id: 4, + supplierId: 2, + groupId: 2, + createdBy: 'admin', + orderTaker: 'Manager Store 2', + customerName: 'Sophie Moreau', + customerPhone: '0612345678', + customerEmail: null, + productDesignation: 'Étagère murale', + productReference: null, + gencode: null, + quantity: 3, + deposit: '75.00' as any, + status: 'En attente de Commande', + isPromotionalPrice: true, + customerNotified: false, + notes: 'Prix promotionnel -20%', + createdAt: new Date('2025-08-16'), + updatedAt: new Date('2025-08-16'), + }; + + // Add more recent orders for Store 1 to show variety + const testOrder5: CustomerOrder = { + id: 5, + supplierId: 1, + groupId: 1, + createdBy: 'admin', + orderTaker: 'Admin', + customerName: 'Michel Blanc', + customerPhone: '0188776655', + customerEmail: 'michel.blanc@test.fr', + productDesignation: 'Set de jardin complet', + productReference: 'JARDIN-SET-01', + gencode: null, + quantity: 1, + deposit: '250.00' as any, + status: 'Livrée', + isPromotionalPrice: false, + customerNotified: true, + notes: 'Commande livrée avec succès', + createdAt: new Date('2025-08-09'), + updatedAt: new Date('2025-08-11'), + }; + + const testOrder6: CustomerOrder = { + id: 6, + supplierId: 1, + groupId: 1, + createdBy: 'admin', + orderTaker: 'Admin', + customerName: 'Isabelle Roux', + customerPhone: '0199887766', + customerEmail: null, + productDesignation: 'Barbecue électrique', + productReference: null, + gencode: null, + quantity: 1, + deposit: '120.00' as any, + status: 'En attente de Commande', + isPromotionalPrice: false, + customerNotified: false, + notes: 'À confirmer avec le client', + createdAt: new Date('2025-08-16'), + updatedAt: new Date('2025-08-16'), }; this.customerOrders.set(1, testOrder1); this.customerOrders.set(2, testOrder2); - this.idCounters.customerOrder = 3; + this.customerOrders.set(3, testOrder3); + this.customerOrders.set(4, testOrder4); + this.customerOrders.set(5, testOrder5); + this.customerOrders.set(6, testOrder6); + this.idCounters.customerOrder = 7; + + console.log('✅ Données de test initialisées:', { + totalOrders: 6, + store1Orders: [1, 2, 5, 6], + store2Orders: [3, 4], + recentDates: '2025-08-09 à 2025-08-16' + }); // Add test DLC products const testDlc1: DlcProduct = {