The Credit Bureau Routing Framework provides a comprehensive, flexible system for integrating and managing multiple credit bureau providers in the Axion platform. It enables intelligent routing, load distribution, failover handling, and dynamic bureau selection without code changes.
Version: Axion 8.x
Package: factory.service/package.homechoice
Branch: feat/hc_bureau
The framework uses a layered architecture with three main components:
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ (Workflows, Forms, API Calls) │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ObjServiceBureauRouter │
│ (Strategy Selection & Orchestration) │
│ │
│ • Query def_bureau_strategy table │
│ • Apply date range filters │
│ • RDG-based load distribution (0-100) │
│ • Failover handling │
│ • Dual bureau calls │
│ • Default bureau fallback │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ObjServiceBureau (Base Framework) │
│ │
│ • Bureau class registry │
│ • Remote connection management │
│ • Buffer management (prevent duplicate calls) │
│ • Standard workflow integration │
│ • Simulation mode support │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Experian │ │ MyData │ │ Future │
│ (SOAP) │ │ (REST) │ │ Bureaus │
│ │ │ │ │ │
│ • XML req │ │ • JSON req │ │ • ... │
│ • Zipped │ │ • Direct │ │ │
│ response │ │ JSON │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
1. Application initiates bureau check
└─→ Calls ObjServiceBureauRouter.resolve(guid)
2. Router queries strategy table
└─→ SELECT * FROM def_bureau_strategy
WHERE (StartDate IS NULL OR StartDate <= CURDATE())
AND (EndDate IS NULL OR EndDate >= CURDATE())
3. Strategy selection
├─→ If strategies found:
│ ├─→ Generate random number 0-100
│ ├─→ Find strategy where RDG_Start <= random <= RDG_End
│ └─→ Use selected bureau
│
└─→ If no strategies found:
└─→ Query default bureau (Default='Y')
4. Bureau instantiation
└─→ Get bureau class from registry
└─→ ObjServiceBureau.get_bureau_class(code)
5. Execute bureau call
├─→ Standard call: call_bureau(code, guid)
├─→ Dual bureau: call_dual_bureau(primary, dual, guid)
└─→ Failover: call_with_failover(primary, failover, guid)
6. Buffer check (within bureau)
├─→ Check if ID number has recent result
├─→ If yes: Copy buffered result to new GUID
└─→ If no: Make API call to bureau
7. API call execution
├─→ Load applicant data from database
├─→ Build bureau-specific request (SOAP/REST/etc)
├─→ Call bureau API endpoint
├─→ Parse response
└─→ Store in bloom tables
8. Return result
└─→ 1 = success, 0 = failure
Purpose: Base class framework for all bureau integrations
Key Features:
def_remoteconnectionsKey Methods:
register_bureau(code, class) - Register implementationget_bureau_class(code) - Get implementation by coderesolve(guid, id_number) - Execute API call (override in subclasses)check_buffer(idnumber) - Check for recent resultsresolve_buffer(guid, idnumber, buffer_time) - Use buffered resultWhen to Use: Never instantiate directly; always subclass for specific bureau
Purpose: Intelligent routing and strategy management
Key Features:
Key Methods:
get_active_strategies() - Query strategy tableget_default_bureau() - Get fallback bureauselect_bureau_by_rdg(strategies) - Random distributioninstantiate_bureau(code, DB) - Dynamic instantiationcall_bureau(code, guid) - Single bureau callcall_dual_bureau(primary, dual, guid) - Two bureauscall_with_failover(primary, failover, guid) - With fallbackresolve(guid, id_number) - Main entry pointWhen to Use: Use as primary entry point for all bureau calls
Purpose: Experian SOAP API integration
Protocol: SOAP XML with base64-encoded ZIP response
Current Status: Legacy implementation, needs migration to framework
Bureau Code: "EXPERIAN"
Purpose: MyData REST API integration (reference implementation)
Protocol: REST/HTTPS with JSON
Authentication: Bearer token
Bureau Code: "MYDATA"
Status: Complete, registered with framework
CREATE TABLE IF NOT EXISTS `def_bureau_strategy` (
`BureauCode` char(50) DEFAULT NULL, -- Primary bureau identifier
`StartDate` date DEFAULT NULL, -- Strategy active from this date
`EndDate` date DEFAULT NULL, -- Strategy active until this date
`RDG_Start` int(11) DEFAULT NULL, -- Random distribution start (0-100)
`RDG_End` int(11) DEFAULT NULL, -- Random distribution end (0-100)
`FailoverBureau` char(50) DEFAULT NULL, -- Backup bureau on failure
`DualBureau` char(50) DEFAULT NULL, -- Call both simultaneously
`Default` char(1) DEFAULT NULL -- Mark as default ('Y'/'1')
) ENGINE=InnoDB;
Control when strategies are active:
Example: Scheduled cutover from old to new bureau
-- Old bureau until June 30
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', '2026-01-01', '2026-06-30', 0, 100, NULL, NULL, NULL);
-- New bureau from July 1
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-01', NULL, 0, 100, NULL, NULL, NULL);
Split traffic using persistent random values 0-100:
data_rdg_idnumber)RDG_Start <= rdg_value <= RDG_EndKey Benefit: Same ID number always routes to same bureau
Example: 70% Experian, 30% MyData
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 70, NULL, NULL, NULL);
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', NULL, NULL, 71, 100, NULL, NULL, NULL);
How It Works:
ID 8901015800082:
First call → RDG1=45 assigned → Routes to EXPERIAN (always)
Second call → RDG1=45 (same) → Routes to EXPERIAN (always)
ID 9001015800083:
First call → RDG1=78 assigned → Routes to MYDATA (always)
Second call → RDG1=78 (same) → Routes to MYDATA (always)
Rollout Strategy:
Week 1: 10% new bureau (0-10 new, 11-100 old) ← 10% of IDs permanently assigned to new
Week 2: 25% new bureau (0-25 new, 26-100 old) ← Additional 15% of IDs move to new
Week 3: 50% new bureau (0-50 new, 51-100 old) ← Additional 25% of IDs move to new
Week 4: 100% new bureau (0-100 new) ← All IDs now on new bureau
Note: IDs that moved to new bureau in Week 1 stay there in subsequent weeks
Automatic backup on primary failure:
Example: Experian with MyData failover
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, 'MYDATA', NULL, NULL);
Use Cases:
Call two bureaus for every request:
Example: Compliance requirement for dual checks
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, NULL, 'MYDATA', NULL);
Use Cases:
Fallback when no strategy matches:
Example: Safety net configuration
-- Active strategies
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-01', '2026-12-31', 0, 100, NULL, NULL, NULL);
-- Default fallback
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, NULL, NULL, NULL, NULL, 'Y');
Trigger Conditions:
The framework integrates with ObjNotify to automatically alert administrators when bureau connections fail. This provides real-time visibility into API issues and enables rapid response.
Notifications are automatically sent when:
Bureau Instantiation Failure
BUREAU_{code}_FAILUREAPI Call Failure
BUREAU_{code}_FAILUREDual Bureau Failure
BUREAU_{code}_DUAL_FAILUREFailover Complete Failure
BUREAU_{code}_FAILOVER_FAILUREEach notification includes:
Example notification:
Bureau connection failure: EXPERIAN
Error: Bureau API call returned failure status
Request GUID: abc123def456
Package: homechoice
Deployment: production
Notifications support multiple delivery channels:
Set up bureau notifications using the provided SQL script:
# Run notification setup SQL
mysql -u user -p database < bureau_notifications_setup.sql
This creates notification codes for:
Notification Codes:
BUREAU_FAILURE - General fallbackBUREAU_EXPERIAN_FAILURE - Experian-specificBUREAU_MYDATA_FAILURE - MyData-specificBUREAU_EXPERIAN_DUAL_FAILURE - Critical dual failureBUREAU_EXPERIAN_FAILOVER_FAILURE - Critical failover failureNotifications are sent to configured user groups:
Configure user group membership in def_usergroupmembers table.
The framework uses intelligent notification logic to reduce alert fatigue:
Single Bureau Call:
Dual Bureau:
Failover:
This ensures:
Test notification setup:
# Test Experian failure notification
from ObjNotify import ObjNotify
notify = ObjNotify()
notify.Run('BUREAU_EXPERIAN_FAILURE', 'Test alert - please ignore')
Verify delivery on configured channels (Slack, email, etc.).
ObjNotify supports multiple modes (configured in def_notify.NotifyMode):
Choose based on your deployment architecture.
To temporarily disable bureau failure notifications:
-- Disable Experian failure notifications
UPDATE def_notify
SET Active = '0'
WHERE Notifycode = 'BUREAU_EXPERIAN_FAILURE';
Re-enable by setting Active = '1'.
Configure bureau API endpoints in def_remoteconnections:
-- Experian SOAP API
INSERT INTO def_remoteconnections (
Remote,
RemoteURL,
Username,
RemotePassword,
RemoteInitSql,
basedir,
Package,
Deployment,
Active
) VALUES (
'NORMALSEARCHSERVICE_SA_PROD',
'https://api.experian.co.za/services/NormalSearch?wsdl',
'api_username',
'api_password',
'SELECT idnumber, gender, dob, firstname, surname, passportflag,
birthdate, application_channel
FROM bloom_hcscore WHERE _guid = $guid$',
'bloom_hcscore',
'homechoice',
'production',
'1'
);
-- MyData REST API
INSERT INTO def_remoteconnections (
Remote,
RemoteURL,
Username,
RemotePassword,
RemoteInitSql,
basedir,
Package,
Deployment,
Active
) VALUES (
'MYDATA_API_PROD',
'https://api.mydata.example.com/v1/credit-check',
'api_user',
'bearer_token_here',
'SELECT idnumber, gender, dob, firstname, surname, passportflag,
birthdate, application_channel
FROM bloom_hcscore WHERE _guid = $guid$',
'bloom_hcscore',
'homechoice',
'production',
'1'
);
Important Fields:
get_remote_connection_pattern()$guid$ placeholder)Set buffer time in data_dim_constants:
INSERT INTO data_dim_constants (Varname, varvalue, Description)
VALUES ('BufferTime', '9', 'Days to buffer bureau results');
Buffer Behavior:
bloom_donormalenquiryConfigure routing strategies in def_bureau_strategy:
-- Example 1: Simple 100% routing
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('EXPERIAN', 0, 100);
-- Example 2: Date-based cutover
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, '2026-06-30', 0, 100, NULL, NULL, NULL);
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-01', NULL, 0, 100, NULL, NULL, NULL);
-- Example 3: Load distribution with failover
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 70, 'MYDATA', NULL, NULL);
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', NULL, NULL, 71, 100, NULL, NULL, NULL);
-- Example 4: Dual bureau for compliance
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, NULL, 'MYDATA', NULL);
-- Example 5: Default fallback
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, NULL, NULL, NULL, NULL, 'Y');
Configure persistent RDG tables for consistent routing:
Step 1: Create def_random configuration table
CREATE TABLE IF NOT EXISTS def_random (
Package VARCHAR(50) NOT NULL,
RDCode VARCHAR(50) NOT NULL,
PrimaryGuid VARCHAR(50) NOT NULL,
RDGFields INT DEFAULT 1,
Description TEXT,
Active CHAR(1) DEFAULT 'Y',
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (Package, RDCode)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Step 2: Add bureau routing configuration
INSERT INTO def_random (Package, RDCode, PrimaryGuid, RDGFields, Description, Active)
VALUES ('homechoice', 'BUREAU_ROUTING', 'idnumber', 1, 'Bureau routing with persistent RDG', 'Y');
Step 3: Create RDG storage table (automatic or manual)
Option A - Automatic (recommended):
Option B - Manual:
python factory.core/ObjRandom.py create-rdg BUREAU_ROUTING
Result: data_rdg_idnumber table created:
CREATE TABLE data_rdg_idnumber (
idnumber VARCHAR(255) NOT NULL,
RDG1 INT DEFAULT NULL,
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (idnumber)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
How Persistent RDG Works:
First request for ID 8901015800082:
data_rdg_idnumber - not foundAll future requests for ID 8901015800082:
data_rdg_idnumber - found: RDG1=45Benefit: Same ID always routes to same bureau!
Step 1: Create bureau service class
# factory.service/package.homechoice/ObjServiceYourBureau.py
import os
import sys
import json
import requests
base_path = os.getcwd()
paths = ["", "/factory.core", "/factory.service",
"/factory.service/package.homechoice"]
for relative_path in paths:
if (base_path + relative_path) not in sys.path:
sys.path.append(base_path + relative_path)
from ObjServiceBureau import ObjServiceBureau
from ObjConstants import BLOOM_DONORMALENQUIRY
class ObjServiceApi(ObjServiceBureau):
"""Your Bureau API integration."""
def __init__(self, DB=0):
self.service_code = "YOURBUREAU"
self.buffer_table = BLOOM_DONORMALENQUIRY
super().__init__(DB)
self._IsA = "YourBureau"
def get_bureau_code(self):
"""Return bureau identifier."""
return "YOURBUREAU"
def get_remote_connection_pattern(self):
"""Return SQL LIKE pattern for connection lookup."""
return "YOURBUREAU_API%"
def resolve(self, guid="", id_number=""):
"""
Execute API call and process response.
Returns:
int: 1 for success, 0 for failure
"""
# 1. Load applicant data
lookup = self.InitSql.replace("$guid$", guid)
(idnumber, gender, dob, firstname, surname,
passportflag, birthdate, application_channel) = \
self.sql_get_values(lookup)
# 2. Check buffer
if self.check_buffer(idnumber):
self.resolve_buffer(guid, idnumber, self.get_buffer_time())
return 1
# 3. Build API request (customize for your bureau)
payload = {
"idNumber": idnumber,
"firstName": firstname,
"surname": surname
}
headers = {"Authorization": f"Bearer {self.Password}"}
# 4. Call API
try:
response = requests.post(
self.Url,
json=payload,
headers=headers,
timeout=30
)
response.raise_for_status()
json_data = response.json()
call_success = 1
except requests.exceptions.RequestException as e:
self.debug(f"API call failed: {e}")
call_success = 0
# 5. Store results
if call_success:
variables = json_data.get("data", {})
self.bloom_table_data_structure(
variables,
table_base=f"bloom_{self.service_code}",
bloom_guid=self.Guid,
base_guid=self.Guid,
base_guid_in="guid"
)
return call_success
# Register with framework
ObjServiceBureau.register_bureau("YOURBUREAU", ObjServiceApi)
if __name__ == '__main__':
import sys
service = ObjServiceApi()
if len(sys.argv) > 1:
service.run_workflow_direct(sys.argv[1])
Step 2: Configure remote connection
INSERT INTO def_remoteconnections
VALUES ('YOURBUREAU_API_PROD', 'https://api.yourbureau.com/check',
'user', 'token', 'SELECT ... FROM bloom_hcscore WHERE _guid = $guid$',
'bloom_hcscore', 'homechoice', 'production', '1');
Step 3: Add to strategy table
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('YOURBUREAU', 0, 100);
Step 4: Test integration
# Direct test
python ObjServiceYourBureau.py {test_guid}
# Through router
python ObjServiceBureauRouter.py {test_guid}
# Before
class ObjServiceApi(ObjApi.ObjApi):
# After
from ObjServiceBureau import ObjServiceBureau
class ObjServiceApi(ObjServiceBureau):
def get_bureau_code(self):
return "EXPERIAN"
def get_remote_connection_pattern(self):
return "NORMALSEARCHSERVICE_SA%"
# At module level, after class definition
ObjServiceBureau.register_bureau("EXPERIAN", ObjServiceApi)
# Replace hardcoded "bloom_donormalenquiry" with constant
from ObjConstants import BLOOM_DONORMALENQUIRY
# Use BLOOM_DONORMALENQUIRY in queries
# Test direct call still works
python ObjServiceHCExperian.py {test_guid}
# Test through router
python ObjServiceBureauRouter.py {test_guid}
Goal: Single bureau with default fallback
-- Primary bureau
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('EXPERIAN', 0, 100);
-- Default safety net
INSERT INTO def_bureau_strategy (BureauCode, `Default`)
VALUES ('EXPERIAN', 'Y');
Goal: Migrate from Experian to MyData over 4 weeks
-- Week 1: 10% to MyData
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-01', '2026-07-07', 0, 10, NULL, NULL, NULL);
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', '2026-07-01', '2026-07-07', 11, 100, NULL, NULL, NULL);
-- Week 2: 25% to MyData
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-08', '2026-07-14', 0, 25, NULL, NULL, NULL);
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', '2026-07-08', '2026-07-14', 26, 100, NULL, NULL, NULL);
-- Week 3: 50% to MyData
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-15', '2026-07-21', 0, 50, NULL, NULL, NULL);
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', '2026-07-15', '2026-07-21', 51, 100, NULL, NULL, NULL);
-- Week 4+: 100% to MyData
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-22', NULL, 0, 100, NULL, NULL, NULL);
-- Default fallback
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, NULL, NULL, NULL, NULL, 'Y');
Goal: Primary with automatic failover
-- Primary with failover
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, 'MYDATA', NULL, NULL);
-- Default
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, NULL, NULL, NULL, NULL, 'Y');
Goal: Call both bureaus for regulatory compliance
-- Dual bureau call
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, NULL, 'MYDATA', NULL);
-- Default
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, NULL, NULL, NULL, NULL, 'Y');
Goal: Test new bureau with 20% of traffic
-- 20% test group - MyData
INSERT INTO def_bureau_strategy
VALUES ('MYDATA', '2026-07-01', '2026-07-31', 0, 20, NULL, NULL, NULL);
-- 80% control group - Experian
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', '2026-07-01', '2026-07-31', 21, 100, NULL, NULL, NULL);
-- Default
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, NULL, NULL, NULL, NULL, 'Y');
Review current bureau integrations
Update ObjConstants.py
BLOOM_DONORMALENQUIRY constant addedDeploy framework files
ObjServiceBureau.pyObjServiceBureauRouter.pyObjServiceHCMyData.py (reference implementation)Create strategy table
CREATE TABLE IF NOT EXISTS `def_bureau_strategy` (
`BureauCode` char(50) DEFAULT NULL,
`StartDate` date DEFAULT NULL,
`EndDate` date DEFAULT NULL,
`RDG_Start` int(11) DEFAULT NULL,
`RDG_End` int(11) DEFAULT NULL,
`FailoverBureau` char(50) DEFAULT NULL,
`DualBureau` char(50) DEFAULT NULL,
`Default` char(1) DEFAULT NULL
) ENGINE=InnoDB;
Migrate ObjServiceHCExperian.py
ObjServiceBureauget_bureau_code() methodMigrate other Experian variants
Update buffer table references
BLOOM_DONORMALENQUIRYSet up default bureau
INSERT INTO def_bureau_strategy (BureauCode, `Default`)
VALUES ('EXPERIAN', 'Y');
Configure active strategies
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('EXPERIAN', 0, 100);
Test router
python ObjServiceBureauRouter.py list
python ObjServiceBureauRouter.py {test_guid}
Update workflow services
Monitor in production
Gradual rollout
Always configure a default bureau
No gaps or overlaps in RDG ranges
Test date transitions
Gradual rollouts for new bureaus
Track bureau performance
Monitor failover frequency
Validate buffer effectiveness
Import bureau modules before router
Use simulation mode for testing
is_simulation() to return TrueEnable debug logging
DO_DEBUG = TrueProtect API credentials
def_remoteconnectionsValidate input data
The framework includes a comprehensive command-line interface for testing, validation, and monitoring bureau integrations.
Ensure required dependencies are installed:
pip install typer rich
Test a bureau with real user data:
# Basic test
python factory.service/package.homechoice/ObjBureauCLI.py test EXPERIAN \
--id 8001011234567 \
--firstname John \
--surname Doe \
--birthdate 19800101
# Show raw JSON response
python factory.service/package.homechoice/ObjBureauCLI.py test MYDATA \
--id 8001011234567 \
--firstname Jane \
--surname Smith \
--raw
Features:
Check status of all registered bureaus:
python factory.service/package.homechoice/ObjBureauCLI.py health
Output:
Compare results from multiple bureaus:
python factory.service/package.homechoice/ObjBureauCLI.py compare \
--bureaus EXPERIAN,MYDATA \
--id 8001011234567 \
--firstname John \
--surname Doe \
--birthdate 19800101
Features:
View bureau usage statistics:
# All bureaus, last 7 days (default)
python factory.service/package.homechoice/ObjBureauCLI.py stats
# Specific bureau, custom time range
python factory.service/package.homechoice/ObjBureauCLI.py stats EXPERIAN --days 30
Metrics Shown:
Validate bureau setup and configuration:
python factory.service/package.homechoice/ObjBureauCLI.py validate-config
Checks:
List all registered bureaus:
python factory.service/package.homechoice/ObjBureauCLI.py list-bureaus
Pre-Production Testing:
# Validate configuration
python ObjBureauCLI.py validate-config
# Test each bureau
python ObjBureauCLI.py test EXPERIAN --id 8001011234567 --firstname John --surname Doe
python ObjBureauCLI.py test MYDATA --id 8001011234567 --firstname John --surname Doe
# Compare performance
python ObjBureauCLI.py compare --bureaus EXPERIAN,MYDATA --id 8001011234567 --firstname John --surname Doe
Production Monitoring:
# Daily health check
python ObjBureauCLI.py health
# Weekly statistics review
python ObjBureauCLI.py stats --days 7
# Investigate specific bureau issues
python ObjBureauCLI.py test EXPERIAN --id {problem_id} --firstname ... --raw
Troubleshooting:
# Verify bureau is working
python ObjBureauCLI.py test EXPERIAN --id 8001011234567 --firstname Test --surname User
# Check raw response for errors
python ObjBureauCLI.py test EXPERIAN --id 8001011234567 --firstname Test --surname User --raw
# Validate all configuration
python ObjBureauCLI.py validate-config
The CLI can be integrated into CI/CD pipelines:
#!/bin/bash
# Pre-deployment health check script
echo "Validating bureau configuration..."
python ObjBureauCLI.py validate-config || exit 1
echo "Testing bureaus..."
python ObjBureauCLI.py health || exit 1
echo "Running comparison test..."
python ObjBureauCLI.py compare --bureaus EXPERIAN,MYDATA \
--id 8001011234567 --firstname Test --surname User || exit 1
echo "All bureau checks passed!"
Retry Logic:
The base class now includes automatic retry with exponential backoff:
# Configure retry behavior in data_dim_constants
INSERT INTO data_dim_constants (Varname, varvalue, Description)
VALUES ('BureauMaxRetries', '3', 'Maximum retry attempts for bureau API calls');
INSERT INTO data_dim_constants (Varname, varvalue, Description)
VALUES ('BureauRetryDelay', '1.0', 'Initial retry delay in seconds');
Using Retry in Code:
from ObjServiceHCExperian import ObjServiceApi
bureau = ObjServiceApi()
# Standard call (no retry)
result = bureau.resolve(guid)
# With automatic retry
result = bureau.resolve_with_retry(guid)
Retry Behavior:
Possible Causes:
Solutions:
# Check strategies
SELECT * FROM def_bureau_strategy
WHERE (StartDate IS NULL OR StartDate <= CURDATE())
AND (EndDate IS NULL OR EndDate >= CURDATE());
# Check default bureau
SELECT * FROM def_bureau_strategy WHERE `Default` IN ('Y', '1');
# Check registered bureaus
python ObjServiceBureauRouter.py list
# Enable debug logging
# Set DO_DEBUG = True in router file
Cause: Bureau module not imported or not registered
Solution:
# Ensure registration at module level
ObjServiceBureau.register_bureau("YOURBUREAU", ObjServiceApi)
# Import bureau before router
import ObjServiceHCExperian # Triggers registration
import ObjServiceHCMyData # Triggers registration
import ObjServiceBureauRouter
Possible Causes:
Solutions:
-- Check buffer configuration
SELECT * FROM data_dim_constants WHERE Varname = 'BufferTime';
-- Check buffer table
SHOW TABLES LIKE 'bloom_donormalenquiry';
-- Check recent buffer entries
SELECT * FROM bloom_donormalenquiry
WHERE IDnumber = '{id}'
ORDER BY Updatedate DESC
LIMIT 5;
Cause: Primary returns success (1) even on error
Solution: Review primary bureau's error handling - ensure it returns 0 on failure
Cause: System date/time issues or strategy dates incorrect
Solutions:
-- Verify current date
SELECT CURDATE();
-- Check strategy dates
SELECT BureauCode, StartDate, EndDate
FROM def_bureau_strategy
WHERE CURDATE() BETWEEN StartDate AND EndDate;
factory.core/ObjConstants.py - Constants including buffer table namefactory.service/package.homechoice/ObjServiceBureau.py - Base framework classfactory.service/package.homechoice/ObjServiceBureau.md - Framework documentationfactory.service/package.homechoice/ObjServiceBureauRouter.py - Routing orchestratorfactory.service/package.homechoice/ObjServiceBureauRouter.md - Router documentationfactory.service/package.homechoice/ObjServiceHCExperian.py - Experian SOAP (to migrate)factory.service/package.homechoice/ObjServiceHCExperian_ESW.py - Experian Eswatinifactory.service/package.homechoice/ObjServiceHCExperian_LES.py - Experian Lesothofactory.service/package.homechoice/ObjServiceHCExperian_NAM.py - Experian Namibiafactory.service/package.homechoice/ObjServiceHCMyData.py - MyData REST (reference)factory.service/package.homechoice/ObjServiceHCMyData.md - MyData documentationdef_remoteconnections - Bureau API configurationsdef_bureau_strategy - Routing strategiesdata_dim_constants - Buffer time configurationbloom_donormalenquiry - Buffer storage tablebloom_* - Bureau-specific result tablesInclude the following information:
When adding new bureau implementations:
Axion Platform v8.x
TechnoCore Automate
Branch: feat/hc_bureau