import React, { useState, useEffect } from 'react'; import { Plus, Package, Euro, Calendar, Truck, Building2, X, Save, AlertCircle } from 'lucide-react'; import { Button } from '../../ui/Button'; import { Input } from '../../ui/Input'; import { Card } from '../../ui/Card'; import { useSuppliers } from '../../../api/hooks/suppliers'; import { useCreatePurchaseOrder } from '../../../api/hooks/suppliers'; import { useTenantStore } from '../../../stores/tenant.store'; import type { ProcurementRequirementResponse, PurchaseOrderItem } from '../../../api/types/orders'; import type { SupplierSummary } from '../../../api/types/suppliers'; interface CreatePurchaseOrderModalProps { isOpen: boolean; onClose: () => void; requirements: ProcurementRequirementResponse[]; onSuccess?: () => void; } /** * CreatePurchaseOrderModal - Modal for creating purchase orders from procurement requirements * Allows supplier selection and purchase order creation for ingredients * Can also be used for manual purchase order creation when no requirements are provided */ export const CreatePurchaseOrderModal: React.FC = ({ isOpen, onClose, requirements, onSuccess }) => { const [selectedSupplierId, setSelectedSupplierId] = useState(''); const [deliveryDate, setDeliveryDate] = useState(''); const [notes, setNotes] = useState(''); const [selectedRequirements, setSelectedRequirements] = useState>({}); const [quantities, setQuantities] = useState>({}); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // For manual creation when no requirements are provided const [manualItems, setManualItems] = useState>([]); const [manualItemInputs, setManualItemInputs] = useState({ product_name: '', product_sku: '', unit_of_measure: '', unit_price: '', quantity: '' }); // Get current tenant const { currentTenant } = useTenantStore(); const tenantId = currentTenant?.id || ''; // Fetch suppliers (without status filter to avoid backend enum issue) const { data: suppliersData, isLoading: isLoadingSuppliers, isError: isSuppliersError, error: suppliersError } = useSuppliers( tenantId, { limit: 100 }, { enabled: !!tenantId && isOpen } ); const suppliers = (suppliersData || []).filter(supplier => supplier.status === 'active'); // Create purchase order mutation const createPurchaseOrderMutation = useCreatePurchaseOrder(); // Initialize quantities when requirements change useEffect(() => { if (requirements && requirements.length > 0) { // Initialize from requirements (existing behavior) const initialQuantities: Record = {}; requirements.forEach(req => { initialQuantities[req.id] = req.approved_quantity || req.net_requirement || req.required_quantity; }); setQuantities(initialQuantities); // Initialize all requirements as selected const initialSelected: Record = {}; requirements.forEach(req => { initialSelected[req.id] = true; }); setSelectedRequirements(initialSelected); // Clear manual items when using requirements setManualItems([]); } else { // Reset for manual creation setQuantities({}); setSelectedRequirements({}); setManualItems([]); } }, [requirements]); // Group requirements by supplier (only when requirements exist) const groupedRequirements = requirements && requirements.length > 0 ? requirements.reduce((acc, req) => { const supplierId = req.preferred_supplier_id || 'unassigned'; if (!acc[supplierId]) { acc[supplierId] = []; } acc[supplierId].push(req); return acc; }, {} as Record) : {}; const handleQuantityChange = (requirementId: string, value: string) => { const numValue = parseFloat(value) || 0; setQuantities(prev => ({ ...prev, [requirementId]: numValue })); }; const handleSelectRequirement = (requirementId: string, checked: boolean) => { setSelectedRequirements(prev => ({ ...prev, [requirementId]: checked })); }; const handleSelectAll = (supplierId: string, checked: boolean) => { const supplierRequirements = groupedRequirements[supplierId] || []; const updatedSelected = { ...selectedRequirements }; supplierRequirements.forEach(req => { updatedSelected[req.id] = checked; }); setSelectedRequirements(updatedSelected); }; // Manual item functions const handleAddManualItem = () => { if (!manualItemInputs.product_name || !manualItemInputs.unit_of_measure || !manualItemInputs.unit_price) { return; } const newItem = { id: `manual-${Date.now()}`, product_name: manualItemInputs.product_name, product_sku: manualItemInputs.product_sku || undefined, unit_of_measure: manualItemInputs.unit_of_measure, unit_price: parseFloat(manualItemInputs.unit_price) || 0 }; setManualItems(prev => [...prev, newItem]); // Reset inputs setManualItemInputs({ product_name: '', product_sku: '', unit_of_measure: '', unit_price: '', quantity: '' }); }; const handleRemoveManualItem = (id: string) => { setManualItems(prev => prev.filter(item => item.id !== id)); }; const handleManualItemQuantityChange = (id: string, value: string) => { const numValue = parseFloat(value) || 0; setQuantities(prev => ({ ...prev, [id]: numValue })); }; const handleCreatePurchaseOrder = async () => { if (!selectedSupplierId) { setError('Por favor, selecciona un proveedor'); return; } let items: PurchaseOrderItem[] = []; if (requirements && requirements.length > 0) { // Create items from requirements const selectedReqs = requirements.filter(req => selectedRequirements[req.id]); if (selectedReqs.length === 0) { setError('Por favor, selecciona al menos un ingrediente'); return; } // Validate quantities const invalidQuantities = selectedReqs.some(req => quantities[req.id] <= 0); if (invalidQuantities) { setError('Todas las cantidades deben ser mayores a 0'); return; } // Prepare purchase order items from requirements items = selectedReqs.map(req => ({ inventory_product_id: req.product_id, product_code: req.product_sku || '', product_name: req.product_name, ordered_quantity: quantities[req.id], unit_of_measure: req.unit_of_measure, unit_price: req.estimated_unit_cost || 0, quality_requirements: req.quality_specifications ? JSON.stringify(req.quality_specifications) : undefined, notes: req.special_requirements || undefined })); } else { // Create items from manual entries if (manualItems.length === 0) { setError('Por favor, agrega al menos un producto'); return; } // Validate quantities for manual items const invalidQuantities = manualItems.some(item => quantities[item.id] <= 0); if (invalidQuantities) { setError('Todas las cantidades deben ser mayores a 0'); return; } // Prepare purchase order items from manual entries items = manualItems.map(item => ({ inventory_product_id: '', // Not applicable for manual items product_code: item.product_sku || '', product_name: item.product_name, ordered_quantity: quantities[item.id], unit_of_measure: item.unit_of_measure, unit_price: item.unit_price, quality_requirements: undefined, notes: undefined })); } setLoading(true); setError(null); try { // Create purchase order await createPurchaseOrderMutation.mutateAsync({ supplier_id: selectedSupplierId, priority: 'normal', required_delivery_date: deliveryDate || undefined, notes: notes || undefined, items }); // Close modal and trigger success callback onClose(); if (onSuccess) { onSuccess(); } } catch (err) { console.error('Error creating purchase order:', err); setError('Error al crear la orden de compra. Por favor, intenta de nuevo.'); } finally { setLoading(false); } }; // Log suppliers when they change for debugging useEffect(() => { // console.log('Suppliers updated:', suppliers); }, [suppliers]); if (!isOpen) return null; return (
{/* Header */}

Crear Orden de Compra

Selecciona proveedor e ingredientes para crear una orden de compra

{/* Content */}
{error && (
{error}
)} {/* Supplier Selection */}
{!tenantId ? (
Cargando información del tenant...
) : isLoadingSuppliers ? (
) : isSuppliersError ? (
Error al cargar proveedores: {suppliersError?.message || 'Error desconocido'}
) : ( )}
{/* Delivery Date */}
setDeliveryDate(e.target.value)} className="w-full" disabled={loading} />
{/* Notes */}