> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nuevesolutions.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin Console

## Overview

The **RAF Admin Console** is a staff-facing Django app (`InviteFriendConsole`) bundled with the Banno integration. FI staff sign in with a Django user account (`is_staff=True`) and manage campaigns, review individual referrals, and pay or record reward payouts.

The console is mounted at `/console/` on the same service that hosts the member plugin. Authentication is Django's standard session login — there is no Banno OIDC on the admin side.

| Route                                  | Purpose                                         |
| -------------------------------------- | ----------------------------------------------- |
| `GET /console/`                        | Per-FI overview: counts + active campaigns      |
| `GET /console/referrals/`              | Filterable referral list + bulk actions         |
| `GET /console/referrals/<id>/`         | Referral detail with eligibility JSON           |
| `POST /console/referrals/<id>/pay/`    | Mark inviter/acceptor reward as paid            |
| `GET /console/campaigns/new/`          | New campaign form                               |
| `POST /console/campaigns/<id>/toggle/` | Activate / deactivate a campaign                |
| `GET /console/campaigns/<id>/edit/`    | Edit dates and switches on an existing campaign |

***

## 1. Overview Dashboard

<img src="https://mintcdn.com/nueve-dfd2a7f8/OP4-IsZ9mjBBJ_aP/images/refer-a-friend/banno/raf_banno_flow9.png?fit=max&auto=format&n=OP4-IsZ9mjBBJ_aP&q=85&s=bf5e6212a2a45030e80d87e508c55115" alt="RAF Admin Console Overview for Garden Credit Union. Seven stat tiles: Total Referrals 1, Submitted 1, Criteria Met 0, Ready to Pay 0, Paid 0, Expired 0, Members 8. Below is a Campaigns table listing Auto Loan Summer Push, Premium Checking Q2 2026, Savings Promo Blitz, Spring 2026 Referral, and Winter 2025 Referral (Expired), with columns Name, Type, User ID, Priority, Start Date, End Date, Inviter Reward Amount, Acceptor Reward Amount, Edit, and Status toggle." style={{ maxWidth: '900px', display: 'block', margin: '24px auto' }} width="1896" height="960" data-path="images/refer-a-friend/banno/raf_banno_flow9.png" />

The landing page shows at-a-glance counts scoped to the signed-in staff user's tenant.

**Stat tiles:**

| Tile            | Derived from                                                                                |
| --------------- | ------------------------------------------------------------------------------------------- |
| Total Referrals | `Referral.count()`                                                                          |
| Submitted       | `Referral.filter(status='submitted').count()`                                               |
| Criteria Met    | `Referral.filter(status='criteria_met').count()`                                            |
| Ready to Pay    | `Referral.filter(status='ready_to_pay').count()`                                            |
| Paid            | `Referral.filter(status='paid').count()`                                                    |
| Expired         | `Referral.filter(status='expired').count()`                                                 |
| Members         | `Member.count()` (all members with an RAF record, not only those who submitted or referred) |

**Campaigns table:**

Lists every campaign for the tenant — active and historical. Each row includes the campaign type (`NewRelationshipCampaign` / `NewProductCampaign`), optional restriction User ID, priority, start/end dates, and both reward amounts.

* **Edit** — opens the edit modal for that campaign.
* **Status toggle** — fires `POST /console/campaigns/<id>/toggle/`. A green toggle indicates the campaign is active and currently within its date window. Toggling off effectively ends the campaign immediately.
* **Add New Campaign** — opens the new-campaign form described below.

**Campaign priority** — when multiple campaigns match a submission, the campaign with the highest `priority` is the one surfaced first in the inviter tile. During submission itself, a referral row is created for **every** matching active campaign regardless of priority.

***

## 2. Referrals List

