Spaces:
Sleeping
Sleeping
| """ | |
| ============================================================= | |
| MIRCHI TRADING API - COMPLETE DOCUMENTATION & DB INSPECTOR | |
| ============================================================= | |
| Run: python scripts/api_docs.py | |
| """ | |
| import asyncio, json, os, sys | |
| from pathlib import Path | |
| # Add backend root to path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # SECTION 1 โ DATABASE SCHEMA SUMMARY (10 lines) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| DB_SCHEMA_SUMMARY = """ | |
| โโโโโโโโโโโโโโโโโโโ DATABASE SCHEMA SUMMARY โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ 1. parties โ Party master: id, name, phone, city, party_type, โ | |
| โ past_due, is_active, previous_names (JSON) โ | |
| โ 2. mirchi_types โ Mirchi varieties: id, name, is_active โ | |
| โ 3. transactions โ Awaak/Jawaak bills: bill_number, bill_date, โ | |
| โ bill_type(awaak|jawaak), party_id, total_amount, โ | |
| โ paid_amount, balance_amount, expenses(JSON), โ | |
| โ lot_number, is_mixed, is_return โ | |
| โ 4. transaction_items โ Line items: mirchi_name, poti_count, โ | |
| โ poti_weights, net_weight, rate_per_kg, amount โ | |
| โ 5. transaction_payments โ Payments per bill: amount, mode, reference, โ | |
| โ is_reversed โ | |
| โ 6. patti_transactions โ Patti bills (patti_awaak|patti_jawaak): โ | |
| โ same as transactions + gross_weight, โ | |
| โ verified_net_weight โ | |
| โ 7. patti_transaction_items โ Same structure as transaction_items โ | |
| โ 8. party_jama_entries โ Standalone payments: party_id, date, amount, โ | |
| โ reference, notes โ | |
| โ 9. stock_ledger โ Stock movements: mirchi_name, movement_type โ | |
| โ (IN|OUT|RETURN_IN|RETURN_OUT), quantity_in/out, โ | |
| โ balance_after, lot_number โ | |
| โ 10.bill_number_sequences โ Auto-numbering: bill_type, year, batch(A-Z),โ | |
| โ current_number (resets at 500 โ next batch) โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| """ | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # SECTION 2 โ ALL API ENDPOINTS + EXAMPLE RESPONSES | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| API_DOCS = { | |
| # โโ PARTIES โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| "GET /api/parties": { | |
| "desc": "List all parties (with live current_balance)", | |
| "query_params": "party_type, search, skip, limit", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| { | |
| "id": "p-abc123", | |
| "name": "เคฐเคพเคฎเคฒเคพเคฒ เคเฅเคฐเฅเคกเคฐเฅเคธ", | |
| "phone": "9876543210", | |
| "city": "เคจเคพเคเคฆเฅเคก", | |
| "party_type": "both", | |
| "past_due": 5000.0, | |
| "current_balance": 12500.50, | |
| "is_active": True | |
| } | |
| ], | |
| "total": 1 | |
| } | |
| }, | |
| "GET /api/parties/{party_id}": { | |
| "desc": "Single party with computed current_balance", | |
| "example_response": { | |
| "success": True, | |
| "data": { | |
| "id": "p-abc123", | |
| "name": "เคฐเคพเคฎเคฒเคพเคฒ เคเฅเคฐเฅเคกเคฐเฅเคธ", | |
| "phone": "9876543210", | |
| "city": "เคจเคพเคเคฆเฅเคก", | |
| "party_type": "both", | |
| "past_due": 5000.0, | |
| "current_balance": 12500.50, | |
| "previous_names": ["เคฐเคพเคฎเคฒเคพเคฒ"], | |
| "notes": "", | |
| "is_active": True | |
| } | |
| } | |
| }, | |
| "GET /api/parties/{party_id}/name-history": { | |
| "desc": "Full rename history for a party", | |
| "example_response": { | |
| "party_id": "p-abc123", | |
| "current_name": "เคฐเคพเคฎเคฒเคพเคฒ เคเฅเคฐเฅเคกเคฐเฅเคธ", | |
| "name_history": ["เคฐเคพเคฎเคฒเคพเคฒ", "เคฐเคพเคฎเคฒเคพเคฒ เคเคเคเคฐเคชเฅเคฐเคพเคฏเคเฅเคธ"] | |
| } | |
| }, | |
| "POST /api/parties": { | |
| "desc": "Create a new party", | |
| "request_body": { | |
| "name": "เคถเฅเคฏเคพเคฎ เคเฅเคฐเฅเคกเคฐเฅเคธ", | |
| "phone": "9988776655", | |
| "city": "เคฒเคพเคคเฅเคฐ", | |
| "party_type": "jawaak", | |
| "past_due": 0.0 | |
| }, | |
| "example_response": { | |
| "success": True, | |
| "message": "Party created successfully", | |
| "data": {"id": "p-xyz789", "name": "เคถเฅเคฏเคพเคฎ เคเฅเคฐเฅเคกเคฐเฅเคธ"} | |
| } | |
| }, | |
| "PUT /api/parties/{party_id}": { | |
| "desc": "Update party (rename auto-saves to history)", | |
| "request_body": {"name": "เคถเฅเคฏเคพเคฎ เคเคเคเคฐเคชเฅเคฐเคพเคฏเคเฅเคธ", "phone": "9988776655"}, | |
| "example_response": {"success": True, "message": "Party updated successfully"} | |
| }, | |
| "DELETE /api/parties/{party_id}": { | |
| "desc": "Soft-delete a party (sets is_active=False)", | |
| "example_response": {"success": True, "message": "Party deactivated successfully"} | |
| }, | |
| # โโ MIRCHI TYPES โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| "GET /api/mirchi-types": { | |
| "desc": "List mirchi varieties", | |
| "query_params": "active_only=true, skip, limit", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| {"id": "m-aaa111", "name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "is_active": True}, | |
| {"id": "m-bbb222", "name": "เคนเคฟเคฐเคตเฅ เคฎเคฟเคฐเคเฅ", "is_active": True} | |
| ], | |
| "total": 2 | |
| } | |
| }, | |
| "GET /api/mirchi-types/{mirchi_id}": { | |
| "desc": "Single mirchi type by ID", | |
| "example_response": {"success": True, "data": {"id": "m-aaa111", "name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "is_active": True}} | |
| }, | |
| "POST /api/mirchi-types": { | |
| "desc": "Create new mirchi type", | |
| "request_body": {"name": "เคเคพเคณเฅ เคฎเคฟเคฐเคเฅ"}, | |
| "example_response": {"success": True, "message": "Mirchi type created successfully", "data": {"id": "m-ccc333", "name": "เคเคพเคณเฅ เคฎเคฟเคฐเคเฅ"}} | |
| }, | |
| "PUT /api/mirchi-types/{mirchi_id}": { | |
| "desc": "Update mirchi type name or active status", | |
| "request_body": {"name": "เคเคพเคณเฅ เคฎเคฟเคฐเคเฅ XL", "is_active": True}, | |
| "example_response": {"success": True, "message": "Mirchi type updated successfully"} | |
| }, | |
| "DELETE /api/mirchi-types/{mirchi_id}": { | |
| "desc": "Hard delete a mirchi type", | |
| "example_response": {"success": True, "message": "Mirchi type deleted successfully"} | |
| }, | |
| # โโ TRANSACTIONS (Awaak / Jawaak) โโโโโโโโโโโโ | |
| "GET /api/transactions": { | |
| "desc": "List all transactions with filters", | |
| "query_params": "bill_type(awaak|jawaak), party_id, search, start_date, end_date, skip, limit", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| { | |
| "id": "t-111aaa", | |
| "bill_number": "A2025A001", | |
| "bill_date": "2025-03-15", | |
| "bill_type": "awaak", | |
| "party_id": "p-abc123", | |
| "party_name": "เคฐเคพเคฎเคฒเคพเคฒ เคเฅเคฐเฅเคกเคฐเฅเคธ", | |
| "subtotal": 15000.0, | |
| "total_amount": 15200.0, | |
| "paid_amount": 10000.0, | |
| "balance_amount": 5200.0, | |
| "lot_number": "LOT001", | |
| "is_mixed": False, | |
| "is_return": False, | |
| "items": [ | |
| { | |
| "mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", | |
| "poti_count": 10, | |
| "net_weight": 500.0, | |
| "rate_per_kg": 30.0, | |
| "amount": 15000.0 | |
| } | |
| ], | |
| "payments": [ | |
| {"amount": 10000.0, "mode": "cash", "paid_at": "2025-03-15"} | |
| ] | |
| } | |
| ], | |
| "total": 1 | |
| } | |
| }, | |
| "GET /api/transactions/next-bill-number": { | |
| "desc": "Get next auto-generated bill number", | |
| "query_params": "bill_type=awaak", | |
| "example_response": {"success": True, "bill_number": "A2025A002"} | |
| }, | |
| "GET /api/transactions/bill-number-info": { | |
| "desc": "Batch/sequence info for bill numbering", | |
| "query_params": "bill_type=awaak&year=2025", | |
| "example_response": { | |
| "success": True, | |
| "bill_type": "awaak", | |
| "year": 2025, | |
| "current_batch": "A", | |
| "current_number": 2, | |
| "remaining": 498 | |
| } | |
| }, | |
| "GET /api/transactions/{transaction_id}": { | |
| "desc": "Get single transaction by ID with items & payments", | |
| "example_response": {"success": True, "data": {"id": "t-111aaa", "bill_number": "A2025A001"}} | |
| }, | |
| "POST /api/transactions": { | |
| "desc": "Create a new Awaak or Jawaak transaction", | |
| "request_body": { | |
| "bill_type": "awaak", | |
| "bill_date": "2025-03-15", | |
| "party_id": "p-abc123", | |
| "lot_number": "LOT001", | |
| "items": [ | |
| {"mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "mirchi_id": "m-aaa111", "poti_count": 10, "poti_weights": "[50,50,50,50,50,50,50,50,50,50]", "net_weight": 500.0, "rate_per_kg": 30.0} | |
| ], | |
| "expenses": {"hamali": 200, "other": 0}, | |
| "payments": [{"amount": 10000.0, "mode": "cash", "paid_at": "2025-03-15"}] | |
| }, | |
| "example_response": { | |
| "success": True, | |
| "message": "Transaction created successfully", | |
| "data": {"id": "t-111aaa", "bill_number": "A2025A001", "total_amount": 15200.0} | |
| } | |
| }, | |
| "POST /api/transactions/{transaction_id}/payment": { | |
| "desc": "Add payment to a transaction", | |
| "query_params": "amount=5000", | |
| "example_response": {"success": True, "message": "Payment updated successfully"} | |
| }, | |
| "POST /api/transactions/{transaction_id}/revert": { | |
| "desc": "Revert a transaction (creates return bill, reverses stock)", | |
| "example_response": {"success": True, "message": "Transaction reverted successfully"} | |
| }, | |
| "DELETE /api/transactions/{transaction_id}": { | |
| "desc": "Delete a transaction", | |
| "example_response": {"success": True, "message": "Transaction deleted successfully"} | |
| }, | |
| # โโ PATTI TRANSACTIONS โโโโโโโโโโโโโโโโโโโโโโโโ | |
| "GET /api/patti-transactions": { | |
| "desc": "List all patti transactions", | |
| "query_params": "bill_type(patti_awaak|patti_jawaak), party_id, search, start_date, end_date, skip, limit", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| { | |
| "id": "pt-222bbb", | |
| "bill_number": "PA2025A001", | |
| "bill_type": "patti_awaak", | |
| "party_name": "เคเคฃเฅเคถ เคชเคพเคเฅเคฒ", | |
| "lot_number": "PLOT001", | |
| "gross_weight": 1000.0, | |
| "verified_net_weight": 980.0, | |
| "total_amount": 29400.0, | |
| "balance_amount": 29400.0 | |
| } | |
| ], | |
| "total": 1 | |
| } | |
| }, | |
| "GET /api/patti-transactions/lots/available/{mirchi_id}": { | |
| "desc": "Get available patti lots for Jawaak billing (with weight/bag info)", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| { | |
| "id": "patti-lot-PLOT001", | |
| "lot_number": "PLOT001", | |
| "mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", | |
| "gross_weight": 1000.0, | |
| "remaining_quantity": 980.0, | |
| "poti_count": 20, | |
| "display": "PLOT001 | 980kg | 20 เคชเฅเคคเฅ" | |
| } | |
| ] | |
| } | |
| }, | |
| "GET /api/patti-transactions/next-bill-number": { | |
| "desc": "Get next patti bill number", | |
| "query_params": "bill_type=patti_awaak", | |
| "example_response": {"success": True, "bill_number": "PA2025A001"} | |
| }, | |
| "POST /api/patti-transactions": { | |
| "desc": "Create a patti_awaak or patti_jawaak transaction", | |
| "request_body": { | |
| "bill_type": "patti_awaak", | |
| "bill_date": "2025-03-15", | |
| "party_id": "p-abc123", | |
| "lot_number": "PLOT001", | |
| "gross_weight": 1000.0, | |
| "verified_net_weight": 980.0, | |
| "items": [ | |
| {"mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "mirchi_id": "m-aaa111", "poti_count": 20, "net_weight": 980.0, "rate_per_kg": 30.0} | |
| ], | |
| "expenses": {"packing": 100, "commission": 200, "hamali": 150} | |
| }, | |
| "example_response": { | |
| "success": True, | |
| "message": "Patti transaction created successfully", | |
| "data": {"id": "pt-222bbb", "bill_number": "PA2025A001"} | |
| } | |
| }, | |
| "POST /api/patti-transactions/{transaction_id}/payment": { | |
| "desc": "Add payment to patti transaction", | |
| "query_params": "amount=10000", | |
| "example_response": {"success": True, "message": "Payment updated successfully"} | |
| }, | |
| "POST /api/patti-transactions/{transaction_id}/revert": { | |
| "desc": "Revert patti transaction (reverses stock from patti holdings)", | |
| "example_response": {"success": True, "message": "Patti transaction reverted successfully"} | |
| }, | |
| "DELETE /api/patti-transactions/{transaction_id}": { | |
| "desc": "Delete a patti transaction", | |
| "example_response": {"success": True, "message": "Patti transaction deleted successfully"} | |
| }, | |
| # โโ STOCK LEDGER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| "GET /api/stock-ledger": { | |
| "desc": "List all stock movement entries", | |
| "query_params": "mirchi_name, movement_type(IN|OUT|RETURN_IN|RETURN_OUT), lot_number, start_date, end_date, skip, limit", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| { | |
| "id": "sl-333ccc", | |
| "mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", | |
| "movement_type": "IN", | |
| "quantity_in": 500.0, | |
| "quantity_out": 0.0, | |
| "balance_after": 500.0, | |
| "lot_number": None, | |
| "created_at": "2025-03-15T10:00:00" | |
| } | |
| ], | |
| "total": 1 | |
| } | |
| }, | |
| "GET /api/stock-ledger/summary": { | |
| "desc": "Summary of current stock by mirchi type", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| {"mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "balance": 500.0, "total_in": 1000.0, "total_out": 500.0} | |
| ] | |
| } | |
| }, | |
| "GET /api/stock-ledger/lots": { | |
| "desc": "Lot-wise stock summary (patti lot tracking)", | |
| "query_params": "mirchi_name (optional)", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| {"mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "lot_number": "PLOT001", "balance": 480.0, "total_in": 980.0, "total_out": 500.0} | |
| ] | |
| } | |
| }, | |
| "GET /api/stock-ledger/available/{mirchi_id}": { | |
| "desc": "Available lots for Jawaak billing (balance > 0)", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| {"id": "lot-PLOT001", "lot_number": "PLOT001", "remaining_quantity": 480.0, "poti_count": 9, "display": "PLOT001 | 480kg | ~9 เคชเฅเคคเฅ"} | |
| ] | |
| } | |
| }, | |
| "GET /api/stock-ledger/balance/{mirchi_name}": { | |
| "desc": "Get current balance for a specific mirchi (optionally by lot)", | |
| "query_params": "lot_number (optional)", | |
| "example_response": { | |
| "success": True, | |
| "data": {"mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", "lot_number": None, "current_balance": 500.0} | |
| } | |
| }, | |
| "GET /api/stock-ledger/analysis": { | |
| "desc": "Lot-wise P&L analysis (buy qty/amt vs sell qty/amt)", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| { | |
| "lot_number": "LOT001", | |
| "mirchi_name": "เคฒเคพเคฒ เคฎเคฟเคฐเคเฅ", | |
| "farmer_name": "เคฐเคพเคฎเคฒเคพเคฒ เคเฅเคฐเฅเคกเคฐเฅเคธ", | |
| "buy_qty": 500.0, | |
| "buy_amt": 15000.0, | |
| "buy_poti": 10, | |
| "sell_qty": 300.0, | |
| "sell_amt": 10500.0, | |
| "sell_poti": 6, | |
| "commission": 0.0, | |
| "is_patti": False | |
| } | |
| ] | |
| } | |
| }, | |
| "GET /api/stock-ledger/{ledger_id}": { | |
| "desc": "Single stock ledger entry by ID", | |
| "example_response": {"success": True, "data": {"id": "sl-333ccc", "movement_type": "IN"}} | |
| }, | |
| # โโ PARTY JAMA (Ledger Payments) โโโโโโโโโโโโโ | |
| "GET /api/party-jama": { | |
| "desc": "List all standalone jama (payment) entries", | |
| "query_params": "party_id, start_date, end_date, skip, limit", | |
| "example_response": { | |
| "success": True, | |
| "data": [ | |
| {"id": "pj-444ddd", "party_id": "p-abc123", "date": "2025-03-14", "amount": 5000.0, "reference": "UPI-123", "notes": ""} | |
| ], | |
| "total": 1 | |
| } | |
| }, | |
| "GET /api/party-jama/party/{party_id}/balance": { | |
| "desc": "Party's computed balance (transactions + jama)", | |
| "example_response": { | |
| "success": True, | |
| "data": { | |
| "party_id": "p-abc123", | |
| "past_due": 5000.0, | |
| "regular_balance": 7500.0, | |
| "patti_balance": 0.0, | |
| "jama_total": 2000.0, | |
| "current_balance": 10500.0 | |
| } | |
| } | |
| }, | |
| "GET /api/party-jama/party/{party_id}/ledger": { | |
| "desc": "Full chronological party ledger (bills + jama entries merged)", | |
| "query_params": "start_date, end_date", | |
| "example_response": { | |
| "success": True, | |
| "data": { | |
| "party": {"id": "p-abc123", "name": "เคฐเคพเคฎเคฒเคพเคฒ เคเฅเคฐเฅเคกเคฐเฅเคธ"}, | |
| "entries": [ | |
| {"date": "2025-03-10", "type": "transaction", "bill_number": "A2025A001", "debit": 15200.0, "credit": 0, "balance": 15200.0}, | |
| {"date": "2025-03-14", "type": "jama", "reference": "UPI-123", "debit": 0, "credit": 5000.0, "balance": 10200.0} | |
| ], | |
| "total_debit": 15200.0, | |
| "total_credit": 5000.0, | |
| "closing_balance": 10200.0 | |
| } | |
| } | |
| }, | |
| "POST /api/party-jama": { | |
| "desc": "Create a standalone jama (payment) entry", | |
| "request_body": { | |
| "party_id": "p-abc123", | |
| "date": "2025-03-15", | |
| "amount": 5000.0, | |
| "reference": "UPI-456", | |
| "notes": "เคเคเคพเค เคฐเคเฅเคเคฎ" | |
| }, | |
| "example_response": {"success": True, "message": "Jama entry created successfully", "data": {"id": "pj-555eee"}} | |
| }, | |
| "PUT /api/party-jama/{entry_id}": { | |
| "desc": "Update a jama entry", | |
| "request_body": {"amount": 6000.0, "notes": "เคธเฅเคงเคพเคฐเคฟเคค เคฐเคเฅเคเคฎ"}, | |
| "example_response": {"success": True, "message": "Jama entry updated successfully"} | |
| }, | |
| "DELETE /api/party-jama/{entry_id}": { | |
| "desc": "Delete a jama entry", | |
| "example_response": {"success": True, "message": "Jama entry deleted successfully"} | |
| }, | |
| # โโ MISC โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| "GET /health": { | |
| "desc": "App health check", | |
| "example_response": {"status": "healthy", "app": "Mirchi Trading API", "version": "1.0.0"} | |
| }, | |
| "GET /": { | |
| "desc": "Root info endpoint", | |
| "example_response": {"message": "Welcome to Mirchi Trading API", "version": "1.0.0", "docs": "/docs"} | |
| } | |
| } | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # SECTION 3 โ LIVE DB TABLE INSPECTION (PostgreSQL) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| async def inspect_database(): | |
| """Connect to PostgreSQL and print table names + column count""" | |
| try: | |
| from sqlalchemy.ext.asyncio import create_async_engine | |
| from sqlalchemy import text | |
| from dotenv import load_dotenv | |
| env_path = Path(__file__).parent.parent / ".env" | |
| load_dotenv(env_path) | |
| db_url = os.getenv("DATABASE_URL", "") | |
| if not db_url: | |
| print("โ ๏ธ DATABASE_URL not found in .env") | |
| return | |
| engine = create_async_engine(db_url, echo=False) | |
| async with engine.connect() as conn: | |
| # Get all tables | |
| tables_result = await conn.execute(text(""" | |
| SELECT table_name | |
| FROM information_schema.tables | |
| WHERE table_schema = 'public' | |
| ORDER BY table_name; | |
| """)) | |
| tables = [row[0] for row in tables_result] | |
| print(f"\n{'='*60}") | |
| print(f" LIVE DATABASE TABLES ({len(tables)} tables found)") | |
| print(f"{'='*60}") | |
| for table in tables: | |
| # Get columns for each table | |
| cols_result = await conn.execute(text(f""" | |
| SELECT column_name, data_type, is_nullable, column_default | |
| FROM information_schema.columns | |
| WHERE table_schema = 'public' AND table_name = '{table}' | |
| ORDER BY ordinal_position; | |
| """)) | |
| cols = cols_result.fetchall() | |
| # Get row count | |
| count_result = await conn.execute(text(f'SELECT COUNT(*) FROM "{table}"')) | |
| row_count = count_result.scalar() | |
| print(f"\n๐ {table.upper()} ({row_count} rows)") | |
| print(f" {'Column':<35} {'Type':<25} {'Nullable'}") | |
| print(f" {'-'*35} {'-'*25} {'-'*8}") | |
| for col in cols: | |
| nullable = "YES" if col[2] == "YES" else "NO " | |
| print(f" {col[0]:<35} {col[1]:<25} {nullable}") | |
| await engine.dispose() | |
| except Exception as e: | |
| print(f"\nโ ๏ธ Could not connect to database: {e}") | |
| print(" (Showing schema from models only)\n") | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # MAIN RUNNER | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| def print_api_docs(): | |
| print(f"\n{'='*70}") | |
| print(" MIRCHI TRADING โ ALL API ENDPOINTS + EXAMPLE RESPONSES") | |
| print(f"{'='*70}") | |
| print(f" Base URL: http://localhost:8000\n") | |
| for i, (endpoint, info) in enumerate(API_DOCS.items(), 1): | |
| print(f"\n[{i:02d}] {endpoint}") | |
| print(f" โณ {info['desc']}") | |
| if "query_params" in info: | |
| print(f" Params: {info['query_params']}") | |
| if "request_body" in info: | |
| body = json.dumps(info['request_body'], ensure_ascii=False, indent=8) | |
| print(f" Body: {body[:200]}{'...' if len(body) > 200 else ''}") | |
| resp = json.dumps(info['example_response'], ensure_ascii=False, indent=8) | |
| resp_short = resp[:300] + ("..." if len(resp) > 300 else "") | |
| print(f" Response: {resp_short}") | |
| print(f" {'โ'*65}") | |
| print(f"\n{'='*70}") | |
| print(f" TOTAL ENDPOINTS: {len(API_DOCS)}") | |
| print(f"{'='*70}\n") | |
| async def main(): | |
| print(DB_SCHEMA_SUMMARY) | |
| await inspect_database() | |
| print_api_docs() | |
| print("\nโ Documentation complete. API docs also available at: http://localhost:8000/docs") | |
| if __name__ == "__main__": | |
| asyncio.run(main()) | |