# Subscription Feature - Testing Guide

This guide helps you manually test the subscription feature quickly and thoroughly.

## What's New in This Version

**Added 6 new advanced scenarios** to improve test coverage:

- **Scenario 7: Status Lifecycle** - Test all status transitions (pending→active, completed, expired)
- **Scenario 8: Multi-Item Subscriptions** - Test subscriptions with multiple products
- **Scenario 9: Phone Orders** - Test admin-created phone order subscriptions
- **Scenario 10: Assessment Expiry** - Test prescription expiry and renewal workflow
- **Scenario 11: Date Edge Cases** - Test month boundaries, rescheduling limits
- **Scenario 12: Coupons & Discounts** - Test subscription discounts and first-order coupons

These scenarios cover critical edge cases and real-world workflows that were previously untested.

## Quick Start

### 1. Setup Test Environment

```bash
# Ensure environment is configured
docker-compose up -d

# Clear caches
docker-compose exec php-apache php artisan config:clear
docker-compose exec php-apache php artisan cache:clear

# Verify subscriptions are enabled
grep SUBSCRIPTIONS_ENABLED .env
# Should show: SUBSCRIPTIONS_ENABLED=true
```

### 2. Create Test Subscription

The fastest way to create a test subscription:

```bash
# Create a basic test subscription
docker-compose exec php-apache php artisan subscriptions:setup-test

# Or with specific options
docker-compose exec php-apache php artisan subscriptions:setup-test \
  --status=active \
  --interval=weeks \
  --multiplier=2 \
  --items=2
```

This command will:
- ✅ Find or create a test member
- ✅ Create a subscription with real products
- ✅ Set realistic dates and pricing
- ✅ Show you URLs to test in browser

## Testing Scenarios

### Scenario 1: Customer Creates Subscription

**Goal:** Test the full customer journey from product selection to subscription creation.

**Steps:**

1. **Browse Products with Subscription Options**
   - Login as a customer: `http://localhost/member/login`
   - Browse product catalog
   - Look for products with subscription options
   - Add to basket with "Subscription" purchase type selected

2. **Complete Checkout**
   - View basket: `http://localhost/shop/checkout/basket_overview.php`
   - Complete payment (use test payment gateway)
   - Note the order ID

3. **Verify Subscription Created**
   ```bash
   # Check if subscription was created from the order
   docker-compose exec php-apache php artisan subscriptions:generate_from_orders

   # Or check database
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, member_id, status, next_issue_date FROM subscriptions ORDER BY id DESC LIMIT 5;"
   ```

4. **View Subscription in Member Area**
   - Go to: `http://localhost/member/orders/subscriptions`
   - Verify subscription appears with correct details

**Expected Results:**
- ✅ Subscription created with status "pending" or "active"
- ✅ Items match basket selection
- ✅ Next issue date is calculated correctly
- ✅ Member can see subscription in their account

---

### Scenario 2: Member Manages Subscription

**Goal:** Test member's ability to pause, reactivate, and cancel subscriptions.

**Setup:**
```bash
# Create active subscription for testing
docker-compose exec php-apache php artisan subscriptions:setup-test --status=active
# Note the subscription ID from output
```

**Steps:**

1. **View Subscription Details**
   - Login as member
   - Visit: `http://localhost/member/orders/subscriptions`
   - Click on subscription to view details

2. **Pause Subscription**
   - Click "Pause" button
   - Verify status changes to "paused"
   - Check email notification (Mailhog: `http://localhost:8025`)

3. **Reactivate Subscription**
   - Click "Reactivate" button
   - Verify status changes back to "active"
   - Verify next issue date is adjusted appropriately

4. **Update Next Issue Date**
   - Try changing the next issue date
   - Verify validation (must be within configured max_reschedule_days)
   - Test with invalid dates (too soon, too far)

5. **Change Item Dosage**
   - Change item size/dosage
   - Verify update notification email

6. **Cancel Subscription**
   - Click "Cancel" button
   - Select cancellation reason
   - Verify status changes to "cancelled"

**Expected Results:**
- ✅ All actions work without errors
- ✅ Status updates correctly
- ✅ Email notifications sent
- ✅ Changes logged in subscription_logs table

**Debugging:**
```bash
# View subscription details
docker-compose exec php-apache php artisan subscriptions:show <ID> --all

# Check logs
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT * FROM subscription_logs WHERE subscription_id=<ID> ORDER BY created_at DESC LIMIT 10;"
```