<img src="https://mintcdn.com/nueve-dfd2a7f8/OP4-IsZ9mjBBJ_aP/images/refer-a-friend/banno/raf_banno_flow10.png?fit=max&auto=format&n=OP4-IsZ9mjBBJ_aP&q=85&s=a25ae00c3d27fe46f527cfd5d4d40e5d" alt="RAF Admin Console Referrals list view. Filters across the top: From Date, To Date, Transaction Status, Campaign dropdown, with a Search and Clear. Table row showing campaign 'Auto Loan Summer Push', inviter 'Dinesh Prasad', inviter reward host account ID 'b5bbc025-3f12-4523-8149-b0bda0fae57e', inviter amount $75, acceptor 'rg', acceptor host account ID 'c36c058a-8e4e-45bd-8fe0-4a6392bc1ba8', acceptor amount $25. Buttons at bottom: Pay Reward, Mark as Paid, Download." style={{ maxWidth: '900px', display: 'block', margin: '24px auto' }} width="1896" height="505" data-path="images/refer-a-friend/banno/raf_banno_flow10.png" />

The referrals list is the primary operational view for FI staff.

**Filters:**

| Filter              | Notes                                                                                              |
| ------------------- | -------------------------------------------------------------------------------------------------- |
| From Date / To Date | Bounds on `submitted_at`. Defaults to the last 7 days.                                             |
| Transaction Status  | Maps to `Referral.status` (`submitted`, `criteria_met`, `ready_to_pay`, `paid`, `expired`, `all`). |
| Campaign            | Drop-down of this tenant's campaigns.                                                              |

**Columns:**

| Column                                   | Source                                                                                                                                              |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Pay Reward / Mark as Paid                | Row-level checkbox for bulk actions                                                                                                                 |
| Ready to Reward?                         | `Yes` when `status='ready_to_pay'`, else `No`                                                                                                       |
| Campaign                                 | `Referral.campaign.name`                                                                                                                            |
| Inviter Name                             | `Member.first_name + last_name` of the inviter                                                                                                      |
| Inviter Reward Host Account ID           | `Referral.inviter_primary_account_id` — snapshotted at submission time from the inviter's Banno accounts, resolved via `campaign.inviter_rda_codes` |
| Inviter Amount                           | `campaign.inviter_amount` captured on the referral                                                                                                  |
| Acceptor Name / Host Account ID / Amount | Same fields for the acceptor                                                                                                                        |

**Bulk actions:**

| Button           | Behavior                                                                                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Pay Reward**   | Triggers the configured payment provider (auto mode) for the selected rows — transfers funds to the snapshotted host account IDs and moves the referral to `paid`. |
| **Mark as Paid** | For `mark_external` mode — records the payout as completed without triggering a transfer. Use when the FI runs payouts outside the system.                         |
| **Download**     | Exports the current filter result as CSV — the same report scheduled monthly to the FI's configured recipient list.                                                |

A helper note at the bottom clarifies the host account ID column: *"Inviter Reward Host Account ID: Inviter Checking Share Host Account ID"* — the account resolution picks the inviter's primary checking account unless the campaign's `inviter_rda_codes` narrows it to a different product code.

***

## 3. New Campaign Form

<img src="https://mintcdn.com/nueve-dfd2a7f8/OP4-IsZ9mjBBJ_aP/images/refer-a-friend/banno/raf_banno_flow11.png?fit=max&auto=format&n=OP4-IsZ9mjBBJ_aP&q=85&s=6d675abaea668c37dc232c7c3a8460e4" alt="New Campaign form. Top row: Name, Campaign Type (New Relationship Campaign selected), Creator User ID, Start Date, End Date. Second row: Inviter Amount, Acceptor Amount, CCW Days (60), Payment Mode (Manual selected), Max Inviter Rewards with Enable checkbox and Count. Third row: Inviter RDA Type, Acceptor RDA Type, Do Not Pay Codes (e.g., INFLCR1, INFLCR2), Priority, Promo Code. Criteria Config section with Logic builder and four toggleable criteria: Account (Checking), Balance (0), Payroll (500), Debit (5). Cancel and Submit buttons." style={{ maxWidth: '900px', display: 'block', margin: '24px auto' }} width="1814" height="759" data-path="images/refer-a-friend/banno/raf_banno_flow11.png" />

