Lease Processing Policy Engine
A 100% database-configurable policy engine where rules, conditions, operators, and actions are all stored in database tables. Nothing is hard-coded — add new policies without changing any PHP code.
100% Database-Driven
All rules stored in DB tables
Flexible Conditions
16+ operators, AND/OR logic
Approval Integration
Uses existing ApprovalEngine
Cumulative Execution
ALL matching policies run
How It Works
Policy Evaluation Process
Lease Processing Created
User submits a new lease application
Load Applicable Policies
Based on scope: Global → Region → Branch → Customer Type
Evaluate Each Policy's Conditions
Check if lease data matches configured rules
Execute ALL Matching Actions
Cumulative: every matched policy's actions run
Trigger Approvals if Needed
Uses existing ApprovalEngine for multi-level approval
flowchart TD
A[📄 New Lease] --> B{Load Policies}
B --> C[Policy 1]
B --> D[Policy 2]
B --> E[Policy N]
C --> F{Conditions Met?}
D --> G{Conditions Met?}
E --> H{Conditions Met?}
F -->|Yes| I[Execute Actions]
G -->|Yes| J[Execute Actions]
H -->|Yes| K[Execute Actions]
F -->|No| L[Skip]
G -->|No| L
H -->|No| L
I --> M{Any Approval
Required?}
J --> M
K --> M
L --> M
M -->|Yes| N[PENDING_APPROVAL]
M -->|No| O[ACTIVE]
style A fill:#7c3aed,stroke:#a78bfa
style N fill:#f59e0b,stroke:#fbbf24
style O fill:#10b981,stroke:#34d399
Complete Enum Reference
All valid enum values for the policy engine. Use these exact values when configuring policies in the database.
ScopeType
Defines where a policy applies (with inheritance)
lease_policy_scopes.scope_type
GLOBAL
Applies to all branches across the organization
scope_value: NULL
REGION
Applies to all branches within a specific region
scope_value: "Punjab", "Sindh"
BRANCH
Applies to a specific branch only
scope_value: "Lahore", "Karachi"
CUSTOMER_TYPE
Applies based on customer category
scope_value: "SALARIED", "VIP"
Inheritance: Policies are loaded in order: GLOBAL → REGION → BRANCH → CUSTOMER_TYPE. All applicable policies execute.
ConditionOperator
How to compare field values against thresholds
lease_policy_conditions.operator
| Operator | Symbol | Description | Value Format | Example |
|---|---|---|---|---|
| Equality Operators | ||||
EQUALS |
= | Exact match | Single value | "SALARIED" |
NOT_EQUALS |
≠ | Not equal to | Single value | "BLACKLISTED" |
| Comparison Operators | ||||
GREATER_THAN |
> | Value greater than threshold | NUMBER | "200000" |
LESS_THAN |
< | Value less than threshold | NUMBER | "500" |
GREATER_OR_EQUAL |
≥ | Value >= threshold | NUMBER | "100000" |
LESS_OR_EQUAL |
≤ | Value <= threshold | NUMBER | "24" |
| Range Operators | ||||
BETWEEN |
min ≤ x ≤ max | Value within range (inclusive) | JSON object | {"min": 100000, "max": 500000} |
NOT_BETWEEN |
x < min OR x > max | Value outside range | JSON object | {"min": 0, "max": 50000} |
| List Operators | ||||
IN |
∈ | Value exists in list | JSON array | ["electronics", "furniture"] |
NOT_IN |
∉ | Value not in list | JSON array | ["blacklisted", "rejected"] |
| String Operators | ||||
CONTAINS |
*x* | String contains substring | STRING | "premium" |
NOT_CONTAINS |
!*x* | String does not contain | STRING | "test" |
STARTS_WITH |
x* | String starts with prefix | STRING | "VIP-" |
ENDS_WITH |
*x | String ends with suffix | STRING | "-GOLD" |
| Null Check Operators | ||||
IS_NULL |
= NULL | Field is null or empty | N/A | — |
IS_NOT_NULL |
≠ NULL | Field has a value | N/A | — |
ValueType
Data type of the condition value for proper parsing
lease_policy_conditions.value_type
NUMBER
Integers, decimals
"200000", "0.15"
STRING
Text values
"SALARIED", "VIP"
DATE
ISO date format
"2026-01-01"
BOOLEAN
True/False
"true", "false"
LIST
JSON arrays
["a", "b"]
ActionType
What happens when policy conditions are met
lease_policy_actions.action_type
REQUIRE_APPROVAL
Triggers approval workflow via the existing ApprovalEngine
action_config: {
"approval_setup_id": 5, // References approval_setups.id
"notification_type": "LEASE_HIGHVALUE_CREATE" // Base type, system appends _APPROVAL/_APPROVED/_REJECTED
}
BLOCK
Completely blocks the lease processing with an error
action_config: {
"reason": "Customer is blacklisted",
"error_code": "BLK_BLACKLIST_001"
}
ADD_FEE
Adds additional fees to the lease (fixed amount or percentage)
action_config: {
"fee_type": "risk_premium", // or "verification_fee", "processing_fee"
"amount": 5000, // Fixed amount (PKR)
"percent": null, // OR percentage of total
"description": "High-risk customer premium"
}
NOTIFY
Sends notifications to specified users/roles
action_config: {
"recipients": ["branch_manager", "risk_officer", "compliance"],
"template": "high_value_lease_notification",
"channels": ["email", "in_app"]
}
MODIFY_TERMS
Automatically modifies lease terms based on policy
action_config: {
"increase_advance_percent": 10, // Add 10% to required advance
"reduce_max_tenure": 6, // Reduce max tenure by 6 months
"increase_interest_rate": 0.5 // Add 0.5% to interest rate
}
LogicGroup
How multiple conditions are combined
lease_policy_conditions.logic_group
AND
All conditions must be TRUE
-- Both must be true to trigger policy
total_amount > 200000 AND item_count > 5
-- Evaluation: TRUE AND TRUE = TRUE
-- TRUE AND FALSE = FALSE
Use AND when you want ALL conditions to be satisfied.
OR
At least one condition must be TRUE
-- Either triggers the policy
total_amount > 500000 OR customer_type = 'NEW'
-- Evaluation: TRUE OR FALSE = TRUE
-- FALSE OR TRUE = TRUE
Use OR when ANY condition being true should trigger.
Complex Condition Grouping (group_order)
-- Group 1 (AND): High amount AND many items
-- Group 2 (OR): OR customer is new
(total_amount > 200000 AND item_count > 3) OR (customer_type = 'NEW')
-- Database records:
INSERT INTO lease_policy_conditions (policy_id, field_name, operator, value, logic_group, group_order) VALUES
(1, 'total_amount', 'GREATER_THAN', '200000', 'AND', 1), -- Group 1
(1, 'item_count', 'GREATER_THAN', '3', 'AND', 1), -- Group 1
(1, 'customer_type', 'EQUALS', 'NEW', 'OR', 2); -- Group 2 (OR with Group 1)
CustomerType
Valid values for customer_type field and CUSTOMER_TYPE scope
SALARIED
Fixed salary employees
SELF_EMPLOYED
Freelancers, contractors
BUSINESS
Business owners
PENSIONER
Retired with pension
GOVERNMENT
Govt employees
CORPORATE
B2B corporate clients
VIP
Premium customers
NEW
First-time customers
ItemCategory
Valid values for item_categories field (use with IN operator)
electronics
furniture
appliances
mobile
computer
solar
generator
vehicle
machinery
other
NotificationType (Base Values)
Base notification types stored in policy config. System appends _APPROVAL/_APPROVED/_REJECTED
Store only the base type. ApprovalEngine appends status suffix automatically.
LEASE_HIGHVALUE_CREATE
High value lease creation
LEASE_MULTIITEM_CREATE
Multiple items lease
LEASE_HIGHRISK_CREATE
High risk customer
LEASE_NEWCUSTOMER_CREATE
New customer verification
LEASE_LONGTERM_CREATE
Long duration lease
LEASE_BRANCH_CREATE
Branch-specific policy
Database Schema
erDiagram
lease_policies {
bigint id PK "1"
string policy_name "High Risk Auto Lease"
string policy_code UK "AUTO-HIGH-RISK-001"
text description "Requires additional approval for customers with credit score below 650"
boolean is_active "true"
int priority "10"
timestamp effective_from "2024-01-01"
timestamp effective_to "2025-12-31"
bigint created_by FK "100"
timestamp created_at "2024-01-15 09:30:00"
timestamp updated_at "2024-06-20 14:15:00"
}
lease_policy_scopes {
bigint id PK "101"
bigint policy_id FK "1"
string scope_type "REGION"
string scope_value "US-WEST"
}
lease_policy_scopes {
bigint id PK "102"
bigint policy_id FK "1"
string scope_type "CUSTOMER_TYPE"
string scope_value "NEW_CUSTOMER"
}
lease_policy_conditions {
bigint id PK "201"
bigint policy_id FK "1"
string field_name "credit_score"
string operator "LESS_THAN"
text value "650"
string value_type "NUMBER"
string logic_group "AND"
int group_order "1"
}
lease_policy_conditions {
bigint id PK "202"
bigint policy_id FK "1"
string field_name "vehicle_value"
string operator "GREATER_THAN"
text value "50000"
string value_type "NUMBER"
string logic_group "AND"
int group_order "2"
}
lease_policy_conditions {
bigint id PK "203"
bigint policy_id FK "1"
string field_name "employment_status"
string operator "EQUALS"
text value "SELF_EMPLOYED"
string value_type "STRING"
string logic_group "OR"
int group_order "1"
}
lease_policy_actions {
bigint id PK "301"
bigint policy_id FK "1"
string action_type "REQUIRE_APPROVAL"
json action_config "{ approver_level: 'SENIOR_MANAGER', timeout_hours: 48 }"
}
lease_policy_actions {
bigint id PK "302"
bigint policy_id FK "1"
string action_type "ADD_FEE"
json action_config "{ fee_code: 'RISK_PREMIUM', amount: 500, currency: 'USD' }"
}
lease_policy_evaluations {
bigint id PK "10001"
bigint lease_processing_id FK "5001"
bigint policy_id FK "1"
boolean condition_met "true"
json evaluation_details "{ matched_conditions: ['credit_score', 'vehicle_value'] }"
string result_action "REQUIRE_APPROVAL"
timestamp evaluated_at "2024-02-15 10:23:45"
}
approval_setups {
bigint id PK "401"
string model_type "LEASE_APPLICATION"
string action "RISK_POLICY_APPROVAL"
boolean is_active "true"
}
lease_policies ||--o{ lease_policy_scopes : has
lease_policies ||--o{ lease_policy_conditions : has
lease_policies ||--o{ lease_policy_actions : has
lease_policies ||--o{ lease_policy_evaluations : logs
lease_policy_actions }o--|| approval_setups : references
Table Definitions
lease_policies
Master policy definitions
CREATE TABLE lease_policies (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
policy_name VARCHAR(255) NOT NULL,
policy_code VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
is_active BOOLEAN DEFAULT TRUE,
priority INT DEFAULT 0, -- Higher = first
effective_from TIMESTAMP NULL,
effective_to TIMESTAMP NULL,
created_by BIGINT REFERENCES users(id),
created_at TIMESTAMP,
updated_at TIMESTAMP
);
lease_policy_scopes
Where policies apply
CREATE TABLE lease_policy_scopes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
policy_id BIGINT REFERENCES lease_policies(id),
scope_type ENUM('GLOBAL','REGION','BRANCH','CUSTOMER_TYPE'),
scope_value VARCHAR(255) NULL,
UNIQUE(policy_id, scope_type, scope_value)
);
-- Examples:
-- GLOBAL, NULL → All branches
-- REGION, 'Punjab' → Punjab region
-- BRANCH, 'Lahore' → Lahore only
-- CUSTOMER_TYPE, 'VIP' → VIP customers
lease_policy_conditions
Configurable rules
CREATE TABLE lease_policy_conditions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
policy_id BIGINT REFERENCES lease_policies(id),
field_name VARCHAR(100) NOT NULL,
operator ENUM(
'EQUALS','NOT_EQUALS',
'GREATER_THAN','LESS_THAN',
'GREATER_OR_EQUAL','LESS_OR_EQUAL',
'BETWEEN','NOT_BETWEEN',
'IN','NOT_IN',
'CONTAINS','NOT_CONTAINS',
'STARTS_WITH','ENDS_WITH',
'IS_NULL','IS_NOT_NULL'
) NOT NULL,
value TEXT NOT NULL,
value_type ENUM('NUMBER','STRING','DATE','BOOLEAN','LIST'),
logic_group ENUM('AND','OR') DEFAULT 'AND',
group_order INT DEFAULT 0
);
lease_policy_actions
What happens when conditions match
CREATE TABLE lease_policy_actions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
policy_id BIGINT REFERENCES lease_policies(id),
action_type ENUM(
'REQUIRE_APPROVAL',
'BLOCK',
'ADD_FEE',
'NOTIFY',
'MODIFY_TERMS'
) NOT NULL,
action_config JSON NOT NULL
);
-- action_config examples shown in ActionType enum above
Detailed Execution Flow
sequenceDiagram
autonumber
actor User
participant LW as Livewire
participant SVC as LeaseService
participant PE as PolicyEngine
participant DB as Database
participant AE as ApprovalEngine
User->>LW: Submit Lease
LW->>SVC: create(leaseData)
SVC->>DB: INSERT LeaseProcessing (DRAFT)
DB-->>SVC: lease_id
SVC->>PE: evaluate(lease)
activate PE
PE->>DB: SELECT policies WHERE scope matches
DB-->>PE: policies[]
loop Each Policy (by priority)
PE->>DB: SELECT conditions WHERE policy_id
DB-->>PE: conditions[]
PE->>PE: evaluateConditions(lease, conditions)
alt Conditions Match
PE->>DB: SELECT actions WHERE policy_id
DB-->>PE: actions[]
loop Each Action
alt REQUIRE_APPROVAL
PE->>AE: createRequest(setup_id, lease_id)
else ADD_FEE
PE->>SVC: addFee(lease, config)
else MODIFY_TERMS
PE->>SVC: modifyTerms(lease, config)
else NOTIFY
PE->>PE: queueNotification(config)
end
end
PE->>DB: INSERT evaluation (MET)
else No Match
PE->>DB: INSERT evaluation (SKIPPED)
end
end
PE-->>SVC: {approvals_needed, fees_added, terms_modified}
deactivate PE
alt approvals_needed
SVC->>DB: UPDATE status = PENDING_APPROVAL
else
SVC->>DB: UPDATE status = ACTIVE
end
SVC-->>LW: Result
LW-->>User: Show Status
Approval Engine Integration
Uses Existing ApprovalEngine
The Policy Engine doesn't create a new approval system. It uses the existing
ApprovalEngineService with
ApprovalSetup and
ApprovalRequest tables.
flowchart LR
subgraph Policy["Policy Engine"]
P["Policy: HVL_APPROVAL"]
C["Condition: amount > 200K"]
A["Action: REQUIRE_APPROVAL
approval_setup_id: 5"]
end
subgraph Approval["Existing ApprovalEngine"]
AS["ApprovalSetup (ID: 5)
model_type: LeaseProcessing"]
ASS["ApprovalSetupSteps
1. Branch Manager
2. Regional Director"]
AR["ApprovalRequest
status: PENDING"]
end
subgraph Lease["LeaseProcessing"]
LP["Status: PENDING_APPROVAL"]
end
P --> C
C -->|Match| A
A -->|Creates| AR
AS --> ASS
AS --> AR
AR --> LP
style Policy fill:#1a1a3e,stroke:#8b5cf6
style Approval fill:#1a3a2e,stroke:#10b981
Policy Action Config:
{
"approval_setup_id": 5,
"notification_type": "LEASE_HIGHVALUE_CREATE" // Base type only
}
PolicyEngine Code:
if ($action->type === 'REQUIRE_APPROVAL') {
$this->approvalEngine->createRequest(
$config->approval_setup_id,
$config->notification_type, // LEASE_HIGHVALUE_CREATE
$leaseProcessing->id
);
}
Notification Type Pattern
Standard Naming Convention
{OPERATION}_{POLICY}_{ACTION}_{STATUS}
All notification types in the ERP follow this naming convention. This ensures consistency across modules. The Policy Engine stores the base type (without status), and the ApprovalEngine appends the status suffix automatically.
OPERATION
Module/Entity
LEASE
POLICY
Policy type (optional)
HIGHVALUE
ACTION
CRUD operation
CREATE
STATUS
Auto-appended
_APPROVAL
How Notifications Are Generated
flowchart LR
subgraph Policy["Policy Action Config"]
B["notification_type:
LEASE_HIGHVALUE_CREATE"]
end
subgraph System["ApprovalEngine Appends"]
S1["+ _APPROVAL"]
S2["+ _APPROVED"]
S3["+ _REJECTED"]
end
subgraph Final["Final Notification Keys"]
F1["LEASE_HIGHVALUE_CREATE_APPROVAL
→ Sent to approvers"]
F2["LEASE_HIGHVALUE_CREATE_APPROVED
→ Sent to initiator"]
F3["LEASE_HIGHVALUE_CREATE_REJECTED
→ Sent to initiator"]
end
B --> S1 --> F1
B --> S2 --> F2
B --> S3 --> F3
style Policy fill:#1a1a3e,stroke:#8b5cf6
style System fill:#2a1a1a,stroke:#f43f5e
style Final fill:#1a2e1a,stroke:#10b981
Complete Lease Notification Types
| Full Notification Type | Trigger | Recipient | Policy Context |
|---|---|---|---|
LEASE_HIGHVALUE_CREATE_APPROVAL |
Policy match (>200K) | Next Approver | High Value |
LEASE_HIGHVALUE_CREATE_APPROVED |
Final approval | Salesperson | High Value |
LEASE_HIGHVALUE_CREATE_REJECTED |
Rejection | Salesperson | High Value |
LEASE_NEWCUSTOMER_CREATE_APPROVAL |
First-time customer | Next Approver | New Customer |
LEASE_NEWCUSTOMER_CREATE_APPROVED |
Verified & approved | Salesperson | New Customer |
LEASE_NEWCUSTOMER_CREATE_REJECTED |
Verification failed | Salesperson | New Customer |
LEASE_HIGHRISK_CREATE_APPROVAL |
Low credit score | Risk Officer | High Risk |
LEASE_HIGHRISK_CREATE_APPROVED |
Risk accepted | Salesperson | High Risk |
LEASE_HIGHRISK_CREATE_REJECTED |
Risk declined | Salesperson | High Risk |
config/approvals.php - Lease Policy Entries
return [
// ─────────────────────────────────────────────
// HIGH VALUE LEASE NOTIFICATIONS
// ─────────────────────────────────────────────
'LEASE_HIGHVALUE_CREATE_APPROVAL' => [
'title' => 'High Value Lease - Approval Required',
'action_url' => '/approvals/{id}',
'message' => '{causer} submitted high value lease #{display} (PKR {amount}) for approval',
'type' => 'LEASE_HIGHVALUE_CREATE_APPROVAL',
],
'LEASE_HIGHVALUE_CREATE_APPROVED' => [
'title' => 'High Value Lease - Approved',
'action_url' => '/leases/{id}',
'message' => 'Your high value lease #{display} has been approved by {approver}',
'type' => 'LEASE_HIGHVALUE_CREATE_APPROVED',
],
'LEASE_HIGHVALUE_CREATE_REJECTED' => [
'title' => 'High Value Lease - Rejected',
'action_url' => '/leases/{id}',
'message' => 'Your high value lease #{display} was rejected. Reason: {remarks}',
'type' => 'LEASE_HIGHVALUE_CREATE_REJECTED',
],
// ─────────────────────────────────────────────
// NEW CUSTOMER LEASE NOTIFICATIONS
// ─────────────────────────────────────────────
'LEASE_NEWCUSTOMER_CREATE_APPROVAL' => [
'title' => 'New Customer Lease - Verification Required',
'action_url' => '/approvals/{id}',
'message' => '{causer} submitted first-time customer lease #{display} for verification',
'type' => 'LEASE_NEWCUSTOMER_CREATE_APPROVAL',
],
'LEASE_NEWCUSTOMER_CREATE_APPROVED' => [
'title' => 'New Customer Lease - Verified',
'action_url' => '/leases/{id}',
'message' => 'New customer lease #{display} verified and approved',
'type' => 'LEASE_NEWCUSTOMER_CREATE_APPROVED',
],
'LEASE_NEWCUSTOMER_CREATE_REJECTED' => [
'title' => 'New Customer Lease - Rejected',
'action_url' => '/leases/{id}',
'message' => 'New customer lease #{display} rejected. Reason: {remarks}',
'type' => 'LEASE_NEWCUSTOMER_CREATE_REJECTED',
],
// ... more policy notification types
];
Notification Flow Sequence
sequenceDiagram
autonumber
participant S as Salesperson
participant PE as PolicyEngine
participant AE as ApprovalEngine
participant NS as NotificationService
participant M as Manager
S->>PE: Submit Lease (350K)
PE->>PE: Evaluate: High Value Policy Matched
PE->>AE: createRequest(setup_id, "LEASE_HIGHVALUE_CREATE", lease_id)
AE->>AE: Append "_APPROVAL" suffix
AE->>NS: send("LEASE_HIGHVALUE_CREATE_APPROVAL", manager_id)
NS->>M: 📧 "High Value Lease - Approval Required"
alt Manager Approves
M->>AE: approve(request_id)
AE->>AE: Append "_APPROVED" suffix
AE->>NS: send("LEASE_HIGHVALUE_CREATE_APPROVED", salesperson_id)
NS->>S: 📧 "High Value Lease - Approved"
else Manager Rejects
M->>AE: reject(request_id, remarks)
AE->>AE: Append "_REJECTED" suffix
AE->>NS: send("LEASE_HIGHVALUE_CREATE_REJECTED", salesperson_id)
NS->>S: 📧 "High Value Lease - Rejected"
end
Key Point
The Policy Engine only stores the base notification type
(e.g., LEASE_HIGHVALUE_CREATE). The
ApprovalEngine automatically appends the status suffix
(_APPROVAL, _APPROVED,
or _REJECTED) based on the workflow action.
Live Scenarios
1 High-Value Lease: PKR 350,000
LEASE DATA
POLICY EVALUATION
HVL_APPROVAL
350K > 200K
MULTI_ITEM
3 ≤ 5
NEW_CUST
prev=2 ≠ 0
ACTIONS EXECUTED
REQUIRE_APPROVAL
→ Branch Manager approval
Final Status:
PENDING_APPROVAL
2 High-Risk: Multiple Policies Triggered
LEASE DATA
4 POLICIES MATCHED
HVL_APPROVAL
MULTI_ITEM
HIGH_RISK
NEW_CUST
CUMULATIVE ACTIONS
REQUIRE_APPROVAL x4ADD_FEE PKR 2,500MODIFY_TERMS +10% advanceNOTIFY Risk TeamCumulative Execution: ALL 4 policies run. Customer must get 4 separate approvals, pays extra fee, and advance requirement increases.
Sample Database Records
-- =============================================
-- POLICY 1: High Value Lease Approval
-- =============================================
INSERT INTO lease_policies
(policy_name, policy_code, description, is_active, priority)
VALUES
('High Value Lease', 'HVL_APPROVAL', 'Approval for leases > 200K', TRUE, 100);
INSERT INTO lease_policy_scopes (policy_id, scope_type, scope_value)
VALUES (1, 'GLOBAL', NULL);
INSERT INTO lease_policy_conditions
(policy_id, field_name, operator, value, value_type, logic_group)
VALUES
(1, 'total_amount', 'GREATER_THAN', '200000', 'NUMBER', 'AND');
INSERT INTO lease_policy_actions (policy_id, action_type, action_config)
VALUES (1, 'REQUIRE_APPROVAL', '{"approval_setup_id": 5, "notification_type": "LEASE_HIGHVALUE_CREATE"}');
-- =============================================
-- POLICY 2: Multi-Item Review (items > 5)
-- =============================================
INSERT INTO lease_policies
(policy_name, policy_code, description, is_active, priority)
VALUES
('Multi-Item Review', 'MULTI_ITEM', 'Review for 5+ items', TRUE, 90);
INSERT INTO lease_policy_scopes (policy_id, scope_type, scope_value)
VALUES (2, 'GLOBAL', NULL);
INSERT INTO lease_policy_conditions
(policy_id, field_name, operator, value, value_type, logic_group)
VALUES
(2, 'item_count', 'GREATER_THAN', '5', 'NUMBER', 'AND');
INSERT INTO lease_policy_actions (policy_id, action_type, action_config)
VALUES (2, 'REQUIRE_APPROVAL', '{"approval_setup_id": 6, "notification_type": "LEASE_MULTIITEM_CREATE"}');
-- =============================================
-- POLICY 3: High Risk (low credit + high amount)
-- =============================================
INSERT INTO lease_policies
(policy_name, policy_code, description, is_active, priority)
VALUES
('High Risk Customer', 'HIGH_RISK', 'Low credit + high value', TRUE, 110);
INSERT INTO lease_policy_scopes (policy_id, scope_type, scope_value)
VALUES (3, 'GLOBAL', NULL);
-- Two conditions with AND logic
INSERT INTO lease_policy_conditions
(policy_id, field_name, operator, value, value_type, logic_group, group_order)
VALUES
(3, 'customer_credit_score', 'LESS_THAN', '500', 'NUMBER', 'AND', 1),
(3, 'total_amount', 'GREATER_THAN', '100000', 'NUMBER', 'AND', 1);
-- Multiple actions
INSERT INTO lease_policy_actions (policy_id, action_type, action_config)
VALUES
(3, 'REQUIRE_APPROVAL', '{"approval_setup_id": 7, "notification_type": "LEASE_HIGHRISK_CREATE"}'),
(3, 'MODIFY_TERMS', '{"increase_advance_percent": 10}'),
(3, 'NOTIFY', '{"recipients": ["risk_officer"], "template": "high_risk_alert"}');
-- =============================================
-- POLICY 4: Branch-Specific (Karachi Electronics)
-- =============================================
INSERT INTO lease_policies
(policy_name, policy_code, description, is_active, priority)
VALUES
('Karachi Electronics', 'KHI_ELECTRONICS', 'Karachi branch electronics policy', TRUE, 80);
-- Branch-specific scope
INSERT INTO lease_policy_scopes (policy_id, scope_type, scope_value)
VALUES (4, 'BRANCH', 'Karachi');
-- Using IN operator for categories
INSERT INTO lease_policy_conditions
(policy_id, field_name, operator, value, value_type, logic_group, group_order)
VALUES
(4, 'item_categories', 'IN', '["electronics", "mobile", "computer"]', 'LIST', 'AND', 1),
(4, 'total_amount', 'GREATER_THAN', '150000', 'NUMBER', 'AND', 1);
INSERT INTO lease_policy_actions (policy_id, action_type, action_config)
VALUES (4, 'REQUIRE_APPROVAL', '{"approval_setup_id": 8, "notification_type": "LEASE_BRANCH_CREATE"}');
Evaluable Fields
These field names can be used in lease_policy_conditions.field_name
Financial
total_amount- Total lease valueadvance_amount- Advance paymentmonthly_installment- EMIprocessing_fee- Feestotal_payable- With interest
Item-Related
item_count- Number of itemsitem_categories- Category listitem_total_value- Items pricehas_electronics- Boolean
Customer
customer_credit_score- Scorecustomer_type- See enumcustomer_income- Monthlycustomer_previous_leases- Countcustomer_status- Active/Blacklisted
Lease Terms
duration_months- Tenureinterest_rate- Rate %advance_percent- Advance %plan_type- Plan code
Historical
customer_default_count- Defaultscustomer_on_time_payments- %customer_total_leased- Lifetime
Context
branch_code- Current branchregion_code- Current regionprocessing_date- Datecreated_by_role- User role
Implementation Roadmap
Phase 1: Database Schema
- □ Create migrations for all 5 tables
- □ Create Eloquent models with relationships
- □ Add database seeders with sample policies
Phase 2: PolicyEngine Core
- □ Create PolicyEngineService class
- □ Implement ConditionEvaluator with all 16 operators
- □ Implement ActionExecutor for all 5 action types
- □ Implement scope-based policy loading
Phase 3: Integration
- □ Integrate with existing ApprovalEngineService
- □ Update LeaseProcessingService to call PolicyEngine
- □ Create notification templates
Phase 4: Testing
- □ Unit tests for ConditionEvaluator
- □ Integration tests for PolicyEngine
- □ Feature tests for complete flows