updates
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Query, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from ..config.database import get_db
|
||||
from ..config.logging_config import get_logger
|
||||
from ..middleware.auth import get_current_user, authorize_roles
|
||||
from ..models.user import User
|
||||
from ..models.invoice import Invoice, InvoiceStatus
|
||||
@@ -10,15 +11,25 @@ from ..models.booking import Booking
|
||||
from ..services.invoice_service import InvoiceService
|
||||
from ..utils.role_helpers import can_access_all_invoices, can_create_invoices
|
||||
from ..utils.response_helpers import success_response
|
||||
from ..utils.request_helpers import get_request_id
|
||||
from ..schemas.invoice import (
|
||||
CreateInvoiceRequest,
|
||||
UpdateInvoiceRequest,
|
||||
MarkInvoicePaidRequest
|
||||
)
|
||||
|
||||
logger = get_logger(__name__)
|
||||
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)):
|
||||
async def get_invoices(request: Request, 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)):
|
||||
try:
|
||||
user_id = None if can_access_all_invoices(current_user, db) 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 success_response(data=result)
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error fetching invoices: {str(e)}', exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get('/{id}')
|
||||
@@ -33,64 +44,96 @@ async def get_invoice_by_id(id: int, current_user: User=Depends(get_current_user
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error fetching invoice by id: {str(e)}', exc_info=True)
|
||||
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)):
|
||||
async def create_invoice(request: Request, invoice_data: CreateInvoiceRequest, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
|
||||
try:
|
||||
if not can_create_invoices(current_user, db):
|
||||
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')
|
||||
try:
|
||||
booking_id = int(booking_id)
|
||||
except (ValueError, TypeError):
|
||||
raise HTTPException(status_code=400, detail='booking_id must be a valid integer')
|
||||
booking_id = invoice_data.booking_id
|
||||
booking = db.query(Booking).filter(Booking.id == booking_id).first()
|
||||
if not booking:
|
||||
raise HTTPException(status_code=404, detail='Booking not found')
|
||||
invoice_kwargs = {'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')}
|
||||
invoice_kwargs = {
|
||||
'company_name': invoice_data.company_name,
|
||||
'company_address': invoice_data.company_address,
|
||||
'company_phone': invoice_data.company_phone,
|
||||
'company_email': invoice_data.company_email,
|
||||
'company_tax_id': invoice_data.company_tax_id,
|
||||
'company_logo_url': invoice_data.company_logo_url,
|
||||
'customer_tax_id': invoice_data.customer_tax_id,
|
||||
'notes': invoice_data.notes,
|
||||
'terms_and_conditions': invoice_data.terms_and_conditions,
|
||||
'payment_instructions': invoice_data.payment_instructions
|
||||
}
|
||||
invoice_notes = invoice_kwargs.get('notes', '')
|
||||
if booking.promotion_code:
|
||||
promotion_note = f'Promotion Code: {booking.promotion_code}'
|
||||
invoice_notes = f'{promotion_note}\n{invoice_notes}'.strip() if invoice_notes else promotion_note
|
||||
invoice_kwargs['notes'] = invoice_notes
|
||||
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), **invoice_kwargs)
|
||||
request_id = get_request_id(request)
|
||||
invoice = InvoiceService.create_invoice_from_booking(
|
||||
booking_id=booking_id,
|
||||
db=db,
|
||||
created_by_id=current_user.id,
|
||||
tax_rate=invoice_data.tax_rate,
|
||||
discount_amount=invoice_data.discount_amount,
|
||||
due_days=invoice_data.due_days,
|
||||
request_id=request_id,
|
||||
**invoice_kwargs
|
||||
)
|
||||
return success_response(data={'invoice': invoice}, message='Invoice created successfully')
|
||||
except HTTPException:
|
||||
raise
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error creating invoice: {str(e)}', exc_info=True)
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error creating invoice: {str(e)}', exc_info=True)
|
||||
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', 'accountant')), db: Session=Depends(get_db)):
|
||||
async def update_invoice(request: Request, id: int, invoice_data: UpdateInvoiceRequest, current_user: User=Depends(authorize_roles('admin', 'staff', 'accountant')), db: Session=Depends(get_db)):
|
||||
try:
|
||||
invoice = db.query(Invoice).filter(Invoice.id == id).first()
|
||||
if not invoice:
|
||||
raise HTTPException(status_code=404, detail='Invoice not found')
|
||||
updated_invoice = InvoiceService.update_invoice(invoice_id=id, db=db, updated_by_id=current_user.id, **invoice_data)
|
||||
request_id = get_request_id(request)
|
||||
invoice_dict = invoice_data.model_dump(exclude_unset=True)
|
||||
updated_invoice = InvoiceService.update_invoice(invoice_id=id, db=db, updated_by_id=current_user.id, request_id=request_id, **invoice_dict)
|
||||
return success_response(data={'invoice': updated_invoice}, message='Invoice updated successfully')
|
||||
except HTTPException:
|
||||
raise
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error updating invoice: {str(e)}', exc_info=True)
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error updating invoice: {str(e)}', exc_info=True)
|
||||
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', 'accountant')), db: Session=Depends(get_db)):
|
||||
async def mark_invoice_as_paid(request: Request, id: int, payment_data: MarkInvoicePaidRequest, current_user: User=Depends(authorize_roles('admin', 'staff', 'accountant')), db: Session=Depends(get_db)):
|
||||
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)
|
||||
request_id = get_request_id(request)
|
||||
amount = payment_data.amount
|
||||
updated_invoice = InvoiceService.mark_invoice_as_paid(invoice_id=id, db=db, amount=amount, updated_by_id=current_user.id, request_id=request_id)
|
||||
return success_response(data={'invoice': updated_invoice}, message='Invoice marked as paid successfully')
|
||||
except HTTPException:
|
||||
raise
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error marking invoice as paid: {str(e)}', exc_info=True)
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error marking invoice as paid: {str(e)}', exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.delete('/{id}')
|
||||
@@ -121,4 +164,6 @@ async def get_invoices_by_booking(booking_id: int, current_user: User=Depends(ge
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error fetching invoices by booking: {str(e)}', exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user