# M-Pesa Integration - Final Fix Guide

## 🔍 What's Actually Happening

Your M-Pesa integration has **TWO separate tables**:

1. **`mpesa_callbacks`** (payments app) - Raw callbacks from M-Pesa
2. **`mpesa_transactions`** (loans app) - Processed transactions

### The Flow:
```
M-Pesa Payment
    ↓
Callback received → Stored in mpesa_callbacks
    ↓
Transaction created → Stored in mpesa_transactions
    ↓
Borrower matched → Updates transaction
    ↓
Loan matched → Updates transaction
    ↓
Repayment created → Shows in /loans/repayments/
```

### Your Problem:
The callback shows "Not linked" because the `transaction` field in the callback is NULL, meaning the transaction was never created or linked properly.

---

## 🚀 Complete Fix - Run These Commands

### Step 1: Check Callbacks
```bash
cd /home/acbptxvs/public_html/branchbusinessadvance.co.ke
python manage.py check_callbacks
```

This will show you:
- All callbacks received
- Which ones are linked to transactions
- Which ones created transactions successfully
- Which ones failed

### Step 2: Check Transactions  
```bash
python manage.py check_mpesa_status --days 30
```

This shows:
- All transactions in the database
- Their matching status
- Whether repayments were created

### Step 3: Fix Everything
```bash
python manage.py fix_mpesa_payments
```

---

## 📤 Files to Upload (5 Files)

### Critical Files:
1. **`loans/models.py`** - Fixed phone matching logic
2. **`payments/management/commands/check_callbacks.py`** - NEW - Check callback status
3. **`payments/management/commands/check_mpesa_status.py`** - Check transaction status
4. **`payments/management/commands/fix_mpesa_payments.py`** - UPDATED - Fix unprocessed
5. **`payments/management/commands/reprocess_mpesa_transaction.py`** - Reprocess specific

### Templates (if needed):
6-9. The 4 template files

---

## 🎯 Expected Results

### From check_callbacks:
```
======================================================================
M-Pesa Callback Status Check
======================================================================

Found 1 callback(s) in the last 7 days

======================================================================
Callback ID: abc123...
Type: confirmation
Date: 2025-11-01 06:07:28
IP Address: 196.201.214.xxx
Trans ID: SKH1234567
Amount: KES 100.00
Phone: 254114565176

Option A - If transaction was created:
✓ Linked to Transaction: def456...
  Status: confirmed
  Borrower: Phin Client
  Loan: LOAN-000123
  Repayment: RCP-000456

Option B - If transaction was NOT created:
✗ NOT LINKED to any transaction
  ✗ No matching transaction found in database
  → Transaction may not have been created from this callback
```

---

## 🐛 Possible Scenarios

### Scenario 1: Callback exists but no transaction
**Symptom:** Callback shows "Not linked", no transaction in database
**Cause:** Transaction creation failed during callback processing
**Why:** Could be database error, validation error, or exception
**Fix:** Check Django error logs for the exact error

### Scenario 2: Transaction exists but not processed
**Symptom:** Transaction in database but no repayment
**Cause:** Phone matching failed or loan matching failed
**Fix:** Run `python manage.py fix_mpesa_payments`

### Scenario 3: Everything exists but not showing in UI
**Symptom:** Repayment exists but not visible
**Cause:** Templates not uploaded or cache issue
**Fix:** Upload templates, restart app, clear browser cache

---

## 🔧 Manual Investigation

### Check if transaction exists in database:
```bash
python manage.py shell -c "
from loans.models import MpesaTransaction
from payments.models import MpesaCallback

# Check callbacks
callbacks = MpesaCallback.objects.filter(
    created_at__date='2025-11-01'
)
print(f'Callbacks on 2025-11-01: {callbacks.count()}')
for c in callbacks:
    print(f'  {c.callback_type}: Transaction={c.transaction}')

# Check transactions
transactions = MpesaTransaction.objects.filter(
    created_at__date='2025-11-01'
)
print(f'\nTransactions on 2025-11-01: {transactions.count()}')
for t in transactions:
    print(f'  {t.trans_id}: Borrower={t.borrower}, Loan={t.loan}, Repayment={t.repayment}')
"
```

