diff --git a/client/src/components/Sidebar.tsx b/client/src/components/Sidebar.tsx
index 2249df9..075e16d 100644
--- a/client/src/components/Sidebar.tsx
+++ b/client/src/components/Sidebar.tsx
@@ -81,13 +81,13 @@ export default function Sidebar() {
path: "/orders",
label: "Commandes",
icon: Package,
- roles: ["admin", "directeur", "manager", "employee"]
+ roles: ["admin", "directeur", "manager"]
},
{
path: "/deliveries",
label: "Livraisons",
icon: Truck,
- roles: ["admin", "directeur", "manager", "employee"]
+ roles: ["admin", "directeur", "manager"]
},
{
path: "/bl-reconciliation",
diff --git a/client/src/components/modals/QuickCreateMenu.tsx b/client/src/components/modals/QuickCreateMenu.tsx
index d617ea2..730983a 100644
--- a/client/src/components/modals/QuickCreateMenu.tsx
+++ b/client/src/components/modals/QuickCreateMenu.tsx
@@ -1,6 +1,8 @@
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Package, Truck } from "lucide-react";
+import { useAuthUnified } from "@/hooks/useAuthUnified";
+import { hasPermission } from "@/lib/permissions";
interface QuickCreateMenuProps {
isOpen: boolean;
@@ -15,6 +17,11 @@ export default function QuickCreateMenu({
onCreateOrder,
onCreateDelivery,
}: QuickCreateMenuProps) {
+ const { user } = useAuthUnified();
+
+ const canCreateOrders = hasPermission(user?.role || '', 'orders', 'create');
+ const canCreateDeliveries = hasPermission(user?.role || '', 'deliveries', 'create');
+
return (
-
+ {canCreateOrders && (
+
+ )}
-
-
-
setShowQuickCreate(true)}
- className="bg-accent hover:bg-orange-600 text-white"
- >
-
- Nouveau
-
+ {(hasPermission(user?.role || '', 'orders', 'create') || hasPermission(user?.role || '', 'deliveries', 'create')) && (
+
setShowQuickCreate(true)}
+ className="bg-accent hover:bg-orange-600 text-white"
+ >
+
+ Nouveau
+
+ )}
diff --git a/replit.md b/replit.md
index 3ccbd29..166ac0e 100644
--- a/replit.md
+++ b/replit.md
@@ -162,4 +162,51 @@ Preferred communication style: Simple, everyday language.
- Added automatic order status synchronization in `updateDelivery` method when delivery marked as delivered
- Created `fix-delivery-order-sync.sql` script to correct existing production data inconsistencies
- Improved Calendar date initialization to show current month instead of hardcoded July 2025
-- **Result**: Calendar now properly displays delivery dates and automatically synchronizes order statuses when deliveries are completed
\ No newline at end of file
+- **Result**: Calendar now properly displays delivery dates and automatically synchronizes order statuses when deliveries are completed
+
+### August 12, 2025 - Employee Permissions Restriction & Database Schema Download
+
+#### Employee Role Permissions Update
+- **Issue**: Employee role had excessive access to orders and deliveries modules, but needed restricted calendar access
+- **Root Cause**: Permission system allowed employees full access to create orders/deliveries from calendar and sidebar navigation
+- **Solution Implemented**:
+ - Updated `shared/permissions.ts`: Removed all permissions for employees on 'orders' and 'deliveries' modules
+ - Modified `client/src/components/Sidebar.tsx`: Removed orders and deliveries menu items for employee role
+ - Enhanced `client/src/pages/Calendar.tsx`: Added permission checks to hide "Nouveau" button for employees
+ - Updated `client/src/components/modals/QuickCreateMenu.tsx`: Added role-based filtering for order/delivery creation options
+- **Employee Access Rules**:
+ - **Calendar**: View-only access, cannot create orders or deliveries
+ - **Sidebar**: No access to Orders and Deliveries menu items
+ - **Customer Orders & DLC**: Maintains supplier list access for creating customer orders and DLC entries
+- **Result**: Employees now have appropriate restricted access while maintaining necessary supplier information for their workflows
+
+#### Database Schema Download Feature
+- **Issue**: Database schema scan results were only available in server logs, needed downloadable reports
+- **Solution Implemented**:
+ - Created new API route `/api/debug/download-schema` for production schema downloads
+ - Added comprehensive schema report generation with tables, columns, constraints, and record counts
+ - Enhanced `client/src/pages/DatabaseDebug.tsx`: Added download button that appears after successful scans
+ - Implemented proper file download headers with automatic filename generation
+ - Added admin-only access restriction and production environment validation
+- **Download Report Features**:
+ - Complete database structure with column details and constraints
+ - Record counts per table for data overview
+ - Foreign key relationships mapping
+ - Formatted text file with timestamps and user information
+- **Result**: Administrators can now download comprehensive database schema reports for documentation and analysis
+
+#### Employee Supplier Access Fix
+- **Issue**: Employee role could not access supplier lists in Customer Orders and DLC modules on production server
+- **Root Cause**: API route `/api/suppliers` was restricted to admin and manager roles only, excluding employees and directeurs
+- **Solution Implemented**:
+ - Updated `/api/suppliers` GET route: Added employee and directeur role access for read operations
+ - Updated `/api/suppliers` POST route: Added directeur role access for creation operations
+ - Updated `/api/suppliers` PUT route: Added directeur role access for edit operations
+ - Updated `/api/suppliers` DELETE route: Restricted to admin and directeur only (removed manager access)
+ - Created test script `test-employee-supplier-access.js` for production verification
+- **Access Matrix Updated**:
+ - **GET /api/suppliers**: admin, directeur, manager, employee (all roles can read)
+ - **POST /api/suppliers**: admin, directeur, manager (creation permissions)
+ - **PUT /api/suppliers**: admin, directeur, manager (edit permissions)
+ - **DELETE /api/suppliers**: admin, directeur only (delete permissions)
+- **Result**: Employees can now access supplier lists in Customer Orders and DLC modules while maintaining appropriate write restrictions
\ No newline at end of file
diff --git a/server/routes.ts b/server/routes.ts
index d67611a..0f85bb9 100644
--- a/server/routes.ts
+++ b/server/routes.ts
@@ -188,7 +188,7 @@ export async function registerRoutes(app: Express): Promise {
app.get('/api/suppliers', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUser(req.user.claims ? req.user.claims.sub : req.user.id);
- if (!user || (user.role !== 'admin' && user.role !== 'manager')) {
+ if (!user || (user.role !== 'admin' && user.role !== 'manager' && user.role !== 'directeur' && user.role !== 'employee')) {
return res.status(403).json({ message: "Insufficient permissions" });
}
@@ -237,8 +237,8 @@ export async function registerRoutes(app: Express): Promise {
console.log('✅ User found:', { username: user.username, role: user.role });
// Vérifier les permissions
- if (user.role !== 'admin' && user.role !== 'manager') {
- console.error('❌ Insufficient permissions:', { userRole: user.role, required: ['admin', 'manager'] });
+ if (user.role !== 'admin' && user.role !== 'manager' && user.role !== 'directeur') {
+ console.error('❌ Insufficient permissions:', { userRole: user.role, required: ['admin', 'manager', 'directeur'] });
return res.status(403).json({ message: "Insufficient permissions" });
}
@@ -279,7 +279,7 @@ export async function registerRoutes(app: Express): Promise {
app.put('/api/suppliers/:id', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUser(req.user.claims ? req.user.claims.sub : req.user.id);
- if (!user || (user.role !== 'admin' && user.role !== 'manager')) {
+ if (!user || (user.role !== 'admin' && user.role !== 'manager' && user.role !== 'directeur')) {
return res.status(403).json({ message: "Insufficient permissions" });
}
@@ -296,7 +296,7 @@ export async function registerRoutes(app: Express): Promise {
app.delete('/api/suppliers/:id', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUser(req.user.claims ? req.user.claims.sub : req.user.id);
- if (!user || (user.role !== 'admin' && user.role !== 'manager')) {
+ if (!user || (user.role !== 'admin' && user.role !== 'directeur')) {
return res.status(403).json({ message: "Insufficient permissions" });
}
diff --git a/shared/permissions.ts b/shared/permissions.ts
index 00af99a..0cd843a 100644
--- a/shared/permissions.ts
+++ b/shared/permissions.ts
@@ -32,20 +32,20 @@ const PERMISSIONS: Record> = {
employee: ['view']
},
- // Commandes - Admin/Directeur tout, Manager tout sauf delete, Employé view
+ // Commandes - Admin/Directeur tout, Manager tout sauf delete, Employé aucun accès
orders: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
- employee: ['view']
+ employee: []
},
- // Livraisons - Admin/Directeur tout, Manager tout sauf delete, Employé view
+ // Livraisons - Admin/Directeur tout, Manager tout sauf delete, Employé aucun accès
deliveries: {
admin: ['view', 'create', 'edit', 'delete'],
directeur: ['view', 'create', 'edit', 'delete'],
manager: ['view', 'create', 'edit'],
- employee: ['view']
+ employee: []
},
// Rapprochement - Admin tout, Directeur tout sauf delete, Manager/Employé rien
diff --git a/test-employee-supplier-access.js b/test-employee-supplier-access.js
new file mode 100644
index 0000000..569f5db
--- /dev/null
+++ b/test-employee-supplier-access.js
@@ -0,0 +1,152 @@
+#!/usr/bin/env node
+
+/**
+ * Script de test pour vérifier l'accès des employés aux fournisseurs
+ * À exécuter sur le serveur de production pour diagnostiquer les problèmes d'accès
+ */
+
+const https = require('https');
+const fs = require('fs');
+
+// Configuration pour votre serveur de production
+const PRODUCTION_URL = process.env.PRODUCTION_URL || 'https://votre-serveur-production.com';
+const TEST_EMPLOYEE_CREDENTIALS = {
+ username: process.env.TEST_EMPLOYEE_USERNAME || 'test_employee',
+ password: process.env.TEST_EMPLOYEE_PASSWORD || 'password123'
+};
+
+console.log('🧪 === TEST D\'ACCÈS FOURNISSEURS POUR EMPLOYÉS ===\n');
+
+async function makeRequest(path, method = 'GET', data = null, cookies = '') {
+ return new Promise((resolve, reject) => {
+ const url = new URL(path, PRODUCTION_URL);
+ const options = {
+ hostname: url.hostname,
+ port: url.port || (url.protocol === 'https:' ? 443 : 80),
+ path: url.pathname + url.search,
+ method: method,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'User-Agent': 'LogiFlow-Test-Script/1.0',
+ ...(cookies ? { 'Cookie': cookies } : {}),
+ ...(data ? { 'Content-Length': Buffer.byteLength(JSON.stringify(data)) } : {})
+ }
+ };
+
+ const req = https.request(options, (res) => {
+ let body = '';
+ res.on('data', (chunk) => body += chunk);
+ res.on('end', () => {
+ try {
+ const parsed = JSON.parse(body);
+ resolve({
+ status: res.statusCode,
+ headers: res.headers,
+ data: parsed
+ });
+ } catch (e) {
+ resolve({
+ status: res.statusCode,
+ headers: res.headers,
+ data: body
+ });
+ }
+ });
+ });
+
+ req.on('error', reject);
+
+ if (data) {
+ req.write(JSON.stringify(data));
+ }
+
+ req.end();
+ });
+}
+
+async function testEmployeeSupplierAccess() {
+ try {
+ console.log('1️⃣ Test de connexion employé...');
+
+ // Étape 1: Se connecter avec un compte employé
+ const loginResponse = await makeRequest('/api/login', 'POST', TEST_EMPLOYEE_CREDENTIALS);
+
+ console.log(` Status: ${loginResponse.status}`);
+ console.log(` Response: ${JSON.stringify(loginResponse.data, null, 2)}\n`);
+
+ if (loginResponse.status !== 200) {
+ console.error('❌ Échec de connexion employé');
+ console.error(' Vérifiez que le compte employé existe et que les identifiants sont corrects');
+ return;
+ }
+
+ // Extraire les cookies de session
+ const setCookieHeaders = loginResponse.headers['set-cookie'] || [];
+ const cookies = setCookieHeaders.join('; ');
+
+ console.log('2️⃣ Test d\'accès aux fournisseurs...');
+
+ // Étape 2: Tester l'accès à la liste des fournisseurs
+ const suppliersResponse = await makeRequest('/api/suppliers', 'GET', null, cookies);
+
+ console.log(` Status: ${suppliersResponse.status}`);
+ console.log(` Response: ${JSON.stringify(suppliersResponse.data, null, 2)}\n`);
+
+ if (suppliersResponse.status === 200) {
+ console.log('✅ SUCCÈS: L\'employé peut accéder aux fournisseurs');
+ console.log(` Nombre de fournisseurs retournés: ${Array.isArray(suppliersResponse.data) ? suppliersResponse.data.length : 'N/A'}`);
+ } else if (suppliersResponse.status === 403) {
+ console.log('❌ ÉCHEC: L\'employé n\'a pas l\'autorisation d\'accéder aux fournisseurs');
+ console.log(' Le problème est confirmé - permissions insuffisantes');
+ } else {
+ console.log(`⚠️ ERREUR INATTENDUE: Status ${suppliersResponse.status}`);
+ }
+
+ console.log('\n3️⃣ Test d\'accès aux fournisseurs DLC...');
+
+ // Étape 3: Tester l'accès aux fournisseurs DLC spécifiquement
+ const dlcSuppliersResponse = await makeRequest('/api/suppliers?dlc=true', 'GET', null, cookies);
+
+ console.log(` Status: ${dlcSuppliersResponse.status}`);
+ console.log(` Response: ${JSON.stringify(dlcSuppliersResponse.data, null, 2)}\n`);
+
+ if (dlcSuppliersResponse.status === 200) {
+ console.log('✅ SUCCÈS: L\'employé peut accéder aux fournisseurs DLC');
+ console.log(` Nombre de fournisseurs DLC retournés: ${Array.isArray(dlcSuppliersResponse.data) ? dlcSuppliersResponse.data.length : 'N/A'}`);
+ } else if (dlcSuppliersResponse.status === 403) {
+ console.log('❌ ÉCHEC: L\'employé n\'a pas l\'autorisation d\'accéder aux fournisseurs DLC');
+ }
+
+ // Résumé final
+ console.log('\n📊 === RÉSUMÉ DU TEST ===');
+ console.log(`Connexion employé: ${loginResponse.status === 200 ? '✅ OK' : '❌ ÉCHEC'}`);
+ console.log(`Accès fournisseurs: ${suppliersResponse.status === 200 ? '✅ OK' : '❌ ÉCHEC'}`);
+ console.log(`Accès fournisseurs DLC: ${dlcSuppliersResponse.status === 200 ? '✅ OK' : '❌ ÉCHEC'}`);
+
+ if (suppliersResponse.status === 200 && dlcSuppliersResponse.status === 200) {
+ console.log('\n🎉 TOUS LES TESTS PASSÉS - L\'accès employé aux fournisseurs fonctionne correctement');
+ } else {
+ console.log('\n⚠️ PROBLÈME DÉTECTÉ - Vérifiez les permissions serveur et la configuration des rôles');
+ }
+
+ } catch (error) {
+ console.error('💥 Erreur lors du test:', error.message);
+ console.error(' Vérifiez que le serveur de production est accessible');
+ }
+}
+
+// Instructions d'utilisation
+console.log('📋 Instructions:');
+console.log('1. Assurez-vous d\'avoir un compte employé de test');
+console.log('2. Configurez les variables d\'environnement si nécessaire:');
+console.log(' - PRODUCTION_URL=https://votre-serveur.com');
+console.log(' - TEST_EMPLOYEE_USERNAME=nom_utilisateur');
+console.log(' - TEST_EMPLOYEE_PASSWORD=mot_de_passe');
+console.log('3. Exécutez: node test-employee-supplier-access.js\n');
+
+// Exécuter le test si le script est appelé directement
+if (require.main === module) {
+ testEmployeeSupplierAccess().catch(console.error);
+}
+
+module.exports = { testEmployeeSupplierAccess };
\ No newline at end of file