Feat: Configuración y Administración de Tipos
This commit is contained in:
@@ -9,6 +9,7 @@ import PaymentModal, { type Payment } from '../components/PaymentModal';
|
||||
import { orderService } from '../services/orderService';
|
||||
import type { CreateOrderRequest } from '../types/Order';
|
||||
import AdEditorModal from '../components/POS/AdEditorModal';
|
||||
import BundleConfiguratorModal, { type ComponentConfig } from '../components/POS/BundleConfiguratorModal';
|
||||
import ClientCreateModal from '../components/POS/ClientCreateModal';
|
||||
import ClientSearchModal from '../components/POS/ClientSearchModal';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
@@ -24,6 +25,8 @@ export default function UniversalPosPage() {
|
||||
// Estados de Modales
|
||||
const [showAdEditor, setShowAdEditor] = useState(false);
|
||||
const [selectedAdProduct, setSelectedAdProduct] = useState<Product | null>(null);
|
||||
const [showBundleConfigurator, setShowBundleConfigurator] = useState(false);
|
||||
const [selectedBundle, setSelectedBundle] = useState<Product | null>(null);
|
||||
const [showCreateClient, setShowCreateClient] = useState(false);
|
||||
const [showClientSearch, setShowClientSearch] = useState(false);
|
||||
|
||||
@@ -70,16 +73,11 @@ export default function UniversalPosPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. COMBOS (BUNDLES) - Lógica de Visualización
|
||||
// 2. COMBOS (BUNDLES) - Lógica de Visualización y Configuración
|
||||
if (product.typeCode === 'BUNDLE') {
|
||||
// Traemos los componentes para mostrarlos en el ticket
|
||||
const components = await productService.getBundleComponents(product.id);
|
||||
const subItemsNames = components.map(c =>
|
||||
`${c.quantity}x ${c.childProduct?.name || 'Item'}`
|
||||
);
|
||||
|
||||
addItem(product, 1, { subItems: subItemsNames });
|
||||
showToast(`Combo agregado con ${components.length} ítems`, 'success');
|
||||
if (!clientId) setClient(1005, "Consumidor Final (Default)");
|
||||
setSelectedBundle(product);
|
||||
setShowBundleConfigurator(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,6 +106,22 @@ export default function UniversalPosPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleBundleConfirmed = (configs: ComponentConfig[]) => {
|
||||
if (selectedBundle) {
|
||||
const subItemsNames = configs.map(c =>
|
||||
`${c.product.name} ${c.isConfigured ? '✓' : ''}`
|
||||
);
|
||||
|
||||
addItem(selectedBundle, 1, {
|
||||
subItems: subItemsNames,
|
||||
componentsData: configs
|
||||
});
|
||||
|
||||
showToast(`${selectedBundle.name} configurado y agregado`, 'success');
|
||||
setShowBundleConfigurator(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCheckout = () => {
|
||||
if (items.length === 0) return showToast("El carrito está vacío", "error");
|
||||
if (!clientId) setClient(1005, "Consumidor Final");
|
||||
@@ -146,12 +160,31 @@ export default function UniversalPosPage() {
|
||||
sellerId: sellerId || 2,
|
||||
isDirectPayment: isDirectPayment,
|
||||
notes: "Venta de Mostrador (Universal POS)",
|
||||
items: items.map(i => ({
|
||||
productId: i.productId,
|
||||
quantity: i.quantity,
|
||||
relatedEntityId: i.relatedEntityId,
|
||||
relatedEntityType: i.relatedEntityType
|
||||
}))
|
||||
items: items.flatMap(i => {
|
||||
if (i.componentsData && i.componentsData.length > 0) {
|
||||
// Expandir el combo en sus partes para el backend
|
||||
// El precio se prorratea según el total del combo
|
||||
const bundleTotal = i.subTotal;
|
||||
const sumAllocations = i.componentsData.reduce((acc, c) => acc + (c.allocationAmount || 0), 0);
|
||||
const ratio = sumAllocations > 0 ? (bundleTotal / sumAllocations) : 1;
|
||||
|
||||
return i.componentsData.map(c => ({
|
||||
productId: c.productId,
|
||||
quantity: 1,
|
||||
unitPrice: (c.allocationAmount || 0) * ratio,
|
||||
relatedEntityId: c.listingId,
|
||||
relatedEntityType: c.listingId ? 'Listing' : undefined
|
||||
}));
|
||||
}
|
||||
|
||||
return [{
|
||||
productId: i.productId,
|
||||
quantity: i.quantity,
|
||||
unitPrice: i.unitPrice,
|
||||
relatedEntityId: i.relatedEntityId,
|
||||
relatedEntityType: i.relatedEntityType
|
||||
}];
|
||||
})
|
||||
};
|
||||
|
||||
const result = await orderService.createOrder(payload);
|
||||
@@ -314,6 +347,15 @@ export default function UniversalPosPage() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{showBundleConfigurator && selectedBundle && (
|
||||
<BundleConfiguratorModal
|
||||
bundle={selectedBundle}
|
||||
clientId={clientId || 1005}
|
||||
onClose={() => setShowBundleConfigurator(false)}
|
||||
onConfirm={handleBundleConfirmed}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* MODAL DE BÚSQUEDA DE CLIENTE (F7) */}
|
||||
<AnimatePresence>
|
||||
{showClientSearch && (
|
||||
|
||||
Reference in New Issue
Block a user