This commit is contained in:
Iliyan Angelov
2025-11-21 15:01:24 +02:00
parent 4ab7546de0
commit 9a6190e8ef
889 changed files with 1912 additions and 57 deletions

View File

@@ -9,6 +9,7 @@ from ..config.database import get_db
from ..config.settings import settings
from ..middleware.auth import get_current_user, authorize_roles
from ..models.user import User
from ..models.role import Role
from ..models.booking import Booking, BookingStatus
from ..models.room import Room, RoomStatus
from ..models.room_type import RoomType
@@ -142,8 +143,9 @@ async def get_my_bookings(request: Request, current_user: User=Depends(get_curre
@router.post('/')
async def create_booking(booking_data: dict, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
if current_user.role in ['admin', 'staff']:
raise HTTPException(status_code=403, detail='Admin and staff users cannot create bookings')
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if role and role.name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot create bookings')
try:
import logging
logger = logging.getLogger(__name__)

View File

@@ -4,6 +4,7 @@ from sqlalchemy import func
from ..config.database import get_db
from ..middleware.auth import get_current_user
from ..models.user import User
from ..models.role import Role
from ..models.favorite import Favorite
from ..models.room import Room
from ..models.room_type import RoomType
@@ -12,8 +13,9 @@ router = APIRouter(prefix='/favorites', tags=['favorites'])
@router.get('/')
async def get_favorites(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
if current_user.role in ['admin', 'staff']:
raise HTTPException(status_code=403, detail='Admin and staff users cannot have favorites')
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if role and role.name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot have favorites')
try:
favorites = db.query(Favorite).filter(Favorite.user_id == current_user.id).order_by(Favorite.created_at.desc()).all()
result = []
@@ -33,8 +35,9 @@ async def get_favorites(current_user: User=Depends(get_current_user), db: Sessio
@router.post('/{room_id}')
async def add_favorite(room_id: int, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
if current_user.role in ['admin', 'staff']:
raise HTTPException(status_code=403, detail='Admin and staff users cannot add favorites')
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if role and role.name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot add favorites')
try:
room = db.query(Room).filter(Room.id == room_id).first()
if not room:
@@ -55,8 +58,9 @@ async def add_favorite(room_id: int, current_user: User=Depends(get_current_user
@router.delete('/{room_id}')
async def remove_favorite(room_id: int, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
if current_user.role in ['admin', 'staff']:
raise HTTPException(status_code=403, detail='Admin and staff users cannot remove favorites')
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if role and role.name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot remove favorites')
try:
favorite = db.query(Favorite).filter(Favorite.user_id == current_user.id, Favorite.room_id == room_id).first()
if not favorite:
@@ -72,7 +76,8 @@ async def remove_favorite(room_id: int, current_user: User=Depends(get_current_u
@router.get('/check/{room_id}')
async def check_favorite(room_id: int, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
if current_user.role in ['admin', 'staff']:
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if role and role.name in ['admin', 'staff', 'accountant']:
return {'status': 'success', 'data': {'isFavorited': False}}
try:
favorite = db.query(Favorite).filter(Favorite.user_id == current_user.id, Favorite.room_id == room_id).first()

View File

@@ -13,7 +13,7 @@ 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)):
try:
user_id = None if current_user.role_id == 1 else current_user.id
user_id = None if current_user.role_id in [1, 4] else current_user.id # admin and accountant can see all invoices
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:
@@ -25,7 +25,7 @@ async def get_invoice_by_id(id: int, current_user: User=Depends(get_current_user
invoice = InvoiceService.get_invoice(id, db)
if not invoice:
raise HTTPException(status_code=404, detail='Invoice not found')
if current_user.role_id != 1 and invoice['user_id'] != current_user.id:
if current_user.role_id not in [1, 4] and invoice['user_id'] != current_user.id: # admin and accountant can see all invoices
raise HTTPException(status_code=403, detail='Forbidden')
return {'status': 'success', 'data': {'invoice': invoice}}
except HTTPException:
@@ -36,7 +36,7 @@ async def get_invoice_by_id(id: int, current_user: User=Depends(get_current_user
@router.post('/')
async def create_invoice(invoice_data: dict, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
try:
if current_user.role_id not in [1, 2]:
if current_user.role_id not in [1, 2, 4]: # admin, staff, and accountant can create invoices
raise HTTPException(status_code=403, detail='Forbidden')
booking_id = invoice_data.get('booking_id')
if not booking_id:
@@ -64,7 +64,7 @@ async def create_invoice(invoice_data: dict, current_user: User=Depends(get_curr
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)):
async def update_invoice(id: int, invoice_data: dict, 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:
@@ -79,7 +79,7 @@ async def update_invoice(id: int, invoice_data: dict, current_user: User=Depends
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)):
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)):
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)
@@ -112,7 +112,7 @@ async def get_invoices_by_booking(booking_id: int, current_user: User=Depends(ge
booking = db.query(Booking).filter(Booking.id == booking_id).first()
if not booking:
raise HTTPException(status_code=404, detail='Booking not found')
if current_user.role_id != 1 and booking.user_id != current_user.id:
if current_user.role_id not in [1, 4] and booking.user_id != current_user.id: # admin and accountant can see all invoices
raise HTTPException(status_code=403, detail='Forbidden')
result = InvoiceService.get_invoices(db=db, booking_id=booking_id)
return {'status': 'success', 'data': result}

View File

@@ -54,7 +54,7 @@ async def get_payments(booking_id: Optional[int]=Query(None), status_filter: Opt
query = query.filter(Payment.payment_status == PaymentStatus(status_filter))
except ValueError:
pass
if current_user.role_id != 1:
if current_user.role_id not in [1, 4]: # admin and accountant can see all payments
query = query.join(Booking).filter(Booking.user_id == current_user.id)
total = query.count()
query = query.options(selectinload(Payment.booking).selectinload(Booking.user))
@@ -106,7 +106,7 @@ async def get_payment_by_id(id: int, current_user: User=Depends(get_current_user
payment = db.query(Payment).filter(Payment.id == id).first()
if not payment:
raise HTTPException(status_code=404, detail='Payment not found')
if current_user.role_id != 1:
if current_user.role_id not in [1, 4]: # admin and accountant can see all payments
if payment.booking and payment.booking.user_id != current_user.id:
raise HTTPException(status_code=403, detail='Forbidden')
payment_dict = {'id': payment.id, 'booking_id': payment.booking_id, 'amount': float(payment.amount) if payment.amount else 0.0, 'payment_method': payment.payment_method.value if isinstance(payment.payment_method, PaymentMethod) else payment.payment_method, 'payment_type': payment.payment_type.value if isinstance(payment.payment_type, PaymentType) else payment.payment_type, 'deposit_percentage': payment.deposit_percentage, 'related_payment_id': payment.related_payment_id, 'payment_status': payment.payment_status.value if isinstance(payment.payment_status, PaymentStatus) else payment.payment_status, 'transaction_id': payment.transaction_id, 'payment_date': payment.payment_date.isoformat() if payment.payment_date else None, 'notes': payment.notes, 'created_at': payment.created_at.isoformat() if payment.created_at else None}
@@ -159,8 +159,8 @@ async def create_payment(payment_data: dict, current_user: User=Depends(get_curr
db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.put('/{id}/status', dependencies=[Depends(authorize_roles('admin', 'staff'))])
async def update_payment_status(id: int, status_data: dict, current_user: User=Depends(authorize_roles('admin', 'staff')), db: Session=Depends(get_db)):
@router.put('/{id}/status', dependencies=[Depends(authorize_roles('admin', 'staff', 'accountant'))])
async def update_payment_status(id: int, status_data: dict, current_user: User=Depends(authorize_roles('admin', 'staff', 'accountant')), db: Session=Depends(get_db)):
try:
payment = db.query(Payment).filter(Payment.id == id).first()
if not payment:

View File

@@ -14,7 +14,7 @@ from ..models.service import Service
router = APIRouter(prefix='/reports', tags=['reports'])
@router.get('')
async def get_reports(from_date: Optional[str]=Query(None, alias='from'), to_date: Optional[str]=Query(None, alias='to'), type: Optional[str]=Query(None), current_user: User=Depends(authorize_roles('admin', 'staff')), db: Session=Depends(get_db)):
async def get_reports(from_date: Optional[str]=Query(None, alias='from'), to_date: Optional[str]=Query(None, alias='to'), type: Optional[str]=Query(None), current_user: User=Depends(authorize_roles('admin', 'staff', 'accountant')), db: Session=Depends(get_db)):
try:
start_date = None
end_date = None
@@ -83,7 +83,7 @@ async def get_reports(from_date: Optional[str]=Query(None, alias='from'), to_dat
raise HTTPException(status_code=500, detail=str(e))
@router.get('/dashboard')
async def get_dashboard_stats(current_user: User=Depends(authorize_roles('admin', 'staff')), db: Session=Depends(get_db)):
async def get_dashboard_stats(current_user: User=Depends(authorize_roles('admin', 'staff', 'accountant')), db: Session=Depends(get_db)):
try:
total_bookings = db.query(Booking).count()
active_bookings = db.query(Booking).filter(Booking.status.in_([BookingStatus.pending, BookingStatus.confirmed, BookingStatus.checked_in])).count()
@@ -150,7 +150,7 @@ async def get_customer_dashboard_stats(current_user: User=Depends(get_current_us
raise HTTPException(status_code=500, detail=str(e))
@router.get('/revenue')
async def get_revenue_report(start_date: Optional[str]=Query(None), end_date: Optional[str]=Query(None), current_user: User=Depends(authorize_roles('admin', 'staff')), db: Session=Depends(get_db)):
async def get_revenue_report(start_date: Optional[str]=Query(None), end_date: Optional[str]=Query(None), current_user: User=Depends(authorize_roles('admin', 'staff', 'accountant')), db: Session=Depends(get_db)):
try:
query = db.query(Payment).filter(Payment.payment_status == PaymentStatus.completed)
if start_date:

View File

@@ -17,7 +17,7 @@ async def get_users(search: Optional[str]=Query(None), role: Optional[str]=Query
if search:
query = query.filter(or_(User.full_name.like(f'%{search}%'), User.email.like(f'%{search}%'), User.phone.like(f'%{search}%')))
if role:
role_map = {'admin': 1, 'staff': 2, 'customer': 3}
role_map = {'admin': 1, 'staff': 2, 'customer': 3, 'accountant': 4}
if role in role_map:
query = query.filter(User.role_id == role_map[role])
if status_filter:
@@ -57,7 +57,7 @@ async def create_user(user_data: dict, current_user: User=Depends(authorize_role
phone_number = user_data.get('phone_number')
role = user_data.get('role', 'customer')
status = user_data.get('status', 'active')
role_map = {'admin': 1, 'staff': 2, 'customer': 3}
role_map = {'admin': 1, 'staff': 2, 'customer': 3, 'accountant': 4}
role_id = role_map.get(role, 3)
existing = db.query(User).filter(User.email == email).first()
if existing:
@@ -90,7 +90,7 @@ async def update_user(id: int, user_data: dict, current_user: User=Depends(get_c
existing = db.query(User).filter(User.email == email).first()
if existing:
raise HTTPException(status_code=400, detail='Email already exists')
role_map = {'admin': 1, 'staff': 2, 'customer': 3}
role_map = {'admin': 1, 'staff': 2, 'customer': 3, 'accountant': 4}
if 'full_name' in user_data:
user.full_name = user_data['full_name']
if 'email' in user_data and current_user.role_id == 1: