""" Invoice Generation System - Test Script This script tests the complete invoice generation flow: 1. Get available tickets 2. Generate invoice 3. View invoice (public) 4. Export CSV 5. Regenerate token Usage: python scripts/test_invoice_generation.py """ import requests import json import sys from datetime import datetime # Configuration BASE_URL = "http://localhost:8000/api/v1" AUTH_TOKEN = "YOUR_AUTH_TOKEN_HERE" # Replace with actual token CONTRACTOR_ID = "YOUR_CONTRACTOR_ID" # Replace with actual UUID CLIENT_ID = "YOUR_CLIENT_ID" # Replace with actual UUID PROJECT_ID = "YOUR_PROJECT_ID" # Replace with actual UUID HEADERS = { "Authorization": f"Bearer {AUTH_TOKEN}", "Content-Type": "application/json" } def print_section(title): """Print section header""" print("\n" + "=" * 60) print(f" {title}") print("=" * 60) def print_success(message): """Print success message""" print(f"✅ {message}") def print_error(message): """Print error message""" print(f"❌ {message}") def print_info(message): """Print info message""" print(f"â„šī¸ {message}") def test_get_available_tickets(): """Test getting available tickets""" print_section("1. Get Available Tickets") try: response = requests.get( f"{BASE_URL}/invoices/available-tickets", params={ "contractor_id": CONTRACTOR_ID, "project_id": PROJECT_ID }, headers=HEADERS ) if response.status_code == 200: data = response.json() tickets = data.get("tickets", []) print_success(f"Found {len(tickets)} available tickets") if tickets: print_info("Sample ticket:") ticket = tickets[0] print(f" - ID: {ticket['id']}") print(f" - Name: {ticket.get('ticket_name', 'N/A')}") print(f" - Type: {ticket['ticket_type']}") print(f" - Images: {ticket['images_count']}") print(f" - Sales Order: {ticket.get('sales_order_number', 'N/A')}") return [t['id'] for t in tickets[:2]] # Return first 2 ticket IDs else: print_error("No available tickets found") print_info("Create some completed tickets first:") print(" UPDATE tickets SET status='completed', completed_at=NOW(), is_invoiced=false WHERE id='YOUR_TICKET_ID';") return None else: print_error(f"Failed: {response.status_code}") print(response.text) return None except Exception as e: print_error(f"Exception: {str(e)}") return None def test_generate_invoice(ticket_ids): """Test generating invoice""" print_section("2. Generate Invoice") if not ticket_ids: print_error("No ticket IDs provided") return None try: payload = { "contractor_id": CONTRACTOR_ID, "client_id": CLIENT_ID, "project_id": PROJECT_ID, "ticket_ids": ticket_ids, "title": f"Test Invoice - {datetime.now().strftime('%Y-%m-%d %H:%M')}", "notes": "This is a test invoice generated by the test script" } response = requests.post( f"{BASE_URL}/invoices/generate", headers=HEADERS, json=payload ) if response.status_code == 200: data = response.json() print_success("Invoice generated successfully") print(f" - Invoice ID: {data['invoice_id']}") print(f" - Invoice Number: {data['invoice_number']}") print(f" - Tickets: {data['tickets_count']}") print(f" - Viewing Link: {data['viewing_link']}") print(f" - CSV Link: {data['csv_download_link']}") print(f" - Notification Created: {data['notification_created']}") return data else: print_error(f"Failed: {response.status_code}") print(response.text) return None except Exception as e: print_error(f"Exception: {str(e)}") return None def test_view_invoice(viewing_link): """Test viewing invoice (public - no auth)""" print_section("3. View Invoice (Public)") if not viewing_link: print_error("No viewing link provided") return False try: # Extract token from link token = viewing_link.split("token=")[1] if "token=" in viewing_link else None if not token: print_error("Could not extract token from link") return False response = requests.get( f"{BASE_URL}/invoices/view", params={"token": token} ) if response.status_code == 200: data = response.json() invoice = data.get("invoice", {}) print_success("Invoice viewed successfully") print(f" - Invoice Number: {invoice.get('invoice_number')}") print(f" - Line Items: {len(invoice.get('line_items', []))}") print(f" - Times Viewed: {data.get('times_viewed')}") print(f" - Token Expires: {data.get('token_expires_at')}") # Check if ticket details are enriched line_items = invoice.get('line_items', []) if line_items: first_item = line_items[0] if 'ticket_details' in first_item: details = first_item['ticket_details'] print_info("Ticket details enriched:") print(f" - Images: {details.get('images_count', 0)}") print(f" - Completion Data: {bool(details.get('completion_data'))}") print(f" - Location: {bool(details.get('work_location'))}") return True else: print_error(f"Failed: {response.status_code}") print(response.text) return False except Exception as e: print_error(f"Exception: {str(e)}") return False def test_export_csv(invoice_id): """Test CSV export""" print_section("4. Export CSV") if not invoice_id: print_error("No invoice ID provided") return False try: response = requests.get( f"{BASE_URL}/invoices/{invoice_id}/export/csv", headers=HEADERS ) if response.status_code == 200: # Save CSV to file filename = f"invoice_{invoice_id}.csv" with open(filename, "wb") as f: f.write(response.content) print_success(f"CSV exported successfully: {filename}") # Show first few lines lines = response.content.decode('utf-8').split('\n') print_info("CSV Preview (first 3 lines):") for i, line in enumerate(lines[:3]): print(f" {i+1}: {line[:100]}...") return True else: print_error(f"Failed: {response.status_code}") print(response.text) return False except Exception as e: print_error(f"Exception: {str(e)}") return False def test_regenerate_token(invoice_id): """Test token regeneration""" print_section("5. Regenerate Token") if not invoice_id: print_error("No invoice ID provided") return False try: response = requests.post( f"{BASE_URL}/invoices/{invoice_id}/regenerate-token", headers=HEADERS, json={"expires_in_days": 30} ) if response.status_code == 200: data = response.json() print_success("Token regenerated successfully") print(f" - New Link: {data['viewing_link']}") print(f" - Expires At: {data['expires_at']}") return True else: print_error(f"Failed: {response.status_code}") print(response.text) return False except Exception as e: print_error(f"Exception: {str(e)}") return False def main(): """Run all tests""" print("\n" + "🚀" * 30) print(" Invoice Generation System - Test Script") print("🚀" * 30) # Check configuration if AUTH_TOKEN == "YOUR_AUTH_TOKEN_HERE": print_error("Please configure AUTH_TOKEN in the script") sys.exit(1) if CONTRACTOR_ID == "YOUR_CONTRACTOR_ID": print_error("Please configure CONTRACTOR_ID in the script") sys.exit(1) # Run tests ticket_ids = test_get_available_tickets() if ticket_ids: invoice_data = test_generate_invoice(ticket_ids) if invoice_data: test_view_invoice(invoice_data['viewing_link']) test_export_csv(invoice_data['invoice_id']) test_regenerate_token(invoice_data['invoice_id']) # Summary print_section("Test Summary") print("✅ All tests completed") print("\nNext steps:") print("1. Check notifications in the database") print("2. Verify tickets are marked as invoiced") print("3. Review audit logs") print("4. Test the viewing link in a browser") print("\n" + "🎉" * 30 + "\n") if __name__ == "__main__": main()