mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-11 17:27:31 +02:00
14 files changed
+910
-16
No files matched your search
@@ -0,0 +1,109 @@
|
||||
# Fix Production Urgent - Employé Commandes Client & DLC
|
||||
|
||||
## Problèmes Identifiés
|
||||
|
||||
1. **Employé ne peut pas créer commandes clients** en production
|
||||
2. **DLC ne fonctionnent pas** en production (même problème qu'en dev)
|
||||
3. **Cache invalidation manquante** pour DLC
|
||||
|
||||
## Analyse du Code
|
||||
|
||||
### ✅ Permissions OK
|
||||
```javascript
|
||||
// shared/permissions.ts - Lignes 67-73 et 75-81
|
||||
'customer-orders': {
|
||||
employee: ['view', 'create'] // ✅ PERMISSION OK
|
||||
},
|
||||
dlc: {
|
||||
employee: ['view', 'create'] // ✅ PERMISSION OK
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Routes Backend OK
|
||||
```javascript
|
||||
// server/routes.ts
|
||||
// POST /api/customer-orders - REMOVED: All role restrictions
|
||||
// POST /api/dlc-products - REMOVED: All role restrictions
|
||||
```
|
||||
|
||||
### ✅ Frontend Permissions OK
|
||||
```javascript
|
||||
// client/src/lib/permissions.ts - Ligne 118
|
||||
const canCreate = (module: Module): boolean => canPerformAction(module, 'create');
|
||||
// usePermissions(user?.role) fonctionne correctement
|
||||
```
|
||||
|
||||
## Root Cause Probable
|
||||
|
||||
Le problème n'est PAS les permissions mais plutôt :
|
||||
|
||||
1. **Cache frontend** - L'employé a peut-être un cache obsolète
|
||||
2. **Erreur validation** - Schema validation qui échoue silencieusement
|
||||
3. **GroupId manquant** - L'employé n'a pas de groupId défini correctement
|
||||
4. **DLC Production** - Même problème cache qu'en dev
|
||||
|
||||
## Solutions Immédiates
|
||||
|
||||
### 1. Fix Cache DLC (Déjà Fait en Dev)
|
||||
```javascript
|
||||
// client/src/pages/DlcPage.tsx
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"], exact: false });
|
||||
```
|
||||
|
||||
### 2. Debug Frontend Production
|
||||
```javascript
|
||||
// À tester en console DevTools sur production:
|
||||
console.log("User:", user);
|
||||
console.log("Role:", user?.role);
|
||||
console.log("Groups:", user?.userGroups);
|
||||
console.log("Can create customer orders:", permissions.canCreate('customer-orders'));
|
||||
console.log("Can create DLC:", permissions.canCreate('dlc'));
|
||||
```
|
||||
|
||||
### 3. Test Manual Production
|
||||
```javascript
|
||||
// Tester en curl direct sur serveur production:
|
||||
curl -X POST https://votre-serveur/api/customer-orders \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Cookie: session=..." \
|
||||
-d '{
|
||||
"customerName": "Test Production",
|
||||
"contactNumber": "0123456789",
|
||||
"productName": "Test",
|
||||
"quantity": 1,
|
||||
"groupId": 2
|
||||
}'
|
||||
```
|
||||
|
||||
## Actions Requises
|
||||
|
||||
### Immédiat
|
||||
1. **Redémarrer serveur production** pour avoir les derniers fixes
|
||||
2. **Vider cache browser** de l'employé (Ctrl+F5 ou mode incognito)
|
||||
3. **Tester création commande** avec DevTools ouvert
|
||||
4. **Noter toute erreur** console/réseau
|
||||
|
||||
### Si Problème Persiste
|
||||
1. **Logs serveur** - Chercher erreurs dans logs production
|
||||
2. **User Groups** - Vérifier que l'employé a bien un groupe assigné
|
||||
3. **Schema Validation** - Tester les données envoyées
|
||||
|
||||
## Checklist Déploiement
|
||||
|
||||
- [x] Routes backend sans restrictions rôle
|
||||
- [x] Permissions employé définies correctement
|
||||
- [x] Cache invalidation DLC avec exact:false
|
||||
- [x] Frontend permissions hook fonctionnel
|
||||
- [ ] Serveur production redémarré
|
||||
- [ ] Cache browser employé vidé
|
||||
- [ ] Tests création commande/DLC validés
|
||||
|
||||
## Fichiers Modifiés
|
||||
|
||||
1. `client/src/pages/DlcPage.tsx` - Cache invalidation fix
|
||||
2. `server/routes.ts` - Debug logs ajoutés
|
||||
3. `server/storage.ts` - MemStorage DLC fix (dev uniquement)
|
||||
|
||||
## Prochain Pas
|
||||
|
||||
**Tester immédiatement** après redémarrage serveur production avec un employé en mode incognito + DevTools.
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
ctions
|
||||
|
||||
|
||||
|
||||
|
||||
🔍 Found 1 group assignments for user _1753266816257
|
||||
|
||||
🔍 Raw query result: [
|
||||
|
||||
{
|
||||
|
||||
user_id: '_1753266816257',
|
||||
|
||||
group_id: 2,
|
||||
|
||||
group_id_ref: 2,
|
||||
|
||||
group_name: 'Houdemont',
|
||||
|
||||
group_color: '#455A64',
|
||||
|
||||
nocodb_config_id: 1,
|
||||
|
||||
nocodb_table_id: 'my7zunxprumahmm',
|
||||
|
||||
nocodb_table_name: 'CommandeH',
|
||||
|
||||
invoice_column_name: 'RefFacture',
|
||||
|
||||
group_created_at: '2025-07-22 11:09:08.977622',
|
||||
|
||||
group_updated_at: '2025-08-12 09:39:32.989'
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
✅ Processed 1 groups for user _1753266816257
|
||||
|
||||
GET /api/groups 304 in 88ms
|
||||
|
||||
GET /api/suppliers 304 in 95ms
|
||||
|
||||
🔍 Querying user_groups for user: _1753266816257
|
||||
|
||||
🔍 Found 1 group assignments for user _1753266816257
|
||||
|
||||
🔍 Raw query result: [
|
||||
|
||||
{
|
||||
|
||||
user_id: '_1753266816257',
|
||||
|
||||
group_id: 2,
|
||||
|
||||
group_id_ref: 2,
|
||||
|
||||
group_name: 'Houdemont',
|
||||
|
||||
group_color: '#455A64',
|
||||
|
||||
nocodb_config_id: 1,
|
||||
|
||||
nocodb_table_id: 'my7zunxprumahmm',
|
||||
|
||||
nocodb_table_name: 'CommandeH',
|
||||
|
||||
invoice_column_name: 'RefFacture',
|
||||
|
||||
group_created_at: '2025-07-22 11:09:08.977622',
|
||||
|
||||
group_updated_at: '2025-08-12 09:39:32.989'
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
✅ Processed 1 groups for user _1753266816257
|
||||
|
||||
🔍 getUserWithGroups called for user: _1753266816257
|
||||
|
||||
🔍 Querying user_groups for user: _1753266816257
|
||||
|
||||
🔍 Found 1 group assignments for user _1753266816257
|
||||
|
||||
🔍 Raw query result: [
|
||||
|
||||
{
|
||||
|
||||
user_id: '_1753266816257',
|
||||
|
||||
group_id: 2,
|
||||
|
||||
group_id_ref: 2,
|
||||
|
||||
group_name: 'Houdemont',
|
||||
|
||||
group_color: '#455A64',
|
||||
|
||||
nocodb_config_id: 1,
|
||||
|
||||
nocodb_table_id: 'my7zunxprumahmm',
|
||||
|
||||
nocodb_table_name: 'CommandeH',
|
||||
|
||||
invoice_column_name: 'RefFacture',
|
||||
|
||||
group_created_at: '2025-07-22 11:09:08.977622',
|
||||
|
||||
group_updated_at: '2025-08-12 09:39:32.989'
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
✅ Processed 1 groups for user _1753266816257
|
||||
|
||||
🔍 getUserWithGroups called for user: _1753266816257
|
||||
|
||||
🔍 Querying user_groups for user: _1753266816257
|
||||
|
||||
🔍 Found 1 group assignments for user _1753266816257
|
||||
|
||||
🔍 Raw query result: [
|
||||
|
||||
{
|
||||
|
||||
user_id: '_1753266816257',
|
||||
|
||||
group_id: 2,
|
||||
|
||||
group_id_ref: 2,
|
||||
|
||||
group_name: 'Houdemont',
|
||||
|
||||
group_color: '#455A64',
|
||||
|
||||
nocodb_config_id: 1,
|
||||
|
||||
nocodb_table_id: 'my7zunxprumahmm',
|
||||
|
||||
nocodb_table_name: 'CommandeH',
|
||||
|
||||
invoice_column_name: 'RefFacture',
|
||||
|
||||
group_created_at: '2025-07-22 11:09:08.977622',
|
||||
|
||||
group_updated_at: '2025-08-12 09:39:32.989'
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
✅ Processed 1 groups for user _1753266816257
|
||||
|
||||
Customer orders - User assigned stores: { groupIds: [ 2 ] }
|
||||
|
||||
Customer orders returned from storage: 23 items
|
||||
|
||||
GET /api/customer-orders 304 in 130ms
|
||||
|
||||
HEAD /api/health 200 in 1ms
|
||||
|
||||
🔍 getUserWithGroups called for user: _1753266816257
|
||||
|
||||
🔍 Querying user_groups for user: _1753266816257
|
||||
|
||||
🔍 Found 1 group assignments for user _1753266816257
|
||||
|
||||
🔍 Raw query result: [
|
||||
|
||||
{
|
||||
|
||||
user_id: '_1753266816257',
|
||||
|
||||
group_id: 2,
|
||||
|
||||
group_id_ref: 2,
|
||||
|
||||
group_name: 'Houdemont',
|
||||
|
||||
group_color: '#455A64',
|
||||
|
||||
nocodb_config_id: 1,
|
||||
|
||||
nocodb_table_id: 'my7zunxprumahmm',
|
||||
|
||||
nocodb_table_name: 'CommandeH',
|
||||
|
||||
invoice_column_name: 'RefFacture',
|
||||
|
||||
group_created_at: '2025-07-22 11:09:08.977622',
|
||||
|
||||
group_updated_at: '2025-08-12 09:39:32.989'
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
✅ Processed 1 groups for user _1753266816257
|
||||
|
||||
GET /api/user 304 in 7ms
|
||||
|
||||
HEAD /api/health 200 in 1ms
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 311 KiB |
@@ -73,9 +73,22 @@ export default function DlcPage() {
|
||||
if (statusFilter && statusFilter !== "all") params.append("status", statusFilter);
|
||||
if (supplierFilter && supplierFilter !== "all") params.append("supplierId", supplierFilter);
|
||||
|
||||
console.log("🔍 Requête DLC products:", {
|
||||
url: `/api/dlc-products?${params.toString()}`,
|
||||
user: user?.role,
|
||||
selectedStoreId,
|
||||
userGroups: user?.userGroups?.map(ug => ({ groupId: ug.groupId, groupName: ug.group?.name }))
|
||||
});
|
||||
|
||||
return apiRequest(`/api/dlc-products?${params.toString()}`);
|
||||
},
|
||||
enabled: !authLoading,
|
||||
onSuccess: (data) => {
|
||||
console.log("📋 DLC products reçus:", {
|
||||
total: data.length,
|
||||
sample: data.slice(0, 3).map(d => ({ id: d.id, productName: d.productName, groupId: d.groupId }))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch DLC stats
|
||||
@@ -105,8 +118,10 @@ export default function DlcPage() {
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: InsertDlcProduct) => apiRequest("/api/dlc-products", "POST", data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"] });
|
||||
// Invalidate all DLC queries with any combination of parameters
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"], exact: false });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"], exact: false });
|
||||
console.log("🔄 Cache DLC invalidé après création");
|
||||
toast({ title: "Produit DLC créé avec succès" });
|
||||
setIsDialogOpen(false);
|
||||
form.reset();
|
||||
@@ -126,8 +141,9 @@ export default function DlcPage() {
|
||||
mutationFn: ({ id, data }: { id: number; data: Partial<InsertDlcProduct> }) =>
|
||||
apiRequest(`/api/dlc-products/${id}`, "PUT", data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"], exact: false });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"], exact: false });
|
||||
console.log("🔄 Cache DLC invalidé après mise à jour");
|
||||
toast({ title: "Produit DLC mis à jour avec succès" });
|
||||
setIsDialogOpen(false);
|
||||
form.reset();
|
||||
@@ -146,8 +162,9 @@ export default function DlcPage() {
|
||||
const validateMutation = useMutation({
|
||||
mutationFn: (id: number) => apiRequest(`/api/dlc-products/${id}/validate`, "PUT"),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"], exact: false });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"], exact: false });
|
||||
console.log("🔄 Cache DLC invalidé après validation");
|
||||
toast({ title: "Produit validé avec succès" });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
@@ -163,8 +180,9 @@ export default function DlcPage() {
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: number) => apiRequest(`/api/dlc-products/${id}`, "DELETE"),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"], exact: false });
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/dlc-products/stats"], exact: false });
|
||||
console.log("🔄 Cache DLC invalidé après suppression");
|
||||
toast({ title: "Produit supprimé avec succès" });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
|
||||
+1
-1
@@ -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 1755094677 connect.sid s%3AMRvtKRB7l8aU-cxKVAyRLza4Hz26hGS3.B0p70oONarXt57Foz6nSvGoPBIEpN6YNyr22RwYgJEc
|
||||
#HttpOnly_localhost FALSE / FALSE 1755095028 connect.sid s%3AxwnR6osGUOsL-I6MHjHctBuJf4K1HUWh.jqsaHkMTtzflaI4dg%2BmJBmTrVplUTDTG45KCUiL%2FVfw
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Debug final pour vérifier pourquoi les DLC créées par l'employé n'apparaissent pas
|
||||
*/
|
||||
|
||||
console.log('🔍 Debug Final - Visibilité DLC Employé');
|
||||
|
||||
async function debugDlcVisibility() {
|
||||
try {
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
console.log('\n=== DEBUG VISIBILITÉ DLC EMPLOYÉ ===');
|
||||
|
||||
// 1. Login admin pour test de contrôle
|
||||
console.log('1. Test admin...');
|
||||
const adminLogin = await fetch('http://localhost:5000/api/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username: 'admin', password: 'admin' })
|
||||
});
|
||||
|
||||
if (!adminLogin.ok) {
|
||||
console.log('❌ Admin login failed');
|
||||
return;
|
||||
}
|
||||
|
||||
const adminCookies = adminLogin.headers.get('set-cookie');
|
||||
|
||||
// 2. Créer une DLC avec admin
|
||||
console.log('2. Création DLC par admin...');
|
||||
const dlcData = {
|
||||
productName: 'Test DLC Visibilité Admin',
|
||||
dlcDate: '2025-08-20',
|
||||
dateType: 'DLC',
|
||||
quantity: 1,
|
||||
unit: 'Unité',
|
||||
supplierId: 1,
|
||||
location: 'Test Rayon',
|
||||
groupId: 2, // Groupe Houdemont (même que l'employé)
|
||||
status: 'en_cours'
|
||||
};
|
||||
|
||||
const createDlc = await fetch('http://localhost:5000/api/dlc-products', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Cookie': adminCookies,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(dlcData)
|
||||
});
|
||||
|
||||
console.log('Status création:', createDlc.status);
|
||||
|
||||
if (createDlc.ok) {
|
||||
const newDlc = await createDlc.json();
|
||||
console.log('✅ DLC créée:', {
|
||||
id: newDlc.id,
|
||||
productName: newDlc.productName,
|
||||
groupId: newDlc.groupId
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Vérifier la liste complète DLC
|
||||
console.log('\n3. Vérification liste DLC...');
|
||||
const dlcList = await fetch('http://localhost:5000/api/dlc-products', {
|
||||
headers: { 'Cookie': adminCookies }
|
||||
});
|
||||
|
||||
if (dlcList.ok) {
|
||||
const dlcs = await dlcList.json();
|
||||
console.log('📋 Total DLC:', dlcs.length);
|
||||
|
||||
// Filtrer par groupe 2 (Houdemont)
|
||||
const group2Dlcs = dlcs.filter(d => d.groupId === 2);
|
||||
console.log('🏪 DLC Groupe 2 (Houdemont):', group2Dlcs.length);
|
||||
|
||||
// Dernières DLC créées
|
||||
const recentDlcs = dlcs.slice(0, 5);
|
||||
console.log('🆕 5 dernières DLC:');
|
||||
recentDlcs.forEach(dlc => {
|
||||
console.log(` - ID: ${dlc.id}, Nom: ${dlc.productName}, Groupe: ${dlc.groupId}`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n4. Instructions pour test employé production:');
|
||||
console.log('- Se connecter avec compte employé');
|
||||
console.log('- Aller sur page DLC Products');
|
||||
console.log('- Vérifier si les DLC du groupe 2 sont visibles');
|
||||
console.log('- Regarder dans les outils dev si la requête API retourne des données');
|
||||
console.log('- Vérifier le cache React Query dans les dev tools');
|
||||
|
||||
console.log('\n🔍 Points à vérifier:');
|
||||
console.log('1. Cache React Query invalidé après création ?');
|
||||
console.log('2. Filtre groupId correct dans la requête ?');
|
||||
console.log('3. État de loading/error du composant ?');
|
||||
console.log('4. Données reçues mais pas affichées ?');
|
||||
|
||||
} catch (error) {
|
||||
console.log('❌ Erreur debug:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
debugDlcVisibility();
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Script de debug pour permissions employé en production
|
||||
// À exécuter dans la console DevTools du navigateur
|
||||
|
||||
const debugEmployeePermissions = () => {
|
||||
console.log('🔍 DEBUG PERMISSIONS EMPLOYÉ PRODUCTION');
|
||||
console.log('=====================================');
|
||||
|
||||
// 1. Vérifier l'utilisateur connecté
|
||||
console.log('\n👤 UTILISATEUR:');
|
||||
if (window.user || localStorage.getItem('user')) {
|
||||
const user = window.user || JSON.parse(localStorage.getItem('user') || '{}');
|
||||
console.log('ID:', user.id);
|
||||
console.log('Role:', user.role);
|
||||
console.log('Groups:', user.userGroups);
|
||||
console.log('Nom:', user.firstName, user.lastName);
|
||||
} else {
|
||||
console.log('❌ Aucun utilisateur trouvé');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Vérifier les permissions via hook
|
||||
console.log('\n🔐 PERMISSIONS HOOK:');
|
||||
try {
|
||||
// Simuler usePermissions
|
||||
const testPermissions = {
|
||||
'customer-orders': ['view', 'create'],
|
||||
'dlc': ['view', 'create']
|
||||
};
|
||||
|
||||
console.log('Customer Orders - canCreate:', testPermissions['customer-orders'].includes('create'));
|
||||
console.log('DLC - canCreate:', testPermissions['dlc'].includes('create'));
|
||||
} catch (error) {
|
||||
console.log('❌ Erreur permissions:', error);
|
||||
}
|
||||
|
||||
// 3. Vérifier les éléments DOM
|
||||
console.log('\n🖥️ INTERFACE:');
|
||||
const nouvelleCommande = document.querySelector('button:contains("Nouvelle Commande")') ||
|
||||
document.querySelector('[class*="button"]:contains("Nouvelle")');
|
||||
console.log('Bouton "Nouvelle Commande" visible:', !!nouvelleCommande);
|
||||
|
||||
const dlcButton = document.querySelector('button:contains("Nouveau DLC")') ||
|
||||
document.querySelector('[class*="button"]:contains("DLC")');
|
||||
console.log('Bouton création DLC visible:', !!dlcButton);
|
||||
|
||||
// 4. Test requête API directe
|
||||
console.log('\n🌐 TEST API:');
|
||||
console.log('Ouvrir DevTools > Network pour voir les requêtes');
|
||||
console.log('Essayer de créer une commande et noter la réponse');
|
||||
|
||||
// 5. Logs à surveiller
|
||||
console.log('\n📋 LOGS À SURVEILLER:');
|
||||
console.log('- Erreurs console (rouge)');
|
||||
console.log('- Requêtes réseau échouées (400/403/500)');
|
||||
console.log('- Messages d\'erreur formulaire');
|
||||
console.log('- Validation schema échouée');
|
||||
|
||||
return {
|
||||
user: window.user || JSON.parse(localStorage.getItem('user') || '{}'),
|
||||
canCreateOrders: true, // Devrait être true pour employé
|
||||
canCreateDLC: true, // Devrait être true pour employé
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
};
|
||||
|
||||
// Instructions pour utilisation en production
|
||||
console.log('🎯 INSTRUCTIONS PRODUCTION:');
|
||||
console.log('1. Ouvrir DevTools (F12)');
|
||||
console.log('2. Aller dans Console');
|
||||
console.log('3. Coller ce script et Entrée');
|
||||
console.log('4. Analyser les résultats');
|
||||
console.log('5. Essayer créer commande/DLC');
|
||||
console.log('6. Envoyer logs complets pour debug');
|
||||
|
||||
// Export pour utilisation
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = debugEmployeePermissions;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Fix pour invalidation cache DLC - Test avec curl direct
|
||||
|
||||
const testDlcEndpoint = async () => {
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
console.log('🔍 Test Direct API DLC Products');
|
||||
|
||||
try {
|
||||
// 1. Login admin
|
||||
console.log('1. Login admin...');
|
||||
const loginResult = execSync(`curl -X POST http://localhost:5000/api/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"admin"}' \
|
||||
-c cookies.txt \
|
||||
-w "%{http_code}" \
|
||||
-s`, { encoding: 'utf8' });
|
||||
|
||||
console.log('Login status:', loginResult.slice(-3));
|
||||
|
||||
// 2. Test GET DLC products
|
||||
console.log('2. GET DLC products...');
|
||||
const dlcResult = execSync(`curl -X GET http://localhost:5000/api/dlc-products \
|
||||
-b cookies.txt \
|
||||
-w "%{http_code}" \
|
||||
-s`, { encoding: 'utf8' });
|
||||
|
||||
const statusCode = dlcResult.slice(-3);
|
||||
const responseBody = dlcResult.slice(0, -3);
|
||||
|
||||
console.log('Status:', statusCode);
|
||||
|
||||
if (statusCode === '200') {
|
||||
const dlcs = JSON.parse(responseBody);
|
||||
console.log('✅ Total DLC:', dlcs.length);
|
||||
|
||||
if (dlcs.length > 0) {
|
||||
console.log('📋 Sample DLC:', {
|
||||
id: dlcs[0].id,
|
||||
productName: dlcs[0].productName,
|
||||
groupId: dlcs[0].groupId,
|
||||
status: dlcs[0].status
|
||||
});
|
||||
|
||||
// Grouper par groupId
|
||||
const byGroup = dlcs.reduce((acc, dlc) => {
|
||||
acc[dlc.groupId] = (acc[dlc.groupId] || 0) + 1;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
console.log('📊 DLC par groupe:', byGroup);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ Erreur:', responseBody);
|
||||
}
|
||||
|
||||
console.log('\n3. Instructions debug frontend:');
|
||||
console.log('- Ouvrir DevTools Network');
|
||||
console.log('- Recharger page DLC Products');
|
||||
console.log('- Vérifier si requête API est envoyée');
|
||||
console.log('- Vérifier la réponse de l\'API');
|
||||
console.log('- Vérifier React Query cache dans Components');
|
||||
|
||||
} catch (error) {
|
||||
console.log('❌ Erreur:', error.message);
|
||||
}
|
||||
};
|
||||
|
||||
testDlcEndpoint();
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Fix urgent production pour employé - création commandes client et DLC
|
||||
// À exécuter sur le serveur de production
|
||||
|
||||
console.log('🚨 URGENT FIX PRODUCTION - Employé + DLC');
|
||||
console.log('📋 Problèmes identifiés:');
|
||||
console.log(' 1. Employé ne peut pas créer commandes clients');
|
||||
console.log(' 2. DLC ne fonctionnent pas en production');
|
||||
console.log(' 3. Cache invalidation manquante pour DLC');
|
||||
|
||||
console.log('\n🔧 Solutions:');
|
||||
console.log(' ✓ Permissions employé OK dans shared/permissions.ts');
|
||||
console.log(' ✓ Routes sans restrictions dans server/routes.ts');
|
||||
console.log(' ✓ Schema validation corrigé');
|
||||
console.log(' ✓ Cache invalidation avec exact:false ajouté');
|
||||
|
||||
console.log('\n📦 Déploiement:');
|
||||
console.log(' 1. Git push les dernières modifications');
|
||||
console.log(' 2. Redémarrer le serveur production');
|
||||
console.log(' 3. Vider le cache browser des employés');
|
||||
console.log(' 4. Tester création commande client + DLC');
|
||||
|
||||
console.log('\n🔍 Debug en cas de problème:');
|
||||
console.log(' - Vérifier les logs serveur pour erreurs validation');
|
||||
console.log(' - Contrôler les requêtes réseau dans DevTools');
|
||||
console.log(' - Confirmer que groupId est bien envoyé dans la requête');
|
||||
|
||||
// Vérifications essentielles pour le déploiement
|
||||
const checks = [
|
||||
'✅ Routes POST /api/customer-orders sans restrictions rôle',
|
||||
'✅ Routes POST /api/dlc-products sans restrictions rôle',
|
||||
'✅ Schema insertCustomerOrderFrontendSchema validé',
|
||||
'✅ Schema insertDlcProductFrontendSchema validé',
|
||||
'✅ Cache invalidation { exact: false } pour toutes mutations DLC',
|
||||
'✅ Frontend logs pour debugging des erreurs'
|
||||
];
|
||||
|
||||
console.log('\n📋 Checklist déploiement:');
|
||||
checks.forEach(check => console.log(` ${check}`));
|
||||
|
||||
console.log('\n⚠️ IMPORTANT:');
|
||||
console.log(' Le problème était dans MemStorage (dev uniquement)');
|
||||
console.log(' En production PostgreSQL, ça devrait fonctionner');
|
||||
console.log(' Si ça ne marche toujours pas, problème côté frontend');
|
||||
|
||||
console.log('\n🎯 Tests à faire après déploiement:');
|
||||
console.log(' 1. Employé: créer commande client avec tous les champs');
|
||||
console.log(' 2. Employé: créer produit DLC');
|
||||
console.log(' 3. Vérifier que DLC apparaît dans la liste');
|
||||
console.log(' 4. Vérifier stats DLC mises à jour');
|
||||
@@ -0,0 +1,94 @@
|
||||
-- Fix urgent production: permissions employé pour commandes client et DLC
|
||||
-- À exécuter sur la base de production
|
||||
|
||||
-- 1. Vérifier les permissions actuelles pour le rôle employé
|
||||
SELECT
|
||||
p.name as permission_name,
|
||||
p.category,
|
||||
CASE WHEN rp.permission_id IS NOT NULL THEN 'GRANTED' ELSE 'DENIED' END as status
|
||||
FROM permissions p
|
||||
LEFT JOIN role_permissions rp ON p.id = rp.permission_id
|
||||
AND rp.role_id = (SELECT id FROM roles WHERE name = 'employee')
|
||||
WHERE p.category IN ('customer-orders', 'dlc')
|
||||
ORDER BY p.category, p.name;
|
||||
|
||||
-- 2. Vérifier si le rôle employé existe
|
||||
SELECT * FROM roles WHERE name = 'employee';
|
||||
|
||||
-- 3. Obtenir l'ID du rôle employé
|
||||
SELECT id FROM roles WHERE name = 'employee';
|
||||
|
||||
-- 4. Vérifier les permissions requises qui pourraient manquer
|
||||
SELECT id, name, category, description
|
||||
FROM permissions
|
||||
WHERE category IN ('customer-orders', 'dlc')
|
||||
AND name IN ('create', 'view')
|
||||
AND id NOT IN (
|
||||
SELECT permission_id
|
||||
FROM role_permissions
|
||||
WHERE role_id = (SELECT id FROM roles WHERE name = 'employee')
|
||||
);
|
||||
|
||||
-- 5. Si des permissions manquent, les ajouter (À DÉCOMMENTER SI NÉCESSAIRE)
|
||||
/*
|
||||
-- Ajouter permission créer commandes client pour employé
|
||||
INSERT INTO role_permissions (role_id, permission_id, assigned_by, created_at)
|
||||
SELECT
|
||||
(SELECT id FROM roles WHERE name = 'employee'),
|
||||
p.id,
|
||||
'system_fix',
|
||||
NOW()
|
||||
FROM permissions p
|
||||
WHERE p.category = 'customer-orders'
|
||||
AND p.name = 'create'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM role_permissions rp
|
||||
WHERE rp.role_id = (SELECT id FROM roles WHERE name = 'employee')
|
||||
AND rp.permission_id = p.id
|
||||
);
|
||||
|
||||
-- Ajouter permission créer DLC pour employé
|
||||
INSERT INTO role_permissions (role_id, permission_id, assigned_by, created_at)
|
||||
SELECT
|
||||
(SELECT id FROM roles WHERE name = 'employee'),
|
||||
p.id,
|
||||
'system_fix',
|
||||
NOW()
|
||||
FROM permissions p
|
||||
WHERE p.category = 'dlc'
|
||||
AND p.name = 'create'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM role_permissions rp
|
||||
WHERE rp.role_id = (SELECT id FROM roles WHERE name = 'employee')
|
||||
AND rp.permission_id = p.id
|
||||
);
|
||||
*/
|
||||
|
||||
-- 6. Vérifier l'utilisateur qui a des problèmes
|
||||
SELECT
|
||||
u.id,
|
||||
u.username,
|
||||
u.role,
|
||||
u.first_name,
|
||||
u.last_name,
|
||||
COUNT(ug.group_id) as group_count
|
||||
FROM users u
|
||||
LEFT JOIN user_groups ug ON u.id = ug.user_id
|
||||
WHERE u.id = '_1753266816257'
|
||||
GROUP BY u.id, u.username, u.role, u.first_name, u.last_name;
|
||||
|
||||
-- 7. Vérifier les groupes de l'utilisateur
|
||||
SELECT
|
||||
ug.user_id,
|
||||
ug.group_id,
|
||||
g.name as group_name,
|
||||
g.color as group_color
|
||||
FROM user_groups ug
|
||||
JOIN groups g ON ug.group_id = g.id
|
||||
WHERE ug.user_id = '_1753266816257';
|
||||
|
||||
-- Notes pour le debugging:
|
||||
-- - Si pas de résultats dans requête 4: permissions OK
|
||||
-- - Si résultats dans requête 4: décommenter section 5
|
||||
-- - Vérifier que l'utilisateur a bien un groupe assigné
|
||||
-- - Le problème peut être côté frontend si permissions OK
|
||||
@@ -43,10 +43,11 @@ Preferred communication style: Simple, everyday language.
|
||||
- **Universal Pagination**: Reusable client-side pagination component across all main tabular data pages.
|
||||
- **Reconciliation Module**: For balancing and tracking financial discrepancies. **PRODUCTION-READY**: Rebuilt with robust UI components to eliminate React #310 errors in production.
|
||||
- **Automatic Reconciliation System**: Dual-mode BL/Invoice reconciliation with automatic validation for suppliers in automatic mode. Auto-validates deliveries when status = "delivered" AND BL number exists.
|
||||
- **Permission System**: Granular, hardcoded permissions (54 permissions across 12 categories, assigned to 4 roles) for improved performance and maintenance.
|
||||
- **Permission System**: Granular, hardcoded permissions (54 permissions across 12 categories, assigned to 4 roles) for improved performance and maintenance. **EMPLOYEE PERMISSIONS**: Employees can create customer orders and DLC products.
|
||||
- **User Management**: Comprehensive features including user deletion with ownership transfer, consistent name and email field handling, and robust password hashing.
|
||||
- **Calendar Synchronization**: Proper display of delivery dates and automatic synchronization of order statuses.
|
||||
- **Database Schema Download**: Admin-only feature to download comprehensive database structure reports.
|
||||
- **DLC Product Management**: **DEV-FIXED**: Corrected MemStorage implementation for proper DLC persistence in development. Cache invalidation fixed with exact:false for production compatibility.
|
||||
- **Robust UI Architecture**: Critical pages rebuilt with custom Tailwind CSS components to eliminate shadcn/ui production bundling issues.
|
||||
|
||||
## External Dependencies
|
||||
|
||||
@@ -2319,12 +2319,21 @@ RÉSUMÉ DU SCAN
|
||||
userGroups: user.userGroups?.map(ug => ({groupId: ug.group.id, groupName: ug.group.name}))
|
||||
});
|
||||
|
||||
console.log("🔍 Pre-validation data:", {
|
||||
body: req.body,
|
||||
userId,
|
||||
combined: { ...req.body, createdBy: userId }
|
||||
});
|
||||
|
||||
const validatedData = insertDlcProductFrontendSchema.parse({
|
||||
...req.body,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
console.log("✅ Post-validation data:", validatedData);
|
||||
|
||||
const dlcProduct = await storage.createDlcProduct(validatedData);
|
||||
console.log("📦 Raw returned DLC product:", dlcProduct);
|
||||
console.log('✅ DLC Product created successfully:', {
|
||||
id: dlcProduct.id,
|
||||
productName: dlcProduct.productName,
|
||||
|
||||
+78
-6
@@ -2014,6 +2014,8 @@ class MemStorage implements IStorage {
|
||||
private tasks = new Map<number, Task>();
|
||||
private publicities = new Map<number, any>();
|
||||
private publicityParticipations = new Array<any>();
|
||||
private dlcProducts = new Map<number, any>();
|
||||
private dlcIdCounter = 1;
|
||||
|
||||
constructor() {
|
||||
// Create default admin user for development
|
||||
@@ -2257,11 +2259,62 @@ class MemStorage implements IStorage {
|
||||
async createCustomerOrder(): Promise<any> { return {}; }
|
||||
async updateCustomerOrder(): Promise<any> { return {}; }
|
||||
async deleteCustomerOrder(): Promise<void> {}
|
||||
async getDlcProducts(): Promise<any[]> { return []; }
|
||||
async getDlcProduct(): Promise<any> { return undefined; }
|
||||
async createDlcProduct(): Promise<any> { return {}; }
|
||||
async updateDlcProduct(): Promise<any> { return {}; }
|
||||
async deleteDlcProduct(): Promise<void> {}
|
||||
async getDlcProducts(groupIds?: number[], filters?: { status?: string; supplierId?: number; }): Promise<any[]> {
|
||||
console.log("📋 MemStorage getDlcProducts:", { groupIds, dlcCount: this.dlcProducts.size });
|
||||
let products = Array.from(this.dlcProducts.values());
|
||||
|
||||
// Filter by groups if provided
|
||||
if (groupIds && groupIds.length > 0) {
|
||||
products = products.filter(p => groupIds.includes(p.groupId));
|
||||
console.log("🔍 Filtered by groups:", { original: this.dlcProducts.size, filtered: products.length, groupIds });
|
||||
}
|
||||
|
||||
// Filter by status
|
||||
if (filters?.status) {
|
||||
products = products.filter(p => p.status === filters.status);
|
||||
}
|
||||
|
||||
// Filter by supplier
|
||||
if (filters?.supplierId) {
|
||||
products = products.filter(p => p.supplierId === filters.supplierId);
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
async getDlcProduct(id: number): Promise<any> {
|
||||
return this.dlcProducts.get(id);
|
||||
}
|
||||
|
||||
async createDlcProduct(dlcProduct: any): Promise<any> {
|
||||
const id = this.dlcIdCounter++;
|
||||
const newProduct = {
|
||||
id,
|
||||
...dlcProduct,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
this.dlcProducts.set(id, newProduct);
|
||||
console.log("✅ MemStorage DLC créé:", { id, productName: newProduct.productName, groupId: newProduct.groupId });
|
||||
return newProduct;
|
||||
}
|
||||
|
||||
async updateDlcProduct(id: number, dlcProduct: any): Promise<any> {
|
||||
const existing = this.dlcProducts.get(id);
|
||||
if (!existing) throw new Error("DLC product not found");
|
||||
|
||||
const updated = {
|
||||
...existing,
|
||||
...dlcProduct,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
this.dlcProducts.set(id, updated);
|
||||
return updated;
|
||||
}
|
||||
|
||||
async deleteDlcProduct(id: number): Promise<void> {
|
||||
this.dlcProducts.delete(id);
|
||||
}
|
||||
async getTasks(): Promise<Task[]> { return Array.from(this.tasks.values()); }
|
||||
async getTask(): Promise<any> { return undefined; }
|
||||
async createTask(): Promise<any> { return {}; }
|
||||
@@ -2295,7 +2348,26 @@ class MemStorage implements IStorage {
|
||||
async getUserEffectivePermissions(): Promise<any[]> { return []; }
|
||||
async userHasPermission(): Promise<boolean> { return false; }
|
||||
async userHasRole(): Promise<boolean> { return false; }
|
||||
async getDlcStats(): Promise<any> { return {}; }
|
||||
async getDlcStats(groupIds?: number[]): Promise<any> {
|
||||
const products = Array.from(this.dlcProducts.values());
|
||||
|
||||
// Filter by groups if provided
|
||||
const filteredProducts = groupIds && groupIds.length > 0
|
||||
? products.filter(p => groupIds.includes(p.groupId))
|
||||
: products;
|
||||
|
||||
const now = new Date();
|
||||
const in15Days = new Date(now.getTime() + 15 * 24 * 60 * 60 * 1000);
|
||||
|
||||
const stats = {
|
||||
active: filteredProducts.filter(p => p.status !== 'valides' && new Date(p.dlcDate) > in15Days).length,
|
||||
expiringSoon: filteredProducts.filter(p => p.status !== 'valides' && new Date(p.dlcDate) <= in15Days && new Date(p.dlcDate) > now).length,
|
||||
expired: filteredProducts.filter(p => p.status !== 'valides' && new Date(p.dlcDate) <= now).length,
|
||||
};
|
||||
|
||||
console.log("📊 MemStorage DLC stats:", stats);
|
||||
return stats;
|
||||
}
|
||||
async validateDlcProduct(id: number, validatedBy: string): Promise<DlcProductFrontend> {
|
||||
// MemStorage stub implementation - return a basic DlcProductFrontend object
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Test complet production pour employé - commandes client et DLC
|
||||
// Script pour reproduire les erreurs et identifier la cause exacte
|
||||
|
||||
const testEmployeeProduction = async () => {
|
||||
console.log('🧪 TEST EMPLOYÉ PRODUCTION');
|
||||
console.log('========================');
|
||||
|
||||
console.log('\n📋 Scénarios à tester:');
|
||||
console.log('1. ✅ Connexion employé');
|
||||
console.log('2. 🔍 Vérifier permissions frontend');
|
||||
console.log('3. 📝 Créer commande client');
|
||||
console.log('4. 🍃 Créer produit DLC');
|
||||
console.log('5. 📊 Vérifier affichage données');
|
||||
|
||||
console.log('\n🔍 Debug Frontend (à faire dans DevTools):');
|
||||
console.log('1. Console.log user object complet');
|
||||
console.log('2. Vérifier hasPermission("customer-orders", "create")');
|
||||
console.log('3. Vérifier hasPermission("dlc", "create")');
|
||||
console.log('4. Logs requêtes POST qui échouent');
|
||||
console.log('5. Vérifier groupId envoyé dans requests');
|
||||
|
||||
console.log('\n📤 Requête test commande client:');
|
||||
const testCustomerOrder = {
|
||||
customerName: "Test Client Production",
|
||||
contactNumber: "0123456789",
|
||||
productName: "Produit Test Employé",
|
||||
quantity: 1,
|
||||
groupId: 2, // Houdemont d'après les logs
|
||||
deposit: 0,
|
||||
isPromotionalPrice: false,
|
||||
notes: "Test création employé production"
|
||||
};
|
||||
console.log(JSON.stringify(testCustomerOrder, null, 2));
|
||||
|
||||
console.log('\n📤 Requête test DLC:');
|
||||
const testDlc = {
|
||||
productName: "DLC Test Employé",
|
||||
dlcDate: "2025-08-25",
|
||||
dateType: "dlc",
|
||||
quantity: 1,
|
||||
unit: "Unité",
|
||||
supplierId: 1,
|
||||
location: "Test Location",
|
||||
groupId: 2, // Houdemont
|
||||
status: "en_cours"
|
||||
};
|
||||
console.log(JSON.stringify(testDlc, null, 2));
|
||||
|
||||
console.log('\n⚠️ Points de contrôle:');
|
||||
console.log('1. Bouton "Créer" visible dans l\'interface?');
|
||||
console.log('2. Formulaire s\'ouvre sans erreur?');
|
||||
console.log('3. Soumission génère une requête HTTP?');
|
||||
console.log('4. Réponse serveur (200/400/403/500)?');
|
||||
console.log('5. Message d\'erreur affiché?');
|
||||
|
||||
console.log('\n🔧 Solutions selon erreurs:');
|
||||
console.log('- 403 Forbidden: Problème permissions base');
|
||||
console.log('- 400 Bad Request: Problème validation schema');
|
||||
console.log('- 500 Server Error: Problème côté serveur');
|
||||
console.log('- Pas de requête: Problème frontend/permissions');
|
||||
|
||||
console.log('\n📋 Checklist production déjà fait:');
|
||||
console.log('✅ Routes backend sans restrictions rôle');
|
||||
console.log('✅ Permissions définies dans shared/permissions.ts');
|
||||
console.log('✅ Schema validation corrigé');
|
||||
console.log('✅ Cache invalidation DLC avec exact:false');
|
||||
|
||||
console.log('\n🎯 Actions immédiates:');
|
||||
console.log('1. Ouvrir DevTools > Console');
|
||||
console.log('2. Essayer créer commande client');
|
||||
console.log('3. Noter toute erreur console/réseau');
|
||||
console.log('4. Même test pour DLC');
|
||||
console.log('5. Envoyer logs complets pour debug');
|
||||
};
|
||||
|
||||
console.log('🚀 Prêt pour test employé production');
|
||||
console.log('👉 Exécuter les étapes manuellement avec DevTools ouverts');
|
||||
Reference in new issue
Block a user