Campaign creation is the FI's main setup flow. Every field maps directly to a column on `Campaign`.

### Top-level fields

| Field                 | Column                   | Notes                                                                                                                                   |
| --------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| Name                  | `name`                   | Human-readable campaign name                                                                                                            |
| Campaign Type         | `campaign_type`          | `NewRelationshipCampaign` or `NewProductCampaign`                                                                                       |
| Creator User ID       | `creator_user_id`        | Optional — restricts code generation to a specific member (used for ambassador / influencer campaigns). Leave blank for open campaigns. |
| Start Date / End Date | `start_date`, `end_date` | Inclusive bounds; the status toggle is only effective within this window                                                                |
| Inviter Amount        | `inviter_amount`         | USD reward paid to the inviter; set to `$0.00` for promo/acceptor-only campaigns                                                        |
| Acceptor Amount       | `acceptor_amount`        | USD reward paid to the acceptor                                                                                                         |
| CCW Days              | `ccw_days`               | Criteria Completion Window — days from submission for the acceptor to satisfy all criteria                                              |
| Payment Mode          | `payment_mode`           | `auto`, `manual`, or `mark_external`                                                                                                    |
| Max Inviter Rewards   | `max_inviter_rewards`    | Checkbox + count. Checked = capped; unchecked = unlimited                                                                               |
| Inviter RDA Type      | `inviter_rda_codes`      | JSON array of product codes used to resolve the inviter's destination account (e.g., `["checking"]`)                                    |
| Acceptor RDA Type     | `acceptor_rda_codes`     | Same for acceptor (e.g., `["savings"]`)                                                                                                 |
| Do Not Pay Codes      | `do_not_pay_codes`       | JSON array of influencer codes — if the acceptor uses one of these, the inviter reward is suppressed for attribution                    |
| Priority              | `priority`               | Higher = shown first if multiple campaigns match                                                                                        |
| Promo Code            | `promo_code`             | Optional FI self-promotion code — acceptor-only reward, `is_promo=true` on the referral                                                 |

### Payment Mode semantics

| Mode            | Behavior                                                                                                                 |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `auto`          | On transition to `ready_to_pay`, the backend automatically calls the payment provider and moves the referral to `paid`.  |
| `manual`        | Referral waits in `ready_to_pay` until a staff user clicks **Pay Reward** in the list view.                              |
| `mark_external` | Referral waits in `ready_to_pay`; staff click **Mark as Paid** to record an off-system payout. No transfer is attempted. |

### Criteria Config builder

| Criterion | Config field                          | Input                                                    |
| --------- | ------------------------------------- | -------------------------------------------------------- |
| Account   | `criteria_config.account`             | Account type string (default `Checking`)                 |
| Balance   | `criteria_config.balance.min_balance` | Minimum acceptor balance during the CCW window           |
| Payroll   | `criteria_config.payroll.min_amount`  | Cumulative direct-deposit threshold (default `500`)      |
| Debit     | `criteria_config.debit.min_count`     | Minimum qualifying debit transaction count (default `5`) |

The **Logic** field builds the composition expression (e.g., `account AND balance AND (payroll OR debit)`) stored on `criteria_config.logic`. Each checkbox enables that criterion; unchecked criteria are ignored by the engine regardless of logic.

### Submit

On **Submit** the form posts to `POST /console/campaigns/`. The server validates:

* `start_date <= end_date`.
* At least one criterion is enabled if the type is `NewProductCampaign`.
* `promo_code` is unique across active campaigns for this tenant.
* `do_not_pay_codes` is valid JSON.

On success the new campaign row is visible on the overview dashboard. Toggling it on makes it live immediately (subject to its date window).
