test bug in facture

This commit is contained in:
mickael 2026-01-20 18:28:23 +03:00
parent 78e75ce41c
commit a2421c86ee

View file

@ -79,7 +79,7 @@ export type StatusCode = keyof typeof FACTURE_STATUS_LABELS;
// TYPES
// ============================================
type FilterType = 'all' | 'paid' | 'pending' | 'validated';
type FilterType = 'all' | 'paid' | 'pending' | 'validated' | 'partial';
interface FactureWithReglement extends Facture {
statut_reglement: string;
@ -143,63 +143,100 @@ const KPI_CONFIG: KPIConfig[] = [
filter: (factures) => factures,
tooltip: { content: "Total des factures sur la période.", source: "Ventes > Factures" }
},
{
id: 'pending',
title: 'Nombre de Factures',
icon: FileText,
color: 'orange',
getValue: (factures) => factures.length,
getSubtitle: (factures) => {
const paid = factures.filter(f => f.statut === 4);
const paymentRate = factures.length > 0 ? ((paid.length / factures.length) * 100).toFixed(1) : '0';
return `${paymentRate}% payées`;
},
getChange: (factures, value, period, allFactures) => {
const previousPeriodFactures = getPreviousPeriodItems(allFactures, period);
const countChange = Number(value) - previousPeriodFactures.length;
return countChange !== 0 ? `${countChange > 0 ? '+' : ''}${countChange}` : '0';
},
getTrend: (factures, value, period, allFactures) => {
const previousPeriodFactures = getPreviousPeriodItems(allFactures, period);
return Number(value) >= previousPeriodFactures.length ? 'up' : 'down';
},
filter: (factures) => factures.filter(f => f.statut === 1),
},
{
id: 'paid',
title: 'Montant Payé',
title: 'Payés',
icon: CheckCircle,
color: 'green',
getValue: (factures) => {
const paid = factures.filter(f => f.statut === 4);
return Math.round(paid.reduce((sum, item) => sum + item.total_ht, 0));
const soldees = factures.filter(f => (f as any).statut_display === 6);
return Math.round(soldees.reduce((sum, item) => sum + item.total_ttc, 0));
},
getSubtitle: (factures) => {
const paid = factures.filter(f => f.statut === 4);
return `${paid.length} facture${paid.length > 1 ? 's' : ''}`;
const soldees = factures.filter(f => (f as any).statut_display === 6);
return `${soldees.length} facture${soldees.length > 1 ? 's' : ''}`;
},
getChange: (factures) => {
const paid = factures.filter(f => f.statut === 4);
return `${paid.length}/${factures.length}`;
getChange: (factures, value, period, allFactures) => {
const soldees = factures.filter(f => (f as any).statut_display === 6);
const totalFacture = factures.length;
return totalFacture > 0 ? `${soldees.length}/${totalFacture}` : '0';
},
getTrend: (factures, value, period, allFactures) => {
const previousPeriodFactures = getPreviousPeriodItems(allFactures, period);
const previousPaid = previousPeriodFactures.filter(f => f.statut === 4);
const previousPaidAmount = previousPaid.reduce((sum, item) => sum + item.total_ht, 0);
return Number(value) >= previousPaidAmount ? 'up' : 'down';
const previousSoldees = previousPeriodFactures.filter(f => (f as any).statut_display === 6);
const previousTotal = previousSoldees.reduce((sum, item) => sum + item.total_ttc, 0);
return Number(value) >= previousTotal ? 'up' : 'down';
},
filter: (factures) => factures.filter(f => f.statut === 4),
tooltip: { content: "Montant des factures payées sur la période.", source: "Ventes > Factures" }
filter: (factures) => factures.filter(f => (f as any).statut_display === 6),
tooltip: { content: "Montant des factures entièrement réglées.", source: "Ventes > Factures" }
},
{
id: 'partial',
title: 'Partiellement réglées',
icon: AlertTriangle,
color: 'orange',
getValue: (factures) => {
const partielles = factures.filter(f => (f as any).statut_display === 7);
return Math.round(partielles.reduce((sum, item) => sum + ((item as any).reste_a_regler || item.total_ttc), 0));
},
getSubtitle: (factures) => {
const partielles = factures.filter(f => (f as any).statut_display === 7);
return `${partielles.length} facture${partielles.length > 1 ? 's' : ''}`;
},
getChange: (factures, value, period, allFactures) => {
const partielles = factures.filter(f => (f as any).statut_display === 7);
const totalFacture = factures.length;
return totalFacture > 0 ? `${partielles.length}/${totalFacture}` : '0';
},
getTrend: (factures, value, period, allFactures) => {
const previousPeriodFactures = getPreviousPeriodItems(allFactures, period);
const previousPartielles = previousPeriodFactures.filter(f => (f as any).statut_display === 7);
const previousTotal = previousPartielles.reduce((sum, item) => sum + ((item as any).reste_a_regler || item.total_ttc), 0);
return Number(value) <= previousTotal ? 'up' : 'down';
},
filter: (factures) => factures.filter(f => (f as any).statut_display === 7),
tooltip: { content: "Montant restant à régler sur les factures partiellement payées.", source: "Ventes > Factures" }
},
{
id: 'pending',
title: 'Non réglées',
icon: FileText,
color: 'red',
getValue: (factures) => {
// Factures ni soldées (6) ni partiellement payées (7)
const nonReglees = factures.filter(f => (f as any).statut_display !== 6 && (f as any).statut_display !== 7);
return nonReglees.length;
},
getSubtitle: (factures) => {
const nonReglees = factures.filter(f => (f as any).statut_display !== 6 && (f as any).statut_display !== 7);
const totalRestant = nonReglees.reduce((sum, item) => sum + ((item as any).reste_a_regler || item.total_ttc), 0);
return `${totalRestant.toLocaleString('fr-FR')}€ à régler`;
},
getChange: (factures, value, period, allFactures) => {
const previousPeriodFactures = getPreviousPeriodItems(allFactures, period);
const previousNonReglees = previousPeriodFactures.filter(f => (f as any).statut_display !== 6 && (f as any).statut_display !== 7);
return previousNonReglees.length > 0
? (((Number(value) - previousNonReglees.length) / previousNonReglees.length) * 100).toFixed(1)
: '0';
},
getTrend: (factures, value, period, allFactures) => {
const previousPeriodFactures = getPreviousPeriodItems(allFactures, period);
const previousNonReglees = previousPeriodFactures.filter(f => (f as any).statut_display !== 6 && (f as any).statut_display !== 7);
// Moins de non réglées = mieux
return Number(value) <= previousNonReglees.length ? 'up' : 'down';
},
filter: (factures) => factures.filter(f => (f as any).statut_display !== 6 && (f as any).statut_display !== 7),
tooltip: { content: "Nombre de factures non réglées.", source: "Ventes > Factures" }
},
{
id: 'validated',
title: 'Factures Validées',
title: 'Validées',
icon: CheckCircle,
color: 'purple',
getValue: (factures) => factures.filter(f => f.valide === 1).length,
getSubtitle: (factures) => {
const pending = factures.filter(f => f.statut === 1);
return `${pending.length} en attente`;
const nonValidees = factures.filter(f => f.valide !== 1);
return `${nonValidees.length} non validée${nonValidees.length > 1 ? 's' : ''}`;
},
getChange: (factures) => {
const validated = factures.filter(f => f.valide === 1);
@ -211,6 +248,7 @@ const KPI_CONFIG: KPIConfig[] = [
return Number(value) >= previousValidated.length ? 'up' : 'down';
},
filter: (factures) => factures.filter(f => f.valide === 1),
tooltip: { content: "Nombre de factures validées.", source: "Ventes > Factures" }
},
];
@ -356,6 +394,7 @@ const InvoicesPage = () => {
});
}, [factures, reglementsMap]);
// ============================================
// Client actuellement sélectionné
// ============================================
@ -376,16 +415,17 @@ const InvoicesPage = () => {
// ============================================
const kpis = useMemo(() => {
const periodFilteredFactures = filterItemByPeriod(factures, period, 'date');
// Utiliser facturesWithReglement au lieu de factures
const periodFilteredFactures = filterItemByPeriod(facturesWithReglement, period, 'date');
return KPI_CONFIG.map(config => {
const value = config.getValue(periodFilteredFactures);
return {
id: config.id,
title: config.title,
value: config.id === 'all' || config.id === 'paid' ? `${value.toLocaleString('fr-FR')}` : value,
change: config.getChange(periodFilteredFactures, value, period, factures),
trend: config.getTrend(periodFilteredFactures, value, period, factures),
value: config.id === 'all' || config.id === 'paid' || config.id === 'partial' ? `${value.toLocaleString('fr-FR')}` : value,
change: config.getChange(periodFilteredFactures, value, period, facturesWithReglement), // aussi ici
trend: config.getTrend(periodFilteredFactures, value, period, facturesWithReglement), // et ici
icon: config.icon,
subtitle: config.getSubtitle(periodFilteredFactures, value),
color: config.color,
@ -394,7 +434,7 @@ const InvoicesPage = () => {
onClick: () => setActiveFilter(prev => (prev === config.id ? 'all' : config.id)),
};
});
}, [factures, period, activeFilter]);
}, [facturesWithReglement, period, activeFilter]);
// ============================================
// Filtrage combiné : Période + KPI + Filtres avancés
@ -429,6 +469,7 @@ const InvoicesPage = () => {
return [...result].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
}, [facturesWithReglement, period, activeFilter, activeFilters, clientCommercialMap]);
// ============================================
// Factures sélectionnables
// ============================================