The Change of Agent feature allows system administrators to transfer member accounts from one agent to another. This documentation covers both single and batch (multiple) member agent changes, including the maker-checker workflow.
- Architecture Overview
- Database Schema
- User Interface Flow
- Backend Logic
- Helper Methods
- Maker-Checker Workflow
- Error Handling
- API Endpoints
┌─────────────────────────────────────────────────────────────────────┐
│ Frontend (Vue/Blade) │
│ index.blade.php (Change Agent UI) │
│ confirm_change_of_agent.blade.php (Confirmation UI) │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Routes (web.php) │
│ POST /handle/multiple/member/agent/change/members_multiple │
│ POST /multiple/member/agent/change/members_multiple │
│ POST /batch/confirm/agent_change ⭐ NEW │
│ POST /single/member/agent/change │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AgentController.php │
│ ├── handleMultipleMemberAgentChange() [Entry point for batch] │
│ ├── multipleMemberAgentChange() [Execution logic] │
│ ├── batchConfirmAgentChange() [⭐ Batch confirm from queue]│
│ ├── handlesingleAgentChange() [Entry for single] │
│ └── singleMemberAgentChange() [Single execution] │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Database Tables │
│ ├── accounts (Main account table) │
│ ├── change_of_agents (Pending changes - maker/checker) │
│ ├── account_agent_log (Audit trail) │
│ ├── um_trans (Transactions) │
│ ├── um_transactions (Transaction records) │
│ ├── um_trans_interests (Interest transactions) │
│ └── um_trans_agent_commissions (Agent commissions) │
└─────────────────────────────────────────────────────────────────────┘
Stores pending agent change requests for maker-checker workflow.
| Column | Type | Description |
|---|---|---|
id |
int | Primary key |
member_no_and_account_no_to_change |
string | Format: member_no;account_no |
agent_from_name |
string | Source agent name |
agent_from_agent_no |
string | Source agent number |
agent_to_name |
string | Destination agent name |
agent_to_agent_no |
string | Destination agent number |
change_reason |
string | Reason for the change |
created_by |
string | Username who initiated |
created_on |
datetime | Creation timestamp |
confirmed |
boolean | Whether change is confirmed |
confirmed_on |
datetime | Confirmation timestamp |
confirmed_by |
string | Username who confirmed |
deleted |
boolean | Soft delete flag |
deleted_on |
datetime | Deletion timestamp |
deleted_by |
string | Username who deleted |
Audit trail for all executed agent changes.
| Column | Type | Description |
|---|---|---|
old_agent |
string | Previous agent number |
new_agent |
string | New agent number |
old_account_no |
string | Previous account number |
new_account_no |
string | New account number (may change) |
staff_name |
string | Username who executed |
reason |
string | Reason for the change |
Location: resources/views/agents/change_agent/index.blade.php
1. SELECT SOURCE AGENT ("Agent From")
├── User types agent number in search input
├── Debounced AJAX call to /agent/search_agent_details
├── Dropdown populated with matching agents
└── On selection: DataTable loads with members belonging to this agent
2. SELECT DESTINATION AGENT ("Agent To")
├── User types agent number in search input
├── Debounced AJAX call to /agent/search_agent_details
└── Dropdown populated with matching agents
3. SELECT MEMBER ACCOUNTS
├── Individual selection via checkboxes
├── "Select All" checkbox for bulk selection
└── Visual feedback shows selected count
4. INITIATE TRANSFER
├── "Batch Transfer" button appears when 2+ accounts selected
├── Modal appears requesting "Change Reason"
└── Confirmation dialog with count and agent details
5. PROCESSING
├── POST to /handle/multiple/member/agent/change/members_multiple
├── If maker-checker enabled → Creates pending records
└── If maker-checker disabled → Direct execution
Location: resources/views/agents/change_agent/confirm_change_of_agent.blade.php
1. VIEW PENDING CHANGES
├── DataTable shows all pending agent changes
├── Each row shows: Member, Account, Agent From, Agent To, Reason, Initiator
2. SELECT CHANGES TO CONFIRM
├── Individual selection via checkboxes
├── "Select All" for bulk selection
├── Can select changes with DIFFERENT source/destination agents
3. BATCH CONFIRM
├── Click "Batch Confirm" button
├── Summary dialog shows grouped transfers:
│ • IFA0033 → IFA0032: 10 accounts
│ • IFA0130 → IFA0131: 10 accounts
└── Confirm to proceed
4. PROCESSING
├── POST to /batch/confirm/agent_change
├── Each record processed with its OWN agent mapping
└── No mix-up between different batches
Purpose: Entry point for batch agent changes from the Change Agent page. Determines whether to use maker-checker workflow or execute directly.
Route: POST /handle/multiple/member/agent/change/members_multiple
Controller: AgentController@handleMultipleMemberAgentChange
{
"_token": "csrf_token_here",
"data": [
["member_no1;account_no1", "member_no2;account_no2"],
["OLD_AGENT_CODE", "NEW_AGENT_CODE"]
],
"change_reason": "Reason for the agent change"
}START
│
▼
┌─────────────────────────────────────────────┐
│ 1. Check system_controls for │
│ 'agent_maker_checker_true' setting │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 2. Is maker-checker enabled? │
└─────────────────────────────────────────────┘
│ │
│ YES │ NO
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Check for │ │ Call │
│ pending changes │ │ multipleMember │
│ (duplicate) │ │ AgentChange() │
└─────────────────┘ │ directly │
│ └─────────────────┘
▼
┌─────────────────────────────────────────────┐
│ 3. Create AgentChange records for each │
│ member/account pair │
│ - Store agent_from and agent_to │
│ - confirmed = false │
│ - Record reason and creator │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 4. Return success: │
│ "Pending Confirmation" │
└─────────────────────────────────────────────┘
Purpose: Confirms multiple pending agent change records from the confirmation page. Each record is processed using its own stored source/destination agent mapping, allowing mixed batches to be confirmed correctly without any mix-up.
Route: POST /batch/confirm/agent_change
Controller: AgentController@batchConfirmAgentChange
{
"_token": "csrf_token_here",
"change_ids": [1, 2, 3, 4, 5, 11, 12, 13, 14, 15]
}The previous approach had a critical flaw:
- Users could select pending changes from different batches (e.g., Agent A → B and Agent C → D)
- The old code took agent info from only the first selected item
- This caused "Cannot process batch: Accounts belong to different agents" error
The new batchConfirmAgentChange method:
- Fetches each pending change record by ID
- Uses the stored agent_from_agent_no and agent_to_agent_no from each record
- Processes each account with its correct source and destination agent
- No mix-up possible
START
│
▼
┌─────────────────────────────────────────────┐
│ 1. Receive array of change_ids │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 2. Fetch pending AgentChange records │
│ WHERE id IN (change_ids) │
│ AND confirmed = false │
│ AND deleted = false │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 3. BEGIN DATABASE TRANSACTION │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 4. FOR EACH pending change record: │
│ ├── Get agent_from from record │
│ ├── Get agent_to from record │
│ ├── Get member_no;account_no from record │
│ ├── Validate account exists │
│ ├── Validate current agent = agent_from │
│ ├── Generate new account number │
│ ├── Update account table │
│ ├── Update related tables │
│ ├── Create audit log │
│ └── Mark change as confirmed │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 5. COMMIT TRANSACTION │
│ Return success with counts │
└─────────────────────────────────────────────┘
- Per-Record Agent Mapping: Each change uses its stored
agent_from_agent_noandagent_to_agent_no - Current Agent Validation: Verifies account's current agent matches expected source agent
- Graceful Skipping: If agent already changed, marks as confirmed and skips
- Atomic Transaction: All changes commit together or rollback together
- Comprehensive Logging: Every step logged for debugging
{
"status": "success",
"message": "Batch confirmation completed. Processed: 20 account(s)",
"processed_count": 20,
"skipped_count": 0,
"error_count": 0,
"errors": [],
"skipped": []
}Purpose: Executes agent changes when all accounts should go to the SAME destination agent. Used for direct execution (non-maker-checker) or when called from handleMultipleMemberAgentChange.
Route: POST /multiple/member/agent/change/members_multiple
Note: This method has strict mode enabled - it rejects batches where accounts belong to different source agents. Use batchConfirmAgentChange for confirming mixed batches from the confirmation page.
For individual account transfers.
Entry point for single member changes. Checks maker-checker setting.
Executes single account transfer with same table updates as batch.
Location: app/Http/Traits/AccountsSubTrait.php
public function getAccountInfoRows($account_number)
{
return Account::join('securities', ...)
->where('account_no', $account_number)
->select('agent_no', 'security_code', 'category',
'member_no', 'mode', 'company_id')
->first();
}Location: app/Http/Traits/AccountsSubTrait.php
Generates new account number with updated agent code:
AGENT_CODE-SECURITY-MEMBER-[SUFFIX]
Example: AG001-SEC001-MEM001 → AG002-SEC001-MEM001
SELECT value FROM system_controls WHERE setting = 'agent_maker_checker_true';
-- 1 = enabled, 0 = disabled┌─────────────────────────────────────────────────────────────────────┐
│ MAKER (Creator) │
│ Uses: index.blade.php │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Creates pending change request in change_of_agents table │
│ Stores: agent_from_agent_no, agent_to_agent_no per record │
│ Status: confirmed = false │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Pending Queue │
│ View: confirm_change_of_agent.blade.php │
│ Route: /confirm/agent_change │
└─────────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ APPROVE (Checker) │ │ REJECT (Checker) │
│ │ │ │
│ Single: Confirm button │ │ Cancel button │
│ Batch: Batch Confirm │ │ cancelAgentChange() │
│ │ │ │
│ Uses stored agent │ │ │
│ from/to per record │ │ │
└─────────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ batchConfirmAgentChange │ │ Sets deleted = true │
│ or singleMemberAgent │ │ Records deleted_by/on │
│ Change() │ │ │
└─────────────────────────┘ └─────────────────────────┘
| Method | Endpoint | Controller Method | Purpose |
|---|---|---|---|
| GET | /change/agent |
viewChangeAgent |
Display change agent UI |
| GET | /show/members_belonging_to_agent/details/{agent_code} |
showMemberAgentDetails |
DataTable for member accounts |
| POST | /handle/multiple/member/agent/change/members_multiple |
handleMultipleMemberAgentChange |
Entry point for batch change |
| POST | /multiple/member/agent/change/members_multiple |
multipleMemberAgentChange |
Execute batch change (same agent) |
| POST | /batch/confirm/agent_change |
batchConfirmAgentChange |
⭐ Batch confirm from queue |
| POST | /single/member/agent/change |
handlesingleAgentChange |
Entry point for single change |
| POST | /single/member/agent_change |
singleMemberAgentChange |
Execute single change |
| GET | /confirm/agent_change |
pendingAgentChange |
View pending changes |
| POST | /single/member/agent_change/cancel |
cancelAgentChange |
Cancel pending change |
The batch confirm button now:
-
Collects change IDs (not member;account pairs)
-
Groups and summarizes the selected changes by transfer direction
-
Shows confirmation dialog with transfer summary:
You are about to confirm 20 agent change(s): • IFA0033 → IFA0032: 10 account(s) • IFA0130 → IFA0131: 10 account(s) Are you sure you want to proceed? -
Calls new endpoint
/batch/confirm/agent_change -
Sends change_ids array instead of member/account pairs + agent codes
- Authentication: All routes protected by
authmiddleware - Permission Check:
create-Change-Of-Agentandconfirm-agent-changepermissions - CSRF Protection: All POST requests require valid CSRF token
- Maker ≠ Checker: Same user cannot confirm their own changes
- Audit Trail: All changes logged to
account_agent_logtable - Transaction Safety: Database transactions ensure data integrity
Check Laravel logs at storage/logs/laravel.log:
Log::info('=== STARTING BATCH CONFIRM AGENT CHANGE ===');
Log::info("Processing: {$memberAccountPair} | From: {$old_agent_code} | To: {$new_agent_code}");
Log::info("=== Successfully processed Change ID: {$pendingChange->id} ===");
Log::info("=== BATCH CONFIRM COMPLETED ===");
Log::info("Processed: {$processedCount}, Errors: X, Skipped: Y");Document Version: 2.0
Last Updated: November 25, 2025
Major Update: Added batchConfirmAgentChange method for mixed batch confirmation