fix(pos-selfpay): use confirmSaleWith to avoid stale state when confirming from modal
This commit is contained in:
@@ -525,6 +525,66 @@ export default function RegisterPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// POS-SELFPAY-FLOW: confirm sale with explicit payment list (avoids stale state in selfpay modal)
|
||||||
|
const confirmSaleWith = async (allocations: PaymentAllocation[]) => {
|
||||||
|
if (!config?.session) {
|
||||||
|
setError('No hay sesión abierta');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cart.length === 0) {
|
||||||
|
setError('Carrito vacío');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const totalAllocated = allocations.reduce((sum, a) => sum + a.amountCents, 0);
|
||||||
|
if (totalAllocated > totals.total) {
|
||||||
|
setError('Los pagos asignados superan el total');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setPayments(allocations);
|
||||||
|
setProcessing(true);
|
||||||
|
setError('');
|
||||||
|
try {
|
||||||
|
const saleItems = cart.map((item) => {
|
||||||
|
if (item.kind === 'free' || !item.variantId) {
|
||||||
|
return {
|
||||||
|
kind: 'free' as const,
|
||||||
|
name: item.name,
|
||||||
|
unitPriceCents: item.unitPriceCents,
|
||||||
|
quantity: item.quantity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kind: 'stock' as const,
|
||||||
|
variantId: item.variantId,
|
||||||
|
quantity: item.quantity,
|
||||||
|
discountCents: item.discountCents,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const result = await posApi.createSale<PosSaleResponse>({
|
||||||
|
idempotencyKey: generateIdempotencyKey(),
|
||||||
|
cashSessionId: config.session.id,
|
||||||
|
terminalId: config.terminal.id,
|
||||||
|
items: saleItems,
|
||||||
|
payments: allocations.map((payment) => ({
|
||||||
|
methodCode: payment.methodCode,
|
||||||
|
amountCents: payment.amountCents,
|
||||||
|
...(payment.kind === 'cash' ? { tenderedCents: payment.tenderedCents } : {}),
|
||||||
|
})),
|
||||||
|
...(customer ? { customerId: customer.id } : {}),
|
||||||
|
});
|
||||||
|
setReceipt(result.receipt);
|
||||||
|
setRestPaymentFor(null);
|
||||||
|
if (isSelfpayMode && selfpayEmail.trim()) {
|
||||||
|
void posApi.emailReceipt(result.receipt.orderId, selfpayEmail.trim()).catch(() => {});
|
||||||
|
}
|
||||||
|
void loadPendingSales();
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : 'No se pudo confirmar la venta');
|
||||||
|
} finally {
|
||||||
|
setProcessing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const parkSale = async () => {
|
const parkSale = async () => {
|
||||||
if (!config?.session) {
|
if (!config?.session) {
|
||||||
setError('No hay sesión abierta');
|
setError('No hay sesión abierta');
|
||||||
@@ -1857,8 +1917,7 @@ export default function RegisterPage() {
|
|||||||
...(method.kind === 'cash' ? { tenderedCents: remainingCents } : {}),
|
...(method.kind === 'cash' ? { tenderedCents: remainingCents } : {}),
|
||||||
changeCents: 0,
|
changeCents: 0,
|
||||||
};
|
};
|
||||||
setPayments([allocation]);
|
void confirmSaleWith([allocation]);
|
||||||
void confirmSale();
|
|
||||||
}}
|
}}
|
||||||
disabled={remainingCents === 0}
|
disabled={remainingCents === 0}
|
||||||
className={`min-h-16 rounded-xl px-2 font-bold text-white disabled:opacity-40 ${method.kind === 'cash' ? 'bg-green-600' : method.kind === 'card' ? 'bg-blue-600' : 'bg-slate-700'}`}
|
className={`min-h-16 rounded-xl px-2 font-bold text-white disabled:opacity-40 ${method.kind === 'cash' ? 'bg-green-600' : method.kind === 'card' ? 'bg-blue-600' : 'bg-slate-700'}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user