mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-11 17:26:32 +02:00
Prix de vente : élaguer le code magasin, qui sert de clé
Le code magasin de `cube_pv` sert de clé de recherche côté Grille (`prixVenteByStore["292"]`). Or la synchronisation Apiflow l'écrit BRUT (`site: r.Site`), là où elle fait passer celui de `cube_stock` par `safeStr` — et aucune des deux ne l'élague. Une colonne MSSQL de largeur fixe remonte complétée d'espaces : la recherche échouerait alors sans rien signaler, et de la pire façon qui soit, le prix restant visible en « tous magasins » et vide magasin par magasin. `TRIM` des deux côtés, plus l'élagage du repli lu depuis le cube de stock. L'opération ne coûte rien quand il n'y a pas de remplissage, et le doute n'avait pas de raison de subsister. La route de diagnostic affiche désormais les valeurs de `site` telles qu'elles sont stockées, avec leur longueur : de quoi vérifier d'un coup d'œil que les clés sont bien « 292 » et « 579 », sur trois caractères. Commentaires SQL déplacés hors du littéral gabarit, comme partout ailleurs dans le fichier : un accent grave dans un commentaire refermait la chaîne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYGgoQCG1VCe42HzbzhAXR
This commit is contained in:
3 files changed
+31
-3
No files matched your search
@@ -111,6 +111,26 @@ export async function GET(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 2 ter. Les valeurs de `site` telles qu'elles sont stockées ──────────
|
||||||
|
// Ces chaînes servent de CLÉ de recherche par magasin côté Grille : un
|
||||||
|
// espace de remplissage ou un code inattendu et le prix par magasin serait
|
||||||
|
// introuvable, sans que rien ne le signale à l'écran.
|
||||||
|
try {
|
||||||
|
const r = await db.execute(sql`
|
||||||
|
SELECT site, LENGTH(site)::int AS longueur, COUNT(*)::int AS lignes
|
||||||
|
FROM cube_pv
|
||||||
|
GROUP BY site, LENGTH(site)
|
||||||
|
ORDER BY lignes DESC
|
||||||
|
LIMIT 12
|
||||||
|
`);
|
||||||
|
diagnostic.sites_cube_pv = {
|
||||||
|
commentaire: "la Grille recherche les codes magasin tels quels — longueur 3 attendue pour « 292 » / « 579 »",
|
||||||
|
valeurs: r.rows,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
diagnostic.sites_cube_pv = { erreur: (e as Error).message?.slice(0, 200) };
|
||||||
|
}
|
||||||
|
|
||||||
// ── 3. Colonnes candidates du schéma, et leur remplissage réel ──────────
|
// ── 3. Colonnes candidates du schéma, et leur remplissage réel ──────────
|
||||||
// C'est la réponse à « le prix est peut-être ailleurs » : une colonne bien
|
// C'est la réponse à « le prix est peut-être ailleurs » : une colonne bien
|
||||||
// nommée mais vide ne sert à rien, seul le comptage tranche.
|
// nommée mais vide ne sert à rien, seul le comptage tranche.
|
||||||
|
|||||||
@@ -394,7 +394,8 @@ async function buildProductRows(input: GetProductRowsInput): Promise<ProductRow[
|
|||||||
const depuisStock: Record<string, number> = {};
|
const depuisStock: Record<string, number> = {};
|
||||||
for (const s of stockMap.get(product.codein) ?? []) {
|
for (const s of stockMap.get(product.codein) ?? []) {
|
||||||
const pv = Number(s.pv);
|
const pv = Number(s.pv);
|
||||||
if (s.site && Number.isFinite(pv) && pv > 0) depuisStock[s.site] = pv;
|
const site = String(s.site ?? "").trim();
|
||||||
|
if (site && Number.isFinite(pv) && pv > 0) depuisStock[site] = pv;
|
||||||
}
|
}
|
||||||
if (Object.keys(depuisStock).length > 0) product.prixVenteByStore = depuisStock;
|
if (Object.keys(depuisStock).length > 0) product.prixVenteByStore = depuisStock;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -450,10 +450,12 @@ function buildNomMap(rows: PgNomRow[]): Map<string, PgNomRow> {
|
|||||||
* 1 requête SQL — remplace la partie stock du référentiel.
|
* 1 requête SQL — remplace la partie stock du référentiel.
|
||||||
*/
|
*/
|
||||||
export async function pgGetStockByFournisseur(codefou: string): Promise<Map<string, PgStockRow[]>> {
|
export async function pgGetStockByFournisseur(codefou: string): Promise<Map<string, PgStockRow[]>> {
|
||||||
|
// `site` est élagué pour la même raison que dans pgGetPrixVenteByFournisseur :
|
||||||
|
// il sert de clé de recherche (derniereLivraisonByStore, prix de repli).
|
||||||
const result = await pgNoParallel(sql`
|
const result = await pgNoParallel(sql`
|
||||||
SELECT
|
SELECT
|
||||||
a.codein,
|
a.codein,
|
||||||
cs.site,
|
TRIM(cs.site::text) AS site,
|
||||||
cs.stockdispo::float,
|
cs.stockdispo::float,
|
||||||
cs.qte::float,
|
cs.qte::float,
|
||||||
cs.valstock::float,
|
cs.valstock::float,
|
||||||
@@ -487,10 +489,15 @@ export async function pgGetStockByFournisseur(codefou: string): Promise<Map<stri
|
|||||||
* tarifé n'est pas un article à 0 €.
|
* tarifé n'est pas un article à 0 €.
|
||||||
*/
|
*/
|
||||||
export async function pgGetPrixVenteByFournisseur(codefou: string): Promise<Map<string, Record<string, number>>> {
|
export async function pgGetPrixVenteByFournisseur(codefou: string): Promise<Map<string, Record<string, number>>> {
|
||||||
|
// Le site sert de CLÉ de recherche côté Grille (prixVenteByStore["292"]), d'où
|
||||||
|
// l'élagage : la synchronisation Apiflow écrit `cube_pv.site` brut, sans passer
|
||||||
|
// par le `safeStr` qu'elle applique à `cube_stock`. Une colonne MSSQL de largeur
|
||||||
|
// fixe remonterait complétée d'espaces, et la recherche échouerait en silence —
|
||||||
|
// le prix resterait visible en « tous magasins » et vide magasin par magasin.
|
||||||
const result = await pgNoParallel(sql`
|
const result = await pgNoParallel(sql`
|
||||||
SELECT
|
SELECT
|
||||||
a.codein,
|
a.codein,
|
||||||
cpv.site,
|
TRIM(cpv.site::text) AS site,
|
||||||
cpv.pv::float AS pv
|
cpv.pv::float AS pv
|
||||||
FROM cube_pv cpv
|
FROM cube_pv cpv
|
||||||
JOIN articles a ON a.no_id = cpv.artnoid
|
JOIN articles a ON a.no_id = cpv.artnoid
|
||||||
|
|||||||
Reference in new issue
Block a user