---

### Scenario 3: Automatic Order Generation

**Goal:** Test that recurring orders are automatically generated.

**Setup:**
```bash
# Create active subscription with next issue date coming up
docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

# Get the subscription ID from output
SUBSCRIPTION_ID=<from-previous-command>
```

**Steps:**

1. **Generate Order Manually (Forced)**
   ```bash
   # Force generate order (bypasses date checks)
   docker-compose exec php-apache php artisan subscriptions:generate_orders \
     --force \
     --subscription-id=$SUBSCRIPTION_ID
   ```

2. **Verify Order Created**
   ```bash
   # Show subscription with orders
   docker-compose exec php-apache php artisan subscriptions:show $SUBSCRIPTION_ID --orders
   ```

3. **Check Order Details**
   - Login as admin: `http://localhost/admin`
   - Go to Orders
   - Find the generated order (should have "sRx" marker)
   - Verify items and pricing match subscription

4. **Test Payment Processing**
   - If using test gateway, order should be auto-paid
   - Check subscription's `previous_payment_id` is set
   - Verify `next_issue_date` was advanced

**Expected Results:**
- ✅ Order created with correct items and pricing
- ✅ Order marked as subscription order
- ✅ Next issue date advanced by interval
- ✅ Issue count incremented
- ✅ Payment processed (if configured)

---

### Scenario 4: Payment Failure Handling

**Goal:** Test what happens when automatic payment fails.

**Steps:**

1. **Create Active Subscription**
   ```bash
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active
   SUBSCRIPTION_ID=<from-output>
   ```

2. **Simulate Failed Payment**
   ```bash
   # Generate order and mark payment as failed
   docker-compose exec php-apache php artisan subscriptions:generate_orders \
     --force \
     --fail \
     --subscription-id=$SUBSCRIPTION_ID
   ```

3. **Verify Failure Handling**
   - Check subscription status changed to "payment-failed"
   - Check email sent to customer (Mailhog: `http://localhost:8025`)
   - Verify basket items marked for retry
   - Check subscription logs

4. **Member Retry Payment**
   - Login as member
   - Should see payment failed notification
   - Should be able to retry payment via basket

**Expected Results:**
- ✅ Subscription status = "payment-failed"
- ✅ Notification email sent
- ✅ Customer can retry payment
- ✅ Failed payment logged

**Debugging:**
```bash
docker-compose exec php-apache php artisan subscriptions:show $SUBSCRIPTION_ID --logs
```

---

### Scenario 5: Admin Subscription Management

**Goal:** Test admin's ability to manage subscriptions.

**Steps:**

1. **View All Subscriptions**
   - Login as admin: `http://localhost/admin`
   - Navigate to: Clinic > Subscriptions
   - Test filters (status, member ID, dates)
   - Export to CSV

2. **Edit Subscription**
   - Click edit on a subscription
   - Modify interval, max issues, expiry date
   - Add/remove items
   - Save changes

3. **View Subscription Logs**
   - Navigate to: Clinic > Subscription Logs
   - Filter by subscription ID
   - Verify all actions are logged
   - Check old/new values for changes

4. **Generate Order Manually**
   - From subscription edit page
   - Click "Generate Order" button
   - Verify order created

**Expected Results:**
- ✅ All subscriptions visible with correct data
- ✅ Filters work correctly
- ✅ CSV export contains all data
- ✅ Edits save successfully
- ✅ Full audit trail visible

---

### Scenario 6: Email Notifications

**Goal:** Test all email notifications are sent correctly.

**Setup:**
```bash
# Make sure Mailhog is accessible
open http://localhost:8025
```

**Email Types to Test:**

1. **Subscription Created** - When order is paid
2. **Subscription Paused** - Member pauses subscription
3. **Subscription Reactivated** - Member reactivates
4. **Subscription Cancelled** - Member cancels with reason
5. **Item Updated** - Member changes dosage
6. **Payment Failed** - Automatic payment fails
7. **Assessment Expiring** - Reminder before assessment expires
8. **Update Reminder** - Before next dispatch

**Testing Commands:**

```bash
# Test expiring assessment email
docker-compose exec php-apache php artisan subscriptions:send_expiring_assessment_email

# Test update reminder email
docker-compose exec php-apache php artisan subscriptions:send_subscription_update_reminder
```

