AhmadYarAI's picture
Done the Update request
b9ec576
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from datetime import datetime
from typing import Optional, List
from pydantic import BaseModel
# SMART IMPORT for both environments
try:
from backend.models.invoice import Invoice, InvoiceItem # Add InvoiceItem here
from backend.core.database import get_db
except ImportError:
from models.invoice import Invoice, InvoiceItem # And add it here
from core.database import get_db
router = APIRouter(prefix="/invoices", tags=["Invoices"])
class ItemCreate(BaseModel):
# These are now defined for every single row
patient_name: str
shade: str
description: str
quantity: int
price_per_unit: float
class InvoiceCreate(BaseModel):
# General Info (Header)
date: Optional[datetime] = None
doctor_name: str
clinic_name: str
# Financials & Notes
received_amount: float = 0.0
notes: Optional[str] = None
# The list of rows containing the patient info
items: List[ItemCreate]
class InvoiceUpdate(BaseModel):
date: Optional[datetime] = None
doctor_name: str
clinic_name: str
received_amount: float = 0.0
notes: Optional[str] = None
items: List[ItemCreate]
@router.post("/")
def create_invoice(data: InvoiceCreate, db: Session = Depends(get_db)):
# 1. Calculate the total by summing all items in the list
total_amount = sum(item.quantity * item.price_per_unit for item in data.items)
# 2. Create the Main Invoice (The Header)
new_invoice = Invoice(
date=data.date or datetime.utcnow(),
doctor_name=data.doctor_name,
clinic_name=data.clinic_name,
total_amount=total_amount,
received_amount=data.received_amount,
remaining_balance=total_amount - data.received_amount,
notes=data.notes,
invoice_no=None # Placeholder for the flush
)
db.add(new_invoice)
db.flush() # Secure the ID from the database
# Generate the professional ID (e.g., INV-0042)
new_invoice.invoice_no = f"INV-{new_invoice.id:04d}"
# 3. Save each row (The Items)
for item in data.items:
db.add(InvoiceItem(
invoice_id=new_invoice.id,
patient_name=item.patient_name, # Row-specific
shade=item.shade, # Row-specific
description=item.description,
quantity=item.quantity,
price_per_unit=item.price_per_unit,
total_price=item.quantity * item.price_per_unit
))
try:
db.commit()
db.refresh(new_invoice)
return {"status": "success", "invoice_no": new_invoice.invoice_no, "id": new_invoice.id}
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
@router.get("/{invoice_id}")
def get_invoice(invoice_id: int, db: Session = Depends(get_db)):
# Look for the invoice and include its items
invoice = db.query(Invoice).filter(Invoice.id == invoice_id).first()
if not invoice:
raise HTTPException(status_code=404, detail="Invoice not found")
return {
"id": invoice.id,
"invoice_no": invoice.invoice_number,
"date": invoice.date,
"doctor_name": invoice.doctor_name,
"clinic_name": invoice.clinic_name,
"total_amount": invoice.total_amount,
"received_amount": invoice.received_amount,
"remaining_balance": invoice.remaining_balance,
"items": [
{
"patient_name": item.patient_name,
"shade": item.shade,
"description": item.description,
"quantity": item.quantity,
"price_per_unit": item.price_per_unit,
"total_price": item.total_price
} for item in invoice.items
]
}
@router.get("/")
def get_all_invoices(db: Session = Depends(get_db)):
invoices = db.query(Invoice).order_by(Invoice.id.desc()).all()
# Include the formatted invoice_no in the response
return [{
"id": inv.id,
"invoice_no": inv.invoice_number,
"doctor_name": inv.doctor_name,
"clinic_name": inv.clinic_name,
"total_amount": inv.total_amount,
"received_amount": inv.received_amount,
"date": inv.date
} for inv in invoices]
# DELETE an invoice
@router.delete("/{invoice_id}")
def delete_invoice(invoice_id: int, db: Session = Depends(get_db)):
db_invoice = db.query(Invoice).filter(Invoice.id == invoice_id).first()
if not db_invoice:
raise HTTPException(status_code=404, detail="Invoice not found")
db.delete(db_invoice)
db.commit()
return {"message": "Deleted successfully"}
@router.put("/{invoice_id}")
def update_invoice(invoice_id: int, data: InvoiceUpdate, db: Session = Depends(get_db)):
invoice = db.query(Invoice).filter(Invoice.id == invoice_id).first()
if not invoice:
raise HTTPException(status_code=404, detail="Invoice not found")
total_amount = sum(item.quantity * item.price_per_unit for item in data.items)
invoice.date = data.date or datetime.utcnow()
invoice.doctor_name = data.doctor_name
invoice.clinic_name = data.clinic_name
invoice.total_amount = total_amount
invoice.received_amount = data.received_amount
invoice.remaining_balance = total_amount - data.received_amount
invoice.notes = data.notes
# Delete old items and replace with new ones
db.query(InvoiceItem).filter(InvoiceItem.invoice_id == invoice_id).delete()
for item in data.items:
db.add(InvoiceItem(
invoice_id=invoice.id,
patient_name=item.patient_name,
shade=item.shade,
description=item.description,
quantity=item.quantity,
price_per_unit=item.price_per_unit,
total_price=item.quantity * item.price_per_unit
))
try:
db.commit()
db.refresh(invoice)
return {"status": "success", "invoice_no": invoice.invoice_no, "id": invoice.id}
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))