Exemplos Práticos
Exemplos completos de decisões usando DMN no Decision Engine.
Exemplo 1: Aprovação de Crédito Simples
Um exemplo básico que aprova ou nega crédito baseado apenas no score.
DMN
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"
id="credit_simple"
name="Simple Credit Decision"
namespace="http://example.com/dmn/credit-simple">
<decision id="creditDecision" name="Credit Decision">
<decisionTable id="creditTable" hitPolicy="FIRST">
<input id="scoreInput" label="Score">
<inputExpression typeRef="number">
<text>score</text>
</inputExpression>
</input>
<output id="resultOutput" name="resultado" typeRef="string"/>
<rule id="rule_denied">
<description>Score muito baixo</description>
<inputEntry><text>< 500</text></inputEntry>
<outputEntry><text>"NEGADO"</text></outputEntry>
</rule>
<rule id="rule_approved">
<description>Score aceitável</description>
<inputEntry><text>>= 500</text></inputEntry>
<outputEntry><text>"APROVADO"</text></outputEntry>
</rule>
</decisionTable>
</decision>
</definitions>
Cenários de Teste
| Score | Resultado Esperado | Regra Acionada |
|---|---|---|
| 400 | NEGADO | rule_denied |
| 500 | APROVADO | rule_approved |
| 720 | APROVADO | rule_approved |
Exemplo 2: Financiamento Veicular Completo
Um exemplo real e complexo que avalia financiamento de veículos considerando:
- Dados do veículo (marca, ano, preço FIPE)
- Perfil do cliente (score, renda, comprometimento)
- Marcas premium com condições especiais
DMN Completo
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"
id="car_financing"
name="Car Financing Decision"
namespace="http://catalisa.com/dmn/car-financing">
<decision id="financingDecision" name="Financing Decision">
<decisionTable id="financingTable" hitPolicy="FIRST">
<!-- Inputs do Veículo -->
<input id="brandInput" label="Marca">
<inputExpression typeRef="string"><text>marca</text></inputExpression>
</input>
<input id="yearInput" label="Ano">
<inputExpression typeRef="number"><text>anoFabricacao</text></inputExpression>
</input>
<input id="fipeInput" label="Preço FIPE">
<inputExpression typeRef="number"><text>precoFipe</text></inputExpression>
</input>
<!-- Inputs do Cliente -->
<input id="scoreInput" label="Credit Score">
<inputExpression typeRef="number"><text>creditScore</text></inputExpression>
</input>
<input id="incomeInput" label="Renda Mensal">
<inputExpression typeRef="number"><text>rendaMensal</text></inputExpression>
</input>
<input id="debtInput" label="Comprometimento">
<inputExpression typeRef="number"><text>comprometimentoRenda</text></inputExpression>
</input>
<!-- Output: STATUS|TAXA|PARCELAS|ENTRADA|OBSERVACAO -->
<output id="resultOutput" name="resultado" typeRef="string"/>
<!-- ============ REGRAS DE NEGAÇÃO ============ -->
<rule id="rule_denied_score">
<description>Negado - score muito baixo</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>< 500</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"NEGADO|0|0|0|Score abaixo do mínimo 500"</text></outputEntry>
</rule>
<rule id="rule_denied_income">
<description>Negado - renda insuficiente</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>< 3000</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"NEGADO|0|0|0|Renda mensal abaixo de R$3000"</text></outputEntry>
</rule>
<rule id="rule_denied_debt">
<description>Negado - comprometimento alto</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 0.6</text></inputEntry>
<outputEntry><text>"NEGADO|0|0|0|Comprometimento acima de 60%"</text></outputEntry>
</rule>
<rule id="rule_denied_old_risky">
<description>Negado - veículo antigo com cliente arriscado</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>< 2015</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>< 650</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"NEGADO|0|0|0|Veiculo antigo para perfil de risco"</text></outputEntry>
</rule>
<!-- ============ REGRAS DE APROVAÇÃO ============ -->
<rule id="rule_approved_premium">
<description>Aprovado Premium - marca premium + cliente excelente</description>
<inputEntry><text>list contains(["BMW", "Mercedes", "Audi", "Porsche", "Volvo", "Land Rover"], marca)</text></inputEntry>
<inputEntry><text>>= 2023</text></inputEntry>
<inputEntry><text>>= 200000</text></inputEntry>
<inputEntry><text>>= 800</text></inputEntry>
<inputEntry><text>>= 20000</text></inputEntry>
<inputEntry><text>< 0.25</text></inputEntry>
<outputEntry><text>"APROVADO_PREMIUM|0.99|72|0.15|Cliente VIP marca premium - taxa 0.99% am"</text></outputEntry>
</rule>
<rule id="rule_approved_excellent">
<description>Aprovado Excelente</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 2020</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 800</text></inputEntry>
<inputEntry><text>>= 10000</text></inputEntry>
<inputEntry><text>< 0.35</text></inputEntry>
<outputEntry><text>"APROVADO|1.19|72|0.15|Excelente perfil - taxa 1.19% am"</text></outputEntry>
</rule>
<rule id="rule_approved_good">
<description>Aprovado Bom</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 2018</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 700</text></inputEntry>
<inputEntry><text>>= 8000</text></inputEntry>
<inputEntry><text>< 0.4</text></inputEntry>
<outputEntry><text>"APROVADO|1.49|60|0.20|Bom perfil - taxa 1.49% am"</text></outputEntry>
</rule>
<rule id="rule_approved_regular">
<description>Aprovado Regular</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 2015</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 600</text></inputEntry>
<inputEntry><text>>= 5000</text></inputEntry>
<inputEntry><text>< 0.5</text></inputEntry>
<outputEntry><text>"APROVADO|1.89|48|0.25|Perfil regular - taxa 1.89% am"</text></outputEntry>
</rule>
<rule id="rule_approved_restricted">
<description>Aprovado com restrição</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 2015</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>>= 500</text></inputEntry>
<inputEntry><text>>= 3000</text></inputEntry>
<inputEntry><text>< 0.6</text></inputEntry>
<outputEntry><text>"APROVADO_RESTRICAO|2.49|36|0.35|Aprovado com restricoes"</text></outputEntry>
</rule>
<!-- ============ FALLBACK ============ -->
<rule id="rule_manual">
<description>Análise manual</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"ANALISE_MANUAL|0|0|0|Requer analise do comite"</text></outputEntry>
</rule>
</decisionTable>
</decision>
</definitions>
Cenários de Teste
Cenário 1: Cliente Premium com BMW
Input:
{
"marca": "BMW",
"anoFabricacao": 2024,
"precoFipe": 450000,
"creditScore": 850,
"rendaMensal": 25000,
"comprometimentoRenda": 0.20
}
Resultado Esperado:
APROVADO_PREMIUM|0.99|72|0.15|Cliente VIP marca premium - taxa 0.99% am
Regra Acionada: rule_approved_premium
Cenário 2: Cliente Bom com Toyota
Input:
{
"marca": "Toyota",
"anoFabricacao": 2022,
"precoFipe": 120000,
"creditScore": 750,
"rendaMensal": 12000,
"comprometimentoRenda": 0.30
}
Resultado Esperado:
APROVADO|1.19|72|0.15|Excelente perfil - taxa 1.19% am
Regra Acionada: rule_approved_excellent
Cenário 3: Cliente Negado - Score Baixo
Input:
{
"marca": "Fiat",
"anoFabricacao": 2020,
"precoFipe": 45000,
"creditScore": 420,
"rendaMensal": 5000,
"comprometimentoRenda": 0.35
}
Resultado Esperado:
NEGADO|0|0|0|Score abaixo do mínimo 500
Regra Acionada: rule_denied_score
Cenário 4: Veículo Antigo + Cliente Arriscado
Input:
{
"marca": "Chevrolet",
"anoFabricacao": 2012,
"precoFipe": 28000,
"creditScore": 520,
"rendaMensal": 4000,
"comprometimentoRenda": 0.55
}
Resultado Esperado:
NEGADO|0|0|0|Veiculo antigo para perfil de risco
Regra Acionada: rule_denied_old_risky
Tabela Completa de Cenários
| Cenário | Marca | Ano | Score | Renda | Comprom. | Resultado | Regra |
|---|---|---|---|---|---|---|---|
| Premium BMW | BMW | 2024 | 850 | 25000 | 0.20 | APROVADO_PREMIUM | rule_approved_premium |
| Premium Mercedes | Mercedes | 2024 | 850 | 22000 | 0.20 | APROVADO_PREMIUM | rule_approved_premium |
| Excelente Toyota | Toyota | 2022 | 820 | 15000 | 0.25 | APROVADO (1.19%) | rule_approved_excellent |
| Bom Honda | Honda | 2019 | 720 | 9000 | 0.38 | APROVADO (1.49%) | rule_approved_good |
| Regular Fiat | Fiat | 2018 | 650 | 6000 | 0.45 | APROVADO (1.89%) | rule_approved_regular |
| Score Baixo | Qualquer | Qualquer | 420 | 5000 | 0.30 | NEGADO | rule_denied_score |
| Renda Baixa | Qualquer | Qualquer | 700 | 2500 | 0.20 | NEGADO | rule_denied_income |
| Alto Comprom. | Qualquer | Qualquer | 700 | 8000 | 0.65 | NEGADO | rule_denied_debt |
| Antigo+Risco | Qualquer | 2012 | 520 | 4000 | 0.50 | NEGADO | rule_denied_old_risky |
Analisando o Trace
Ao executar uma decisão, o trace mostra exatamente quais regras foram avaliadas e qual foi acionada.
Exemplo de Trace Detalhado
Entrada:
{
"marca": "Toyota",
"anoFabricacao": 2022,
"precoFipe": 120000,
"creditScore": 750,
"rendaMensal": 12000,
"comprometimentoRenda": 0.30
}
Trace:
{
"output": "APROVADO|1.19|72|0.15|Excelente perfil - taxa 1.19% am",
"trace": [
{
"decisionId": "financingDecision",
"decisionName": "Financing Decision",
"outcome": "APROVADO|1.19|72|0.15|Excelente perfil - taxa 1.19% am",
"rulesEvaluated": [
{
"ruleId": "rule_denied_score",
"triggered": false,
"conditions": ["creditScore: 750"],
"outcome": null
},
{
"ruleId": "rule_denied_income",
"triggered": false,
"conditions": ["rendaMensal: 12000"],
"outcome": null
},
{
"ruleId": "rule_denied_debt",
"triggered": false,
"conditions": ["comprometimentoRenda: 0.30"],
"outcome": null
},
{
"ruleId": "rule_denied_old_risky",
"triggered": false,
"conditions": ["anoFabricacao: 2022", "creditScore: 750"],
"outcome": null
},
{
"ruleId": "rule_approved_premium",
"triggered": false,
"conditions": ["marca: Toyota", "..."],
"outcome": null
},
{
"ruleId": "rule_approved_excellent",
"triggered": true,
"conditions": ["anoFabricacao: 2022", "creditScore: 750", "rendaMensal: 12000", "comprometimentoRenda: 0.30"],
"outcome": "APROVADO|1.19|72|0.15|Excelente perfil - taxa 1.19% am"
}
]
}
],
"executionTimeMs": 45,
"versionUsed": "4.0.0"
}
Análise do Trace
Fluxo de avaliação (hitPolicy=FIRST):
1. rule_denied_score → creditScore=750 >= 500 → NÃO acionada
2. rule_denied_income → rendaMensal=12000 >= 3000 → NÃO acionada
3. rule_denied_debt → comprometimento=0.30 < 0.6 → NÃO acionada
4. rule_denied_old_risky → ano=2022 >= 2015 → NÃO acionada
5. rule_approved_premium → marca="Toyota" não está na lista premium → NÃO acionada
6. rule_approved_excellent → TODAS condições OK → ACIONADA ✓
Resultado: APROVADO (1.19% a.m.)
Dicas para Debugging
1. Verifique a Ordem das Regras
Com hitPolicy=FIRST, a ordem importa. Regras de negação devem vir antes das de aprovação.
2. Use o Trace
O trace mostra exatamente por que uma regra foi ou não acionada. Analise as condições de cada regra.
3. Teste Casos Limite
Teste valores nos limites das condições:
- Score = 499 (negado) vs Score = 500 (aprovado)
- Comprometimento = 0.59 vs 0.60
4. Verifique list contains
Se usar list contains, certifique-se que:
- A lista usa colchetes:
["BMW", "Mercedes"] - O nome da variável corresponde ao input:
marca - As strings estão corretas (case-sensitive)
<!-- Correto -->
<inputEntry><text>list contains(["BMW", "Mercedes"], marca)</text></inputEntry>
<!-- Errado (sem colchetes) -->
<inputEntry><text>list contains("BMW", "Mercedes", marca)</text></inputEntry>