Files
Hotel-Booking/Backend/src/routes/invoice_routes.py
Iliyan Angelov 0c59fe1173 updates
2025-11-17 18:26:30 +02:00

250 lines
8.0 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.orm import Session
from typing import Optional
from datetime import datetime
from ..config.database import get_db
from ..middleware.auth import get_current_user, authorize_roles
from ..models.user import User
from ..models.invoice import Invoice, InvoiceStatus
from ..models.booking import Booking
from ..services.invoice_service import InvoiceService
router = APIRouter(prefix="/invoices", tags=["invoices"])
@router.get("/")
async def get_invoices(
booking_id: Optional[int] = Query(None),
status_filter: Optional[str] = Query(None, alias="status"),
page: int = Query(1, ge=1),
limit: int = Query(10, ge=1, le=100),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get invoices for current user (or all invoices for admin)"""
try:
# Admin can see all invoices, users can only see their own
user_id = None if current_user.role_id == 1 else current_user.id
result = InvoiceService.get_invoices(
db=db,
user_id=user_id,
booking_id=booking_id,
status=status_filter,
page=page,
limit=limit
)
return {
"status": "success",
"data": result
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/{id}")
async def get_invoice_by_id(
id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get invoice by ID"""
try:
invoice = InvoiceService.get_invoice(id, db)
if not invoice:
raise HTTPException(status_code=404, detail="Invoice not found")
# Check access: admin can see all, users can only see their own
if current_user.role_id != 1 and invoice["user_id"] != current_user.id:
raise HTTPException(status_code=403, detail="Forbidden")
return {
"status": "success",
"data": {"invoice": invoice}
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/")
async def create_invoice(
invoice_data: dict,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Create a new invoice from a booking (Admin/Staff only)"""
try:
# Only admin/staff can create invoices
if current_user.role_id not in [1, 2]:
raise HTTPException(status_code=403, detail="Forbidden")
booking_id = invoice_data.get("booking_id")
if not booking_id:
raise HTTPException(status_code=400, detail="booking_id is required")
# Check if booking exists
booking = db.query(Booking).filter(Booking.id == booking_id).first()
if not booking:
raise HTTPException(status_code=404, detail="Booking not found")
# Create invoice
invoice = InvoiceService.create_invoice_from_booking(
booking_id=booking_id,
db=db,
created_by_id=current_user.id,
tax_rate=invoice_data.get("tax_rate", 0.0),
discount_amount=invoice_data.get("discount_amount", 0.0),
due_days=invoice_data.get("due_days", 30),
company_name=invoice_data.get("company_name"),
company_address=invoice_data.get("company_address"),
company_phone=invoice_data.get("company_phone"),
company_email=invoice_data.get("company_email"),
company_tax_id=invoice_data.get("company_tax_id"),
company_logo_url=invoice_data.get("company_logo_url"),
customer_tax_id=invoice_data.get("customer_tax_id"),
notes=invoice_data.get("notes"),
terms_and_conditions=invoice_data.get("terms_and_conditions"),
payment_instructions=invoice_data.get("payment_instructions"),
)
return {
"status": "success",
"message": "Invoice created successfully",
"data": {"invoice": invoice}
}
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.put("/{id}")
async def update_invoice(
id: int,
invoice_data: dict,
current_user: User = Depends(authorize_roles("admin", "staff")),
db: Session = Depends(get_db)
):
"""Update an invoice (Admin/Staff only)"""
try:
invoice = db.query(Invoice).filter(Invoice.id == id).first()
if not invoice:
raise HTTPException(status_code=404, detail="Invoice not found")
# Update invoice
updated_invoice = InvoiceService.update_invoice(
invoice_id=id,
db=db,
updated_by_id=current_user.id,
**invoice_data
)
return {
"status": "success",
"message": "Invoice updated successfully",
"data": {"invoice": updated_invoice}
}
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/{id}/mark-paid")
async def mark_invoice_as_paid(
id: int,
payment_data: dict,
current_user: User = Depends(authorize_roles("admin", "staff")),
db: Session = Depends(get_db)
):
"""Mark an invoice as paid (Admin/Staff only)"""
try:
amount = payment_data.get("amount")
updated_invoice = InvoiceService.mark_invoice_as_paid(
invoice_id=id,
db=db,
amount=amount,
updated_by_id=current_user.id
)
return {
"status": "success",
"message": "Invoice marked as paid successfully",
"data": {"invoice": updated_invoice}
}
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/{id}")
async def delete_invoice(
id: int,
current_user: User = Depends(authorize_roles("admin")),
db: Session = Depends(get_db)
):
"""Delete an invoice (Admin only)"""
try:
invoice = db.query(Invoice).filter(Invoice.id == id).first()
if not invoice:
raise HTTPException(status_code=404, detail="Invoice not found")
db.delete(invoice)
db.commit()
return {
"status": "success",
"message": "Invoice deleted successfully"
}
except HTTPException:
raise
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.get("/booking/{booking_id}")
async def get_invoices_by_booking(
booking_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get all invoices for a specific booking"""
try:
# Check if booking exists and user has access
booking = db.query(Booking).filter(Booking.id == booking_id).first()
if not booking:
raise HTTPException(status_code=404, detail="Booking not found")
# Check access: admin can see all, users can only see their own bookings
if current_user.role_id != 1 and booking.user_id != current_user.id:
raise HTTPException(status_code=403, detail="Forbidden")
result = InvoiceService.get_invoices(
db=db,
booking_id=booking_id
)
return {
"status": "success",
"data": result
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))