Especialização em Sistemas com Python 3.12+ • Capítulo 03


🎯 Demonstração Prática: Conciliação Financeira com zip, enumerate e for-else

O exemplo abaixo implementa um simulador corporativo de conciliação bancária e amortização de carteira de crédito:

  • Emprego de zip(..., strict=True) para sincronização estrita de lotes de dados contábeis.
  • Utilização de enumerate(..., start=1) para numeração e rastreamento de lançamentos.
  • Construção for-else para validação de conformidade de integridade sem uso de variáveis sentinelas.
  • Aritmética financeira com o módulo decimal.
"""
demonstracao_conciliacao_repetitiva.py
Conciliação e Amortização de Lançamentos com Protocolo de Iteração e Python 3.12+.
"""

from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_EVEN
from typing import Final, Iterator

# ==============================================================================
# 1. MODELOS DE DADOS PARA AUDITORIA
# ==============================================================================
@dataclass(slots=True)
class LancamentoExtrato:
    documento: str
    descricao: str
    valor_esperado: Decimal

@dataclass(slots=True)
class ConciliacaoItem:
    numero_linha: int
    documento: str
    valor_sistema: Decimal
    valor_banco: Decimal
    divergencia: Decimal
    conformidade: bool

# ==============================================================================
# 2. MOTOR DE CONCILIAÇÃO COM ITERAÇÃO E ZIP STRICT
# ==============================================================================
TOLERANCIA_CENTAVOS: Final[Decimal] = Decimal("0.05")

def conciliar_lotes(
    lancamentos_internos: list[LancamentoExtrato],
    extrato_bancario_valores: list[Decimal]
) -> Iterator[ConciliacaoItem]:
    """
    Pareia lançamentos do ledger interno com os valores retornados pelo banco.
    Garante sincronização 1:1 via zip(strict=True).
    """
    # zip com strict=True lança ValueError caso as listas tenham tamanhos divergentes
    for indice, (interno, valor_banco) in enumerate(
        zip(lancamentos_internos, extrato_bancario_valores, strict=True),
        start=1
    ):
        diferenca = (interno.valor_esperado - valor_banco).quantize(
            Decimal("0.01"), rounding=ROUND_HALF_EVEN
        )
        esta_conforme = abs(diferenca) <= TOLERANCIA_CENTAVOS

        yield ConciliacaoItem(
            numero_linha=indice,
            documento=interno.documento,
            valor_sistema=interno.valor_esperado,
            valor_banco=valor_banco,
            divergencia=diferenca,
            conformidade=esta_conforme
        )

# ==============================================================================
# 3. ROTINA DE AMORTIZAÇÃO COM WHILE E WALRUS OPERATOR
# ==============================================================================
def calcular_cronograma_amortizacao(
    saldo_devedor_inicial: Decimal,
    taxa_juros_mensal: Decimal,
    pagamento_mensal_fixo: Decimal,
    limite_meses: int = 12
) -> list[tuple[int, Decimal, Decimal, Decimal]]:
    """Gera o extrato de amortização decrescente até liquidação total da dívida."""
    cronograma: list[tuple[int, Decimal, Decimal, Decimal]] = []
    saldo_atual: Decimal = saldo_devedor_inicial
    mes: int = 1

    # While com critério duplo de parada
    while saldo_atual > Decimal("0.00") and mes <= limite_meses:
        juros = (saldo_atual * taxa_juros_mensal).quantize(Decimal("0.01"), ROUND_HALF_EVEN)
        
        # Ajuste da última parcela se o pagamento superar a dívida restante
        parcela = min(pagamento_mensal_fixo, saldo_atual + juros)
        amortizacao = parcela - juros
        saldo_atual = (saldo_atual - amortizacao).quantize(Decimal("0.01"), ROUND_HALF_EVEN)

        cronograma.append((mes, juros, amortizacao, saldo_atual))
        mes += 1

    return cronograma

# ==============================================================================
# 4. EXECUÇÃO PRINCIPAL
# ==============================================================================
if __name__ == "__main__":
    # Dados de teste para conciliação
    lote_interno: list[LancamentoExtrato] = [
        LancamentoExtrato("DOC-9801", "Assinatura Cloud Pro", Decimal("450.00")),
        LancamentoExtrato("DOC-9802", "Licenciamento JetBrains", Decimal("890.50")),
        LancamentoExtrato("DOC-9803", "Gateway SMS Twilio", Decimal("125.30")),
        LancamentoExtrato("DOC-9804", "Domínios e DNS Route53", Decimal("75.00")),
    ]

    valores_recebidos_banco: list[Decimal] = [
        Decimal("450.00"),
        Decimal("890.50"),
        Decimal("125.28"), # Divergência de R$ 0.02 (Dentro da tolerância)
        Decimal("75.00"),
    ]

    print("=" * 80)
    print("      RELATÓRIO DE CONCILIAÇÃO BANCÁRIA (ZIP STRICT + ENUMERATE)")
    print("=" * 80)
    print(f"{'Linha':<6} | {'Documento':<10} | {'Sistema':>12} | {'Banco':>12} | {'Dif':>8} | {'Status':<12}")
    print("-" * 80)

    # Consumo do gerador e validação com for-else
    for item in conciliar_lotes(lote_interno, valores_recebidos_banco):
        status_txt = "CONFORME" if item.conformidade else "DIVERGENTE"
        print(
            f"{item.numero_linha:<6} | "
            f"{item.documento:<10} | "
            f"R$ {item.valor_sistema:>9.2f} | "
            f"R$ {item.valor_banco:>9.2f} | "
            f"R$ {item.divergencia:>5.2f} | "
            f"[{status_txt}]"
        )
        if not item.conformidade:
            print(f"\n[ALERTA] Divergência grave detectada na linha {item.numero_linha}. Auditoria abortada.")
            break
    else:
        # Apenas executa se nenhum break disparou
        print("-" * 80)
        print(">> SUCESSO: Todos os lançamentos do lote foram homologados sem divergências impeditivas!")
        print("=" * 80)

    # Demonstração de Amortização
    print("\n" + "=" * 80)
    print("      CRONOGRAMA DE AMORTIZAÇÃO DE CAPITAL (WHILE)")
    print("=" * 80)
    print(f"{'Mês':<6} | {'Juros':>14} | {'Amortização':>14} | {'Saldo Devedor':>18}")
    print("-" * 80)

    plano = calcular_cronograma_amortizacao(
        saldo_devedor_inicial=Decimal("5000.00"),
        taxa_juros_mensal=Decimal("0.015"), # 1.5% ao mês
        pagamento_mensal_fixo=Decimal("1200.00"),
        limite_meses=6
    )

    for mes, juros, amortizacao, saldo in plano:
        print(f"{mes:<6} | R$ {juros:>11.2f} | R$ {amortizacao:>11.2f} | R$ {saldo:>15.2f}")
    print("=" * 80)