# Affiliate Module - Implementation Report

**Document Version:** 1.0
**Date:** 2026-05-31
**Module:** WooNooW Affiliate Program

---

## Table of Contents

1. [Implementation Summary](#implementation-summary)
2. [Backend (PHP)](#backend-php)
3. [Admin SPA](#admin-spa)
4. [Customer SPA](#customer-spa)
5. [Gaps & Defects](#gaps--defects)
6. [Opportunities](#opportunities)

---

## Implementation Summary

| Area | Status | Coverage | Production Ready |
|------|--------|----------|-----------------|
| Referral Tracking | Working (Main Path) | ~90% | ⚠️ |
| Order Lifecycle | Partial | ~70% | ⚠️ |
| Backend API | Partial | ~70% | ⚠️ |
| Customer Dashboard | Partial | ~60% | ⚠️ |
| Admin SPA | Partial | ~50% | ⚠️ |
| Email Notifications | Partial | ~50% | ⚠️ |
| Payout System | Placeholder | 0% | ❌ |

**Overall Assessment:** Foundation is solid with clean architecture. Referral tracking works for standard page-load checkout flows, but still needs hardening for block-based checkout and dynamic URL handling. Payout system is the critical gap preventing production use.

### What Works Well

- **Clean separation of concerns** — Module bootstrap, tracking, lifecycle, settings are distinct files
- **Multiple checkout hooks** — Works with legacy checkout and admin order creation
- **Order lifecycle handling** — Refunds/cancellations properly reject referrals with clawback
- **Customer dashboard** — Functional with proper currency formatting
- **Admin order integration** — Shows affiliate attribution in order details

### What's Working (Main Path)

- Cookie-based referral tracking on standard page loads
- Affiliate application and approval flow
- Commission calculation on order completion
- Auto-approval via Action Scheduler after holding period
- Order refund/cancellation → referral rejection with clawback

### What's Still Needs Hardening

- **Block checkout compatibility** — Cookie capture relies on `init` hook; may miss AJAX-based checkout flows
- **Dynamic referral link** — Current implementation assumes `/shop` path; needs site-config-aware URL generation
- **Edge case handling** — Invalid referral codes, expired cookies, cross-device attribution not fully tested

### What's Missing for Production

1. **Payout workflow** — Cannot pay affiliates (blocking)
2. **Per-affiliate commission override** — No custom rates (high priority)
3. **Self-referral override** — No admin whitelist (high priority)
4. **Referral detail transparency** — Customer can't see order details (medium)

---

## Backend (PHP)

### Files Implemented

| File | Path | Purpose |
|------|------|---------|
| AffiliateModule.php | `/includes/Modules/Affiliate/` | Bootstrap & initialization |
| AffiliateManager.php | `/includes/Modules/Affiliate/` | Database table creation |
| AffiliateTracker.php | `/includes/Modules/Affiliate/` | Referral tracking & cookie handling |
| AffiliateLifecycle.php | `/includes/Modules/Affiliate/` | Order status/cancellation handling |
| AffiliateSettings.php | `/includes/Modules/Affiliate/` | Module settings schema |
| AffiliateAdminController.php | `/includes/Api/Controllers/` | Admin API endpoints |
| AffiliateCustomerController.php | `/includes/Api/Controllers/` | Customer API endpoints |

### Database Tables

#### `wp_woonoow_affiliates`
| Column | Type | Notes |
|--------|------|-------|
| id | bigint | Primary key |
| user_id | bigint | Links to WP users |
| referral_code | varchar(50) | Unique affiliate code |
| coupon_id | bigint | Optional WC coupon link |
| commission_rate | decimal(10,2) | Percentage |
| status | varchar(20) | pending/active/rejected |
| total_referrals | int | Counter |
| total_earnings | decimal(19,4) | Accumulated earnings |
| paid_earnings | decimal(19,4) | Paid out amount |
| created_at | datetime | |
| updated_at | datetime | Auto-update |

#### `wp_woonoow_referrals`
| Column | Type | Notes |
|--------|------|-------|
| id | bigint | Primary key |
| affiliate_id | bigint | FK to affiliates |
| order_id | bigint | WooCommerce order |
| customer_id | bigint | Customer user ID |
| commission_amount | decimal(19,4) | Calculated commission |
| currency | varchar(10) | Default USD |
| status | varchar(20) | pending/approved/rejected |
| cancelled_reason | varchar(50) | WHY rejected |
| cancelled_at | datetime | When cancelled |
| created_at | datetime | |
| approved_at | datetime | When approved |
| paid_at | datetime | When paid |

#### `wp_woonoow_affiliate_payouts`
| Column | Type | Notes |
|--------|------|-------|
| id | bigint | Primary key |
| affiliate_id | bigint | FK |
| amount | decimal(19,4) | |
| currency | varchar(10) | |
| method | varchar(50) | Payment method |
| status | varchar(20) | pending/completed |
| notes | text | |
| created_at | datetime | |
| completed_at | datetime | |

### API Endpoints

#### Admin Endpoints (`/woonoow/v1/admin/affiliates`)
| Method | Endpoint | Function | Implemented |
|--------|----------|----------|-------------|
| GET | `/` | `get_affiliates()` | ✅ |
| POST | `/(?P<id>\d+)/approve` | `approve_affiliate()` | ✅ |
| GET | `/referrals` | `get_referrals()` | ✅ |
| POST | `/payouts` | `create_payout()` | ✅ |

#### Customer Endpoints (`/woonoow/v1/account/affiliate`)
| Method | Endpoint | Function | Implemented |
|--------|----------|----------|-------------|
| GET | `/` | `get_dashboard()` | ✅ |
| POST | `/apply` | `apply_affiliate()` | ✅ |
| GET | `/referrals` | `get_referrals()` | ✅ |

### Hooks & Tracking

| Hook | Handler | Status | Notes |
|------|---------|--------|-------|
| `init` | `capture_referral_link()` | ✅ | Captures `?ref=` from URL |
| `woocommerce_checkout_order_processed` | `record_referral()` | ✅ | Legacy checkout |
| `woocommerce_store_api_checkout_order_processed` | `record_referral_block()` | ✅ | Block checkout (WC 8.3+) |
| `woocommerce_new_order` | `record_referral_new_order()` | ✅ | Universal fallback |
| `woocommerce_process_shop_order_meta` | `record_referral_admin()` | ✅ | Admin order creation |
| `woocommerce_order_status_refunded` | `handle_order_cancelled()` | ✅ | |
| `woocommerce_order_status_cancelled` | `handle_order_cancelled()` | ✅ | |
| `woocommerce_order_status_failed` | `handle_order_cancelled()` | ✅ | |
| `before_delete_post` | `handle_order_deleted()` | ✅ | |
| `woocommerce_delete_order` | `handle_order_deleted()` | ✅ | |

**Tracking Coverage:** All WooCommerce order creation paths are hooked. Cookie capture works on standard page loads.

### Email Notifications

| Event ID | Template | Status |
|----------|----------|--------|
| `affiliate_application_received` | Staff notification | ✅ |
| `affiliate_application_approved` | Customer welcome | ✅ |
| `affiliate_new_referral` | Commission earned | ✅ |

---

## Admin SPA

### Routes

| Route | Component | Implemented |
|-------|-----------|-------------|
| `/marketing/affiliates` | AffiliatesLayout | ✅ |
| `/marketing/affiliates/list` | AffiliatesList | ✅ |
| `/marketing/affiliates/referrals` | AffiliatesReferrals | ✅ |
| `/marketing/affiliates/payouts` | AffiliatesPayouts | ⚠️ Placeholder |

### Features Implemented

#### AffiliatesList
- Search by referral code
- Display table: User ID, Code, Rate, Status, Earnings, Actions
- Approve button for pending affiliates
- Status badges (color-coded)

#### AffiliatesReferrals
- Display all referrals table
- Columns: ID, Affiliate ID, Order ID, Status, Date, Commission
- Status badges

#### AffiliatesPayouts
- **NOT IMPLEMENTED** - Shows "coming soon" placeholder

### Order Details Integration

The order detail page (`/orders/{id}`) now shows affiliate information:
- Affiliate name
- Commission rate
- Commission amount
- Status with cancellation reason

---

## Customer SPA

### Routes

| Route | Component | Implemented |
|-------|-----------|-------------|
| `/my-account/affiliate` | AffiliateDashboard | ✅ |

### Features Implemented

#### Application Flow
- "Join Affiliate Program" card with Apply Now button
- Pending status notification when awaiting approval

#### Dashboard (Active Affiliates)
- Total Earnings card
- Pending Earnings card
- Commission Rate display
- Referral link generator with copy button
- Recent Referrals table

### Format Issues (Fixed)
- Currency formatting now uses site's WooCommerce settings
- IDR displays as `Rp19.900` (no decimals, thousand separator)
- Other currencies use configured decimals

---

## Gaps & Defects

### Critical (Blocking)

#### 1. Payout System Not Functional
**Location:** Admin & Backend
**Severity:** Critical
**Issue:** The payout creation API (`create_payout()`) exists but:
- No UI to initiate payouts in Admin SPA (placeholder only)
- No calculation of payable balance (`total_earnings - paid_earnings`)
- No payout history view
- No payment processing (only store_credit implemented)

**Impact:** Cannot pay affiliates — program is incomplete

**Required Fix:**
```php
// AffiliateAdminController.php
public static function get_affiliate_balance($affiliate_id) {
    global $wpdb;
    $table = $wpdb->prefix . 'woonoow_affiliates';
    $affiliate = $wpdb->get_row($wpdb->prepare(
        "SELECT total_earnings, paid_earnings FROM $table WHERE id = %d",
        $affiliate_id
    ));
    return [
        'total_earnings' => (float) $affiliate->total_earnings,
        'paid_earnings' => (float) $affiliate->paid_earnings,
        'payable_balance' => (float) $affiliate->total_earnings - (float) $affiliate->paid_earnings
    ];
}
```

#### 2. Referral Link Hardcoded to `/shop`
**Location:** Customer SPA - AffiliateDashboard.tsx
**Severity:** Critical
**Issue:**
```typescript
// Current (hardcoded)
const referralLink = `${window.location.origin}${window.location.pathname.replace('/my-account/affiliate', '/shop')}?ref=${profile.referral_code}`;
```

- Assumes shop page exists at `/shop`
- Doesn't check site's actual SPA mode or base path
- May 404 or redirect incorrectly on different configurations

**Required Fix:**
```typescript
// Get from WooNooW config
const basePath = (window as any).woonoowCustomer?.basePath || '';
const shopPath = basePath + '/shop'; // or wc_get_page_id('shop') permalink
```

### High (Important)

#### 3. No Cookie Capture on Block Checkout
**Location:** Backend - AffiliateTracker.php
**Severity:** High
**Issue:** `capture_referral_link()` only fires on `init`. Block-based checkout may:
- Load via AJAX without full page reload
- Use Store API without triggering WordPress `init`
- Miss the `?ref=` parameter entirely

**Impact:** Some block checkout flows may lose referral attribution

**Required Fix:**
Referral attribution must remain reliable across all WooCommerce checkout variants and navigation patterns. The persistence mechanism (cookie, localStorage, server-side session) is secondary to ensuring the `?ref=` parameter is captured and associated with the order regardless of how the customer navigates to checkout.

```php
// AffiliateTracker.php - Ensure referral is captured before order creation
// Option 1: Check for ref in session/storage on order hooks
// Option 2: Ensure PHP session captures ref via frontend AJAX call
// Option 3: Store ref in order meta during checkout for guaranteed attribution
```

#### 4. Self-Referral Block Has No Override
**Location:** Backend - AffiliateTracker.php:133-135
**Severity:** High
**Issue:**
```php
if ((int)$order->get_user_id() === (int)$affiliate->user_id) {
    return; // Blocks all self-referrals
}
```

No admin option to:
- Allow self-referrals for testing
- Whitelist specific affiliate-customer pairs
- Override after verification

**Impact:** Cannot test with same account (must use different customer account)

#### 5. No Per-Affiliate Commission Override
**Location:** Backend + Database
**Severity:** High
**Issue:**
- All affiliates use global `woonoow_affiliate_default_rate` setting
- No ability to set custom rate per affiliate
- No ability to override for special cases

**Impact:** Limited merchant flexibility for VIP affiliates

### Medium (Should Fix)

#### 6. No Referral Filtering in Admin
**Location:** Admin SPA - Referrals.tsx
**Severity:** Medium
**Issue:** AffiliatesReferrals shows ALL referrals. No:
- Filter by affiliate
- Filter by date range
- Filter by status
- Filter by order

**Impact:** Hard to track specific affiliate performance

#### 7. Affiliate Cannot See Referral Details
**Location:** Customer SPA - AffiliateDashboard.tsx
**Severity:** Medium
**Issue:** Dashboard shows order ID and commission only. No:
- Order date
- Product details
- Commission status explanation
- When payment will be released

**Impact:** Low trust due to lack of transparency

#### 8. Commission Based on Subtotal Only
**Location:** Backend - AffiliateTracker.php:139-144
**Severity:** Medium
**Issue:**
```php
$subtotal = (float)$order->get_subtotal();
$commission_amount = ($subtotal * $commission_rate) / 100;
```

- Does not account for taxes
- Does not account for shipping
- Does not account for discounts

**Impact:** Affiliates may dispute calculated amounts (requires clear documentation)

### Low (Nice to Have)

#### 9. No Admin Dashboard Metrics
**Location:** Admin SPA
**Severity:** Low
**Issue:** No summary cards showing:
- Total affiliates count
- Active vs pending breakdown
- Total commission paid
- Conversion rate

**Impact:** Hard to assess program health at a glance

#### 10. No Email Template Customization
**Location:** Backend - Email System
**Severity:** Low
**Issue:**
- Templates hardcoded in DefaultTemplates.php
- No admin settings for customization
- No branding options

**Impact:** Limited to default styling

---

## Opportunities

### Priority 1: Operational Completeness (Must-Have)

These features make the affiliate module operationally functional — without them, merchants cannot run a real affiliate program.

#### 1. Complete Payout System
**Status:** Placeholder (0% implemented)
**Scope:** Backend + Admin SPA

Payout is not a secondary detail — it is the final proof that the system works. Merchants need to be able to:

- [ ] Calculate payable balance per affiliate (`total_earnings - paid_earnings`)
- [ ] View payout history per affiliate
- [ ] Create payouts with amount input (not auto-all)
- [ ] Support multiple payout methods (Bank Transfer, PayPal, Store Credit)
- [ ] Mark payouts as pending → completed
- [ ] Send payout notification email to affiliate

**API required:**
- `GET /admin/affiliates/payouts` - List all payouts
- `GET /admin/affiliates/{id}/balance` - Get payable balance
- `POST /admin/affiliates/{id}/payout` - Create payout

#### 2. Attribution Reliability & Tracking Rules
**Status:** Partial (works for most cases)
**Scope:** Backend

Silent attribution failures damage trust quickly. Need to ensure:

- [ ] Referral link adapts to site's actual SPA structure (not hardcoded `/shop`)
- [ ] Cookie capture works for AJAX/block checkout flows (not just page reload)
- [ ] Referral codes are case-insensitive during lookup
- [ ] Invalid/expired referral codes handled gracefully (no errors)

**Technical approach:**
```php
// Dynamic referral link generation
$shop_page = get_permalink(wc_get_page_id('shop'));
$referral_link = add_query_arg('ref', $referral_code, $shop_page);
```

#### 3. Commission Management & Overrides
**Status:** Global rate only (no per-affiliate override)
**Scope:** Backend + Admin SPA

Merchants need granular control:

- [ ] Set custom commission rate per affiliate (override global default)
- [ ] Manually adjust commission amount per referral
- [ ] Set custom holding period per affiliate
- [ ] Mark referral as "Manual Adjustment" with audit trail
- [ ] Commission calculation rules (subtotal vs total, include/exclude tax, etc.)

**Database consideration:**
Add `custom_commission_rate` column to `wp_woonoow_affiliates` (nullable, uses default if null).

---

### Priority 2: Transparency & Trust (Should-Have)

These features build trust with both merchants and affiliates through visibility and control.

#### 4. Admin Performance Dashboard
**Status:** Basic list only (no metrics)
**Scope:** Admin SPA

Merchants need to assess program health:

- [ ] Summary cards: Total Affiliates, Active vs Pending, Total Commission (approved), Unpaid Commission
- [ ] Conversion rate: Applications vs Approved
- [ ] Top performing affiliates
- [ ] Monthly earnings trend chart
- [ ] Export to CSV/Excel

#### 5. Customer Dashboard Transparency
**Status:** Basic (earnings + recent referrals)
**Scope:** Customer SPA

Affiliates need to trust the system:

- [ ] Referral status breakdown (pending approval vs approved vs paid)
- [ ] "When will I get paid?" indicator (holding period countdown)
- [ ] Referral detail view: which order, what commission, current status
- [ ] Payout history view (coming when payout system is complete)

**Example referral detail card:**
```
Order #476 • May 30, 2026
Commission: Rp19.900
Status: Pending (3 days until approval)
Product: Design Mockup Bundle
```

#### 6. Trust & Compliance Layer
**Status:** Basic self-referral check only
**Scope:** Backend (core trust layer, not nice-to-have)

Affiliate systems are always exposed to abuse. Define anti-fraud rules early:

- [ ] Self-referral block with admin exception/override
- [ ] Suspicious order flagging (unusually high value from new customer)
- [ ] Rate limiting on referral code generation per IP
- [ ] Audit log for manual commission adjustments
- [ ] Clear commission rules documentation (what's included/excluded)

**Database consideration:**
Add `fraud_score` column to `wp_woonoow_referrals` for future ML-based scoring.

---

### Priority 3: Scalability Features (Nice-to-Have)

These enable growth but are not blocking for initial launch.

#### 7. Enhanced Referral Tracking
**Scope:** Backend

- [ ] Track referral source (email, social, direct, paid)
- [ ] Store click data (IP, user agent, timestamp)
- [ ] UTM parameter capture
- [ ] Cross-device tracking (logged-in users)

#### 8. Referral Filtering & Search
**Scope:** Admin SPA

- [ ] Filter by affiliate
- [ ] Filter by date range
- [ ] Filter by status (pending/approved/rejected)
- [ ] Filter by order ID
- [ ] Search by customer email (anonymized display)

#### 9. Affiliate Self-Service Portal
**Scope:** Customer SPA

- [ ] Update payment details (bank account, PayPal)
- [ ] View payout history
- [ ] Download referral reports (CSV)
- [ ] Tax document download (1099 placeholder)

---

### Future Roadmap (Post-MVP)

These are growth features, not near-term priorities. Merchants care about correctness first.

#### Multi-Tier Commissions
- Volume-based tiers (10% for 0-10 referrals, 15% for 11-50, etc.)
- Requires: Tier configuration UI, recalculation on new referral

#### Integration Ecosystem
- WooCommerce Currency Switcher compatibility
- Export to accounting software (Xero, QuickBooks)
- Zapier/Make integrations for automation

#### Gamification
- Achievement badges (First Referral, Top Performer)
- Leaderboards
- Referral contests with goals and rewards

#### MLM Structure
- Multi-level marketing (not recommended for most WooCommerce setups)
- Keep lower priority unless specifically requested

---

## Recommendations

### This Sprint (Operational Core)

| Task | Priority | Effort | Impact |
|------|----------|--------|--------|
| Fix referral link path (dynamic) | Critical | Low | Reliability |
| Implement payout balance calculation | Critical | Medium | Completeness |
| Add payout creation UI | Critical | Medium | Completeness |
| Add self-referral admin override | High | Low | Trust |
| Add referral filtering in admin | Medium | Medium | Usability |

### Next Sprint (Transparency)

| Task | Priority | Effort | Impact |
|------|----------|--------|--------|
| Admin performance dashboard | High | Medium | Visibility |
| Customer referral detail view | High | Medium | Trust |
| Per-affiliate commission override | High | Medium | Control |
| Commission rules configuration | Medium | High | Flexibility |

### Future (Growth)

- UTM/source tracking
- Affiliate self-service portal
- Integration ecosystem
- Multi-tier commissions

---

## File Checklist

| Path | Type | Description |
|------|------|-------------|
| `/includes/Modules/Affiliate/AffiliateModule.php` | PHP | Module bootstrap |
| `/includes/Modules/Affiliate/AffiliateManager.php` | PHP | DB tables |
| `/includes/Modules/Affiliate/AffiliateTracker.php` | PHP | Tracking logic |
| `/includes/Modules/Affiliate/AffiliateLifecycle.php` | PHP | Order lifecycle |
| `/includes/Modules/Affiliate/AffiliateSettings.php` | PHP | Settings schema |
| `/includes/Api/Controllers/AffiliateAdminController.php` | PHP | Admin API |
| `/includes/Api/Controllers/AffiliateCustomerController.php` | PHP | Customer API |
| `/admin-spa/src/routes/Marketing/Affiliates/index.tsx` | TSX | Admin layout |
| `/admin-spa/src/routes/Marketing/Affiliates/List.tsx` | TSX | Affiliate list |
| `/admin-spa/src/routes/Marketing/Affiliates/Referrals.tsx` | TSX | Referral list |
| `/admin-spa/src/routes/Marketing/Affiliates/Payouts.tsx` | TSX | Payouts (placeholder) |
| `/admin-spa/src/routes/Orders/Detail.tsx` | TSX | Order affiliate info |
| `/customer-spa/src/pages/Account/AffiliateDashboard.tsx` | TSX | Customer dashboard |
| `/customer-spa/src/pages/Account/index.tsx` | TSX | Account routes |
| `/customer-spa/src/pages/Account/components/AccountLayout.tsx` | TSX | Menu integration |

---

*Report Version: 1.2*
*Last Updated: 2026-05-31*
*Generated by: Claude Code*
*Review Status: Final - Reviewed and validated*