# Account Aggregator Banking BRE Flow --- ## Overview Triggered the **banking BRE (Business Rules Engine) flow** automatically once the Account Aggregator (AA) analytics report is fetched and saved. Previously, fetching the AA analytics only saved the JSON/Excel/PDF reports to S3 and removed the bank-statement requirement from the mandatory document list. Now, after the files are saved, an auto-rejection + auto-decision (ABB) pipeline runs automatically so that the AA-sourced bank data can drive lending decisions without manual intervention. The AA bank data is identified throughout the BRE chain by the `account_aggregator` record id, passed down as **`account_aggregator_id`**. --- ## Business Rules - **Trigger point**: Runs once at the end of `AccountAggregator::fetchAnalytics()`, after the JSON/Excel/PDF analytics files have been fetched and saved to S3 (guarded by an internal "analytics saved" flag). - **Applicant scope**: Primary applicant only (`applicant_type = 1`). AA analytics files are saved with `applicant_type = 1`, so AA is primary-only. - **Skip condition**: If the application already has a `status_logs` entry of `approved` or `cf approved`, the flow is skipped entirely. - **Rejection path**: If the rejection BRE returns a reject decision, the application `state` is set to `rejected` and a `rejected` status log is inserted (user id `107` — system). - **Auto-decision (ABB) path**: If not rejected, and the application is in a valid state, and the grade carries the ABB banking rule, the auto-decision runs: - **Valid states**: `form completed`, `waiting for documents`, `waiting for decision`, `in-process` - **Banking rule check**: The grade (`grade_v1`) must have an active `approval_rule` whose `rules` contain `emi_multiplier_on_abb` - If auto-decision does **not** approve, the application is moved to `waiting for decision`. Approval / `cf approved` is handled inside the auto-decision routine. --- ## Logic Added #### AA BRE Trigger `AccountAggregator::runBankingBre()` - New private method that runs the banking BRE pipeline after the AA analytics are saved. - Uses `$this->application_id` (consumer application id) and `$this->request_id` (the `account_aggregator` record id, used as `account_aggregator_id`). - Flow: skip if already approved → run `AutoRejection::autoReject(false, $id, 'banking', '', $accountAggregatorId)` → if rejected, set `rejected` + status log → else, if grade has the ABB rule, call `runAutoDecision($id, 'banking_decision_webhook', $accountAggregatorId)` and move to `waiting for decision` when not approved. - Wrapped in try/catch; failures raise a Slack alert (`STAGE_TESTING` group) rather than breaking the analytics fetch. #### Trigger Guard - New `$fetchAnalyticsSaved` flag on `AccountAggregator`, set to `true` inside `saveAnalyticsFile()` after a successful S3 `put`. - `fetchAnalytics()` calls `runBankingBre()` only once, after all three (JSON/Excel/PDF) fetches complete and only if at least one file was saved. This avoids re-running the BRE inside `saveAnalyticsFile()` / `handleResponse()`, which execute three times per fetch. #### Threading `account_aggregator_id` to the BRE payload The AA record id is threaded through both BRE paths so the BRE engine sources bank data from the AA report: - **Rejection path**: `AutoRejection::autoReject()` → `autoRejectJSONBRE()` → `JsonBREController::runRejection()`. A new trailing `$account_aggregator_id` parameter is added at each hop, and `runRejection()` sets `$bre_api_payload['account_aggregator_id']` when present. - **Approval path**: `ConsumerApplicationController::runAutoDecision()` adds `account_aggregator_id` to the request attributes, which propagate through `runAutoDecisionAlgorithm()` → `GradeController` → `JsonBREController::runJsonBreApproval()`, where it is read from the request attributes and set on the payload. All new parameters are **optional trailing arguments**, so existing callers are unaffected. --- ## Impact — Files Changed | File | Type | Change | |------|------|--------| | `app/AccountAggregator.php` | Modified | Added `ConsumerApplicationController` + `AutoRejection` imports; added `$fetchAnalyticsSaved` flag (set in `saveAnalyticsFile()`); added `runBankingBre()`; triggered it once at the end of `fetchAnalytics()` | | `app/Http/Controllers/Grade/AutoRejection.php` | Modified | Added optional `$account_aggregator_id` param to `autoReject()` and `autoRejectJSONBRE()`; passed it to `runRejection()` | | `app/Http/Controllers/JsonBREController.php` | Modified | `runRejection()`: added `$account_aggregator_id` param, sets `$bre_api_payload['account_aggregator_id']`; `runJsonBreApproval()`: reads `account_aggregator_id` from request attributes and sets the same payload key | | `app/Http/Controllers/Admin/ConsumerApplicationController.php` | Modified | `runAutoDecision()`: added optional `$account_aggregator_id` param; adds it to the request attributes so it reaches the approval BRE | --- ### Notes / Assumptions - **Idempotency**: There is no persisted "BRE already run" flag for AA. The flow relies on the single end-of-`fetchAnalytics()` trigger plus the `approved` / `cf approved` status check. If `fetchAnalytics()` is invoked twice for the same application before approval, the BRE could run twice. - **BRE backend contract**: The BRE engine is assumed to resolve `account_aggregator_id` to fetch the AA bank data. This is a backend (BRE API) concern outside this repository. - If pirimid tracking id exists then the account aggregator flow will not work as it prioritizes the pirimid tracking id. This is due to same json structure of pirimid analysis and account aggregator analysis which reads as a single key value in JSON BRE engine (s3.analytics)