Add auto-matching endpoint and data storage for easier demo workflow
This commit is contained in:
@@ -41,6 +41,10 @@ drive_sync = GoogleDriveSync()
|
||||
# In-memory storage for uploaded files (in production, use a database)
|
||||
uploaded_files = {}
|
||||
|
||||
# Store imported transactions globally for easy access
|
||||
stored_transactions = []
|
||||
processed_receipts = {}
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
"""Health check endpoint"""
|
||||
@@ -137,6 +141,10 @@ async def import_quickbooks_transactions_csv(file: UploadFile = File(...)):
|
||||
})
|
||||
except Exception as e:
|
||||
errors.append(f"Row {idx+1}: {str(e)}")
|
||||
# Store transactions globally for auto-matching
|
||||
global stored_transactions
|
||||
stored_transactions = transactions
|
||||
|
||||
# Use the same logic as the JSON import endpoint
|
||||
request_obj = QuickBooksImportRequest(transactions=transactions)
|
||||
response = await import_quickbooks_transactions(request_obj)
|
||||
@@ -219,6 +227,21 @@ async def process_document(file_id: str):
|
||||
else:
|
||||
uploaded_files[file_id]["status"] = "processed"
|
||||
uploaded_files[file_id]["extracted_data"] = result
|
||||
|
||||
# Store processed receipt data for auto-matching
|
||||
global processed_receipts
|
||||
processed_receipts[file_id] = {
|
||||
"filename": file_info["filename"],
|
||||
"upload_date": file_info["upload_date"],
|
||||
"extraction_success": result.get("extraction_success", False),
|
||||
"vendor": result.get("vendor"),
|
||||
"total_amount": result.get("total_amount"),
|
||||
"tax_amount": result.get("tax_amount"),
|
||||
"date": result.get("date"),
|
||||
"category": result.get("category"),
|
||||
"confidence": result.get("confidence"),
|
||||
"error": result.get("error")
|
||||
}
|
||||
|
||||
return DocumentProcessResponse(
|
||||
file_id=file_id,
|
||||
@@ -422,6 +445,74 @@ async def match_receipts_transactions(request: MatchingRequest):
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/match-auto", response_model=MatchingResponse)
|
||||
async def match_auto():
|
||||
"""
|
||||
Automatically match all processed receipts against all imported transactions.
|
||||
|
||||
This endpoint uses the stored transaction data from CSV import and
|
||||
all processed receipts to perform matching without requiring manual data input.
|
||||
"""
|
||||
try:
|
||||
if not stored_transactions:
|
||||
raise HTTPException(status_code=400, detail="No transactions imported. Please upload CSV first.")
|
||||
|
||||
if not processed_receipts:
|
||||
raise HTTPException(status_code=400, detail="No receipts processed. Please upload and process receipts first.")
|
||||
|
||||
# Convert stored transactions to Receipt/Transaction models
|
||||
transactions = [
|
||||
Transaction(
|
||||
id=t["id"],
|
||||
transaction_date=datetime.strptime(t["txn_date"], "%Y-%m-%d"),
|
||||
amount=abs(t["amount"]),
|
||||
vendor=t["payee_name"],
|
||||
notes=t.get("memo", "")
|
||||
) for t in stored_transactions
|
||||
]
|
||||
|
||||
receipts = []
|
||||
for file_id, receipt_data in processed_receipts.items():
|
||||
if receipt_data.get("extraction_success"):
|
||||
receipts.append(Receipt(
|
||||
id=file_id,
|
||||
file_name=receipt_data.get("filename", ""),
|
||||
upload_date=receipt_data.get("upload_date", datetime.now()),
|
||||
receipt_date=datetime.strptime(receipt_data.get("date", "2024-01-01"), "%Y-%m-%d"),
|
||||
amount=receipt_data.get("total_amount", 0.0),
|
||||
tax=receipt_data.get("tax_amount", 0.0),
|
||||
vendor=receipt_data.get("vendor", ""),
|
||||
category=receipt_data.get("category", "")
|
||||
))
|
||||
|
||||
if not receipts:
|
||||
raise HTTPException(status_code=400, detail="No successfully processed receipts found.")
|
||||
|
||||
# Process matching using AI engine
|
||||
matches = matching_engine.process_matching(receipts, transactions)
|
||||
|
||||
# Convert to response format
|
||||
match_responses = [
|
||||
MatchResponse(
|
||||
receipt_id=match.receipt.id,
|
||||
transaction_id=match.transaction.id,
|
||||
confidence_score=match.confidence_score,
|
||||
match_reason=match.match_reason,
|
||||
receipt_vendor=match.receipt.vendor,
|
||||
receipt_amount=match.receipt.amount,
|
||||
transaction_vendor=match.transaction.vendor,
|
||||
transaction_amount=match.transaction.amount
|
||||
) for match in matches
|
||||
]
|
||||
|
||||
# Get statistics
|
||||
stats = matching_engine.get_matching_stats(matches)
|
||||
|
||||
return MatchingResponse(matches=match_responses, stats=stats)
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/approve")
|
||||
async def approve_match(request: ApprovalRequest):
|
||||
"""
|
||||
@@ -504,7 +595,26 @@ async def get_stats():
|
||||
"recent_feedback_logs": len(recent_logs),
|
||||
"active_rules": len([r for r in matching_engine.rules_engine.rules if r.status == "active"]),
|
||||
"uploaded_documents": len(uploaded_files),
|
||||
"processed_documents": len([f for f in uploaded_files.values() if f["status"] == "processed"])
|
||||
"processed_documents": len([f for f in uploaded_files.values() if f["status"] == "processed"]),
|
||||
"stored_transactions": len(stored_transactions),
|
||||
"processed_receipts": len(processed_receipts)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/status")
|
||||
async def get_status():
|
||||
"""Get current system status for demo purposes"""
|
||||
try:
|
||||
return {
|
||||
"csv_uploaded": len(stored_transactions) > 0,
|
||||
"transactions_count": len(stored_transactions),
|
||||
"receipts_uploaded": len(uploaded_files),
|
||||
"receipts_processed": len(processed_receipts),
|
||||
"ready_for_matching": len(stored_transactions) > 0 and len(processed_receipts) > 0,
|
||||
"sample_transactions": stored_transactions[:3] if stored_transactions else [],
|
||||
"sample_receipts": list(processed_receipts.keys())[:3] if processed_receipts else []
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user