File size: 6,211 Bytes
f9ba6a9
6153aab
ea7352f
 
 
d7dc866
cd9bdbe
d7dc866
cd9bdbe
d7dc866
 
cd9bdbe
d7dc866
cd9bdbe
6153aab
 
 
49c4331
9cdda17
 
6153aab
 
 
 
 
49c4331
 
6153aab
 
49c4331
 
 
67d26ff
49c4331
 
6153aab
 
b9ec576
 
 
 
 
 
 
 
6153aab
 
49c4331
 
6153aab
49c4331
6153aab
2b9b19c
6153aab
 
49c4331
6153aab
49c4331
5e6e3b3
49c4331
6153aab
 
 
49c4331
4b8a633
49c4331
c370c93
 
49c4331
6153aab
5e6e3b3
6153aab
49c4331
 
6153aab
4b8a633
 
 
5e6e3b3
6153aab
c370c93
49c4331
c370c93
49c4331
c370c93
 
49c4331
 
886a6a9
dce516f
 
 
 
 
 
 
 
f9ba6a9
dce516f
886a6a9
f9ba6a9
 
 
 
 
dce516f
 
9cdda17
 
886a6a9
 
f9ba6a9
 
dce516f
 
4b4aa27
 
 
 
 
 
 
 
 
 
f9ba6a9
4b4aa27
f9ba6a9
4b4aa27
 
 
 
 
 
 
 
 
 
 
f9ba6a9
b9ec576
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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))