**Expected Results:**
- ✅ All emails received in Mailhog
- ✅ Correct subscriber email address
- ✅ Correct subject lines
- ✅ Basket details displayed correctly
- ✅ Links work (subscription management, payment retry)

---

### Scenario 7: Subscription Status Lifecycle

**Goal:** Test all status transitions and edge cases to ensure subscriptions move through states correctly.

**Steps:**

1. **Test Pending → Active Transition**
   ```bash
   # Create a test order with subscription items
   # Complete checkout and mark order as UNPAID initially

   # Check subscription created in pending state
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, status FROM subscriptions WHERE id=(SELECT MAX(id) FROM subscriptions);"

   # Should show: status='pending'

   # Now mark the order as paid (simulate payment)
   docker-compose exec php-apache php artisan subscriptions:generate_from_orders

   # Verify status changed to active
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, status, next_issue_date FROM subscriptions WHERE id=<ID>;"
   ```

2. **Test Active → Completed Transition**
   ```bash
   # Create subscription with max_number_of_issues = 3
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active
   # Note the subscription ID

   # Update max issues to 3
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET max_number_of_issues=3 WHERE id=<ID>;"

   # Generate 3 orders
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Verify status is now 'completed' and next_issue_date is null
   docker-compose exec php-apache php artisan subscriptions:show <ID>

   # Attempt to generate 4th order (should fail/skip)
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>
   ```

3. **Test Active → Expired Transition**
   ```bash
   # Create active subscription
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

   # Set expiry_date to yesterday
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET expiry_date=DATE_SUB(NOW(), INTERVAL 1 DAY) WHERE id=<ID>;"

   # Attempt order generation
   docker-compose exec php-apache php artisan subscriptions:generate_orders --subscription-id=<ID>

   # Verify no order was created (expired subscriptions should be skipped)
   docker-compose exec php-apache php artisan subscriptions:show <ID> --orders
   ```

4. **Test Payment-Failed → Active Recovery**
   ```bash
   # Create active subscription and generate failed payment
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --fail --subscription-id=<ID>

   # Verify status = 'payment-failed'
   docker-compose exec php-apache php artisan subscriptions:show <ID>

   # Check email sent (Mailhog: http://localhost:8025)

   # Member logs in and pays the failed order via basket
   # Navigate to: http://localhost/shop/checkout/basket_overview.php
   # Complete payment for the unpaid order

   # Verify status returns to 'active'
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, status, next_issue_date FROM subscriptions WHERE id=<ID>;"
   ```

5. **Test Invalid Status Transitions**
   - Attempt to pause a cancelled subscription (should fail)
   - Attempt to reactivate a completed subscription (should fail)
   - Verify appropriate error messages displayed

**Expected Results:**
- ✅ Status changes occur automatically based on events
- ✅ Pending → Active when order is paid
- ✅ Active → Completed when max issues reached
- ✅ Active → Expired when prescription expires
- ✅ Payment-Failed → Active when payment recovered
- ✅ Invalid transitions rejected with errors
- ✅ All transitions logged in subscription_logs

**Debugging:**
```bash
# View all status changes for a subscription
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT * FROM subscription_logs WHERE subscription_id=<ID> AND action_type='status_changed' ORDER BY created_at;"
```

---

### Scenario 8: Multi-Item Subscriptions

**Goal:** Test subscriptions with multiple products to ensure all items are handled correctly.

**Setup:**
```bash
# Create a multi-item test subscription
docker-compose exec php-apache php artisan subscriptions:setup-test --status=active --items=3
# Note the subscription ID from output
```

**Steps:**

1. **Verify Multi-Item Creation**
   ```bash
   # Check all items in subscription
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, subscription_id, shop_item_id, shop_item_size_id, quantity FROM subscription_items WHERE subscription_id=<ID>;"

   # Should show 3 items
   ```

2. **View in Member Area**
   - Login as member
   - Visit: `http://localhost/member/orders/subscriptions`
   - Click on the subscription
   - Verify all 3 items are displayed with correct dosages and prices

3. **Update Individual Item**
   - Click "Change dosage" on item #1
   - Select different size
   - Verify only item #1 updated, items #2 and #3 unchanged
   - Check email notification shows updated item details

