Credit Rules¶
Context¶
This document describes the business rules for credit evaluation in our banking system.
Simple Evaluation¶
The basic rule checks whether the client's balance exceeds the requested amount.
Contract¶
evaluate_credit
Evaluate whether the client can obtain a credit for the requested amount. The rule is simple: the client's balance must exceed the requested amount.
| Inputs | ||
|---|---|---|
| Parameter | Type | Default |
client_id | str | — |
amount | float | — |
| Output | ||
return | bool | — |
Source Code¶
def evaluate_credit(client_id: str, amount: float) -> bool:
"""Evaluate whether the client can obtain a credit for the requested amount.
The rule is simple: the client's balance must exceed the requested amount.
"""
try:
result = CheckClientBalance().call(client_id)
except ServiceError:
return False
return result.balance > amount
External Service¶
class CheckClientBalance(ExternalService):
"""Call to the Core Banking API (Blackbox)."""
component_name = "CoreBanking"
def execute(self, client_id: str) -> ClientBalance:
pass # type: ignore[return-value]
def mock(self, client_id: str) -> MockResponse:
return MockResponse(data=ClientBalance(
balance=1500.0,
currency="USD",
account_status="active",
))
def mock_error(self, client_id: str) -> MockErrorResponse:
return MockErrorResponse(
error_code="CLIENT_NOT_FOUND",
error_message="The specified client was not found.",
http_code=404,
)
Execution Flow¶
Try it Live¶
Advanced Evaluation¶
The advanced rule combines balance and credit score.
Contract¶
evaluate_credit_advanced
Advanced evaluation combining balance and credit score. Returns a structured CreditDecision with the decision and details.
| Inputs | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Parameter | Type | Default | ||||||||||||||||||
client_id | str | — | ||||||||||||||||||
amount | float | — | ||||||||||||||||||
score_threshold | int | 600 | ||||||||||||||||||
| Output | ||||||||||||||||||||
return | CreditDecision | — | ||||||||||||||||||
| ||||||||||||||||||||
| Parameter | Type | Default |
|---|---|---|
approved * | bool | — |
balance * | float | — |
score | int | None | None |
incidents | int | None | None |
reasons | list[str] | [] |
Source Code¶
def evaluate_credit_advanced(client_id: str, amount: float, score_threshold: int = 600) -> CreditDecision:
"""Advanced evaluation combining balance and credit score.
Returns a structured CreditDecision with the decision and details.
"""
result = CheckClientBalance().call(client_id)
if result.balance > amount:
history = CheckCreditHistory().call(client_id)
score_ok = history.score >= score_threshold
incidents_ok = history.incidents == 0
reasons = [
r for r in [
"Credit score too low" if not score_ok else None,
"Incidents detected" if not incidents_ok else None,
]
if r
]
return CreditDecision(
approved=score_ok and incidents_ok,
balance=result.balance,
score=history.score,
incidents=history.incidents,
reasons=reasons,
)
else:
return CreditDecision(
approved=False,
balance=result.balance,
reasons=["Insufficient balance"],
)
Execution Flow¶
Sequence diagram — evaluate_credit_advanced
sequenceDiagram
participant evaluate_credit_advanced
participant CheckClientBalance as CoreBanking / CheckClientBalance
participant CheckCreditHistory as CoreBanking / CheckCreditHistory
evaluate_credit_advanced->>+CheckClientBalance: client_id
CheckClientBalance-->>-evaluate_credit_advanced: response
alt result.balance > amount
evaluate_credit_advanced->>+CheckCreditHistory: client_id
CheckCreditHistory-->>-evaluate_credit_advanced: response
else
end
Try it Live¶
Typed Evaluation (with Pydantic/Dataclass models)¶
This version uses structured types for inputs and outputs. The contract table below lets you unfold each type to see its internal structure.
Contract¶
evaluate_credit_typed
Evaluate a credit request using structured types. Accepts a CreditRequest and returns a FullCreditDecision with full details. The contract table will show the structure of both types.
| Inputs | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Parameter | Type | Default | |||||||||||||||
request | CreditRequest | — | |||||||||||||||
| |||||||||||||||||
| Parameter | Type | Default |
|---|---|---|
client_id * | str | — |
amount * | float | — |
score_threshold | int | 600 |
include_history | bool | True |
returnFullCreditDecisionFullCreditDecision The full credit evaluation result.
| Parameter | Type | Default |
|---|---|---|
approved * | bool | — |
balance * | float | — |
history | CreditHistory | None | None |
reasons | list[str] | [] |
Data Models¶
class CreditRequest(BaseModel):
"""A structured credit evaluation request."""
client_id: str
amount: float
score_threshold: int = 600
include_history: bool = True
Source Code¶
def evaluate_credit_typed(request: CreditRequest) -> FullCreditDecision:
"""Evaluate a credit request using structured types.
Accepts a CreditRequest and returns a FullCreditDecision with full details.
The contract table will show the structure of both types.
"""
try:
result = CheckClientBalance().call(request.client_id)
except ServiceError:
return FullCreditDecision(
approved=False,
balance=0.0,
reasons=["Unable to verify balance"],
)
if result.balance <= request.amount:
return FullCreditDecision(
approved=False,
balance=result.balance,
reasons=["Insufficient balance"],
)
if not request.include_history:
return FullCreditDecision(approved=True, balance=result.balance)
history = CheckCreditHistory().call(request.client_id)
score_ok = history.score >= request.score_threshold
incidents_ok = history.incidents == 0
reasons = [
r for r in [
"Credit score too low" if not score_ok else None,
"Incidents detected" if not incidents_ok else None,
]
if r
]
return FullCreditDecision(
approved=score_ok and incidents_ok,
balance=result.balance,
history=history,
reasons=reasons if reasons else [],
)