Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Staff Wallet API Test Script | |
| Demonstrates wallet management operations with example requests. | |
| """ | |
| import asyncio | |
| import json | |
| import uuid | |
| from datetime import datetime | |
| from typing import Dict, Any | |
| import httpx | |
| class WalletAPITester: | |
| """Test client for Staff Wallet Management APIs.""" | |
| def __init__(self, base_url: str = "http://localhost:8002", token: str = None): | |
| self.base_url = base_url | |
| self.headers = { | |
| "Content-Type": "application/json" | |
| } | |
| if token: | |
| self.headers["Authorization"] = f"Bearer {token}" | |
| async def test_wallet_operations(self): | |
| """Run comprehensive wallet operation tests.""" | |
| print("π§ͺ Staff Wallet API Test Suite") | |
| print("=" * 50) | |
| # Test staff ID | |
| staff_id = "123e4567-e89b-12d3-a456-426614174000" | |
| async with httpx.AsyncClient() as client: | |
| # Test 1: Health Check | |
| await self._test_health_check(client) | |
| # Test 2: Get Wallet Summary (might not exist initially) | |
| await self._test_get_wallet_summary(client, staff_id) | |
| # Test 3: Credit Commission | |
| await self._test_credit_commission(client, staff_id) | |
| # Test 4: Get Updated Wallet Summary | |
| await self._test_get_wallet_summary(client, staff_id) | |
| # Test 5: Get Wallet Ledger with Projection | |
| await self._test_get_wallet_ledger(client, staff_id) | |
| # Test 6: Credit Another Commission | |
| await self._test_credit_commission(client, staff_id, points=75, bill_ref="BILL_2024_002") | |
| # Test 7: Debit for Transfer | |
| await self._test_debit_for_transfer(client, staff_id) | |
| # Test 8: Admin Adjustment (Credit) | |
| await self._test_admin_adjustment(client, staff_id, points=25, reason="Bonus points") | |
| # Test 9: Admin Adjustment (Debit) | |
| await self._test_admin_adjustment(client, staff_id, points=-10, reason="Correction") | |
| # Test 10: Reverse Commission | |
| await self._test_reverse_commission(client, staff_id, "BILL_2024_001") | |
| # Test 11: Final Wallet Summary | |
| await self._test_get_wallet_summary(client, staff_id) | |
| # Test 12: Full Ledger History | |
| await self._test_get_full_ledger(client, staff_id) | |
| # Test 13: Error Cases | |
| await self._test_error_cases(client, staff_id) | |
| async def _test_health_check(self, client: httpx.AsyncClient): | |
| """Test wallet service health check.""" | |
| print("\nπ₯ Testing Health Check") | |
| try: | |
| response = await client.get(f"{self.base_url}/api/v1/wallet/health") | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"Service: {data.get('service')} - {data.get('status')}") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Health check failed: {e}") | |
| async def _test_get_wallet_summary(self, client: httpx.AsyncClient, staff_id: str): | |
| """Test getting wallet summary.""" | |
| print(f"\nπ° Testing Get Wallet Summary for {staff_id}") | |
| try: | |
| response = await client.get( | |
| f"{self.base_url}/api/v1/wallet/summary/{staff_id}", | |
| headers=self.headers | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"Available Points: {data.get('available_points')}") | |
| print(f"Lifetime Points: {data.get('lifetime_points')}") | |
| print(f"Updated: {data.get('updated_at')}") | |
| elif response.status_code == 404: | |
| print("Wallet not found (expected for new staff)") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Get wallet summary failed: {e}") | |
| async def _test_credit_commission(self, client: httpx.AsyncClient, staff_id: str, points: int = 50, bill_ref: str = "BILL_2024_001"): | |
| """Test crediting commission points.""" | |
| print(f"\nπ³ Testing Credit Commission: {points} points") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "points": points, | |
| "source_ref": bill_ref, | |
| "bill_amount": 1000.00 | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/credit/commission", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"β Success: {data.get('message')}") | |
| print(f"New Balance: {data.get('new_balance')}") | |
| print(f"Ledger ID: {data.get('ledger_id')}") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Credit commission failed: {e}") | |
| async def _test_debit_for_transfer(self, client: httpx.AsyncClient, staff_id: str, points: int = 30): | |
| """Test debiting points for transfer.""" | |
| print(f"\nπΈ Testing Debit for Transfer: {points} points") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "points": points, | |
| "source_ref": f"TRANSFER_{datetime.now().strftime('%Y%m%d_%H%M%S')}", | |
| "transfer_to": "Bank Account" | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/debit/transfer", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"β Success: {data.get('message')}") | |
| print(f"New Balance: {data.get('new_balance')}") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Debit for transfer failed: {e}") | |
| async def _test_admin_adjustment(self, client: httpx.AsyncClient, staff_id: str, points: int, reason: str): | |
| """Test admin adjustment.""" | |
| operation = "Credit" if points > 0 else "Debit" | |
| print(f"\nβοΈ Testing Admin {operation}: {abs(points)} points") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "points": points, | |
| "reason": reason, | |
| "admin_user_id": str(uuid.uuid4()) | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/admin/adjustment", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"β Success: {data.get('message')}") | |
| print(f"New Balance: {data.get('new_balance')}") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Admin adjustment failed: {e}") | |
| async def _test_reverse_commission(self, client: httpx.AsyncClient, staff_id: str, original_ref: str): | |
| """Test reversing a commission.""" | |
| print(f"\nπ Testing Reverse Commission: {original_ref}") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "original_source_ref": original_ref, | |
| "reason": "Customer returned item" | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/reverse/commission", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"β Success: {data.get('message')}") | |
| print(f"New Balance: {data.get('new_balance')}") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Reverse commission failed: {e}") | |
| async def _test_get_wallet_ledger(self, client: httpx.AsyncClient, staff_id: str): | |
| """Test getting wallet ledger with projection.""" | |
| print(f"\nπ Testing Get Wallet Ledger (with projection)") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "filters": {}, | |
| "skip": 0, | |
| "limit": 5, | |
| "projection_list": ["entry_type", "points", "balance_after", "created_at"] | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/ledger/list", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"Total Entries: {data.get('total')}") | |
| print(f"Returned: {len(data.get('entries', []))}") | |
| for i, entry in enumerate(data.get('entries', [])[:3]): | |
| print(f" {i+1}. {entry.get('entry_type')}: {entry.get('points')} pts (Balance: {entry.get('balance_after')})") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Get wallet ledger failed: {e}") | |
| async def _test_get_full_ledger(self, client: httpx.AsyncClient, staff_id: str): | |
| """Test getting full wallet ledger without projection.""" | |
| print(f"\nπ Testing Get Full Wallet Ledger") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "filters": {}, | |
| "skip": 0, | |
| "limit": 10 | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/ledger/list", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| print(f"Total Entries: {data.get('total')}") | |
| for i, entry in enumerate(data.get('entries', [])): | |
| print(f" {i+1}. {entry.get('entry_type')}: {entry.get('points')} pts") | |
| print(f" Source: {entry.get('source_type')} - {entry.get('source_ref')}") | |
| print(f" Balance After: {entry.get('balance_after')}") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"β Get full ledger failed: {e}") | |
| async def _test_error_cases(self, client: httpx.AsyncClient, staff_id: str): | |
| """Test various error scenarios.""" | |
| print(f"\nβ Testing Error Cases") | |
| # Test insufficient balance | |
| print("Testing insufficient balance...") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "points": 10000, # Very high amount | |
| "source_ref": f"TRANSFER_ERROR_{datetime.now().strftime('%Y%m%d_%H%M%S')}", | |
| "transfer_to": "Test" | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/debit/transfer", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code} (Expected: 400)") | |
| if response.status_code == 400: | |
| print("β Correctly rejected insufficient balance") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"Error test failed: {e}") | |
| # Test duplicate credit | |
| print("\nTesting duplicate credit...") | |
| try: | |
| payload = { | |
| "staff_id": staff_id, | |
| "points": 50, | |
| "source_ref": "BILL_2024_001", # Same as first credit | |
| "bill_amount": 1000.00 | |
| } | |
| response = await client.post( | |
| f"{self.base_url}/api/v1/wallet/credit/commission", | |
| headers=self.headers, | |
| json=payload | |
| ) | |
| print(f"Status: {response.status_code} (Expected: 409)") | |
| if response.status_code == 409: | |
| print("β Correctly rejected duplicate credit") | |
| else: | |
| print(f"Response: {response.text}") | |
| except Exception as e: | |
| print(f"Error test failed: {e}") | |
| async def main(): | |
| """Run the wallet API tests.""" | |
| # You can set a JWT token here if authentication is required | |
| token = None # Replace with actual JWT token if needed | |
| tester = WalletAPITester(token=token) | |
| await tester.test_wallet_operations() | |
| print("\n" + "=" * 50) | |
| print("π Wallet API Test Suite Complete!") | |
| print("\nTo run with authentication:") | |
| print("python test_wallet_api.py --token YOUR_JWT_TOKEN") | |
| if __name__ == "__main__": | |
| import sys | |
| # Simple argument parsing for token | |
| token = None | |
| if "--token" in sys.argv: | |
| try: | |
| token_index = sys.argv.index("--token") | |
| token = sys.argv[token_index + 1] | |
| except (IndexError, ValueError): | |
| print("Usage: python test_wallet_api.py --token YOUR_JWT_TOKEN") | |
| sys.exit(1) | |
| # Run the tests | |
| asyncio.run(main()) |