# Merchant API Testing Guide

## Overview

This guide provides comprehensive testing procedures for all merchant-related APIs in the UPI PSP platform. The merchant APIs allow partners to enroll, manage, and monitor their merchants for UPI payment processing.

## API Endpoints Coverage

### 🏗️ Merchant Enrollment & Management

#### 1. Create Merchant
- **Endpoint**: `POST /api/v1/partners/:partner_id/merchants`
- **Purpose**: Enroll a new merchant under a partner
- **Authentication**: Partner API token required

#### 2. List Merchants
- **Endpoint**: `GET /api/v1/partners/:partner_id/merchants`
- **Purpose**: Retrieve all merchants for a partner with filtering
- **Authentication**: Partner API token required

#### 3. Get Merchant Details
- **Endpoint**: `GET /api/v1/partners/:partner_id/merchants/:id`
- **Purpose**: Retrieve detailed information for a specific merchant
- **Authentication**: Partner API token required

#### 4. Update Merchant
- **Endpoint**: `PUT /api/v1/partners/:partner_id/merchants/:id`
- **Purpose**: Update merchant information
- **Authentication**: Partner API token required

### 🔧 Merchant Operations

#### 5. Update Merchant Status
- **Endpoint**: `PATCH /api/v1/partners/:partner_id/merchants/:id/status`
- **Purpose**: Change merchant status (ACTIVE, SUSPENDED, INACTIVE)
- **Authentication**: Partner API token required

#### 6. Validate Merchant
- **Endpoint**: `GET /api/v1/partners/:partner_id/merchants/:id/validate`
- **Purpose**: Validate merchant for transaction processing
- **Authentication**: Partner API token required

#### 7. Check Transaction Limits
- **Endpoint**: `POST /api/v1/partners/:partner_id/merchants/:id/check-limits`
- **Purpose**: Verify if a transaction amount is within merchant limits
- **Authentication**: Partner API token required

### 🔍 Merchant Discovery & Analytics

#### 8. Search Merchants
- **Endpoint**: `GET /api/v1/partners/:partner_id/merchants-search`
- **Purpose**: Search merchants using query filters
- **Authentication**: Partner API token required

#### 9. Merchant Statistics
- **Endpoint**: `GET /api/v1/partners/:partner_id/merchants-stats`
- **Purpose**: Get aggregated statistics for partner's merchants
- **Authentication**: Partner API token required

### 🏷️ QR Code Management

#### 10. Generate QR Code
- **Endpoint**: `POST /api/v1/qr-generate`
- **Purpose**: Generate QR codes for merchant payments
- **Authentication**: Partner API token required

#### 11. Check QR Status
- **Endpoint**: `GET /api/v1/qr-status/:id`
- **Purpose**: Check status and details of generated QR codes
- **Authentication**: Partner API token required

## Testing Prerequisites

### 1. Authentication Setup
```bash
# Set your API token
export API_TOKEN="your_partner_api_token_here"
export BASE_URL="https://api.mercurypay.com"
export PARTNER_ID="PARTNER_001"
```

### 2. Test Data Setup
```json
{
  "test_partners": [
    {"id": "PARTNER_001", "name": "Test Partner Alpha"},
    {"id": "PARTNER_002", "name": "Test Partner Beta"}
  ],
  "test_merchants": [
    {"code": "RETAIL001", "type": "retail"},
    {"code": "REST001", "type": "restaurant"},
    {"code": "ECOM001", "type": "ecommerce"}
  ]
}
```

## Detailed Testing Scenarios

### Scenario 1: Complete Merchant Lifecycle

#### Step 1: Create Retail Merchant
```bash
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "RETAIL001",
    "brand_name": "ABC Electronics Store",
    "merchant_vpa": "abcelectronics@upi",
    "business_type": "RETAIL",
    "corridors": ["DOMESTIC"],
    "contact_email": "owner@abcelectronics.com",
    "contact_phone": "+91-9876543210"
  }'
```

**Expected Response:**
```json
{
  "success": true,
  "data": {
    "id": "MERCHANT_12345",
    "merchant_code": "RETAIL001",
    "brand_name": "ABC Electronics Store",
    "status": "ACTIVE"
  },
  "message": "Merchant enrolled successfully"
}
```

