diff --git a/.gitignore b/.gitignore index f9ba7f8..3a35e07 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,13 @@ dist .DS_Store server/public vite.config.ts.* -*.tar.gz \ No newline at end of file +*.tar.gz + +# Secrets et fichiers de session : ne jamais committer +.env +.env.local +cookie*.txt + +# Artefacts de debug locaux +*.log +scratch/ diff --git a/MIGRATION_PRODUCTION_URGENTE.sql b/MIGRATION_PRODUCTION_URGENTE.sql deleted file mode 100644 index ceea0a6..0000000 --- a/MIGRATION_PRODUCTION_URGENTE.sql +++ /dev/null @@ -1,24 +0,0 @@ --- MIGRATION URGENTE PRODUCTION DLC --- Exécutez cette commande directement sur votre serveur - --- Ajout des colonnes DLC stock épuisé -ALTER TABLE dlc_products -ADD COLUMN IF NOT EXISTS stock_epuise boolean DEFAULT false NOT NULL, -ADD COLUMN IF NOT EXISTS stock_epuise_by varchar(255), -ADD COLUMN IF NOT EXISTS stock_epuise_at timestamp; - --- Index pour performance -CREATE INDEX IF NOT EXISTS idx_dlc_products_stock_epuise ON dlc_products(stock_epuise); - --- Initialisation des valeurs -UPDATE dlc_products -SET stock_epuise = false -WHERE stock_epuise IS NULL; - --- Vérification -SELECT - 'Migration DLC terminée' as status, - COUNT(*) as colonnes_ajoutees -FROM information_schema.columns -WHERE table_name = 'dlc_products' -AND column_name IN ('stock_epuise', 'stock_epuise_by', 'stock_epuise_at'); \ No newline at end of file diff --git a/after_load.png b/after_load.png deleted file mode 100644 index 9e3f72f..0000000 Binary files a/after_load.png and /dev/null differ diff --git a/attached_assets/Pasted--Images-Networks-Volumes-Events-Host-Administration-User-related-Environment-relat-1762270133118_1762270133118.txt b/attached_assets/Pasted--Images-Networks-Volumes-Events-Host-Administration-User-related-Environment-relat-1762270133118_1762270133118.txt deleted file mode 100644 index 80b9c7c..0000000 --- a/attached_assets/Pasted--Images-Networks-Volumes-Events-Host-Administration-User-related-Environment-relat-1762270133118_1762270133118.txt +++ /dev/null @@ -1,245 +0,0 @@ - -Images -Networks -Volumes -Events - -Host - -Administration - -User-related - - -Environment-related - -Registries - -Logs - -Notifications - -Settings - -New version available 2.33.3 -DismissSee what's new -Community Edition -2.27.6 LTS -Containers>logiflow-logiflow-1>Logs -Container logs - - -admin -Log viewer settings -Auto-refresh logs -Wrap lines -Display timestamps -Fetch -All logs -Search -Filter... -Lines -100 -Actions - - - - - storeId: 2, - - createdBy: 'admin', - - createdAt: 2025-09-24T11:26:13.521Z - - }, - - { - - id: 17, - - title: 'Module Avoir', - - content: "Le module d'avoir est en place", - - type: 'error', - - storeId: 1, - - createdBy: 'admin', - - createdAt: 2025-09-09T07:47:47.650Z - - }, - - { - - id: 16, - - title: 'Mise à jour Prix', - - content: 'Merci de mettre vos prix a jour tous les matins, certain magasin ne le font pas.', - - type: 'success', - - storeId: null, - - createdBy: 'admin', - - createdAt: 2025-08-18T10:45:08.585Z - - }, - - { - - id: 8, - - title: 'Bon de Livraison', - - content: 'Lorsque vous rentrez un numéro de bon de livraison, faite le a l identique, même les majuscules. Pour My candy Shop, prendre le numéro de commande.', - - type: 'info', - - storeId: null, - - createdBy: 'admin_local', - - createdAt: 2025-08-07T11:04:38.123Z - - } - -] - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -❌ [PRODUCTION] User not found with username: admin_local - -🔍 [PRODUCTION] User search result: Not found - -🎯 [PRODUCTION] Found announcements: 4 - -GET /api/announcements 304 in 18ms - -📢 [SERVER] Fetching announcements for user: _1754936203292 environment: production - -📢 [SERVER] User found: { username: 'ff292', role: 'employee' } - -🎯 [PRODUCTION] Using PostgreSQL DASHBOARD_MESSAGES table - -GET /api/groups 304 in 4ms - -🔍 [PRODUCTION] Raw messages from DB: 4 items: [ - - { - - id: 20, - - title: 'DLC', - - content: 'Attention des DLC sont en expiré bientôt ou expiré, il faut s en occuper', - - type: 'success', - - storeId: 2, - - createdBy: 'admin', - - createdAt: 2025-09-24T11:26:13.521Z - - }, - - { - - id: 17, - - title: 'Module Avoir', - - content: "Le module d'avoir est en place", - - type: 'error', - - storeId: 1, - - createdBy: 'admin', - - createdAt: 2025-09-09T07:47:47.650Z - - }, - - { - - id: 16, - - title: 'Mise à jour Prix', - - content: 'Merci de mettre vos prix a jour tous les matins, certain magasin ne le font pas.', - - type: 'success', - - storeId: null, - - createdBy: 'admin', - - createdAt: 2025-08-18T10:45:08.585Z - - }, - - { - - id: 8, - - title: 'Bon de Livraison', - - content: 'Lorsque vous rentrez un numéro de bon de livraison, faite le a l identique, même les majuscules. Pour My candy Shop, prendre le numéro de commande.', - - type: 'info', - - storeId: null, - - createdBy: 'admin_local', - - createdAt: 2025-08-07T11:04:38.123Z - - } - -] - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Not found - -❌ [PRODUCTION] User not found with username: admin_local - -🎯 [PRODUCTION] Found announcements: 4 - -GET /api/announcements 304 in 8ms - -GET /api/user 304 in 13ms - -GET /api/suppliers 304 in 4ms - -GET /api/dlc-products 304 in 58ms - diff --git a/attached_assets/Pasted--Images-Networks-Volumes-Events-Host-Administration-User-related-Environment-relat-1762270274693_1762270274693.txt b/attached_assets/Pasted--Images-Networks-Volumes-Events-Host-Administration-User-related-Environment-relat-1762270274693_1762270274693.txt deleted file mode 100644 index 80b9c7c..0000000 --- a/attached_assets/Pasted--Images-Networks-Volumes-Events-Host-Administration-User-related-Environment-relat-1762270274693_1762270274693.txt +++ /dev/null @@ -1,245 +0,0 @@ - -Images -Networks -Volumes -Events - -Host - -Administration - -User-related - - -Environment-related - -Registries - -Logs - -Notifications - -Settings - -New version available 2.33.3 -DismissSee what's new -Community Edition -2.27.6 LTS -Containers>logiflow-logiflow-1>Logs -Container logs - - -admin -Log viewer settings -Auto-refresh logs -Wrap lines -Display timestamps -Fetch -All logs -Search -Filter... -Lines -100 -Actions - - - - - storeId: 2, - - createdBy: 'admin', - - createdAt: 2025-09-24T11:26:13.521Z - - }, - - { - - id: 17, - - title: 'Module Avoir', - - content: "Le module d'avoir est en place", - - type: 'error', - - storeId: 1, - - createdBy: 'admin', - - createdAt: 2025-09-09T07:47:47.650Z - - }, - - { - - id: 16, - - title: 'Mise à jour Prix', - - content: 'Merci de mettre vos prix a jour tous les matins, certain magasin ne le font pas.', - - type: 'success', - - storeId: null, - - createdBy: 'admin', - - createdAt: 2025-08-18T10:45:08.585Z - - }, - - { - - id: 8, - - title: 'Bon de Livraison', - - content: 'Lorsque vous rentrez un numéro de bon de livraison, faite le a l identique, même les majuscules. Pour My candy Shop, prendre le numéro de commande.', - - type: 'info', - - storeId: null, - - createdBy: 'admin_local', - - createdAt: 2025-08-07T11:04:38.123Z - - } - -] - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -❌ [PRODUCTION] User not found with username: admin_local - -🔍 [PRODUCTION] User search result: Not found - -🎯 [PRODUCTION] Found announcements: 4 - -GET /api/announcements 304 in 18ms - -📢 [SERVER] Fetching announcements for user: _1754936203292 environment: production - -📢 [SERVER] User found: { username: 'ff292', role: 'employee' } - -🎯 [PRODUCTION] Using PostgreSQL DASHBOARD_MESSAGES table - -GET /api/groups 304 in 4ms - -🔍 [PRODUCTION] Raw messages from DB: 4 items: [ - - { - - id: 20, - - title: 'DLC', - - content: 'Attention des DLC sont en expiré bientôt ou expiré, il faut s en occuper', - - type: 'success', - - storeId: 2, - - createdBy: 'admin', - - createdAt: 2025-09-24T11:26:13.521Z - - }, - - { - - id: 17, - - title: 'Module Avoir', - - content: "Le module d'avoir est en place", - - type: 'error', - - storeId: 1, - - createdBy: 'admin', - - createdAt: 2025-09-09T07:47:47.650Z - - }, - - { - - id: 16, - - title: 'Mise à jour Prix', - - content: 'Merci de mettre vos prix a jour tous les matins, certain magasin ne le font pas.', - - type: 'success', - - storeId: null, - - createdBy: 'admin', - - createdAt: 2025-08-18T10:45:08.585Z - - }, - - { - - id: 8, - - title: 'Bon de Livraison', - - content: 'Lorsque vous rentrez un numéro de bon de livraison, faite le a l identique, même les majuscules. Pour My candy Shop, prendre le numéro de commande.', - - type: 'info', - - storeId: null, - - createdBy: 'admin_local', - - createdAt: 2025-08-07T11:04:38.123Z - - } - -] - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Not found - -❌ [PRODUCTION] User not found with username: admin_local - -🎯 [PRODUCTION] Found announcements: 4 - -GET /api/announcements 304 in 8ms - -GET /api/user 304 in 13ms - -GET /api/suppliers 304 in 4ms - -GET /api/dlc-products 304 in 58ms - diff --git a/attached_assets/Pasted--storeId-2-createdBy-admin-createdAt-2025-09-24T11-26-13-521Z--1762269307429_1762269307429.txt b/attached_assets/Pasted--storeId-2-createdBy-admin-createdAt-2025-09-24T11-26-13-521Z--1762269307429_1762269307429.txt deleted file mode 100644 index 26f1410..0000000 --- a/attached_assets/Pasted--storeId-2-createdBy-admin-createdAt-2025-09-24T11-26-13-521Z--1762269307429_1762269307429.txt +++ /dev/null @@ -1,202 +0,0 @@ - - - storeId: 2, - - createdBy: 'admin', - - createdAt: 2025-09-24T11:26:13.521Z - - }, - - { - - id: 17, - - title: 'Module Avoir', - - content: "Le module d'avoir est en place", - - type: 'error', - - storeId: 1, - - createdBy: 'admin', - - createdAt: 2025-09-09T07:47:47.650Z - - }, - - { - - id: 16, - - title: 'Mise à jour Prix', - - content: 'Merci de mettre vos prix a jour tous les matins, certain magasin ne le font pas.', - - type: 'success', - - storeId: null, - - createdBy: 'admin', - - createdAt: 2025-08-18T10:45:08.585Z - - }, - - { - - id: 8, - - title: 'Bon de Livraison', - - content: 'Lorsque vous rentrez un numéro de bon de livraison, faite le a l identique, même les majuscules. Pour My candy Shop, prendre le numéro de commande.', - - type: 'info', - - storeId: null, - - createdBy: 'admin_local', - - createdAt: 2025-08-07T11:04:38.123Z - - } - -] - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin_local - -❌ [PRODUCTION] User not found with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Not found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🎯 [PRODUCTION] Found announcements: 4 - -GET /api/announcements 304 in 8ms - -📢 [SERVER] Fetching announcements for user: _1754936203292 environment: production - -📢 [SERVER] User found: { username: 'ff292', role: 'employee' } - -🎯 [PRODUCTION] Using PostgreSQL DASHBOARD_MESSAGES table - -🔍 [PRODUCTION] Raw messages from DB: 4 items: [ - - { - - id: 20, - - title: 'DLC', - - content: 'Attention des DLC sont en expiré bientôt ou expiré, il faut s en occuper', - - type: 'success', - - storeId: 2, - - createdBy: 'admin', - - createdAt: 2025-09-24T11:26:13.521Z - - }, - - { - - id: 17, - - title: 'Module Avoir', - - content: "Le module d'avoir est en place", - - type: 'error', - - storeId: 1, - - createdBy: 'admin', - - createdAt: 2025-09-09T07:47:47.650Z - - }, - - { - - id: 16, - - title: 'Mise à jour Prix', - - content: 'Merci de mettre vos prix a jour tous les matins, certain magasin ne le font pas.', - - type: 'success', - - storeId: null, - - createdBy: 'admin', - - createdAt: 2025-08-18T10:45:08.585Z - - }, - - { - - id: 8, - - title: 'Bon de Livraison', - - content: 'Lorsque vous rentrez un numéro de bon de livraison, faite le a l identique, même les majuscules. Pour My candy Shop, prendre le numéro de commande.', - - type: 'info', - - storeId: null, - - createdBy: 'admin_local', - - createdAt: 2025-08-07T11:04:38.123Z - - } - -] - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin - -🔍 [PRODUCTION] Looking for user with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -❌ [PRODUCTION] User not found with username: admin_local - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Found - -🔍 [PRODUCTION] User search result: Not found - -🎯 [PRODUCTION] Found announcements: 4 - -GET /api/announcements 304 in 9ms - -GET /api/groups 304 in 3ms - -GET /api/user 304 in 5ms - -GET /api/suppliers 304 in 4ms - -GET /api/dlc-products 304 in 45ms - -HEAD /api/health 200 in 0ms - diff --git a/attached_assets/image_1762267338308.png b/attached_assets/image_1762267338308.png deleted file mode 100644 index 038493e..0000000 Binary files a/attached_assets/image_1762267338308.png and /dev/null differ diff --git a/attached_assets/{053E4C93-A4BA-4106-8530-38501E1EADEE}_1762269064399.png b/attached_assets/{053E4C93-A4BA-4106-8530-38501E1EADEE}_1762269064399.png deleted file mode 100644 index cc88b9a..0000000 Binary files a/attached_assets/{053E4C93-A4BA-4106-8530-38501E1EADEE}_1762269064399.png and /dev/null differ diff --git a/attached_assets/{1665ED95-20B6-4344-8493-11A55C558DA8}_1762270285012.png b/attached_assets/{1665ED95-20B6-4344-8493-11A55C558DA8}_1762270285012.png deleted file mode 100644 index 46caf83..0000000 Binary files a/attached_assets/{1665ED95-20B6-4344-8493-11A55C558DA8}_1762270285012.png and /dev/null differ diff --git a/attached_assets/{20F16595-1D55-42B5-B63C-FBB1B8C893E8}_1762269074780.png b/attached_assets/{20F16595-1D55-42B5-B63C-FBB1B8C893E8}_1762269074780.png deleted file mode 100644 index 41c2842..0000000 Binary files a/attached_assets/{20F16595-1D55-42B5-B63C-FBB1B8C893E8}_1762269074780.png and /dev/null differ diff --git a/attached_assets/{3604C248-7F41-46CC-8972-47C38222F2B0}_1762265360405.png b/attached_assets/{3604C248-7F41-46CC-8972-47C38222F2B0}_1762265360405.png deleted file mode 100644 index 707933a..0000000 Binary files a/attached_assets/{3604C248-7F41-46CC-8972-47C38222F2B0}_1762265360405.png and /dev/null differ diff --git a/attached_assets/{5DD75BD0-365E-402A-99DA-82F24637B27B}_1762270384666.png b/attached_assets/{5DD75BD0-365E-402A-99DA-82F24637B27B}_1762270384666.png deleted file mode 100644 index 2d67c53..0000000 Binary files a/attached_assets/{5DD75BD0-365E-402A-99DA-82F24637B27B}_1762270384666.png and /dev/null differ diff --git a/attached_assets/{76762EAD-952D-467A-A003-D3F763C1B334}_1762267435658.png b/attached_assets/{76762EAD-952D-467A-A003-D3F763C1B334}_1762267435658.png deleted file mode 100644 index 1a81e4c..0000000 Binary files a/attached_assets/{76762EAD-952D-467A-A003-D3F763C1B334}_1762267435658.png and /dev/null differ diff --git a/attached_assets/{9A963AF5-8CA1-4143-8A50-BF6B1320ABA2}_1762263946868.png b/attached_assets/{9A963AF5-8CA1-4143-8A50-BF6B1320ABA2}_1762263946868.png deleted file mode 100644 index 062d432..0000000 Binary files a/attached_assets/{9A963AF5-8CA1-4143-8A50-BF6B1320ABA2}_1762263946868.png and /dev/null differ diff --git a/attached_assets/{B4E9E8F0-2C31-4B0E-AC00-C5EBBDB91FCC}_1762269830356.png b/attached_assets/{B4E9E8F0-2C31-4B0E-AC00-C5EBBDB91FCC}_1762269830356.png deleted file mode 100644 index e3b81f9..0000000 Binary files a/attached_assets/{B4E9E8F0-2C31-4B0E-AC00-C5EBBDB91FCC}_1762269830356.png and /dev/null differ diff --git a/attached_assets/{CA0A7F2F-9BAD-4A42-8B00-2EF6EFED443A}_1762267992011.png b/attached_assets/{CA0A7F2F-9BAD-4A42-8B00-2EF6EFED443A}_1762267992011.png deleted file mode 100644 index 7fea852..0000000 Binary files a/attached_assets/{CA0A7F2F-9BAD-4A42-8B00-2EF6EFED443A}_1762267992011.png and /dev/null differ diff --git a/attached_assets/{CA3DEE31-2D2B-4434-875F-336714E13B38}_1762269295473.png b/attached_assets/{CA3DEE31-2D2B-4434-875F-336714E13B38}_1762269295473.png deleted file mode 100644 index f52b7dd..0000000 Binary files a/attached_assets/{CA3DEE31-2D2B-4434-875F-336714E13B38}_1762269295473.png and /dev/null differ diff --git a/attached_assets/{CACBFFDA-B7C7-4B0D-892C-80A666E41814}_1762266527968.png b/attached_assets/{CACBFFDA-B7C7-4B0D-892C-80A666E41814}_1762266527968.png deleted file mode 100644 index d417411..0000000 Binary files a/attached_assets/{CACBFFDA-B7C7-4B0D-892C-80A666E41814}_1762266527968.png and /dev/null differ diff --git a/attached_assets/{CB80C8CC-D314-4E12-A25E-1169225B0395}_1762268004420.png b/attached_assets/{CB80C8CC-D314-4E12-A25E-1169225B0395}_1762268004420.png deleted file mode 100644 index b6593f5..0000000 Binary files a/attached_assets/{CB80C8CC-D314-4E12-A25E-1169225B0395}_1762268004420.png and /dev/null differ diff --git a/attached_assets/{E2F8586B-F34F-4395-838D-6340E1F407DD}_1762260398088.png b/attached_assets/{E2F8586B-F34F-4395-838D-6340E1F407DD}_1762260398088.png deleted file mode 100644 index 8cdb39e..0000000 Binary files a/attached_assets/{E2F8586B-F34F-4395-838D-6340E1F407DD}_1762260398088.png and /dev/null differ diff --git a/attached_assets/{F1228CA9-8789-481D-9840-D8D872BAF1ED}_1762270116892.png b/attached_assets/{F1228CA9-8789-481D-9840-D8D872BAF1ED}_1762270116892.png deleted file mode 100644 index e609d8a..0000000 Binary files a/attached_assets/{F1228CA9-8789-481D-9840-D8D872BAF1ED}_1762270116892.png and /dev/null differ diff --git a/attached_assets/{F5E72738-3287-4989-AD4F-8A12528BD627}_1762265876680.png b/attached_assets/{F5E72738-3287-4989-AD4F-8A12528BD627}_1762265876680.png deleted file mode 100644 index f61803a..0000000 Binary files a/attached_assets/{F5E72738-3287-4989-AD4F-8A12528BD627}_1762265876680.png and /dev/null differ diff --git a/client/src/pages/Avoirs_backup.tsx b/client/src/pages/Avoirs_backup.tsx deleted file mode 100644 index abc78c8..0000000 --- a/client/src/pages/Avoirs_backup.tsx +++ /dev/null @@ -1 +0,0 @@ -// Backup temporaire pour restaurer si nécessaire \ No newline at end of file diff --git a/client/src/pages/BLReconciliationNative.tsx b/client/src/pages/BLReconciliationNative.tsx deleted file mode 100644 index 9c7bf4e..0000000 --- a/client/src/pages/BLReconciliationNative.tsx +++ /dev/null @@ -1,778 +0,0 @@ -import { useState, useEffect } from "react"; -import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; -import { safeFormat } from "@/lib/dateUtils"; -import { useToast } from "@/hooks/use-toast"; -import { apiRequest } from "@/lib/queryClient"; -import { useStore } from "@/contexts/StoreContext"; -import { useAuthUnified } from "@/hooks/useAuthUnified"; -import { usePermissions } from "@shared/permissions"; -import { Search, Edit, FileText, Settings, Eye, AlertTriangle, X, Check, Trash2, Ban, ChevronLeft, ChevronRight } from "lucide-react"; -import type { Supplier } from "@shared/schema"; - -export default function BLReconciliation() { - const { user } = useAuthUnified(); - const { selectedStoreId } = useStore(); - const { toast } = useToast(); - const queryClient = useQueryClient(); - const permissions = usePermissions(user?.role); - - // Vérification des permissions d'accès au module - if (!permissions.canView('reconciliation')) { - return ( -
-
-
-
- -
-
-

