# Fix M-Pesa Phone Number Matching Issue

## 🐛 Problem Identified

**Callback received but payment not linked to borrower**

### Root Cause
Phone number format mismatch:
- **User in database**: `+254114565176` (with + prefix)
- **M-Pesa sends**: `254114565176` (without + prefix)
- **Old matching logic**: Didn't try all format combinations

## ✅ Solution Implemented

### 1. Enhanced Phone Matching Logic

Updated `loans/models.py` → `match_borrower()` method to try ALL possible phone formats:

**Now tries these variants for `254114565176`:**
- `254114565176` (original)
- `+254114565176` (with +)
- `0114565176` (local format)
- And more combinations

**This will match:**
- `+254114565176` ✓
- `254114565176` ✓
- `0114565176` ✓
- All other variants ✓

### 2. Created Reprocessing Command

New management command to fix existing unmatched transactions:
`payments/management/commands/reprocess_mpesa_transaction.py`

## 🚀 How to Fix

### Step 1: Upload Updated Files to Production

Upload these files to production server:

1. **`loans/models.py`** (updated phone matching logic)
2. **`payments/management/commands/reprocess_mpesa_transaction.py`** (new command)

### Step 2: Restart Application

```bash
touch /home/acbptxvs/public_html/branchbusinessadvance.co.ke/passenger_wsgi.py
```

### Step 3: Reprocess Existing Unmatched Transaction

**Option A: Reprocess specific transaction**

Find the transaction ID from the callbacks page, then run:

```bash
cd /home/acbptxvs/public_html/branchbusinessadvance.co.ke
python manage.py reprocess_mpesa_transaction <TRANSACTION_ID>
```

**Option B: Reprocess all pending transactions**

```bash
cd /home/acbptxvs/public_html/branchbusinessadvance.co.ke
python manage.py reprocess_mpesa_transaction --all-pending
```

This will:
- Find all unmatched transactions
- Try to match them with the new logic
- Show results for each

### Step 4: Verify Fix

1. Check the transaction in admin:
   - Should now show matched borrower
   - Should show matched loan
   - Repayment should be created

2. Check the loan:
   - Outstanding balance should be reduced
   - Repayment record should exist

## 📋 Commands Reference

### Reprocess Single Transaction
```bash
# By transaction UUID
python manage.py reprocess_mpesa_transaction 1020ad2a-9134-4735-b5be-c55dd653deb8

# By M-Pesa TransID
python manage.py reprocess_mpesa_transaction SKH1234567
```

### Reprocess All Pending
```bash
python manage.py reprocess_mpesa_transaction --all-pending
```

### Check Transaction Status (Django Shell)
```python
from loans.models import MpesaTransaction

# Find recent unmatched transactions
unmatched = MpesaTransaction.objects.filter(
    loan__isnull=True,
    status='confirmed'
).order_by('-created_at')[:5]

for t in unmatched:
    print(f"{t.trans_id}: {t.phone_number} - {t.processing_notes}")
```

## 🔍 What the Fix Does

### Before (Old Logic)
```python
# Only tried 3 variants:
- 254114565176
- 254114565176  (duplicate)
- +254114565176
```

### After (New Logic)
```python
# Tries ALL possible formats:
- 254114565176      (original)
- +254114565176     (with +)
- 0114565176        (local format)
- 114565176         (without country code)
```

Plus logs all attempted variants for debugging!

## ✅ Testing

### Test 1: New Payments
Make a new payment and verify it matches automatically.

### Test 2: Existing Unmatched
Run reprocess command and verify old transactions now match.

### Test 3: Different Formats
Test with borrowers who have phone numbers in different formats:
- `+254...`
- `254...`
- `0...`

All should work now!

## 🎯 Expected Results

After uploading and reprocessing:

1. ✅ Old unmatched transaction should link to borrower
2. ✅ Loan should be matched
3. ✅ Repayment should be created
4. ✅ Loan balance should be updated
5. ✅ Future payments will match automatically

## 📝 Files Changed

1. **`loans/models.py`**
   - Enhanced `match_borrower()` method
   - Better phone number normalization
   - Tries all format combinations
   - Logs attempted variants

2. **`payments/management/commands/reprocess_mpesa_transaction.py`** (NEW)
   - Command to reprocess transactions
   - Can process single or all pending
   - Shows detailed results

## 🚨 Important Notes

- The fix is **backward compatible** - won't break existing matched transactions
- Works with **all phone formats** in database
- **Logs all attempts** for debugging
- Can be run **multiple times** safely

## 💡 Prevention

To avoid this in future:

1. **Standardize phone format** in database (recommend `+254...`)
2. **Validate on user registration** - convert to standard format
3. **Update existing users** - normalize all phone numbers

### Optional: Normalize All Phone Numbers

```python
# Django shell - normalize all borrower phone numbers
from users.models import User

borrowers = User.objects.filter(role='borrower')
for b in borrowers:
    if b.phone_number:
        # Remove all non-digits
        clean = ''.join(filter(str.isdigit, b.phone_number))
        # Convert to +254 format
        if clean.startswith('0'):
            b.phone_number = '+254' + clean[1:]
        elif clean.startswith('254'):
            b.phone_number = '+' + clean
        else:
            b.phone_number = '+254' + clean
        b.save()
        print(f"Updated: {b.get_full_name()} -> {b.phone_number}")
```

---

**Status**: Ready to deploy  
**Priority**: High - Fixes payment matching issue  
**Impact**: All future and past unmatched payments
