POS: totales y pago en USD con tipo de cambio

- Equivalente USD en totales del ticket (TC configurable)
- Selector MXN/USD al cobrar: recibido en dólares convertido a MXN,
  cambio en ambas monedas, referencia 'USD X @ TC Y' en el pago
- Validación de TC antes de crear la venta (sin ventas huérfanas)
This commit is contained in:
2026-08-14 06:42:18 +00:00
parent 84f34c542f
commit 953cdf1108
3 changed files with 138 additions and 17 deletions

View File

@@ -2016,6 +2016,17 @@ class SkeenFrontendController(http.Controller):
}))
total_est = max(0.0, subtotal - discount)
# Moneda y tipo de cambio: validar ANTES de crear nada
currency = data.get('currency', 'MXN')
rate_used = None
if currency == 'USD':
tc = request.env['skeen.tipo.cambio'].sudo().search([], order='date desc, id desc', limit=1)
if not tc:
return json_response({'status': 'error', 'message': 'Configura el tipo de cambio USD en Configuración'}, 400)
rate_used = tc.rate
elif currency != 'MXN':
return json_response({'status': 'error', 'message': 'Moneda no soportada (MXN/USD)'}, 400)
# Validar saldo de puntos ANTES de crear nada
pay_with_points = bool(data.get('pay_with_points'))
Monedero = request.env['skeen.monedero'].sudo()
@@ -2061,16 +2072,27 @@ class SkeenFrontendController(http.Controller):
restante = round(venta.amount_due, 2)
pago = None
cambio = 0.0
cambio_usd = 0.0
recibido_usd = 0.0
if restante > 0:
received = float(data.get('amount_received', restante) or restante)
reference = ''
if currency == 'USD':
# Recibido en dólares: convertir a MXN con el TC vigente (ya validado arriba)
recibido_usd = received
received = round(recibido_usd * rate_used, 2)
reference = f'USD {recibido_usd:.2f} @ TC {rate_used:.2f}'
pay_amount = restante if received >= restante - 0.001 else received
cambio = max(0.0, round(received - restante, 2)) if received > restante else 0.0
if rate_used:
cambio_usd = round(cambio / rate_used, 2)
pago = request.env['skeen.pago'].sudo().create({
'partner_id': partner.id,
'amount': pay_amount,
'payment_method': method,
'state': 'completed',
'payment_date': fields.Datetime.now(),
'provider_reference': reference,
})
venta.write({'amount_paid': venta.amount_paid + pay_amount})
if venta.amount_paid >= venta.total:
@@ -2086,6 +2108,9 @@ class SkeenFrontendController(http.Controller):
'sale': self._sale_to_dict(venta),
'payment': self._payment_to_dict(pago) if pago else None,
'cambio': cambio,
'cambio_usd': cambio_usd,
'rate_used': rate_used,
'recibido_usd': recibido_usd,
'puntos_usados': puntos_usados,
'puntos_ganados': int(venta.total / 10) if venta.state == 'paid' else 0,
'wallet_points': partner.wallet_points,