Merge pull request #465 from R0m1k3/1.1

1.1
This commit is contained in:
LogiFlow authored and GitHub committed 2025-09-23 16:20:59 +02:00
commit c8b284e0ff
3 files changed
+17 -13

No files matched your search

+4
View File
@@ -27,6 +27,10 @@ externalPort = 3000
localPort = 38451 localPort = 38451
externalPort = 3002 externalPort = 3002
[[ports]]
localPort = 41035
externalPort = 5000
[[ports]] [[ports]]
localPort = 41343 localPort = 41343
externalPort = 3001 externalPort = 3001
+4 -4
View File
@@ -8,7 +8,7 @@ import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { useAuthUnified } from "@/hooks/useAuthUnified"; import { useAuthUnified } from "@/hooks/useAuthUnified";
import { useStore } from "@/contexts/StoreContext"; import { useStore } from "@/contexts/StoreContext";
import { CalendarIcon, Download, RefreshCw, TrendingUp, Package, Clock, Euro, Store, Truck, BarChart3, PieChart, Activity, FileDown } from "lucide-react"; import { CalendarIcon, Download, RefreshCw, TrendingUp, Package, CheckCircle2, Euro, Store, Truck, BarChart3, PieChart, Activity, FileDown } from "lucide-react";
import { addDays, format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, startOfYear, endOfYear } from "date-fns"; import { addDays, format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, startOfYear, endOfYear } from "date-fns";
import { fr } from "date-fns/locale"; import { fr } from "date-fns/locale";
import { LineChart, Line, BarChart, Bar, PieChart as RechartsChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from "recharts"; import { LineChart, Line, BarChart, Bar, PieChart as RechartsChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from "recharts";
@@ -362,15 +362,15 @@ export default function Analytics() {
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardTitle className="text-sm font-medium text-gray-600"> <CardTitle className="text-sm font-medium text-gray-600">
Taux de ponctualité Taux de réconciliation
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="text-2xl font-bold"> <div className="text-2xl font-bold">
{summary?.onTimeRate ? `${summary.onTimeRate.toFixed(1)}%` : '0%'} {summary?.reconciliationRate ? `${summary.reconciliationRate.toFixed(1)}%` : '0%'}
</div> </div>
<Clock className="h-8 w-8 text-orange-500 opacity-50" /> <CheckCircle2 className="h-8 w-8 text-green-500 opacity-50" />
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
+9 -9
View File
@@ -274,7 +274,7 @@ export interface IStorage {
}): Promise<{ }): Promise<{
totalOrders: number; totalOrders: number;
totalDeliveries: number; totalDeliveries: number;
onTimeRate: number; reconciliationRate: number;
totalAmount: number; totalAmount: number;
avgDeliveryDelay: number; avgDeliveryDelay: number;
topSuppliers: Array<{ id: number; name: string; count: number; amount: number }>; topSuppliers: Array<{ id: number; name: string; count: number; amount: number }>;
@@ -2863,7 +2863,7 @@ export class DatabaseStorage implements IStorage {
}): Promise<{ }): Promise<{
totalOrders: number; totalOrders: number;
totalDeliveries: number; totalDeliveries: number;
onTimeRate: number; reconciliationRate: number;
totalAmount: number; totalAmount: number;
avgDeliveryDelay: number; avgDeliveryDelay: number;
topSuppliers: Array<{ id: number; name: string; count: number; amount: number }>; topSuppliers: Array<{ id: number; name: string; count: number; amount: number }>;
@@ -2905,7 +2905,7 @@ export class DatabaseStorage implements IStorage {
const deliveryQuery = db.select({ const deliveryQuery = db.select({
count: sql<number>`COUNT(*)`, count: sql<number>`COUNT(*)`,
totalAmount: sql<number>`COALESCE(SUM(CAST(bl_amount AS NUMERIC)), 0) + COALESCE(SUM(CAST(invoice_amount AS NUMERIC)), 0)`, totalAmount: sql<number>`COALESCE(SUM(CAST(bl_amount AS NUMERIC)), 0) + COALESCE(SUM(CAST(invoice_amount AS NUMERIC)), 0)`,
onTime: sql<number>`COUNT(CASE WHEN delivered_date <= scheduled_date THEN 1 END)`, reconciled: sql<number>`COUNT(CASE WHEN reconciled = true OR reconciled = 1 THEN 1 END)`,
avgDelay: sql<number>`AVG(EXTRACT(EPOCH FROM (delivered_date - scheduled_date)) / 86400)` // days avgDelay: sql<number>`AVG(EXTRACT(EPOCH FROM (delivered_date - scheduled_date)) / 86400)` // days
}).from(deliveries); }).from(deliveries);
if (deliveryConditions.length) deliveryQuery.where(and(...deliveryConditions)); if (deliveryConditions.length) deliveryQuery.where(and(...deliveryConditions));
@@ -2949,7 +2949,7 @@ export class DatabaseStorage implements IStorage {
return { return {
totalOrders: Number(totalOrders) || 0, totalOrders: Number(totalOrders) || 0,
totalDeliveries: Number(deliveryStats.count) || 0, totalDeliveries: Number(deliveryStats.count) || 0,
onTimeRate: deliveryStats.count ? (Number(deliveryStats.onTime) / Number(deliveryStats.count)) * 100 : 0, reconciliationRate: deliveryStats.count ? (Number(deliveryStats.reconciled) / Number(deliveryStats.count)) * 100 : 0,
totalAmount: Number(deliveryStats.totalAmount) || 0, totalAmount: Number(deliveryStats.totalAmount) || 0,
avgDeliveryDelay: Number(deliveryStats.avgDelay) || 0, avgDeliveryDelay: Number(deliveryStats.avgDelay) || 0,
topSuppliers: topSuppliers.map(s => ({ topSuppliers: topSuppliers.map(s => ({
@@ -5134,7 +5134,7 @@ export class MemStorage implements IStorage {
}): Promise<{ }): Promise<{
totalOrders: number; totalOrders: number;
totalDeliveries: number; totalDeliveries: number;
onTimeRate: number; reconciliationRate: number;
totalAmount: number; totalAmount: number;
avgDeliveryDelay: number; avgDeliveryDelay: number;
topSuppliers: Array<{ id: number; name: string; count: number; amount: number }>; topSuppliers: Array<{ id: number; name: string; count: number; amount: number }>;
@@ -5166,10 +5166,10 @@ export class MemStorage implements IStorage {
// Calculate metrics // Calculate metrics
const totalOrders = filteredOrders.length; const totalOrders = filteredOrders.length;
const totalDeliveries = filteredDeliveries.length; const totalDeliveries = filteredDeliveries.length;
const onTimeDeliveries = filteredDeliveries.filter(d => const reconciledDeliveries = filteredDeliveries.filter(d =>
d.deliveredDate && d.deliveredDate <= d.scheduledDate d.reconciled === true || d.reconciled === 1
).length; ).length;
const onTimeRate = totalDeliveries > 0 ? (onTimeDeliveries / totalDeliveries) * 100 : 0; const reconciliationRate = totalDeliveries > 0 ? (reconciledDeliveries / totalDeliveries) * 100 : 0;
const totalAmount = filteredDeliveries.reduce((sum, d) => { const totalAmount = filteredDeliveries.reduce((sum, d) => {
return sum + (parseFloat(d.blAmount as any) || 0) + (parseFloat(d.invoiceAmount as any) || 0); return sum + (parseFloat(d.blAmount as any) || 0) + (parseFloat(d.invoiceAmount as any) || 0);
@@ -5217,7 +5217,7 @@ export class MemStorage implements IStorage {
return { return {
totalOrders, totalOrders,
totalDeliveries, totalDeliveries,
onTimeRate, reconciliationRate,
totalAmount, totalAmount,
avgDeliveryDelay: 0, // Simplified for development avgDeliveryDelay: 0, // Simplified for development
topSuppliers, topSuppliers,