pratikbackend / scripts /api_docs.py
Antaram's picture
Upload 109 files
2f5dcf7 verified
Raw
History Blame Contribute Delete
25.7 kB
"""
=============================================================
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())