### Check Django error logs:
```bash
# In cPanel, check error logs for the time of the callback
# Look for Python exceptions around 2025-11-01 06:07:28
```

### Manually create transaction from callback:
```python
# Django shell
from payments.models import MpesaCallback
from loans.models import MpesaTransaction

# Get the callback
callback = MpesaCallback.objects.filter(
    created_at__date='2025-11-01',
    callback_type='confirmation'
).first()

if callback and not callback.transaction:
    print("Callback has no transaction, creating one...")
    
    # Extract data
    data = callback.raw_data
    trans_id = data.get('TransID')
    
    # Create transaction
    transaction = MpesaTransaction.objects.create(
        trans_id=trans_id,
        transaction_type=data.get('TransactionType', 'Pay Bill'),
        amount=data.get('TransAmount', 0),
        phone_number=data.get('MSISDN', ''),
        msisdn=data.get('MSISDN'),
        trans_time=data.get('TransTime'),
        business_short_code=data.get('BusinessShortCode'),
        bill_ref_number=data.get('BillRefNumber'),
        first_name=data.get('FirstName'),
        last_name=data.get('LastName'),
        raw_confirmation_data=data,
        status='confirmed'
    )
    
    # Link callback to transaction
    callback.transaction = transaction
    callback.save()
    
    print(f"✓ Transaction created: {transaction.id}")
    
    # Process the payment
    success = transaction.process_payment()
    print(f"Processing result: {success}")
    
    if transaction.repayment:
        print(f"✓ Repayment created: {transaction.repayment.receipt_number}")
    else:
        print(f"✗ Repayment not created: {transaction.processing_notes}")
```

---

## ✅ Success Checklist

After running all commands, verify:

- [ ] `check_callbacks` shows callback linked to transaction
- [ ] `check_mpesa_status` shows transaction with borrower, loan, and repayment
- [ ] `/payments/callbacks/` shows "Processed" status
- [ ] `/payments/transactions/` shows matched borrower and loan
- [ ] `/loans/repayments/` shows payment with M-Pesa badge
- [ ] `/loans/` shows updated loan balance
- [ ] Borrower received notification

---

## 🆘 If Still Not Working

### 1. Check if callback was even received:
```bash
python manage.py check_callbacks --days 1
```

If no callbacks found:
- M-Pesa is not sending callbacks to your server
- Check URL registration
- Check firewall/SSL

### 2. Check if transaction was created:
```bash
python manage.py check_mpesa_status --days 1
```

If no transactions found:
- Callback was received but transaction creation failed
- Check Django error logs
- Check database permissions

### 3. Check if repayment was created:
```bash
python manage.py shell -c "
from loans.models import Repayment
recent = Repayment.objects.filter(payment_method='mpesa').order_by('-created_at')[:5]
for r in recent:
    print(f'{r.receipt_number}: {r.loan.borrower.get_full_name()} - KES {r.amount}')
"
```

If no repayments found:
- Transaction exists but wasn't processed
- Run `python manage.py fix_mpesa_payments`

---

## 📞 Quick Commands Reference

```bash
# Check everything
python manage.py check_callbacks
python manage.py check_mpesa_status

# Fix everything
python manage.py fix_mpesa_payments

# Check specific date
python manage.py check_callbacks --days 1
python manage.py check_mpesa_status --days 1

# Show only unprocessed
python manage.py check_callbacks --unprocessed-only
```

---

## 🎯 Most Likely Issue

Based on the symptoms (callback exists but shows "Not linked"), the most likely issue is:

**Transaction was never created from the callback**

This could be because:
1. Exception during callback processing
2. Database error
3. Validation error
4. Missing required fields

**Solution:**
1. Check Django error logs for exceptions
2. Run `python manage.py check_callbacks` to see the exact status
3. Manually create transaction from callback (see code above)
4. Or wait for next payment and monitor logs

---

**Upload the 5 command files → Run check_callbacks → See what's actually wrong → Fix it!**