- Accès restreint
- Seuls les directeurs et administrateurs peuvent accéder au module de rapprochement BL/Factures. -

-
-
-
-
- ); - } - - const [activeTab, setActiveTab] = useState("manual"); - const [searchTerm, setSearchTerm] = useState(""); - const [currentPage, setCurrentPage] = useState(1); - const itemsPerPage = 20; - - // Récupérer les fournisseurs pour la logique automatique - const { data: suppliers = [], isLoading: suppliersLoading } = useQuery({ - queryKey: ['/api/suppliers'], - }); - - // Récupérer les livraisons validées avec BL - const { data: deliveriesWithBL = [], isLoading } = useQuery({ - queryKey: ['/api/deliveries/bl', selectedStoreId], - queryFn: async () => { - const params = new URLSearchParams({}); - if (selectedStoreId && user?.role === 'admin') { - params.append('storeId', selectedStoreId.toString()); - } - - const response = await fetch(`/api/deliveries?${params.toString()}`, { - credentials: 'include' - }); - - if (!response.ok) { - throw new Error('Failed to fetch deliveries'); - } - - const deliveries = await response.json(); - const filtered = Array.isArray(deliveries) ? deliveries.filter((d: any) => d.status === 'delivered') : []; - - return filtered.sort((a: any, b: any) => new Date(b.deliveredDate || b.updatedAt).getTime() - new Date(a.deliveredDate || a.updatedAt).getTime()); - }, - }); - - // Séparer les livraisons selon le mode de rapprochement du fournisseur - const manualReconciliationDeliveries = deliveriesWithBL.filter((delivery: any) => { - const supplier = suppliers.find((s: any) => s.id === delivery.supplierId); - return !supplier?.automaticReconciliation; - }); - - const automaticReconciliationDeliveries = deliveriesWithBL.filter((delivery: any) => { - const supplier = suppliers.find((s: any) => s.id === delivery.supplierId); - return supplier?.automaticReconciliation; - }); - - // Mutations pour les actions - const validateManualMutation = useMutation({ - mutationFn: async (deliveryId: number) => { - return await apiRequest(`/api/deliveries/${deliveryId}`, "PUT", { - reconciled: true, - validatedAt: new Date().toISOString() - }); - }, - onSuccess: () => { - toast({ - title: "Succès", - description: "Rapprochement validé avec succès", - }); - queryClient.invalidateQueries({ queryKey: ['/api/deliveries/bl'] }); - }, - onError: () => { - toast({ - title: "Erreur", - description: "Impossible de valider le rapprochement", - variant: "destructive", - }); - } - }); - - const devalidateMutation = useMutation({ - mutationFn: async (deliveryId: number) => { - return await apiRequest(`/api/deliveries/${deliveryId}`, "PUT", { - reconciled: false, - validatedAt: null - }); - }, - onSuccess: () => { - toast({ - title: "Succès", - description: "Rapprochement dévalidé avec succès", - }); - queryClient.invalidateQueries({ queryKey: ['/api/deliveries/bl'] }); - }, - onError: () => { - toast({ - title: "Erreur", - description: "Impossible de dévalider le rapprochement", - variant: "destructive", - }); - } - }); - - const deleteMutation = useMutation({ - mutationFn: async (deliveryId: number) => { - return await apiRequest(`/api/deliveries/${deliveryId}`, "DELETE"); - }, - onSuccess: () => { - toast({ - title: "Succès", - description: "Ligne supprimée avec succès", - }); - queryClient.invalidateQueries({ queryKey: ['/api/deliveries/bl'] }); - }, - onError: () => { - toast({ - title: "Erreur", - description: "Impossible de supprimer la ligne", - variant: "destructive", - }); - } - }); - - // Fonctions de gestion des actions - const handleValidateManual = (deliveryId: number) => { - if (!permissions.canValidate('reconciliation')) { - toast({ - title: "Accès refusé", - description: "Vous n'avez pas les permissions pour valider les rapprochements", - variant: "destructive", - }); - return; - } - validateManualMutation.mutate(deliveryId); - }; - - const handleDevalidate = (deliveryId: number) => { - if (!permissions.canEdit('reconciliation')) { - toast({ - title: "Accès refusé", - description: "Seuls les administrateurs peuvent dévalider les rapprochements", - variant: "destructive", - }); - return; - } - if (confirm("Êtes-vous sûr de vouloir dévalider ce rapprochement ?")) { - devalidateMutation.mutate(deliveryId); - } - }; - - const handleDelete = (deliveryId: number) => { - if (!permissions.canDelete('reconciliation')) { - toast({ - title: "Accès refusé", - description: "Seuls les administrateurs peuvent supprimer les lignes", - variant: "destructive", - }); - return; - } - if (confirm("Êtes-vous sûr de vouloir supprimer cette ligne ? Cette action est irréversible.")) { - deleteMutation.mutate(deliveryId); - } - }; - - // Filtrage des livraisons par recherche - const filterDeliveries = (deliveries: any[]) => { - return deliveries.filter((delivery: any) => { - const searchLower = searchTerm.toLowerCase(); - return ( - delivery.supplier?.name?.toLowerCase().includes(searchLower) || - delivery.blNumber?.toLowerCase().includes(searchLower) || - delivery.invoiceReference?.toLowerCase().includes(searchLower) - ); - }); - }; - - const filteredManualDeliveries = filterDeliveries(manualReconciliationDeliveries); - const filteredAutomaticDeliveries = filterDeliveries(automaticReconciliationDeliveries); - - // Pagination - const getCurrentPageData = (data: any[]) => { - const startIndex = (currentPage - 1) * itemsPerPage; - const endIndex = startIndex + itemsPerPage; - return data.slice(startIndex, endIndex); - }; - - const getTotalPages = (data: any[]) => { - return Math.ceil(data.length / itemsPerPage); - }; - - const currentManualData = getCurrentPageData(filteredManualDeliveries); - const currentAutomaticData = getCurrentPageData(filteredAutomaticDeliveries); - - const totalManualPages = getTotalPages(filteredManualDeliveries); - const totalAutomaticPages = getTotalPages(filteredAutomaticDeliveries); - - // Reset page when changing tabs or searching - useEffect(() => { - setCurrentPage(1); - }, [activeTab, searchTerm]); - - // Vérifier si une ligne est dévalidée (pour la coloration) - const isDevalidated = (delivery: any) => { - return delivery.reconciled === false && delivery.validatedAt === null; - }; - - // Composant de pagination simplifiée - const NativePagination = ({ currentPage, totalPages, onPageChange, totalItems, itemsPerPage }: { - currentPage: number; - totalPages: number; - onPageChange: (page: number) => void; - totalItems: number; - itemsPerPage: number; - }) => { - if (totalPages <= 1) return null; - - const startItem = (currentPage - 1) * itemsPerPage + 1; - const endItem = Math.min(currentPage * itemsPerPage, totalItems); - - return ( -
-
- - Affichage de {startItem} à {endItem} sur {totalItems} éléments - -
-
- - - - Page {currentPage} sur {totalPages} - - - -
-
- ); - }; - - // Badge native - const NativeBadge = ({ children, variant = "default", className = "" }: { children: React.ReactNode, variant?: string, className?: string }) => { - const baseClasses = "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"; - const variantClasses = { - default: "bg-blue-100 text-blue-800", - secondary: "bg-gray-100 text-gray-800", - destructive: "bg-red-100 text-red-800", - outline: "border border-gray-300 text-gray-700 bg-white" - }; - - return ( - - {children} - - ); - }; - - // Button native - const NativeButton = ({ children, onClick, disabled = false, variant = "default", size = "default", className = "", title = "" }: { - children: React.ReactNode, - onClick?: () => void, - disabled?: boolean, - variant?: string, - size?: string, - className?: string, - title?: string - }) => { - const baseClasses = "inline-flex items-center justify-center font-medium rounded transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2"; - const variantClasses = { - default: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500", - ghost: "text-gray-600 hover:text-gray-900 hover:bg-gray-100", - outline: "border border-gray-300 bg-white text-gray-700 hover:bg-gray-50" - }; - const sizeClasses = { - default: "px-4 py-2 text-sm", - sm: "px-2 py-1 text-xs" - }; - - return ( - - ); - }; - - if (isLoading || suppliersLoading) { - return ( -
-
-
-
-
-
- ); - } - - return ( -
- {/* Header avec onglets */} -
-
-
-

- - Rapprochement BL/Factures -

-

- Gestion des rapprochements manuels et automatiques -

-
-
- - {manualReconciliationDeliveries.length} rapprochements manuels - - - {automaticReconciliationDeliveries.length} rapprochements automatiques - -
-
- - {/* Onglets natifs */} -
- -
-
- - {/* Filtre de recherche */} -
-
- - setSearchTerm(e.target.value)} - className="pl-10 pr-4 py-2 w-full border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" - /> -
-
- - {/* Contenu des onglets */} - {activeTab === "manual" && ( -
- {filteredManualDeliveries.length === 0 ? ( -
- -

- Aucun rapprochement manuel trouvé -

-

- Les livraisons de fournisseurs en mode manuel apparaîtront ici. -

-
- ) : ( -
- {/* Pagination du haut */} - - -
- - - - - - - - - - - - - - - {currentManualData.map((delivery: any) => ( - - - - - - - - - - - ))} - -
FournisseurN° BLDate Livr.Montant BLRef. FactureMontant Fact.StatutActions
-
- {delivery.supplier?.name} -
-
-
- {delivery.blNumber || ( - Non renseigné - )} -
-
-
- {safeFormat(delivery.scheduledDate, 'dd/MM/yy')} -
-
-
- {delivery.blAmount ? - `${parseFloat(delivery.blAmount).toFixed(2)}€` : - Non renseigné - } -
-
-
- {delivery.invoiceReference || ( - Non renseigné - )} -
-
-
- {delivery.invoiceAmount ? - `${parseFloat(delivery.invoiceAmount).toFixed(2)}€` : - Non renseigné - } -
-
- {delivery.reconciled ? ( - - Validé - - ) : isDevalidated(delivery) ? ( - - Dévalidé - - ) : ( - - En attente - - )} - -
- {permissions.canEdit('reconciliation') && ( - - - - )} - - {!delivery.reconciled && permissions.canValidate('reconciliation') && ( - handleValidateManual(delivery.id)} - disabled={validateManualMutation.isPending} - className="text-green-600 hover:text-green-700 p-1" - title="Valider" - > - - - )} - - {delivery.reconciled && permissions.canEdit('reconciliation') && user?.role === 'admin' && ( - handleDevalidate(delivery.id)} - disabled={devalidateMutation.isPending} - className="text-orange-600 hover:text-orange-700 p-1" - title="Dévalider" - > - - - )} - - {permissions.canDelete('reconciliation') && ( - handleDelete(delivery.id)} - disabled={deleteMutation.isPending} - className="text-red-600 hover:text-red-700 p-1" - title="Supprimer" - > - - - )} -
-
-
- - {/* Pagination du bas */} - -
- )} -
- )} - - {activeTab === "automatic" && ( -
- {/* Message d'information */} -
-
- -
-

Mode rapprochement automatique

-

- Les livraisons de fournisseurs en mode automatique sont validées automatiquement lorsqu'elles ont le statut "delivered" et un numéro de BL. - {permissions.canEdit('reconciliation') ? ( - " Vous pouvez dévalider ces rapprochements si nécessaire." - ) : ( - " Seuls les directeurs et administrateurs peuvent modifier ces rapprochements." - )} -

-
-
-
- - {filteredAutomaticDeliveries.length === 0 ? ( -
- -

- Aucun rapprochement automatique trouvé -

-

- Les livraisons de fournisseurs en mode automatique apparaîtront ici. -

-
- ) : ( -
- {/* Pagination du haut */} - - -
- - - - - - - - - - - - - - - {currentAutomaticData.map((delivery: any) => ( - - - - - - - - - - - ))} - -
- Fournisseur - AUTO - N° BLDate Livr.Date Valid.Montant BLRef. FactureStatutActions
-
-
- {delivery.supplier?.name} -
-
-
-
-
- {delivery.blNumber || '-'} -
-
-
- {safeFormat(delivery.scheduledDate, 'dd/MM/yy')} -
-
-
- {delivery.reconciled && delivery.validatedAt ? - safeFormat(delivery.validatedAt, 'dd/MM/yy') : - '-' - } -
-
-
- {delivery.blAmount ? - `${parseFloat(delivery.blAmount).toFixed(2)}€` : - '-' - } -
-
-
- {delivery.invoiceReference || '-'} -
-
- {isDevalidated(delivery) ? ( - - Dévalidé - - ) : ( - - Auto-validé - - )} - -
- {isDevalidated(delivery) && permissions.canEdit('reconciliation') && ( - <> - - - - handleValidateManual(delivery.id)} - disabled={validateManualMutation.isPending} - className="text-green-600 hover:text-green-700 p-1" - title="Valider" - > - - - - )} - - {!isDevalidated(delivery) && permissions.canEdit('reconciliation') && ( - handleDevalidate(delivery.id)} - disabled={devalidateMutation.isPending} - className="text-orange-600 hover:text-orange-700 p-1" - title="Dévalider" - > - - - )} - - {permissions.canDelete('reconciliation') && ( - handleDelete(delivery.id)} - disabled={deleteMutation.isPending} - className="text-red-600 hover:text-red-700 p-1" - title="Supprimer" - > - - - )} -
-
-
- - {/* Pagination du bas */} - -
- )} -
- )} -
- ); -} \ No newline at end of file diff --git a/client/src/pages/TasksListSimple.tsx b/client/src/pages/TasksListSimple.tsx deleted file mode 100644 index 2e57e57..0000000 --- a/client/src/pages/TasksListSimple.tsx +++ /dev/null @@ -1,568 +0,0 @@ -import { useState, useEffect } from "react"; - -// Interface pour les tâches -interface Task { - id: number; - title: string; - description?: string; - priority: 'low' | 'medium' | 'high'; - status: 'pending' | 'completed'; - assignedTo: string; - startDate?: string | null; - dueDate?: string | null; - createdAt?: string; - groupId?: number; - createdBy?: string; -} - -export default function TasksListSimple() { - const [tasks, setTasks] = useState([]); - const [loading, setLoading] = useState(true); - const [editingId, setEditingId] = useState(null); - const [searchTerm, setSearchTerm] = useState(""); - const [statusFilter, setStatusFilter] = useState("all"); - const [showCreateForm, setShowCreateForm] = useState(false); - - // Charger les tâches - const loadTasks = async () => { - try { - const response = await fetch('/api/tasks'); - if (response.ok) { - const data = await response.json(); - setTasks(data); - } else { - console.error('Erreur lors du chargement des tâches:', response.status); - } - } catch (error) { - console.error('Erreur lors du chargement des tâches:', error); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - loadTasks(); - }, []); - - // Créer une tâche - const createTask = async (formData: FormData) => { - const title = formData.get('title') as string; - const description = formData.get('description') as string; - const priority = formData.get('priority') as string; - const status = formData.get('status') as string; - const assignedTo = formData.get('assignedTo') as string; - const startDate = formData.get('startDate') as string; - const dueDate = formData.get('dueDate') as string; - - if (!title?.trim()) { - alert("Le titre est requis"); - return false; - } - - if (!assignedTo?.trim()) { - alert("L'assignation est requise"); - return false; - } - - try { - const taskData = { - title: title.trim(), - description: description?.trim() || "", - priority: priority || "medium", - status: status || "pending", - assignedTo: assignedTo.trim(), - startDate: startDate || null, - dueDate: dueDate || null, - groupId: 1, - createdBy: 'admin', - }; - - console.log('📤 Creating task:', taskData); - - const response = await fetch('/api/tasks', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(taskData), - }); - - if (!response.ok) { - const errorText = await response.text(); - console.error('❌ Create Error:', { status: response.status, error: errorText }); - throw new Error(`Erreur ${response.status}: ${errorText}`); - } - - alert("Tâche créée avec succès"); - loadTasks(); - return true; - } catch (error) { - console.error('Erreur lors de la création:', error); - alert("Erreur lors de la création"); - return false; - } - }; - - // Modifier une tâche - const updateTask = async (id: number, formData: FormData) => { - const title = formData.get('title') as string; - const description = formData.get('description') as string; - const priority = formData.get('priority') as string; - const status = formData.get('status') as string; - const assignedTo = formData.get('assignedTo') as string; - const startDate = formData.get('startDate') as string; - const dueDate = formData.get('dueDate') as string; - - if (!title?.trim()) { - alert("Le titre est requis"); - return false; - } - - if (!assignedTo?.trim()) { - alert("L'assignation est requise"); - return false; - } - - try { - // Préparer les données exactement comme le serveur les attend - const taskData: Partial = { - title: title.trim(), - description: description?.trim() || "", - priority: (priority as Task['priority']) || "medium", - status: (status as Task['status']) || "pending", - assignedTo: assignedTo.trim(), - }; - - // Gestion spéciale des dates pour éviter les erreurs de format - if (startDate && startDate.trim() !== '') { - taskData.startDate = startDate; - } else { - taskData.startDate = null; - } - - if (dueDate && dueDate.trim() !== '') { - taskData.dueDate = dueDate; - } else { - taskData.dueDate = null; - } - - console.log('📤 Updating task:', { id, taskData }); - - const response = await fetch(`/api/tasks/${id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(taskData), - }); - - console.log('📥 Update Response:', { status: response.status, ok: response.ok }); - - if (!response.ok) { - const errorText = await response.text(); - console.error('❌ Update Error:', { status: response.status, error: errorText }); - throw new Error(`Erreur ${response.status}: ${errorText}`); - } - - alert("Tâche modifiée avec succès"); - setEditingId(null); - loadTasks(); - return true; - } catch (error) { - console.error('Erreur lors de la modification:', error); - alert("Erreur lors de la modification"); - return false; - } - }; - - // Filtrer les tâches - const filteredTasks = tasks.filter(task => { - const matchesSearch = !searchTerm || task.title?.toLowerCase().includes(searchTerm.toLowerCase()); - const matchesStatus = statusFilter === "all" || task.status === statusFilter; - return matchesSearch && matchesStatus; - }); - - // Formulaire inline - const TaskForm = ({ task, onSubmit, onCancel }: { - task?: Task; - onSubmit: (formData: FormData) => Promise; - onCancel: () => void; - }) => { - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const success = await onSubmit(formData); - if (success && !task) { - (e.target as HTMLFormElement).reset(); - } - }; - - return ( - - -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
-
- - - ); - }; - - if (loading) { - return ( -
-

Chargement des tâches...

-
- ); - } - - return ( -
- {/* Header */} -
-
-

- 📋 Gestion des Tâches -

- -
- - {/* Filtres */} -
-
- setSearchTerm(e.target.value)} - style={{ - width: '100%', - padding: '8px 12px', - border: '1px solid #d1d5db', - borderRadius: '6px', - fontSize: '14px' - }} - /> -
-
- -
-
-
- - {/* Tableau des tâches */} -
- - - - - - - - - - - - - {showCreateForm && ( - setShowCreateForm(false)} - /> - )} - - {filteredTasks.length === 0 ? ( - - - - ) : ( - filteredTasks.map((task) => ( - editingId === task.id ? ( - updateTask(task.id, formData)} - onCancel={() => setEditingId(null)} - /> - ) : ( - - - - - - - - - ) - )) - )} - -
TitrePrioritéStatutAssigné àDatesActions
- Aucune tâche trouvée -
-
-
- {task.title} -
- {task.description && ( -
- {task.description} -
- )} -
-
- - {task.priority === 'high' ? '🔴 Élevée' : task.priority === 'medium' ? '🟡 Moyenne' : '🟢 Faible'} - - - - {task.status === 'completed' ? '✅ Terminée' : '⏳ En cours'} - - - {task.assignedTo} - - {task.startDate && ( -
📅 {new Date(task.startDate).toLocaleDateString('fr-FR')}
- )} - {task.dueDate && ( -
⏰ {new Date(task.dueDate).toLocaleDateString('fr-FR')}
- )} -
- -
-
-
- ); -} \ No newline at end of file diff --git a/client/src/pages/TasksProductionSimple.tsx b/client/src/pages/TasksProductionSimple.tsx deleted file mode 100644 index 7c3c9c4..0000000 --- a/client/src/pages/TasksProductionSimple.tsx +++ /dev/null @@ -1,546 +0,0 @@ -import { useState, useEffect } from "react"; - -// Version 100% autonome sans aucune dépendance externe -export default function TasksProductionSimple() { - const [tasks, setTasks] = useState([]); - const [loading, setLoading] = useState(true); - const [showCreateModal, setShowCreateModal] = useState(false); - const [showEditModal, setShowEditModal] = useState(false); - const [selectedTask, setSelectedTask] = useState(null); - const [searchTerm, setSearchTerm] = useState(""); - const [statusFilter, setStatusFilter] = useState("all"); - - // Charger les tâches - const loadTasks = async () => { - try { - const response = await fetch('/api/tasks'); - if (response.ok) { - const data = await response.json(); - setTasks(data); - } - } catch (error) { - console.error('Erreur lors du chargement des tâches:', error); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - loadTasks(); - }, []); - - // Filtrer les tâches - const filteredTasks = tasks.filter(task => { - const matchesSearch = task.title?.toLowerCase().includes(searchTerm.toLowerCase()); - const matchesStatus = statusFilter === "all" || task.status === statusFilter; - return matchesSearch && matchesStatus; - }); - - // Composant formulaire inline - const TaskForm = ({ task, onClose }: any) => { - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - const formData = new FormData(e.currentTarget); - const title = formData.get('title') as string; - const description = formData.get('description') as string; - const priority = formData.get('priority') as string; - const status = formData.get('status') as string; - const assignedTo = formData.get('assignedTo') as string; - const startDate = formData.get('startDate') as string; - const dueDate = formData.get('dueDate') as string; - - if (!title?.trim()) { - alert("Le titre est requis"); - return; - } - - if (!assignedTo?.trim()) { - alert("L'assignation est requise"); - return; - } - - const submitBtn = e.currentTarget.querySelector('button[type="submit"]') as HTMLButtonElement; - submitBtn.disabled = true; - submitBtn.textContent = "..."; - - try { - const taskData = { - title: title.trim(), - description: description?.trim() || "", - priority: priority || "medium", - status: status || "pending", - assignedTo: assignedTo.trim(), - startDate: startDate || null, - dueDate: dueDate || null, - }; - - const url = task ? `/api/tasks/${task.id}` : '/api/tasks'; - const method = task ? 'PUT' : 'POST'; - - if (!task) { - (taskData as any).groupId = 1; - (taskData as any).createdBy = 'admin'; - } - - console.log('📤 Sending request:', { url, method, taskData }); - - const response = await fetch(url, { - method, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(taskData), - }); - - console.log('📥 Response:', { status: response.status, ok: response.ok }); - - if (!response.ok) { - const errorText = await response.text(); - console.error('❌ API Error:', { status: response.status, error: errorText }); - throw new Error(`Erreur ${response.status}: ${errorText}`); - } - - alert(task ? "Tâche modifiée avec succès" : "Tâche créée avec succès"); - onClose(); - loadTasks(); // Recharger les tâches - - } catch (error) { - console.error('Erreur:', error); - alert("Erreur lors de l'opération"); - submitBtn.disabled = false; - submitBtn.textContent = task ? "Modifier" : "Créer"; - } - }; - - return ( -
-
-

