# ============================================
# SISTEMA DE REGRAS PARA APROVAÇÃO DE CRÉDITO
# ============================================
from typing import Dict, List, Callable, Any
from dataclasses import dataclass
from enum import Enum
class Decisao(Enum):
APROVADO = "Aprovado"
REPROVADO = "Reprovado"
REVISAR_MANUAL = "Revisar manualmente"
@dataclass
class Cliente:
nome: str
renda_mensal: float
divida_total: float
score_credito: int
tempo_emprego_meses: int
idade: int
ja_cliente: bool = False
quantidade_parcelas_sugerida: int = 0
@dataclass
class ResultadoAvaliacao:
cliente_nome: str
decisao: Decisao
razoes: List[str]
score_final: int
valor_maximo: float
parcelas_sugeridas: int
# ============================================
# BASE DE REGRAS (DEFINIDAS DECLARATIVAMENTE)
# ============================================
# Formato: (condicao, acao, descricao)
regras = []
def regra(condicao, acao, descricao):
"""Decorador para adicionar regras à base."""
regras.append((condicao, acao, descricao))
return acao
# Regras de reprovação (motivos bloqueantes)
def motivo_reprovacao(cond):
return lambda dados: cond(dados)
@regra(
lambda c: c.score_credito < 300,
lambda c: "Score abaixo de 300",
"Cliente com score muito baixo é reprovado automaticamente"
)
def regra_score_minimo(cliente):
return "Score abaixo de 300"
@regra(
lambda c: c.renda_mensal < 1000,
lambda c: "Renda abaixo de R$ 1.000",
"Renda mínima necessária é R$ 1.000"
)
def regra_renda_minima(cliente):
return "Renda abaixo de R$ 1.000"
@regra(
lambda c: c.idade < 18,
lambda c: "Idade mínima não atingida (18 anos)",
"Cliente deve ser maior de idade"
)
def regra_idade_minima(cliente):
return "Idade mínima não atingida"
@regra(
lambda c: (c.divida_total / c.renda_mensal) > 0.5,
lambda c: f"Comprometimento de renda alto: {(c.divida_total/c.renda_mensal)*100:.1f}%",
"Dívida não pode exceder 50% da renda mensal"
)
def regra_comprometimento(cliente):
return f"Comprometimento de renda alto"
# Regras de bonificação (aumento de score)
@regra(
lambda c: c.tempo_emprego_meses > 24,
lambda c: 15,
"Bônus de +15 pontos por tempo de emprego (>2 anos)"
)
def bonus_tempo_emprego(cliente):
return 15
@regra(
lambda c: c.ja_cliente,
lambda c: 10,
"Bônus de +10 pontos por ser cliente antigo"
)
def bonus_cliente_antigo(cliente):
return 10
@regra(
lambda c: c.idade >= 25 and c.idade <= 40,
lambda c: 5,
"Bônus de +5 pontos pela faixa etária ideal"
)
def bonus_idade(cliente):
return 5
# Regras de decisão final baseadas no score final
def calcular_valor_aprovado(score, renda):
"""Calcula valor máximo de crédito baseado no score."""
if score >= 700:
return renda * 0.8 # 80% da renda
elif score >= 500:
return renda * 0.5
elif score >= 350:
return renda * 0.3
else:
return 0
def calcular_parcelas(score, renda, valor):
"""Sugere número de parcelas baseado no score."""
if score >= 700:
return min(36, int(valor / (renda * 0.1)))
elif score >= 500:
return min(24, int(valor / (renda * 0.15)))
else:
return 12
# ============================================
# MOTOR DE SIMULAÇÃO
# ============================================
def simular_cliente(cliente: Cliente) -> ResultadoAvaliacao:
"""Aplica todas as regras a um cliente e retorna decisão."""
razoes_reprovacao = []
bonus_total = 0
# Verificar regras de reprovação
for condicao, acao, descricao in regras:
# Se condição parece ser de reprovação (retorna string)
if callable(acao) and descricao != "Bônus de ...":
try:
if condicao(cliente):
resultado = acao(cliente)
if isinstance(resultado, str):
razoes_reprovacao.append(resultado)
except:
pass
# Calcular bônus (regras que retornam números)
for condicao, acao, descricao in regras:
if "Bônus" in descricao and callable(condicao):
if condicao(cliente):
if callable(acao):
bonus = acao(cliente)
if isinstance(bonus, (int, float)):
bonus_total += bonus
# Score final
score_final = cliente.score_credito + bonus_total
# Decidir com base nas reprovações e score
if razoes_reprovacao:
decisao = Decisao.REPROVADO
elif score_final >= 500:
decisao = Decisao.APROVADO
elif score_final >= 350:
decisao = Decisao.REVISAR_MANUAL
else:
decisao = Decisao.REPROVADO
# Calcular valor máximo e parcelas
if decisao == Decisao.APROVADO:
valor_maximo = calcular_valor_aprovado(score_final, cliente.renda_mensal)
parcelas = calcular_parcelas(score_final, cliente.renda_mensal, valor_maximo)
else:
valor_maximo = 0
parcelas = 0
return ResultadoAvaliacao(
cliente_nome=cliente.nome,
decisao=decisao,
razoes=razoes_reprovacao,
score_final=score_final,
valor_maximo=valor_maximo,
parcelas_sugeridas=parcelas
)
# ============================================
# SIMULAÇÃO DE MÚLTIPLOS CENÁRIOS
# ============================================
def simular_cenarios(clientes: List[Cliente]) -> List[ResultadoAvaliacao]:
"""Simula vários clientes em lote."""
resultados = []
for cliente in clientes:
resultado = simular_cliente(cliente)
resultados.append(resultado)
return resultados
def analisar_sensibilidade(cliente_base: Cliente, variavel: str, valores: List[Any]):
"""Testa como uma variável impacta a decisão."""
print(f"\n=== Análise de sensibilidade: {variavel} ===")
for valor in valores:
cliente_mod = Cliente(**cliente_base.__dict__)
setattr(cliente_mod, variavel, valor)
resultado = simular_cliente(cliente_mod)
print(f"{variavel} = {valor}: {resultado.decisao.value} (Score: {resultado.score_final})")
# ============================================
# EXECUÇÃO DOS EXEMPLOS
# ============================================
if __name__ == "__main__":
print("=== SIMULAÇÃO DE REGRAS DE CRÉDITO ===\n")
# Cenários de teste
clientes_teste = [
Cliente("Ana Silva", 5000, 1000, 720, 36, 30, True),
Cliente("Carlos Souza", 800, 200, 550, 12, 25, False),
Cliente("Mariana Lima", 3000, 2000, 480, 6, 22, False),
Cliente("Roberto Alves", 4500, 0, 650, 48, 45, True),
Cliente("Juliana M", 2000, 1200, 320, 3, 19, False),
Cliente("Fernando R", 6000, 2500, 590, 18, 35, True),
]
# Simular todos
resultados = simular_cenarios(clientes_teste)
# Exibir resultados
for r in resultados:
print(f"Cliente: {r.cliente_nome}")
print(f" Decisão: {r.decisao.value}")
print(f" Score final: {r.score_final}")
if r.razoes:
for razao in r.razoes:
print(f" - {razao}")
if r.decisao == Decisao.APROVADO:
print(f" Valor máximo: R$ {r.valor_maximo:,.2f}")
print(f" Parcelas sugeridas: {r.parcelas_sugeridas}x")
print()
# Análise de sensibilidade
cliente_referencia = Cliente("Referência", 3000, 800, 550, 24, 30, True)
analisar_sensibilidade(cliente_referencia, "score_credito", [300, 400, 500, 600, 700])
analisar_sensibilidade(cliente_referencia, "renda_mensal", [1500, 2500, 3500, 5000])
analisar_sensibilidade(cliente_referencia, "divida_total", [500, 1000, 1500, 2000])
# ============================================
# SIMULAÇÃO COM REGRAS BASEADAS EM PYTHON PURO
# ============================================
print("\n=== Simulação de Regras com pyDatalog (Opcional) ===")
print("Para simulações mais avançadas, instale pyDatalog:")
print("pip install pyDatalog")
# Exemplo conceitual sem dependência
print("\nExemplo de regras declarativas (simuladas):")
print("""
Regras para desconto progressivo:
- SE valor > 1000 ENTÃO desconto = 10%
- SE valor > 5000 ENTÃO desconto = 15%
- SE cliente_vip ENTÃO desconto_adicional = 5%
- SE primeira_compra ENTÃO desconto_adicional = 0%
""")
def calcular_desconto(valor, vip, primeira_compra):
if valor > 5000:
desconto = 0.15
elif valor > 1000:
desconto = 0.10
else:
desconto = 0.05
if vip:
desconto += 0.05
if primeira_compra:
desconto = max(0.05, desconto - 0.02)
return min(desconto, 0.30) # Cap de 30%
testes_desconto = [
(6000, True, False, "VIP com alto valor"),
(2000, False, True, "Primeira compra valor médio"),
(800, False, False, "Compra pequena normal"),
]
for valor, vip, primeira, desc in testes_desconto:
desc_calc = calcular_desconto(valor, vip, primeira)
print(f" {desc}: Valor R${valor}, VIP={vip}, 1ª compra={primeira} -> Desconto {desc_calc*100:.0f}%")