4. **Generate Order with Multiple Items**
   ```bash
   # Generate order
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Get the order ID
   docker-compose exec php-apache php artisan subscriptions:show <ID> --orders

   # Verify order contains all 3 items
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT oi.id, oi.shop_item_id, oi.quantity FROM order_items oi WHERE oi.order_id=<ORDER_ID>;"
   ```

5. **Verify Shared Schedule**
   - All items should have the same next_issue_date
   - All items should follow the same interval
   - Pause should affect all items together

**Expected Results:**
- ✅ Multiple items created in single subscription
- ✅ All items visible in member area
- ✅ Individual items can be updated independently
- ✅ Generated orders contain all items
- ✅ All items share same schedule/interval
- ✅ Price_per_issue = sum of all item prices

**Debugging:**
```bash
# Show detailed subscription with items
docker-compose exec php-apache php artisan subscriptions:show <ID> --all
```

---

### Scenario 9: Phone Order Subscriptions

**Goal:** Test phone order special handling for admin-created subscriptions.

**Steps:**

1. **Admin Creates Phone Order with Subscription**
   - Login as admin: `http://localhost/admin`
   - Navigate to: Orders > Create Phone Order
   - Add items with subscription option selected
   - Complete the order and mark as paid manually
   - Note the order ID

2. **Generate Subscription from Phone Order**
   ```bash
   # Create subscription from phone order
   docker-compose exec php-apache php artisan subscriptions:generate_from_orders

   # Get subscription ID
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, member_id, admin_id, status FROM subscriptions ORDER BY id DESC LIMIT 1;"

   # Note: admin_id should be set (indicates phone order origin)
   ```

3. **Verify Phone Order Detection**
   ```bash
   # Check if first order is marked as phone order
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT o.id, p.VendorTxCode, p.type FROM \`order\` o JOIN protx_records p ON o.id=p.order_id WHERE o.id=<FIRST_ORDER_ID>;"

   # VendorTxCode should start with 'PHONE-'
   # type should be 'phone'
   ```

4. **Generate Recurring Phone Order**
   ```bash
   # Generate next order
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Get the new order ID
   docker-compose exec php-apache php artisan subscriptions:show <ID> --orders

   # Verify new order also has PHONE- reference
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT o.id, p.VendorTxCode, p.type, o.paid FROM \`order\` o JOIN protx_records p ON o.id=p.order_id WHERE o.id=<NEW_ORDER_ID>;"

   # Should show: VendorTxCode='PHONE-xxx', type='phone', paid=1 (auto-paid)
   ```

5. **Verify Auto-Payment**
   - Check that recurring phone orders are automatically marked as paid
   - No payment collection attempted
   - Order appears in admin panel as completed

**Expected Results:**
- ✅ Phone orders create subscriptions with admin_id preserved
- ✅ First order VendorTxCode starts with 'PHONE-'
- ✅ Recurring orders also generate with PHONE- reference
- ✅ Recurring orders auto-marked as paid (TestPaymentGateway)
- ✅ No payment collection attempted
- ✅ Member can still manage subscription (pause, cancel, etc.)

**Debugging:**
```bash
# Check protx records for subscription orders
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT p.* FROM protx_records p JOIN subscriptions_orders so ON p.order_id=so.order_id WHERE so.subscription_id=<ID>;"
```

---

### Scenario 10: Assessment Expiry Workflow

**Goal:** Test complete prescription expiry and renewal workflow.

**Setup:**
```bash
# Create subscription with expiry in 7 days
docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

# Set expiry date to 7 days from now
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "UPDATE subscriptions SET expiry_date=DATE_ADD(NOW(), INTERVAL 7 DAY), is_assessment_updated=1 WHERE id=<ID>;"
```

**Steps:**

1. **Test Expiring Assessment Email**
   ```bash
   # Run the expiring assessment email command
   docker-compose exec php-apache php artisan subscriptions:send_expiring_assessment_email

   # Check Mailhog for email: http://localhost:8025
   # Email should contain assessment renewal link

   # Verify is_assessment_updated flag set to 0
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, expiry_date, is_assessment_updated FROM subscriptions WHERE id=<ID>;"
   ```

2. **Test Email Not Sent Twice**
   ```bash
   # Run command again same day
   docker-compose exec php-apache php artisan subscriptions:send_expiring_assessment_email

   # Check Mailhog - no new email should be sent (flag prevents duplicate)
   ```