#### Step 2: Validate Merchant
```bash
curl -H "Authorization: Bearer $API_TOKEN" \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants/MERCHANT_12345/validate"
```

#### Step 3: Check Transaction Limits
```bash
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants/MERCHANT_12345/check-limits" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount": "1000.00"}'
```

#### Step 4: Generate QR Code
```bash
curl -X POST \
  "$BASE_URL/api/v1/qr-generate" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_id": "MERCHANT_12345",
    "amount": "500.00",
    "note": "Payment for electronics"
  }'
```

### Scenario 2: International Merchant Setup

#### Create International Merchant
```bash
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "INTL001",
    "brand_name": "Global Import Export",
    "merchant_vpa": "globalimport@upi",
    "business_type": "IMPORT_EXPORT",
    "corridors": ["SGD-INR", "USD-INR", "EUR-INR"],
    "contact_email": "finance@globalimport.com",
    "contact_phone": "+91-9876543211",
    "fbar_number": "FBAR123456789"
  }'
```

### Scenario 3: Error Handling Tests

#### Test 1: Duplicate Merchant Code
```bash
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "RETAIL001",
    "brand_name": "Duplicate Store",
    "merchant_vpa": "duplicate@upi",
    "business_type": "RETAIL"
  }'
```

**Expected Response:**
```json
{
  "success": false,
  "errors": {
    "merchant_code": ["has already been taken"]
  }
}
```

#### Test 2: Invalid VPA Format
```bash
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "TEST001",
    "brand_name": "Test Store",
    "merchant_vpa": "invalid-vpa-format",
    "business_type": "RETAIL"
  }'
```

#### Test 3: Missing Required Fields
```bash
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "TEST002"
  }'
```

### Scenario 4: Status Management

#### Suspend Merchant
```bash
curl -X PATCH \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants/MERCHANT_12345/status" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status": "SUSPENDED"}'
```

#### Reactivate Merchant
```bash
curl -X PATCH \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants/MERCHANT_12345/status" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status": "ACTIVE"}'
```

### Scenario 5: Search and Analytics

#### Search Merchants
```bash
curl -H "Authorization: Bearer $API_TOKEN" \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants-search?q=electronics&status=ACTIVE"
```

#### Get Partner Statistics
```bash
curl -H "Authorization: Bearer $API_TOKEN" \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants-stats"
```

## Performance Testing

### Load Testing Parameters
- **Concurrent Users**: 100-500
- **Test Duration**: 15-30 minutes
- **Request Rate**: 10-50 requests/second per endpoint

### Rate Limiting Tests
```bash
# Test rate limiting (should hit 100/min limit)
for i in {1..105}; do
  curl -H "Authorization: Bearer $API_TOKEN" \
    "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" &
done
wait
```

## Security Testing

### 1. Authentication Tests
```bash
# Test without token
curl "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants"

# Test with invalid token
curl -H "Authorization: Bearer invalid_token" \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants"
```

### 2. Authorization Tests
```bash
# Test accessing another partner's merchants
curl -H "Authorization: Bearer $API_TOKEN" \
  "$BASE_URL/api/v1/partners/OTHER_PARTNER/merchants"
```

### 3. Input Validation Tests
```bash
# SQL injection attempt
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "'; DROP TABLE merchants; --",
    "brand_name": "Test Store"
  }'

# XSS attempt  
curl -X POST \
  "$BASE_URL/api/v1/partners/$PARTNER_ID/merchants" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_code": "TEST001",
    "brand_name": "<script>alert('xss')</script>"
  }'
```

## Automated Testing Scripts