- 📅 Date de début = Quand la tâche devient visible
- ⏰ Date d'échéance = Quand la tâche doit être terminée -

- -
- -
-
- - -
- -
- - - - - -
- -
- - - - \ No newline at end of file diff --git a/urgent_production_fix.sh b/urgent_production_fix.sh deleted file mode 100755 index 8796a6e..0000000 --- a/urgent_production_fix.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -# Script de correction urgente pour la production -# Applique la migration DLC immédiatement - -set -e - -echo "🚨 CORRECTION URGENTE - Migration DLC Production" -echo "================================================" - -# Vérifier que Docker Compose est disponible -if ! command -v docker-compose &> /dev/null; then - echo "❌ docker-compose non trouvé" - exit 1 -fi - -# Vérifier que le conteneur PostgreSQL est en cours d'exécution -if ! docker-compose ps | grep -q logiflow-db; then - echo "❌ Conteneur logiflow-db non trouvé" - echo "Containers disponibles:" - docker-compose ps - exit 1 -fi - -echo "✅ Conteneur PostgreSQL trouvé" - -# Appliquer la migration DLC -echo "🔄 Application de la migration DLC..." - -docker-compose exec -T logiflow-db psql -U logiflow_admin -d logiflow_db << 'EOF' --- Migration DLC Stock Épuisé -ALTER TABLE dlc_products -ADD COLUMN IF NOT EXISTS stock_epuise boolean DEFAULT false NOT NULL, -ADD COLUMN IF NOT EXISTS stock_epuise_by varchar(255), -ADD COLUMN IF NOT EXISTS stock_epuise_at timestamp; - --- Index pour performance -CREATE INDEX IF NOT EXISTS idx_dlc_products_stock_epuise ON dlc_products(stock_epuise); - --- Vérification -SELECT 'Migration DLC appliquée avec succès' as status; - --- Afficher les colonnes ajoutées -SELECT column_name, data_type -FROM information_schema.columns -WHERE table_name = 'dlc_products' -AND column_name LIKE '%stock_epuise%' -ORDER BY column_name; -EOF - -if [ $? -eq 0 ]; then - echo "✅ Migration DLC appliquée avec succès" -else - echo "❌ Erreur lors de la migration" - exit 1 -fi - -# Redémarrer l'application -echo "🔄 Redémarrage de l'application..." -docker-compose restart logiflow - -if [ $? -eq 0 ]; then - echo "✅ Application redémarrée" -else - echo "❌ Erreur lors du redémarrage" - exit 1 -fi - -echo "" -echo "🎉 CORRECTION TERMINÉE" -echo "L'erreur 'column does not exist' devrait maintenant être résolue" -echo "" -echo "Vérifiez dans les logs que l'API /api/dlc-products fonctionne maintenant" \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index ce3e3d1..c435e97 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -20,7 +20,6 @@ export default defineConfig({ alias: { "@": path.resolve(import.meta.dirname, "client", "src"), "@shared": path.resolve(import.meta.dirname, "shared"), - "@assets": path.resolve(import.meta.dirname, "attached_assets"), }, }, root: path.resolve(import.meta.dirname, "client"),