3. **Test Expired Subscription Blocks Orders**
   ```bash
   # Set expiry_date to yesterday
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET expiry_date=DATE_SUB(NOW(), INTERVAL 1 DAY) WHERE id=<ID>;"

   # Attempt order generation
   docker-compose exec php-apache php artisan subscriptions:generate_orders --subscription-id=<ID>

   # Verify no order created
   docker-compose exec php-apache php artisan subscriptions:show <ID> --orders
   # Count should not increase
   ```

4. **Member Renews Assessment**
   - Member clicks link in expiry email
   - Completes assessment questionnaire
   - Assessment approval updates expiry_date

   ```bash
   # Simulate assessment renewal (admin updates expiry)
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET expiry_date=DATE_ADD(NOW(), INTERVAL 365 DAY), is_assessment_updated=1 WHERE id=<ID>;"
   ```

5. **Verify Subscription Resumes**
   ```bash
   # Now order generation should work
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Verify order created
   docker-compose exec php-apache php artisan subscriptions:show <ID> --orders
   ```

**Expected Results:**
- ✅ Email sent 7 days before expiry
- ✅ is_assessment_updated flag prevents duplicate emails
- ✅ Expired subscriptions block order generation
- ✅ Member can renew via assessment link
- ✅ After renewal, subscription resumes normally
- ✅ New expiry_date set appropriately (e.g., +365 days)

**Debugging:**
```bash
# Check subscription expiry details
docker-compose exec php-apache php artisan subscriptions:show <ID>
```

---

### Scenario 11: Date Edge Cases and Rescheduling

**Goal:** Test complex date scenarios and rescheduling limits.

**Steps:**

1. **Test Month Boundary Calculations**
   ```bash
   # Create monthly subscription starting Jan 31
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active --interval=months --multiplier=1

   # Set next_issue_date to Jan 31
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET next_issue_date='2026-01-31' WHERE id=<ID>;"

   # Generate order (should advance to Feb 28/29)
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Check new next_issue_date
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, next_issue_date FROM subscriptions WHERE id=<ID>;"
   # Should show: 2026-02-28

   # Generate next order (should advance to Mar 28 or Mar 31)
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>
   ```

2. **Test Reactivation After Long Pause**
   ```bash
   # Create active subscription
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

   # Pause it
   # Login as member and pause via UI, or:
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET status='paused', next_issue_date=NULL WHERE id=<ID>;"

   # Simulate 6 months passing (set last order date to 6 months ago)
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET updated_at=DATE_SUB(NOW(), INTERVAL 6 MONTH) WHERE id=<ID>;"

   # Reactivate via member area or API
   # Login as member: http://localhost/member/orders/subscriptions
   # Click "Reactivate" button

   # Verify next_issue_date calculated correctly (should be in future, not in past)
   docker-compose exec php-apache php artisan subscriptions:show <ID>
   ```

3. **Test Maximum Reschedule Limit**
   ```bash
   # Set config (default is 45 days)
   echo "SUBSCRIPTION_MAX_RESCHEDULE_DAYS=30" >> .env
   docker-compose exec php-apache php artisan config:clear

   # Create active subscription
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

   # Login as member: http://localhost/member/orders/subscriptions
   # Attempt to reschedule 31 days in future
   # Should show error: "Next dispatch date must be greater than [DATE] and less than [MAX_DATE]"

   # Attempt 30 days (should succeed)
   # Calculate: Today + 4 days + 30 days = valid date

   # Change config to 60 days and test again
   ```

4. **Test Reschedule with Past next_issue_date**
   ```bash
   # Create subscription with next_issue_date in past
   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

   # Set to 2 months ago
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET next_issue_date=DATE_SUB(NOW(), INTERVAL 2 MONTH) WHERE id=<ID>;"

   # Login as member and attempt reschedule
   # Max limit should be calculated from TODAY, not from past date
   # Max allowed = TODAY + max_reschedule_days (45 days default)
   ```

