mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-12 01:36:43 +02:00
Le sync Qlik calculait déjà les ventes réseau mois par mois mais les
sommait en un total. On conserve désormais le détail mensuel.
- Sync : accumulation additive qteByMonth { code: { 'YYYY-MM': qté } }
in-page (chemins rapide + par lots), rattachée au métrique réseau.
Reset propre en cas de repli code 15. Total inchangé.
- Stockage : colonne jsonb qte_by_month sur qlik_network_metrics
(schema + db-init ALTER), upsert + lecture.
- ProductRow.qteReseauByMonth propagé jusqu'à la grille.
- UI grille :
· colonne '% Présence réseau' remplacée par 'Tendance réseau' :
sparkline 12 mois teintée + flèche + variation % (moyenne 4 derniers
mois vs 4 précédents), triable ;
· cellule 'Nb magasins' rendue cliquable → modal des ventes réseau
mois par mois (barres, 12 derniers mois).
Nécessite un nouveau Sync Qlik pour peupler le détail mensuel (les
données déjà en cache n'ont que le total → modal 'pas encore de détail').
148 lines
5.5 KiB
TypeScript
148 lines
5.5 KiB
TypeScript
/**
|
|
* CollectFlow - Core Grid Types
|
|
*/
|
|
|
|
/** One row in the data grid, representing a product at a store for one period. */
|
|
export interface VenteProduit {
|
|
id: number;
|
|
codein: string;
|
|
codeFournisseur: string | null;
|
|
nomFournisseur: string | null;
|
|
libelle1: string | null;
|
|
gtin: string | null;
|
|
reference: string | null;
|
|
codeGamme: GammeCode | null;
|
|
codeGammeInit: GammeCode | null;
|
|
code3: string | null;
|
|
libelle3: string | null;
|
|
magasin: string;
|
|
codeMagasin: string | null;
|
|
annee: number | null;
|
|
mois: number | null;
|
|
periode: string;
|
|
quantite: number | null;
|
|
montantMvt: number | null;
|
|
margeMvt: number | null;
|
|
}
|
|
|
|
/** A/B/C/Z status codes for product categories, but can be any string from DB (like 'Aucune') */
|
|
export type GammeCode = string;
|
|
|
|
/** A product row with its 12-month sales history and computed KPIs */
|
|
export interface ProductRow {
|
|
codein: string;
|
|
codeFournisseur: string;
|
|
nomFournisseur: string;
|
|
/** Dernier fournisseur enregistré pour cet article (artfou1.no_id DESC). Peut différer du fournisseur consulté. */
|
|
fournisseurPrincipalCode?: string;
|
|
fournisseurPrincipalNom?: string;
|
|
libelle1: string;
|
|
gtin: string;
|
|
reference: string;
|
|
code1: string;
|
|
libelleNiveau1: string;
|
|
code2: string;
|
|
libelleNiveau2: string;
|
|
code3: string;
|
|
libelle3: string;
|
|
codeGamme: GammeCode | null;
|
|
codeGammeInit: GammeCode | null;
|
|
/** Draft gamme value before saving */
|
|
codeGammeDraft: GammeCode | null;
|
|
/** 12-month sales quantities, indexed by YYYYMM key */
|
|
sales12m: Record<string, number>;
|
|
/** End-of-month stock levels, indexed by YYYYMM key */
|
|
stock12m: Record<string, number>;
|
|
/** Monthly reception quantities, indexed by YYYYMM key */
|
|
receptions12m: Record<string, number>;
|
|
/** Per-store breakdown (site → YYYYMM → qty) — always present even in TOTAL mode */
|
|
sales12mByStore?: Record<string, Record<string, number>>;
|
|
/** Per-store stock breakdown (site → YYYYMM → stock fin de mois) */
|
|
stock12mByStore?: Record<string, Record<string, number>>;
|
|
/** Per-store reception breakdown (site → YYYYMM → qté reçue) */
|
|
receptions12mByStore?: Record<string, Record<string, number>>;
|
|
/** Per-store last delivery/reception date (site → ISO date string) */
|
|
derniereLivraisonByStore?: Record<string, string>;
|
|
/** Per-store CA totals */
|
|
caByStore?: Record<string, number>;
|
|
/** Per-store quantity totals */
|
|
quantiteByStore?: Record<string, number>;
|
|
/** Per-store margin totals */
|
|
margeByStore?: Record<string, number>;
|
|
totalQuantite: number;
|
|
totalCa: number;
|
|
totalMarge: number;
|
|
tauxMarge: number;
|
|
workingStores: string[];
|
|
/** Rotation normalisée : unités vendues / magasin / mois */
|
|
unitsPerStorePerMonth?: number;
|
|
/** CA normalisé : € / magasin / an */
|
|
caPerStorePerYear?: number;
|
|
/** Produit récent (≤ 3 mois de données) */
|
|
isRecent?: boolean;
|
|
/** Seul produit du fournisseur dans le lot */
|
|
isLastProduct?: boolean;
|
|
/** Top 30% CA du lot fournisseur */
|
|
isTop30Supplier?: boolean;
|
|
/** SQL Server internal ID — nécessaire pour /api/articles/:noid/mensuel */
|
|
noid?: number;
|
|
/** Données stock & approvisionnement (API FF Nancy) */
|
|
pcb?: number; // Conditionnement (pack size)
|
|
prixAchat?: number; // PA / PRMP
|
|
prixVente?: number; // PV central
|
|
stockActuel?: number; // Stock dispo agrégé tous sites
|
|
stockTotal?: number; // Qte en stock agrégé
|
|
stockValeur?: number; // Valeur stock agrégée
|
|
pa?: number; // PRMP (alias prixAchat)
|
|
derniereVente?: string; // ISO date de dernière vente
|
|
derniereLivraison?: string; // ISO date de dernière réception
|
|
nbJoursDerniereVente?: number; // Nb jours sans vente
|
|
commandesEnCours?: number; // Qté en commande fournisseur
|
|
/** Moyennes de comparaison pour l'IA */
|
|
avgQtyFournisseur?: number;
|
|
avgQtyRayon?: number;
|
|
/** Poids relatifs (%) du produit chez le fournisseur */
|
|
shareCa?: number;
|
|
shareMarge?: number;
|
|
shareQty?: number;
|
|
/** Référentiels globaux */
|
|
totalFournisseurCa?: number;
|
|
/** Code centrale (clé jointure Qlik, format 10000XXXXXX) */
|
|
codeCentrale?: string;
|
|
/** Données réseau Qlik (~270 magasins) */
|
|
caReseau?: number;
|
|
qteReseau?: number;
|
|
nbMagasinsReseau?: number;
|
|
/** CA moyen par magasin réseau (productivité normalisée présence) */
|
|
caParMagasinReseau?: number;
|
|
/** Taux de marge réseau (ratio brut Qlik, ex 0.32 = 32%) */
|
|
margePctReseau?: number;
|
|
/** Taux de présence réseau = nbMagasinsReseau / 270 */
|
|
tauxPresenceReseau?: number;
|
|
/** Quantité vendue réseau par mois : { "YYYY-MM": qté } (tendance / modal). */
|
|
qteReseauByMonth?: Record<string, number> | null;
|
|
/** Fraîcheur des données réseau (ISO) */
|
|
networkFetchedAt?: string;
|
|
}
|
|
|
|
/** Summary bar totals for the currently visible/filtered rows */
|
|
export interface GridSummary {
|
|
totalProducts: number;
|
|
totalRows: number;
|
|
totalQuantite: number;
|
|
totalCa: number;
|
|
totalMarge: number;
|
|
tauxMargeGlobal: number;
|
|
}
|
|
|
|
/** Filters applied to the grid */
|
|
export interface GridFilters {
|
|
magasin: string | null;
|
|
codeFournisseur: string | null;
|
|
code1: string | null;
|
|
code2: string | null;
|
|
code3: string | null;
|
|
codeGamme: GammeCode | null;
|
|
search: string;
|
|
}
|