diff --git a/client/src/pages/DlcPage.tsx b/client/src/pages/DlcPage.tsx index 24f2716..07beb77 100644 --- a/client/src/pages/DlcPage.tsx +++ b/client/src/pages/DlcPage.tsx @@ -128,19 +128,33 @@ export default function DlcPage() { eanDebounceRef.current = setTimeout(async () => { setEanLookupLoading(true); try { + // Étape 1 : récupérer l'article par EAN const res = await fetch(`/api/ffnancy/articles?ean=${encodeURIComponent(gencodeValue)}&limit=1`, { credentials: 'include' }); if (!res.ok) return; const data = await res.json(); const article = data.articles?.[0]; if (!article) return; - // Toujours mettre à jour le nom du produit form.setValue("productName", article.libelle1, { shouldValidate: true }); - // Matcher le fournisseur par codefou en priorité, sinon par nom - if (article.codefou_principal) { + // Étape 2 : chercher le fournisseur de la dernière entrée en stock + let codefouToMatch = article.codefou_principal; + try { + const mvtRes = await fetch( + `/api/ffnancy/mouvements/entrees?artNoId=${article.no_id}&limit=1&dateDebut=2000-01-01`, + { credentials: 'include' } + ); + if (mvtRes.ok) { + const mvtData = await mvtRes.json(); + const lastEntree = mvtData.entrees?.[0]; + if (lastEntree?.codefou) codefouToMatch = lastEntree.codefou; + } + } catch { /* fallback sur codefou_principal */ } + + // Matching : codefou exact en priorité, fallback par nom + if (codefouToMatch) { const matched = (suppliers as any[]).find((s: any) => - s.codefou && s.codefou.trim().toLowerCase() === article.codefou_principal.trim().toLowerCase() + s.codefou && s.codefou.trim().toLowerCase() === codefouToMatch.trim().toLowerCase() ) || (suppliers as any[]).find((s: any) => s.name.toLowerCase().trim().includes(article.nom_fou_principal?.toLowerCase().trim() || '') || (article.nom_fou_principal?.toLowerCase().trim() || '').includes(s.name.toLowerCase().trim()) diff --git a/client/src/pages/mobile/DlcPage.tsx b/client/src/pages/mobile/DlcPage.tsx index ea263ae..8798290 100644 --- a/client/src/pages/mobile/DlcPage.tsx +++ b/client/src/pages/mobile/DlcPage.tsx @@ -153,6 +153,7 @@ export default function MobileDlcPage() { eanDebounceRef.current = setTimeout(async () => { setEanLookupLoading(true); try { + // Étape 1 : récupérer l'article par EAN const res = await fetch(`/api/ffnancy/articles?ean=${encodeURIComponent(gencodeValue)}&limit=1`, { credentials: 'include' }); if (!res.ok) return; const data = await res.json(); @@ -161,9 +162,24 @@ export default function MobileDlcPage() { form.setValue("productName", article.libelle1, { shouldValidate: true }); - if (article.codefou_principal) { + // Étape 2 : chercher le fournisseur de la dernière entrée en stock + let codefouToMatch = article.codefou_principal; + try { + const mvtRes = await fetch( + `/api/ffnancy/mouvements/entrees?artNoId=${article.no_id}&limit=1&dateDebut=2000-01-01`, + { credentials: 'include' } + ); + if (mvtRes.ok) { + const mvtData = await mvtRes.json(); + const lastEntree = mvtData.entrees?.[0]; + if (lastEntree?.codefou) codefouToMatch = lastEntree.codefou; + } + } catch { /* fallback sur codefou_principal */ } + + // Matching : codefou exact en priorité, fallback par nom + if (codefouToMatch) { const matched = (suppliers as any[]).find((s: any) => - s.codefou && s.codefou.trim().toLowerCase() === article.codefou_principal.trim().toLowerCase() + s.codefou && s.codefou.trim().toLowerCase() === codefouToMatch.trim().toLowerCase() ) || (suppliers as any[]).find((s: any) => s.name.toLowerCase().trim().includes(article.nom_fou_principal?.toLowerCase().trim() || '') || (article.nom_fou_principal?.toLowerCase().trim() || '').includes(s.name.toLowerCase().trim()) diff --git a/server/routes.ts b/server/routes.ts index 4cea8c7..c35ff2e 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -6040,12 +6040,24 @@ RÉSUMÉ DU SCAN if (req.query[key]) params.append(key, req.query[key] as string); } const response = await fetch(`https://api.ffnancy.fr/api/articles?${params}`); - if (!response.ok) { - return res.status(response.status).json({ error: 'API ffnancy error' }); + if (!response.ok) return res.status(response.status).json({ error: 'API ffnancy error' }); + res.json(await response.json()); + } catch { + res.status(500).json({ error: 'Failed to reach API ffnancy' }); + } + }); + + app.get('/api/ffnancy/mouvements/entrees', requireAuth, async (req: Request, res: Response) => { + try { + const params = new URLSearchParams(); + const allowed = ['artNoId', 'dateDebut', 'dateFin', 'site', 'page', 'limit']; + for (const key of allowed) { + if (req.query[key]) params.append(key, req.query[key] as string); } - const data = await response.json(); - res.json(data); - } catch (error) { + const response = await fetch(`https://api.ffnancy.fr/api/mouvements/entrees?${params}`); + if (!response.ok) return res.status(response.status).json({ error: 'API ffnancy error' }); + res.json(await response.json()); + } catch { res.status(500).json({ error: 'Failed to reach API ffnancy' }); } });