# Affiliate & Partner Commission Architecture

This document describes the commercial referral rules captured on a MembershipOrder when it is created. Rates, recipients and amounts are snapshots: later Admin setting changes do not alter an existing order.

## First payment — direct Partner

When the direct referrer is a Partner, the configured Partner First-Payment Benefit Rate creates a benefit pool from the Membership base price. The direct Partner's allocation divides that pool between Partner commission and buyer discount.

```text
Ali (Partner) → Abu

Membership base price
  → Partner first-payment benefit pool
    → Ali's Partner Wallet commission (Partner allocation)
    → Abu's buyer discount (discount allocation)
```

No AffiliateCommission or upstream rollover is created in this case.

## First payment — direct Non-Partner with Partner ancestry

When the direct referrer is not a Partner, the direct Affiliate commission is calculated first from the snapshot non-Partner rate. The remaining first-payment Partner rate is:

```text
max(partner_first_payment_benefit_rate - non_partner_first_membership_commission_rate, 0)
```

If the referral ancestry contains a Partner, the same highest-Partner resolver used by renewal commission receives that remaining amount in Partner Wallet. The direct Affiliate receives the direct commission in normal E-Wallet.

```text
Ali (Partner) → Abu (Non-Partner) → Amin

Amin's first Membership
  → Abu: AffiliateCommission + E-Wallet credit
  → Ali: first-payment rollover PartnerCommissionPayout + Partner Wallet credit
```

Example at RM50, Partner first benefit 50%, and Non-Partner rate 25%:

- Abu receives RM12.50.
- Ali receives RM12.50.
- Total referral benefit is RM25.00.

If no eligible Partner is in the snapshot ancestry, no rollover is paid. If the non-Partner rate is above the Partner benefit rate, the rollover is zero; the direct Affiliate rate is not reduced.

## Renewal

Non-Partner Affiliate commission does not apply to a renewal. The highest Partner in the commercial `users.referred_by_user_id` ancestry receives the full snapshotted Partner renewal rate in Partner Wallet.

```text
Ali (Partner) → Abu (Non-Partner) → Amin

Amin renewal
  → Abu: no commission
  → Ali: Partner renewal commission
```

VastPro `introducer_user_id` hierarchy is separate and never participates in these calculations.

## Wallets and fulfilment

- Non-Partner Affiliate: `AffiliateCommission` and normal E-Wallet ledger.
- Partner commission, including rollover: `PartnerCommissionPayout` and Partner Wallet ledger.
- One first order may legitimately create one AffiliateCommission and one PartnerCommissionPayout.
- Paid fulfilment, order locks, and order/type uniqueness prevent repeated callbacks from duplicating either payout.
- Zero-payable Membership orders retain the existing policy: they activate Membership without referral payout generation.
- A Partner recipient is snapshotted through `top_partner_user_id`; an order created while that Partner is eligible still pays its rollover after later Partner removal. The separate Partner-removal/withdrawal policy is not changed here.

## Partner removal and financial settlement

Removing `is_partner` ends active commercial Partner eligibility immediately: no new Partner allocation changes, referral-link programme features, or new Partner snapshots are available. It does not rewrite historical orders, commission payouts, Wallet entries, withdrawal records, or receipts.

A former Partner has **Former Partner — Financial Settlement** access only while a Partner Wallet balance or reservation remains, or while a pending/approved withdrawal remains actionable. That limited view permits Wallet balance/history, receipts, and withdrawals under the existing financial rules. Active allocation and other commercial Partner features remain unavailable. When no settlement state remains, Partner portal access ends.

## Referral ownership integrity

`users.referred_by_user_id` is commercial referral ownership. It is set at registration and is locked thereafter. Generic account/profile updates cannot set, replace, or clear it, including where it was initially null.

The only correction path is an authorised Admin correction with a new active referrer, a reason, and explicit confirmation. It runs in a database transaction with row locks, rejects self-reference and ancestry cycles, updates only future commercial snapshots, and writes an immutable `referral_corrections` audit record containing target, old/new referrer, Admin, reason, and timestamp. Existing Membership orders, commissions, Wallet entries, and payouts are never recalculated or reassigned.

Candidate lookup is server-side by name, email, MTA number, or affiliate code and excludes the target and cycle-forming descendants. VastPro `introducer_user_id` remains separate from this referral ownership model.

### Plain-language examples

**Partner removal.** Ali has RM200 in Partner Wallet. Admin removes Partner status. Ali no longer qualifies for new Partner snapshots or allocation changes, but can use the settlement-only view to withdraw the RM200. An older Membership order already snapshotted to Ali can still credit that historical entitlement. Settlement-only access ends after all funds and actionable withdrawals are settled.

**Referral correction.** Abu was registered under Ali by mistake. An Admin verifies Sarah is the correct referrer, supplies a reason, and confirms the correction. Abu's old Membership commissions and Partner payouts remain attributed exactly as already snapshotted. Future Membership orders use Sarah's referral hierarchy. Abu's VastPro introducer is unchanged.

## Cross-portal policy (Phase 4)

Affiliate and Partner are commercial capabilities, not portal memberships. A
TakafulHub Agent and a VastPro Agent can therefore have the same Affiliate or
Partner status without creating duplicate commission, wallet, payout or
withdrawal records. The shared Affiliate, Partner Wallet and Partner Payout
services remain the authoritative commercial implementation in both portals.

VastPro Affiliate uses the normal Affiliate workspace, but its referral URL
always points to the canonical TakafulHub registration host. It does not
introduce a VastPro membership or a second registration funnel. VastPro users
see Partner navigation and Partner notification preferences only while they
are active Partners or retain legitimate financial-settlement access. A former
Partner without an outstanding wallet balance, reserve or actionable
withdrawal is not given Partner portal access.

`users.referred_by_user_id` is the commercial referral relationship used for
Affiliate and Partner entitlement. `agent_profiles.introducer_user_id` is the
separate VastPro team hierarchy relationship. Admin correction tools label
these separately and never mutate the VastPro introducer when correcting a
commercial referrer. Commercial status does not alter VastPro rank, approval,
team visibility or GETB lead logic.

For one shared user, commercial notification actions resolve to VastPro when a
VastPro AgentProfile exists; otherwise they resolve to TakafulHub. This is a
presentation/action target only and never changes financial ownership.