### Bash Testing Script
```bash
#!/bin/bash
# merchant_api_test.sh

set -e

# Configuration
API_TOKEN="${API_TOKEN:-your_token_here}"
BASE_URL="${BASE_URL:-https://api.mercurypay.com}"
PARTNER_ID="${PARTNER_ID:-PARTNER_001}"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

# Test function
test_endpoint() {
    local method=$1
    local endpoint=$2
    local data=$3
    local expected_status=$4
    
    log "Testing: $method $endpoint"
    
    if [ -n "$data" ]; then
        response=$(curl -s -w "\n%{http_code}" -X "$method" \
            "$BASE_URL$endpoint" \
            -H "Authorization: Bearer $API_TOKEN" \
            -H "Content-Type: application/json" \
            -d "$data")
    else
        response=$(curl -s -w "\n%{http_code}" -X "$method" \
            "$BASE_URL$endpoint" \
            -H "Authorization: Bearer $API_TOKEN")
    fi
    
    status_code=$(echo "$response" | tail -n1)
    body=$(echo "$response" | head -n -1)
    
    if [ "$status_code" -eq "$expected_status" ]; then
        log "✓ Test passed (Status: $status_code)"
        echo "$body" | jq . 2>/dev/null || echo "$body"
    else
        error "✗ Test failed (Expected: $expected_status, Got: $status_code)"
        echo "$body"
    fi
    
    echo "---"
}

# Run tests
log "Starting Merchant API Tests"

# Test 1: Create merchant
test_endpoint "POST" "/api/v1/partners/$PARTNER_ID/merchants" \
    '{"merchant_code":"TEST001","brand_name":"Test Store","merchant_vpa":"test@upi","business_type":"RETAIL"}' \
    201

# Test 2: List merchants
test_endpoint "GET" "/api/v1/partners/$PARTNER_ID/merchants" "" 200

# Test 3: Get merchant stats
test_endpoint "GET" "/api/v1/partners/$PARTNER_ID/merchants-stats" "" 200

log "All tests completed!"
```

### Python Testing Script
```python
#!/usr/bin/env python3
"""
Merchant API Testing Suite
"""

import requests
import json
import time
import os
from typing import Dict, Any

class MerchantAPITester:
    def __init__(self, base_url: str, api_token: str, partner_id: str):
        self.base_url = base_url
        self.headers = {
            'Authorization': f'Bearer {api_token}',
            'Content-Type': 'application/json'
        }
        self.partner_id = partner_id
        self.session = requests.Session()
        self.session.headers.update(self.headers)
    
    def log(self, message: str, level: str = "INFO"):
        colors = {
            "INFO": "\033[92m",
            "ERROR": "\033[91m", 
            "WARN": "\033[93m",
            "END": "\033[0m"
        }
        print(f"{colors.get(level, '')}{message}{colors['END']}")
    
    def test_create_merchant(self, merchant_data: Dict[str, Any]):
        """Test merchant creation"""
        self.log("Testing merchant creation...")
        
        response = self.session.post(
            f"{self.base_url}/api/v1/partners/{self.partner_id}/merchants",
            json=merchant_data
        )
        
        if response.status_code == 201:
            self.log("✓ Merchant created successfully")
            return response.json()['data']['id']
        else:
            self.log(f"✗ Failed to create merchant: {response.text}", "ERROR")
            return None
    
    def test_list_merchants(self):
        """Test listing merchants"""
        self.log("Testing merchant listing...")
        
        response = self.session.get(
            f"{self.base_url}/api/v1/partners/{self.partner_id}/merchants"
        )
        
        if response.status_code == 200:
            data = response.json()
            self.log(f"✓ Listed {len(data['data'])} merchants")
            return data['data']
        else:
            self.log(f"✗ Failed to list merchants: {response.text}", "ERROR")
            return []
    
    def test_get_merchant(self, merchant_id: str):
        """Test getting merchant details"""
        self.log(f"Testing get merchant {merchant_id}...")
        
        response = self.session.get(
            f"{self.base_url}/api/v1/partners/{self.partner_id}/merchants/{merchant_id}"
        )
        
        if response.status_code == 200:
            self.log("✓ Retrieved merchant details")
            return response.json()
        else:
            self.log(f"✗ Failed to get merchant: {response.text}", "ERROR")
            return None
    
    def test_update_merchant_status(self, merchant_id: str, status: str):
        """Test updating merchant status"""
        self.log(f"Testing status update to {status}...")
        
        response = self.session.patch(
            f"{self.base_url}/api/v1/partners/{self.partner_id}/merchants/{merchant_id}/status",
            json={"status": status}
        )
        
        if response.status_code == 200:
            self.log(f"✓ Status updated to {status}")
            return True
        else:
            self.log(f"✗ Failed to update status: {response.text}", "ERROR")
            return False
    
    def test_check_limits(self, merchant_id: str, amount: str):
        """Test checking transaction limits"""
        self.log(f"Testing transaction limits for amount {amount}...")
        
        response = self.session.post(
            f"{self.base_url}/api/v1/partners/{self.partner_id}/merchants/{merchant_id}/check-limits",
            json={"amount": amount}
        )
        
        if response.status_code == 200:
            result = response.json()
            status = "allowed" if result['allowed'] else "blocked"
            self.log(f"✓ Transaction {status}")
            return result
        else:
            self.log(f"✗ Failed to check limits: {response.text}", "ERROR")
            return None
    
    def run_comprehensive_test(self):
        """Run comprehensive test suite"""
        self.log("=== Starting Comprehensive Merchant API Test ===")
        
        # Test data
        merchant_data = {
            "merchant_code": f"TEST{int(time.time())}",
            "brand_name": "Automated Test Store",
            "merchant_vpa": f"teststore{int(time.time())}@upi",
            "business_type": "RETAIL",
            "corridors": ["DOMESTIC"],
            "contact_email": "test@example.com"
        }
        
        # Test 1: Create merchant
        merchant_id = self.test_create_merchant(merchant_data)
        if not merchant_id:
            return False
        
        # Test 2: List merchants
        merchants = self.test_list_merchants()
        
        # Test 3: Get merchant details
        merchant_details = self.test_get_merchant(merchant_id)
        
        # Test 4: Check limits
        self.test_check_limits(merchant_id, "100.00")
        self.test_check_limits(merchant_id, "10000.00")
        
        # Test 5: Update status
        self.test_update_merchant_status(merchant_id, "SUSPENDED")
        self.test_update_merchant_status(merchant_id, "ACTIVE")
        
        self.log("=== Test Suite Completed ===")
        return True

if __name__ == "__main__":
    # Configuration from environment
    base_url = os.getenv("BASE_URL", "https://api.mercurypay.com")
    api_token = os.getenv("API_TOKEN", "your_token_here")
    partner_id = os.getenv("PARTNER_ID", "PARTNER_001")
    
    tester = MerchantAPITester(base_url, api_token, partner_id)
    tester.run_comprehensive_test()
```