5. **Test ORDER_CREATE_DAYS_BEFORE_DISPATCH Window**
   ```bash
   # ORDER_CREATE_DAYS_BEFORE_DISPATCH = 3
   # Orders are generated when next_issue_date <= now + 3 days
   # i.e. the order is created up to 3 days BEFORE the dispatch date

   docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

   # Set next_issue_date to 5 days from now (outside the 3-day window)
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET next_issue_date=DATE_ADD(NOW(), INTERVAL 5 DAY) WHERE id=<ID>;"

   # Run order generation (should NOT generate - outside window)
   docker-compose exec php-apache php artisan subscriptions:generate_orders --subscription-id=<ID>

   # Verify no order created

   # Set next_issue_date to tomorrow (within the 3-day window)
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "UPDATE subscriptions SET next_issue_date=DATE_ADD(NOW(), INTERVAL 1 DAY) WHERE id=<ID>;"

   # Run order generation (should generate - within window)
   docker-compose exec php-apache php artisan subscriptions:generate_orders --subscription-id=<ID>

   # Verify order created
   docker-compose exec php-apache php artisan subscriptions:show <ID> --orders
   ```

**Expected Results:**
- ✅ Month boundaries handled correctly (Jan 31 → Feb 28)
- ✅ Long pauses recalculate dates correctly
- ✅ Reschedule limits enforced based on config
- ✅ Past dates use TODAY as reference for max calculation
- ✅ ORDER_CREATE_DAYS_BEFORE_DISPATCH window respected
- ✅ Member cannot reschedule too soon (< 4 days)

---

### Scenario 12: Coupon and Discount Testing

**Goal:** Test subscription discounts and coupon application.

**Steps:**

1. **Configure Subscription Discount**
   - Login as admin: `http://localhost/admin`
   - Navigate to: Clinic > Subscription Preferences
   - Find a product size
   - Set discount_percentage = 20
   - Save changes

2. **Test Discount Display in Basket**
   - Login as member
   - Add the product to basket with subscription option
   - Verify discounted price displayed (20% off)
   - Price should show: ~~£50.00~~ £40.00 (example)

3. **Complete Order with Discount**
   - Complete checkout and payment
   - Note the order ID

   ```bash
   # Generate subscription
   docker-compose exec php-apache php artisan subscriptions:generate_from_orders

   # Verify subscription has correct discounted price
   docker-compose exec php-apache php artisan subscriptions:show <ID>
   ```

4. **Verify Recurring Order Uses Discount**
   ```bash
   # Generate recurring order
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Check order total reflects discount
   docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
     -e "SELECT id, cost_total FROM \`order\` WHERE id=<NEW_ORDER_ID>;"
   ```

5. **Test First Subscription Order Coupon**
   ```bash
   # Create coupon with first_subscription_order = 1
   # Apply £10 off first subscription order

   # Add item to basket with subscription + coupon
   # Complete first order
   # Verify coupon applied to first order: £40 - £10 = £30

   # Generate second order
   docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>

   # Verify coupon NOT applied to second order: £40 (subscription discount only)
   ```

6. **Test Discount on Item Change**
   - Change subscription item to different size with different discount (e.g., 15%)
   - Generate order
   - Verify new discount percentage applied

**Expected Results:**
- ✅ Discount percentage configured per product size
- ✅ Discounted price displayed in basket
- ✅ Subscription created with discount applied
- ✅ Recurring orders use discounted price
- ✅ First-order coupons apply only to first order
- ✅ Item changes use new discount percentage

**Debugging:**
```bash
# Check subscription preferences
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT * FROM subscription_preferences WHERE shop_item_size_id=<SIZE_ID>;"
```

---

## Useful Commands Reference

### Debugging Commands

```bash
# Show detailed subscription info
docker-compose exec php-apache php artisan subscriptions:show <ID>

# Show with logs
docker-compose exec php-apache php artisan subscriptions:show <ID> --logs

# Show with orders
docker-compose exec php-apache php artisan subscriptions:show <ID> --orders

# Show everything
docker-compose exec php-apache php artisan subscriptions:show <ID> --all
```

### Data Generation Commands

```bash
# Create test subscription (basic)
docker-compose exec php-apache php artisan subscriptions:setup-test

# Create active subscription
docker-compose exec php-apache php artisan subscriptions:setup-test --status=active

# Create weekly subscription
docker-compose exec php-apache php artisan subscriptions:setup-test \
  --interval=weeks \
  --multiplier=1

# Create with multiple items
docker-compose exec php-apache php artisan subscriptions:setup-test --items=3

# Create for specific member
docker-compose exec php-apache php artisan subscriptions:setup-test --member-id=123
```

