import { useState } from 'react'; import { ShoppingBag, Plus, MoreVertical, Eye, CheckCircle, XCircle, Calendar, DollarSign, RefreshCw, Search, FileText, Package, Download, } from 'lucide-react'; import { Button } from '@components/atoms/Button'; import { Card, CardHeader, CardTitle, CardContent } from '@components/molecules/Card'; import { DataTable, type Column } from '@components/organisms/DataTable'; import { Dropdown, type DropdownItem } from '@components/organisms/Dropdown'; import { Breadcrumbs } from '@components/organisms/Breadcrumbs'; import { ConfirmModal } from '@components/organisms/Modal'; import { NoDataEmptyState, ErrorEmptyState } from '@components/templates/EmptyState'; import { usePurchaseOrders } from '@features/purchases/hooks'; import type { PurchaseOrder, PurchaseOrderStatus } from '@features/purchases/types'; import { formatDate, formatNumber } from '@utils/formatters'; const statusLabels: Record = { draft: 'Borrador', sent: 'Enviado', confirmed: 'Confirmado', done: 'Completado', cancelled: 'Cancelado', }; const statusColors: Record = { draft: 'bg-gray-100 text-gray-700', sent: 'bg-blue-100 text-blue-700', confirmed: 'bg-green-100 text-green-700', done: 'bg-purple-100 text-purple-700', cancelled: 'bg-red-100 text-red-700', }; // Helper function to format currency with 2 decimals const formatCurrency = (value: number): string => { return formatNumber(value, 'es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }; export function PurchaseOrdersPage() { const [selectedStatus, setSelectedStatus] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const [dateFrom, setDateFrom] = useState(''); const [dateTo, setDateTo] = useState(''); const [orderToConfirm, setOrderToConfirm] = useState(null); const [orderToCancel, setOrderToCancel] = useState(null); const { orders, total, page, totalPages, isLoading, error, setPage, refresh, confirmOrder, cancelOrder, downloadPdf, } = usePurchaseOrders({ status: selectedStatus || undefined, search: searchTerm || undefined, dateFrom: dateFrom || undefined, dateTo: dateTo || undefined, limit: 20, }); const getActionsMenu = (order: PurchaseOrder): DropdownItem[] => { const items: DropdownItem[] = [ { key: 'view', label: 'Ver detalle', icon: , onClick: () => console.log('View', order.id), }, { key: 'pdf', label: 'Descargar PDF', icon: , onClick: () => downloadPdf(order.id, `OC-${order.name}.pdf`), }, ]; if (order.status === 'draft') { items.push({ key: 'confirm', label: 'Confirmar orden', icon: , onClick: () => setOrderToConfirm(order), }); items.push({ key: 'cancel', label: 'Cancelar', icon: , danger: true, onClick: () => setOrderToCancel(order), }); } if (order.status === 'confirmed') { items.push({ key: 'receive', label: 'Recibir productos', icon: , onClick: () => console.log('Receive', order.id), }); items.push({ key: 'invoice', label: 'Crear factura', icon: , onClick: () => console.log('Invoice', order.id), }); } return items; }; const columns: Column[] = [ { key: 'name', header: 'Orden', render: (order) => (
{order.name}
{order.ref && (
Ref: {order.ref}
)}
), }, { key: 'partner', header: 'Proveedor', render: (order) => (
{order.partnerName || order.partnerId}
), }, { key: 'date', header: 'Fecha', sortable: true, render: (order) => ( {formatDate(order.orderDate, 'short')} ), }, { key: 'expectedDate', header: 'Entrega Esperada', render: (order) => ( {order.expectedDate ? formatDate(order.expectedDate, 'short') : '-'} ), }, { key: 'amount', header: 'Total', sortable: true, render: (order) => (
${formatCurrency(order.amountTotal)}
{order.currencyCode && order.currencyCode !== 'MXN' && (
{order.currencyCode}
)}
), }, { key: 'receiptStatus', header: 'Recepcion', render: (order) => { const status = order.receiptStatus || 'pending'; const colors: Record = { pending: 'bg-amber-100 text-amber-700', partial: 'bg-blue-100 text-blue-700', received: 'bg-green-100 text-green-700', }; const labels: Record = { pending: 'Pendiente', partial: 'Parcial', received: 'Recibido', }; return ( {labels[status] || status} ); }, }, { key: 'status', header: 'Estado', render: (order) => ( {statusLabels[order.status]} ), }, { key: 'actions', header: '', render: (order) => ( } items={getActionsMenu(order)} align="right" /> ), }, ]; const handleConfirm = async () => { if (orderToConfirm) { await confirmOrder(orderToConfirm.id); setOrderToConfirm(null); } }; const handleCancel = async () => { if (orderToCancel) { await cancelOrder(orderToCancel.id); setOrderToCancel(null); } }; // Calculate summary stats const draftCount = orders.filter(o => o.status === 'draft').length; const confirmedCount = orders.filter(o => o.status === 'confirmed').length; const totalAmount = orders.reduce((sum, o) => sum + o.amountTotal, 0); const pendingReceipt = orders.filter(o => o.receiptStatus === 'pending' && o.status === 'confirmed').length; if (error) { return (
); } return (

Ordenes de Compra

Gestiona ordenes de compra y recepciones de proveedores

{/* Summary Stats */}
setSelectedStatus('draft')}>
Borradores
{draftCount}
setSelectedStatus('confirmed')}>
Confirmadas
{confirmedCount}
Por Recibir
{pendingReceipt}
Total Compras
${formatCurrency(totalAmount)}
Lista de Ordenes
{/* Filters */}
setSearchTerm(e.target.value)} className="w-full rounded-md border border-gray-300 py-2 pl-10 pr-4 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" />
setDateFrom(e.target.value)} className="rounded-md border border-gray-300 px-3 py-2 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" /> - setDateTo(e.target.value)} className="rounded-md border border-gray-300 px-3 py-2 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" />
{(selectedStatus || searchTerm || dateFrom || dateTo) && ( )}
{/* Table */} {orders.length === 0 && !isLoading ? ( ) : ( )}
{/* Confirm Order Modal */} setOrderToConfirm(null)} onConfirm={handleConfirm} title="Confirmar orden de compra" message={`¿Confirmar la orden ${orderToConfirm?.name}? Esta accion enviara la orden al proveedor.`} variant="success" confirmText="Confirmar" /> {/* Cancel Order Modal */} setOrderToCancel(null)} onConfirm={handleCancel} title="Cancelar orden de compra" message={`¿Cancelar la orden ${orderToCancel?.name}? Esta accion no se puede deshacer.`} variant="danger" confirmText="Cancelar orden" />
); } export default PurchaseOrdersPage;