| """Calculadora de ICMS com suporte a ST, DIFAL e FCP.""" |
| from __future__ import annotations |
|
|
| from dataclasses import dataclass, field |
| from decimal import Decimal |
| from typing import Optional |
|
|
| from src.calculators import ResultadoCalculo, arred |
| from src.fiscal.constants import ALIQ_ICMS_INTERNA, aliq_icms_interestadual |
|
|
|
|
| @dataclass |
| class ParametrosICMS: |
| valor_mercadoria: Decimal |
| aliquota: Decimal |
| cst: str = "000" |
| uf_origem: str = "SP" |
| uf_destino: str = "SP" |
| reducao_base: Decimal = Decimal("0") |
| frete: Decimal = Decimal("0") |
| seguro: Decimal = Decimal("0") |
| outras_despesas: Decimal = Decimal("0") |
| desconto: Decimal = Decimal("0") |
| |
| aliq_st: Optional[Decimal] = None |
| mva: Optional[Decimal] = None |
| base_st_retido: Decimal = Decimal("0") |
| |
| aliq_fcp: Decimal = Decimal("0") |
| aliq_fcp_st: Decimal = Decimal("0") |
| |
| calcular_difal: bool = False |
| consumidor_final: bool = False |
|
|
|
|
| @dataclass |
| class ResultadoICMS: |
| base_calculo: Decimal = Decimal("0") |
| aliquota: Decimal = Decimal("0") |
| valor_icms: Decimal = Decimal("0") |
| |
| base_st: Decimal = Decimal("0") |
| aliq_st: Decimal = Decimal("0") |
| valor_st: Decimal = Decimal("0") |
| |
| base_fcp: Decimal = Decimal("0") |
| valor_fcp: Decimal = Decimal("0") |
| valor_fcp_st: Decimal = Decimal("0") |
| |
| valor_difal_origem: Decimal = Decimal("0") |
| valor_difal_destino: Decimal = Decimal("0") |
| |
| valor_total_icms: Decimal = Decimal("0") |
|
|
|
|
| def calcular_icms(p: ParametrosICMS) -> ResultadoICMS: |
| r = ResultadoICMS() |
|
|
| if p.cst in {"040", "041", "050", "051", "060"}: |
| return r |
|
|
| base_bruta = ( |
| p.valor_mercadoria + p.frete + p.seguro + p.outras_despesas - p.desconto |
| ) |
|
|
| if p.cst in {"020", "070"}: |
| r.base_calculo = arred(base_bruta * (1 - p.reducao_base / 100)) |
| else: |
| r.base_calculo = arred(base_bruta) |
|
|
| r.aliquota = p.aliquota |
| r.valor_icms = arred(r.base_calculo * p.aliquota / 100) |
|
|
| |
| if p.aliq_fcp > 0: |
| r.base_fcp = r.base_calculo |
| r.valor_fcp = arred(r.base_fcp * p.aliq_fcp / 100) |
|
|
| |
| if p.cst in {"010", "030", "070"} and p.aliq_st is not None and p.mva is not None: |
| aliq_interna_dest = ALIQ_ICMS_INTERNA.get(p.uf_destino, Decimal("18")) |
| r.base_st = arred(r.base_calculo * (1 + p.mva / 100)) |
| r.aliq_st = aliq_interna_dest |
| icms_proprio_dest = arred(r.base_st * aliq_interna_dest / 100) |
| r.valor_st = max(Decimal("0"), arred(icms_proprio_dest - r.valor_icms)) |
| if p.aliq_fcp_st > 0: |
| r.valor_fcp_st = arred(r.base_st * p.aliq_fcp_st / 100) |
|
|
| |
| if p.calcular_difal and p.consumidor_final and p.uf_origem != p.uf_destino: |
| aliq_interestadual = aliq_icms_interestadual(p.uf_origem, p.uf_destino) |
| aliq_interna_dest = ALIQ_ICMS_INTERNA.get(p.uf_destino, Decimal("18")) |
| difal = arred(r.base_calculo * (aliq_interna_dest - aliq_interestadual) / 100) |
| |
| r.valor_difal_destino = arred(difal * Decimal("0.60")) |
| r.valor_difal_origem = arred(difal * Decimal("0.40")) |
|
|
| r.valor_total_icms = arred( |
| r.valor_icms + r.valor_st + r.valor_fcp + r.valor_fcp_st |
| + r.valor_difal_destino + r.valor_difal_origem |
| ) |
| return r |
|
|
|
|
| def calcular_icms_credito_entrada( |
| valor_nf: Decimal, |
| aliquota: Decimal, |
| percentual_aproveitamento: Decimal = Decimal("100"), |
| ) -> Decimal: |
| credito_bruto = arred(valor_nf * aliquota / 100) |
| return arred(credito_bruto * percentual_aproveitamento / 100) |
|
|
|
|
| def calcular_icms_apuracao( |
| debitos: list[Decimal], |
| creditos: list[Decimal], |
| saldo_anterior: Decimal = Decimal("0"), |
| ) -> ResultadoCalculo: |
| total_debitos = arred(sum(debitos)) |
| total_creditos = arred(sum(creditos) + saldo_anterior) |
| saldo = total_creditos - total_debitos |
| valor_a_recolher = max(Decimal("0"), arred(total_debitos - total_creditos)) |
| saldo_credor = max(Decimal("0"), arred(total_creditos - total_debitos)) |
| return ResultadoCalculo( |
| base_calculo=total_debitos, |
| aliquota=Decimal("0"), |
| valor_tributo=total_debitos, |
| deducoes=Decimal("0"), |
| creditos=total_creditos, |
| valor_a_recolher=valor_a_recolher, |
| detalhes={ |
| "total_debitos": total_debitos, |
| "total_creditos": total_creditos, |
| "saldo_devedor": valor_a_recolher, |
| "saldo_credor": saldo_credor, |
| }, |
| ) |
|
|