### Subscription Processing Commands

```bash
# Generate subscriptions from paid orders
docker-compose exec php-apache php artisan subscriptions:generate_from_orders

# Generate orders (respects timing)
docker-compose exec php-apache php artisan subscriptions:generate_orders

# Force generate orders (bypass timing)
docker-compose exec php-apache php artisan subscriptions:generate_orders --force

# Test specific subscription
docker-compose exec php-apache php artisan subscriptions:generate_orders \
  --force \
  --subscription-id=123

# Simulate payment failure
docker-compose exec php-apache php artisan subscriptions:generate_orders \
  --force \
  --fail \
  --subscription-id=123
```

### Email Testing Commands

```bash
# Send expiring assessment emails
docker-compose exec php-apache php artisan subscriptions:send_expiring_assessment_email

# Send update reminder emails
docker-compose exec php-apache php artisan subscriptions:send_subscription_update_reminder
```

---

## Database Queries for Testing

```bash
# View all subscriptions
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT id, member_id, status, interval_multiplier, interval, next_issue_date FROM subscriptions;"

# View subscription items
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT * FROM subscription_items WHERE subscription_id=<ID>;"

# View subscription logs
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT id, action_type, action_description, source, created_at FROM subscription_logs WHERE subscription_id=<ID> ORDER BY created_at DESC;"

# View orders linked to subscriptions
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT s.id as sub_id, o.id as order_id, o.date, o.paid, o.cost_total FROM subscriptions s JOIN subscriptions_orders so ON s.id = so.subscription_id JOIN \`order\` o ON so.order_id = o.id WHERE s.id=<ID>;"
```

---

## Configuration Testing

Test different configuration values:

```bash
# Test max reschedule days limit
# Edit .env
echo "SUBSCRIPTION_MAX_RESCHEDULE_DAYS=30" >> .env

# Clear config
docker-compose exec php-apache php artisan config:clear

# Verify config loaded
docker-compose exec php-apache php -r "require 'vendor/autoload.php'; \$app = require_once 'bootstrap/app.php'; \$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); echo config('subscription.max_reschedule_days') . PHP_EOL;"

# Test in member area - try to reschedule beyond 30 days
```

---

## Troubleshooting

### Subscription Not Created from Order

**Check:**
1. Order is marked as paid
2. Basket item has `has_requested_subscription = 1`
3. No existing subscription for this order
4. Command ran: `subscriptions:generate_from_orders`

**Debug:**
```bash
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT id, has_subscription, paid FROM \`order\` WHERE id=<ORDER_ID>;"

docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "SELECT id, has_requested_subscription FROM basket_item WHERE id IN (SELECT basket_item_id FROM order_items WHERE order_id=<ORDER_ID>);"
```

### Order Not Generated

**Check:**
1. Subscription status is "active"
2. `next_issue_date` is set and within timing window
3. `previous_payment_id` is set (if auto-payment enabled)
4. Subscription has necessary details (member addresses, items)

**Note:** Subscriptions created via `subscriptions:setup-test` have no initial order. The first generated order will use default delivery settings (delivery_method_id=1). Subsequent orders will copy details from the first order.

**Debug:**
```bash
docker-compose exec php-apache php artisan subscriptions:show <ID>

# Check if can generate
docker-compose exec php-apache php artisan subscriptions:generate_orders --force --subscription-id=<ID>
```

### Emails Not Sending

**Check:**
1. Mailhog is running: `http://localhost:8025`
2. Queue is processing (if using queues)
3. Email configuration in `.env`

**Debug:**
```bash
# Check Mailhog
docker-compose logs mailhog

# Check Laravel logs
docker-compose exec php-apache tail -f storage/logs/laravel.log
```

---

## Performance Testing

For testing with larger datasets:

```bash
# Create 10 test subscriptions
for i in {1..10}; do
  docker-compose exec php-apache php artisan subscriptions:setup-test --status=active
done

# Generate orders for all
docker-compose exec php-apache php artisan subscriptions:generate_orders --force

# Monitor performance
docker-compose exec php-apache php artisan subscriptions:generate_from_orders -vvv
```

---

## Cleanup Test Data

