Facturación electrónica (App B)Cálculos (IVA, exoneración, MAG)

Cálculos (Facturación)

Moneda canónica: CRC. Al vender en otra moneda, los precios (que viven en CRC) se convierten con el tipo de cambio. El total autoritativo lo calcula el servidor (calculo.ts); la UI muestra una previsualización con la misma lógica.

Tarifas de IVA

Código (codigoTarifaIVA)Tarifa
0813 %
044 %
032 %
021 %
090.5 %
01 / exento0 %

Cálculo por línea

base       = cantidad × precioUnitario − descuento
tarifa     = (exento || noSujeto) ? 0 : TARIFA[codigoTarifaIVA]
IVA_línea  = base × (tarifa / 100)

Exoneración (reduce el IVA)

Cuando el cliente tiene un documento de exoneración vigente que cubre el CABYS de la línea:

IVA_línea = max(0, IVA_línea − base × (tarifaExonerada / 100))
  • tarifaExonerada = porcentajeExoneracion que devuelve Hacienda (validado en /api/facturacion/exoneracion).
  • Se auto-rellena por línea (camposExoAuto/exoParaCabys) si el CABYS está en la lista cubierta del documento y no está vencido; editable por línea.
  • Los CABYS cubiertos viven en un sub-doc del cliente: receptores/{id}/exo/cabys (se cargan on-demand).
  • No aplica en exportación (FEE 09).

Régimen MAG (agropecuario)

El MAG no exonera: fija el IVA de la línea en 1 % (codigoTarifaIVA = "02").

  • Disponible por línea si el cliente tiene MAG vigente (activoMAG y no vencido).
  • Mutuamente excluyente con la exoneración. No aplica a productos exentos.

IVA devuelto (salud + tarjeta)

Servicios de salud (tarifa 4 %, CABYS que no empieza en 64 = aviación) pagados con tarjeta → su IVA se devuelve:

ivaDevuelto = (medioPago == "02") ? Σ IVA_línea(salud 4%) : 0

No aplica a líneas MAG ni exoneradas.

Otros impuestos / otros cargos

  • Otros impuestos por línea (ISC, IUC…): oiMonto o base × oiTarifa%.
  • Otros cargos (nivel comprobante): p.ej. el cargo 06 (servicio 10 %) se calcula automático = 10 % del subtotal de las líneas.

Total del comprobante

total = subtotal + IVA + otrosImpuestos + otrosCargos − ivaDevuelto

subtotal = Σ base de líneas. En la previsualización del POS, el total mostrado se redondea a 2 decimales (evita el “céntimo fantasma” del botón Exacto y el vuelto).

Cantidades fraccionables vs. enteras

Cada producto define permiteFracciones:

  • Fraccionables (kg, g, L, mL, m, cm, h…): aceptan decimales (ej. 0.250), normalizados a 3 decimales.
  • Enteras (Unid, Sp, Otros): entero, mínimo 1 (se redondea con Math.round, piso 1).

Reglas de aplicación:

  • POS: usa el flag guardado del producto. La cantidad inicial al agregar = 1, o el disponible si es fraccionable y queda < 1 (ej. 0.2 kg); topada al stock; si te pasás, avisa.
  • Nueva factura: el flag se deriva de la unidad de la línea (unidadFraccionable), así no se desincroniza al cambiar la unidad; valida contra el stock del producto.
  • La Cantidad del XML de Hacienda es xs:decimal → las fracciones llegan correctas a la factura, a las NC/ND y al descuento de inventario.

Topes en notas (NC/ND)

  • NC: la cantidad a acreditar ≤ saldoCant de la línea (cantidad original − créditos previos). El monto ≤ saldo restante (montoSaldo).
  • ND: la cantidad ≤ cantidadOrigen (cantidad original de la factura). Las NC previas no reducen ese tope.
  • No fraccionables: en NC/ND también se exige entero ≥ 1.

Redondeos y precisión

  • Total mostrado/cobrado → 2 decimales.
  • Cantidades fraccionables → parseFloat(n.toFixed(3)).
  • IVA exonerado → piso 0 (nunca negativo).
  • Inventario optimista en cache local con Math.max(0, …) (evita stock negativo visual).