Add fixes to procurement logic and fix rel-time connections

This commit is contained in:
Urtzi Alfaro
2025-10-02 13:20:30 +02:00
parent c9d8d1d071
commit 1243c2ca6d
24 changed files with 4984 additions and 348 deletions

View File

@@ -0,0 +1,210 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, CardHeader, CardBody } from '../../ui/Card';
import { Button } from '../../ui/Button';
import {
FileText,
CheckCircle,
Clock,
Truck,
AlertCircle,
ChevronRight,
Euro,
Calendar,
Package
} from 'lucide-react';
import { useProcurementDashboard } from '../../../api/hooks/orders';
import { useCurrentTenant } from '../../../stores/tenant.store';
const PurchaseOrdersTracking: React.FC = () => {
const navigate = useNavigate();
const currentTenant = useCurrentTenant();
const tenantId = currentTenant?.id || '';
const { data: dashboard, isLoading } = useProcurementDashboard(tenantId);
const getStatusIcon = (status: string) => {
switch (status) {
case 'draft':
return <Clock className="w-4 h-4" />;
case 'pending_approval':
return <AlertCircle className="w-4 h-4" />;
case 'approved':
return <CheckCircle className="w-4 h-4" />;
case 'in_execution':
return <Truck className="w-4 h-4" />;
case 'completed':
return <CheckCircle className="w-4 h-4" />;
default:
return <FileText className="w-4 h-4" />;
}
};
const getStatusColor = (status: string) => {
switch (status) {
case 'draft':
return 'text-[var(--text-tertiary)] bg-[var(--bg-tertiary)]';
case 'pending_approval':
return 'text-yellow-700 bg-yellow-100';
case 'approved':
return 'text-green-700 bg-green-100';
case 'in_execution':
return 'text-blue-700 bg-blue-100';
case 'completed':
return 'text-green-700 bg-green-100';
case 'cancelled':
return 'text-red-700 bg-red-100';
default:
return 'text-[var(--text-secondary)] bg-[var(--bg-secondary)]';
}
};
const getStatusLabel = (status: string) => {
const labels: Record<string, string> = {
draft: 'Borrador',
pending_approval: 'Pendiente Aprobación',
approved: 'Aprobado',
in_execution: 'En Ejecución',
completed: 'Completado',
cancelled: 'Cancelado'
};
return labels[status] || status;
};
const handleViewAllPOs = () => {
navigate('/app/operations/procurement');
};
const handleViewPODetails = (planId: string) => {
navigate(`/app/operations/procurement?plan=${planId}`);
};
if (isLoading) {
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<FileText className="w-5 h-5 text-[var(--color-primary)]" />
<h3 className="text-lg font-semibold text-[var(--text-primary)]">Órdenes de Compra</h3>
</div>
</div>
<p className="text-sm text-[var(--text-secondary)] mt-1">Seguimiento de órdenes de compra</p>
</CardHeader>
<CardBody>
<div className="flex items-center justify-center py-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--color-primary)]"></div>
</div>
</CardBody>
</Card>
);
}
const recentPlans = dashboard?.recent_plans || [];
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<FileText className="w-5 h-5 text-[var(--color-primary)]" />
<h3 className="text-lg font-semibold text-[var(--text-primary)]">Órdenes de Compra</h3>
</div>
<Button
variant="ghost"
size="sm"
onClick={handleViewAllPOs}
className="text-[var(--color-primary)] hover:text-[var(--color-primary)]/80"
>
Ver Todas
<ChevronRight className="w-4 h-4 ml-1" />
</Button>
</div>
<p className="text-sm text-[var(--text-secondary)] mt-1">Seguimiento de órdenes de compra</p>
</CardHeader>
<CardBody>
{recentPlans.length === 0 ? (
<div className="text-center py-8">
<Package className="w-12 h-12 text-[var(--text-tertiary)] mx-auto mb-3" />
<p className="text-[var(--text-secondary)]">No hay órdenes de compra recientes</p>
<Button
variant="outline"
size="sm"
onClick={handleViewAllPOs}
className="mt-4"
>
Crear Plan de Compras
</Button>
</div>
) : (
<div className="space-y-3">
{recentPlans.slice(0, 5).map((plan: any) => (
<div
key={plan.id}
className="flex items-center justify-between p-4 bg-[var(--bg-secondary)] rounded-lg hover:bg-[var(--bg-tertiary)] transition-colors cursor-pointer"
onClick={() => handleViewPODetails(plan.id)}
>
<div className="flex items-start gap-3 flex-1">
<div className={`p-2 rounded-lg ${getStatusColor(plan.status)}`}>
{getStatusIcon(plan.status)}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="font-medium text-[var(--text-primary)]">
{plan.plan_number}
</span>
<span className={`px-2 py-0.5 rounded-full text-xs ${getStatusColor(plan.status)}`}>
{getStatusLabel(plan.status)}
</span>
</div>
<div className="flex items-center gap-4 text-sm text-[var(--text-secondary)]">
<div className="flex items-center gap-1">
<Calendar className="w-3.5 h-3.5" />
<span>{new Date(plan.plan_date).toLocaleDateString('es-ES')}</span>
</div>
<div className="flex items-center gap-1">
<Package className="w-3.5 h-3.5" />
<span>{plan.total_requirements} items</span>
</div>
<div className="flex items-center gap-1">
<Euro className="w-3.5 h-3.5" />
<span>{plan.total_estimated_cost?.toFixed(2) || '0.00'}</span>
</div>
</div>
</div>
</div>
<ChevronRight className="w-5 h-5 text-[var(--text-tertiary)] flex-shrink-0" />
</div>
))}
</div>
)}
{/* Summary Stats */}
{dashboard?.stats && (
<div className="grid grid-cols-3 gap-4 mt-4 pt-4 border-t border-[var(--border-primary)]">
<div className="text-center">
<div className="text-2xl font-bold text-[var(--text-primary)]">
{dashboard.stats.total_plans || 0}
</div>
<div className="text-xs text-[var(--text-secondary)] mt-1">Total Planes</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-[var(--color-success)]">
{dashboard.stats.approved_plans || 0}
</div>
<div className="text-xs text-[var(--text-secondary)] mt-1">Aprobados</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-[var(--color-warning)]">
{dashboard.stats.pending_plans || 0}
</div>
<div className="text-xs text-[var(--text-secondary)] mt-1">Pendientes</div>
</div>
</div>
)}
</CardBody>
</Card>
);
};
export default PurchaseOrdersTracking;

View File

@@ -4,6 +4,7 @@
export { default as RealTimeAlerts } from './RealTimeAlerts';
export { default as ProcurementPlansToday } from './ProcurementPlansToday';
export { default as ProductionPlansToday } from './ProductionPlansToday';
export { default as PurchaseOrdersTracking } from './PurchaseOrdersTracking';
// Production Management Dashboard Widgets
export { default as ProductionCostMonitor } from './ProductionCostMonitor';