Improve DLC product data handling and cache management

Update DLC product fetching to include group filtering, implement precise cache invalidation for DLC-related queries using `exact: false`, and add detailed logging for API requests and responses to aid in debugging.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: b163d4c0-de5e-4f4e-a9c0-aed4c7049718
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/b163d4c0-de5e-4f4e-a9c0-aed4c7049718/rEII9fE
This commit is contained in:
michaelschal committed 2025-08-12 14:24:19 +00:00
1 parent fcad53ae1d
commit 4ca3c17bad
8 files changed
+495 -15

No files matched your search

@@ -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

+26 -8
View File
@@ -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
View File
@@ -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
+104
View File
@@ -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();
+70
View File
@@ -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();
+9
View File
@@ -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
View File
@@ -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 {