## Expected Response Codes

| Endpoint | Success | Client Error | Server Error |
|----------|---------|--------------|--------------|
| Create Merchant | 201 | 400, 409, 422 | 500 |
| List Merchants | 200 | 400, 403 | 500 |
| Get Merchant | 200 | 404, 403 | 500 |
| Update Merchant | 200 | 400, 404, 422 | 500 |
| Update Status | 200 | 400, 404 | 500 |
| Validate Merchant | 200 | 404, 403 | 500 |
| Check Limits | 200 | 400, 404 | 500 |
| Search Merchants | 200 | 400, 403 | 500 |
| Merchant Stats | 200 | 403 | 500 |
| Generate QR | 201 | 400, 404 | 500 |
| Check QR Status | 200 | 404, 403 | 500 |

## Troubleshooting

### Common Issues

1. **401 Unauthorized**
   - Check API token validity
   - Ensure proper Authorization header format
   - Verify partner permissions

2. **429 Too Many Requests**
   - Implement exponential backoff
   - Check rate limit headers
   - Consider request batching

3. **422 Validation Error**
   - Review request body format
   - Check required field presence
   - Validate data types and formats

4. **404 Not Found**
   - Verify partner ID exists
   - Check merchant ID validity
   - Ensure proper URL paths

### Debug Tips

1. **Enable verbose curl output**:
   ```bash
   curl -v -H "Authorization: Bearer $API_TOKEN" "$URL"
   ```

2. **Check response headers**:
   ```bash
   curl -I -H "Authorization: Bearer $API_TOKEN" "$URL"
   ```

3. **Monitor API logs** (if available):
   ```bash
   tail -f /var/log/api/requests.log
   ```

## Performance Benchmarks

| Endpoint | Target Response Time | Max Concurrent |
|----------|---------------------|----------------|
| Create Merchant | < 500ms | 50 |
| List Merchants | < 200ms | 100 |
| Get Merchant | < 100ms | 200 |
| Update Operations | < 300ms | 100 |
| Search | < 400ms | 50 |
| Statistics | < 1000ms | 20 |

## Conclusion

This testing guide provides comprehensive coverage for all merchant API endpoints. Regular execution of these tests ensures API reliability, proper error handling, and optimal performance.

For additional support or questions, please refer to the API documentation or contact the development team.