```bash
# Delete all test subscriptions (CAUTION!)
docker-compose exec -T mariadb mysql -u pharma_admin -ppharma_password pharma_db \
  -e "DELETE FROM subscription_logs; DELETE FROM subscription_items; DELETE FROM subscriptions_orders; DELETE FROM subscriptions;"

# Or reset database completely
docker-compose exec php-apache php artisan migrate:fresh --seed
```

---

## Automated Testing Checklist

Use this checklist for comprehensive manual testing:

### Basic Functionality (Scenarios 1-6)
- [ ] Customer can select subscription option during checkout
- [ ] Subscription created after payment
- [ ] Member can view subscriptions in account
- [ ] Member can pause subscription
- [ ] Member can reactivate subscription
- [ ] Member can cancel subscription with reason
- [ ] Member can update next issue date (within limits)
- [ ] Member can change item dosage
- [ ] Recurring orders generated automatically
- [ ] Payment processed for recurring orders
- [ ] Payment failure handled gracefully
- [ ] Failed payment email sent
- [ ] Customer can retry failed payment
- [ ] Admin can view all subscriptions
- [ ] Admin can filter subscriptions
- [ ] Admin can export subscriptions to CSV
- [ ] Admin can edit subscriptions
- [ ] Admin can view subscription logs
- [ ] All actions properly logged
- [ ] Email notifications sent for all events
- [ ] Assessment expiry reminder sent
- [ ] Subscription update reminder sent
- [ ] Orders marked with "sRx" indicator
- [ ] Subscription preferences configurable per product
- [ ] Configuration changes respected (max_reschedule_days)

### Status Lifecycle (Scenario 7)
- [ ] Pending → Active transition on payment
- [ ] Active → Completed when max issues reached
- [ ] Active → Expired when prescription expires
- [ ] Payment-Failed → Active recovery works
- [ ] Invalid status transitions rejected
- [ ] All status changes logged

### Multi-Item Subscriptions (Scenario 8)
- [ ] Multi-item subscriptions created correctly
- [ ] All items displayed in member area
- [ ] Individual items can be updated
- [ ] Orders contain all subscription items
- [ ] All items share same schedule
- [ ] Price calculated as sum of items

### Phone Orders (Scenario 9)
- [ ] Phone orders create subscriptions with admin_id
- [ ] First order marked with PHONE- reference
- [ ] Recurring orders use PHONE- reference
- [ ] Recurring orders auto-marked as paid
- [ ] No payment collection attempted
- [ ] Member can manage phone order subscriptions

### Assessment Expiry (Scenario 10)
- [ ] Expiry email sent 7 days before
- [ ] is_assessment_updated flag prevents duplicates
- [ ] Expired subscriptions block orders
- [ ] Member can renew via assessment
- [ ] Subscription resumes after renewal
- [ ] New expiry date set correctly

### Date Edge Cases (Scenario 11)
- [ ] Month boundaries calculated correctly
- [ ] Long pause recalculates dates properly
- [ ] Reschedule limits enforced
- [ ] Past dates use TODAY as reference
- [ ] ORDER_CREATE_DAYS_BEFORE_DISPATCH respected
- [ ] Cannot reschedule too soon (< 4 days)

### Coupons & Discounts (Scenario 12)
- [ ] Subscription discount configured per size
- [ ] Discounted price shown in basket
- [ ] Subscription created with discount
- [ ] Recurring orders use discounted price
- [ ] First-order coupons apply once only
- [ ] Item change updates discount percentage

---

## Browser Testing URLs

Quick reference for browser testing:

- **Member Login:** `http://localhost/member/login`
- **Member Subscriptions:** `http://localhost/member/orders/subscriptions`
- **Admin Login:** `http://localhost/admin`
- **Admin Subscriptions:** `http://localhost/admin/subscriptions`
- **Admin Subscription Logs:** `http://localhost/admin/subscription-logs`
- **Mailhog:** `http://localhost:8025`
- **Product Catalog:** `http://localhost/shop/browse.php`
- **Basket:** `http://localhost/shop/checkout/basket_overview.php`

---

## Support

If you encounter issues during testing:

1. Check Laravel logs: `docker-compose exec php-apache tail -f storage/logs/laravel.log`
2. Check subscription logs: `docker-compose exec php-apache php artisan subscriptions:show <ID> --logs`
3. Verify configuration: `grep SUBSCRIPTION .env`
4. Clear caches: `docker-compose exec php-apache php artisan config:clear && php artisan cache:clear`

For more details, see [README.md](README.md)
