This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
Cálculo de IVA (Impuesto al Valor Agregado) — Chile 19%.
|
||||
|
||||
Funcionalidades:
|
||||
- Calcular IVA desde monto neto
|
||||
- Calcular neto desde monto bruto (con IVA incluido)
|
||||
- Desglose completo: neto + IVA = bruto
|
||||
- Cálculo con tasas especiales (exento, construcción 65%)
|
||||
|
||||
Autor: José Nicolás Candia (@mechjook)
|
||||
"""
|
||||
|
||||
TASA_IVA_ESTANDAR = 0.19
|
||||
TASA_IVA_CONSTRUCCION = 0.65 # 65% del IVA en crédito especial
|
||||
|
||||
|
||||
def calcular_iva_desde_neto(monto_neto: float, tasa: float = TASA_IVA_ESTANDAR) -> dict:
|
||||
"""
|
||||
Calcula IVA y bruto a partir del monto neto.
|
||||
|
||||
Args:
|
||||
monto_neto: Monto sin IVA
|
||||
tasa: Tasa de IVA (default 0.19 = 19%)
|
||||
|
||||
Returns:
|
||||
dict con neto, iva, bruto, tasa
|
||||
"""
|
||||
if monto_neto < 0:
|
||||
raise ValueError("El monto neto no puede ser negativo")
|
||||
if not 0 <= tasa <= 1:
|
||||
raise ValueError("La tasa debe estar entre 0 y 1")
|
||||
|
||||
iva = round(monto_neto * tasa)
|
||||
bruto = monto_neto + iva
|
||||
|
||||
return {
|
||||
"monto_neto": round(monto_neto),
|
||||
"iva": iva,
|
||||
"monto_bruto": round(bruto),
|
||||
"tasa_iva": tasa,
|
||||
"tasa_iva_porcentaje": f"{tasa * 100:.0f}%",
|
||||
}
|
||||
|
||||
|
||||
def calcular_neto_desde_bruto(monto_bruto: float, tasa: float = TASA_IVA_ESTANDAR) -> dict:
|
||||
"""
|
||||
Calcula monto neto e IVA a partir del monto bruto (IVA incluido).
|
||||
|
||||
Args:
|
||||
monto_bruto: Monto con IVA incluido
|
||||
tasa: Tasa de IVA (default 0.19 = 19%)
|
||||
|
||||
Returns:
|
||||
dict con neto, iva, bruto, tasa
|
||||
"""
|
||||
if monto_bruto < 0:
|
||||
raise ValueError("El monto bruto no puede ser negativo")
|
||||
if not 0 <= tasa <= 1:
|
||||
raise ValueError("La tasa debe estar entre 0 y 1")
|
||||
|
||||
neto = round(monto_bruto / (1 + tasa))
|
||||
iva = monto_bruto - neto
|
||||
|
||||
return {
|
||||
"monto_neto": neto,
|
||||
"iva": round(iva),
|
||||
"monto_bruto": round(monto_bruto),
|
||||
"tasa_iva": tasa,
|
||||
"tasa_iva_porcentaje": f"{tasa * 100:.0f}%",
|
||||
}
|
||||
|
||||
|
||||
def desglose_factura(items: list[dict]) -> dict:
|
||||
"""
|
||||
Genera desglose completo de una factura con múltiples items.
|
||||
|
||||
Cada item debe tener: {"descripcion": str, "cantidad": int, "precio_unitario_neto": float}
|
||||
|
||||
Returns:
|
||||
dict con items detallados, subtotal_neto, iva_total, total_bruto
|
||||
"""
|
||||
detalle = []
|
||||
subtotal_neto = 0
|
||||
|
||||
for item in items:
|
||||
descripcion = item.get("descripcion", "")
|
||||
cantidad = item.get("cantidad", 1)
|
||||
precio_unitario = item.get("precio_unitario_neto", 0)
|
||||
|
||||
if cantidad < 0:
|
||||
raise ValueError(f"Cantidad negativa en item '{descripcion}'")
|
||||
if precio_unitario < 0:
|
||||
raise ValueError(f"Precio negativo en item '{descripcion}'")
|
||||
|
||||
neto_linea = round(cantidad * precio_unitario)
|
||||
iva_linea = round(neto_linea * TASA_IVA_ESTANDAR)
|
||||
|
||||
detalle.append({
|
||||
"descripcion": descripcion,
|
||||
"cantidad": cantidad,
|
||||
"precio_unitario_neto": round(precio_unitario),
|
||||
"neto_linea": neto_linea,
|
||||
"iva_linea": iva_linea,
|
||||
"total_linea": neto_linea + iva_linea,
|
||||
})
|
||||
subtotal_neto += neto_linea
|
||||
|
||||
iva_total = round(subtotal_neto * TASA_IVA_ESTANDAR)
|
||||
|
||||
return {
|
||||
"detalle": detalle,
|
||||
"subtotal_neto": subtotal_neto,
|
||||
"iva_total": iva_total,
|
||||
"total_bruto": subtotal_neto + iva_total,
|
||||
"tasa_iva": TASA_IVA_ESTANDAR,
|
||||
"cantidad_items": len(items),
|
||||
}
|
||||
Reference in New Issue
Block a user