updates
This commit is contained in:
57
Backend/add_accountant_role.py
Normal file
57
Backend/add_accountant_role.py
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to add the 'accountant' role to the database.
|
||||
Run this script once to create the accountant role if it doesn't exist.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the Backend directory to the path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from src.config.database import SessionLocal
|
||||
from src.models.role import Role
|
||||
|
||||
def add_accountant_role():
|
||||
"""Add the accountant role to the database if it doesn't exist."""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Check if accountant role already exists
|
||||
existing_role = db.query(Role).filter(Role.name == 'accountant').first()
|
||||
|
||||
if existing_role:
|
||||
print("✓ Accountant role already exists in the database.")
|
||||
print(f" Role ID: {existing_role.id}")
|
||||
print(f" Role Name: {existing_role.name}")
|
||||
return
|
||||
|
||||
# Create the accountant role
|
||||
accountant_role = Role(
|
||||
name='accountant',
|
||||
description='Accountant role with access to financial data, payments, and invoices'
|
||||
)
|
||||
db.add(accountant_role)
|
||||
db.commit()
|
||||
db.refresh(accountant_role)
|
||||
|
||||
print("✓ Accountant role created successfully!")
|
||||
print(f" Role ID: {accountant_role.id}")
|
||||
print(f" Role Name: {accountant_role.name}")
|
||||
print(f" Description: {accountant_role.description}")
|
||||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
print(f"✗ Error creating accountant role: {e}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Adding accountant role to the database...")
|
||||
print("-" * 50)
|
||||
add_accountant_role()
|
||||
print("-" * 50)
|
||||
print("Done!")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -28,8 +28,7 @@ def seed_about_page(db: Session):
|
||||
"title": "About Luxury Hotel",
|
||||
"subtitle": "Where Excellence Meets Unforgettable Experiences",
|
||||
"description": "Discover the story behind our commitment to luxury hospitality and exceptional service.",
|
||||
"story_content":
|
||||
,
|
||||
"story_content": "For over three decades, Luxury Hotel has been a beacon of excellence in the hospitality industry. Founded with a vision to redefine luxury travel, we have grown from a single property to a collection of world-renowned destinations, each offering a unique blend of timeless elegance and modern sophistication. Our journey has been marked by countless awards, memorable moments, and the unwavering trust of our guests who return year after year.",
|
||||
"mission": "To provide unparalleled luxury hospitality experiences that exceed expectations, creating lasting memories for our guests through exceptional service, attention to detail, and genuine care.",
|
||||
"vision": "To be recognized as the world's premier luxury hotel brand, setting the standard for excellence in hospitality while maintaining our commitment to sustainability and community engagement.",
|
||||
"about_hero_image": "https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1920&h=1080&fit=crop",
|
||||
|
||||
156
Backend/seed_initial_data.py
Normal file
156
Backend/seed_initial_data.py
Normal file
@@ -0,0 +1,156 @@
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from sqlalchemy.orm import Session
|
||||
from src.config.database import SessionLocal
|
||||
from src.models.role import Role
|
||||
from src.models.room_type import RoomType
|
||||
from src.models.user import User
|
||||
import bcrypt
|
||||
from datetime import datetime
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
return db
|
||||
finally:
|
||||
pass
|
||||
|
||||
def seed_roles(db: Session):
|
||||
print('=' * 80)
|
||||
print('SEEDING ROLES')
|
||||
print('=' * 80)
|
||||
|
||||
roles_data = [
|
||||
{'name': 'admin', 'description': 'Administrator with full access'},
|
||||
{'name': 'staff', 'description': 'Staff member with limited admin access'},
|
||||
{'name': 'customer', 'description': 'Regular customer'},
|
||||
{'name': 'accountant', 'description': 'Accountant role with access to financial data, payments, and invoices'}
|
||||
]
|
||||
|
||||
for role_data in roles_data:
|
||||
existing = db.query(Role).filter(Role.name == role_data['name']).first()
|
||||
if existing:
|
||||
print(f' ✓ Role "{role_data["name"]}" already exists')
|
||||
else:
|
||||
role = Role(**role_data)
|
||||
db.add(role)
|
||||
print(f' ✓ Created role: {role_data["name"]}')
|
||||
|
||||
db.commit()
|
||||
print('✓ Roles seeded successfully!\n')
|
||||
|
||||
def seed_room_types(db: Session):
|
||||
print('=' * 80)
|
||||
print('SEEDING ROOM TYPES')
|
||||
print('=' * 80)
|
||||
|
||||
room_types_data = [
|
||||
{
|
||||
'name': 'Standard Room',
|
||||
'description': 'Comfortable and well-appointed standard accommodation',
|
||||
'base_price': 150.00,
|
||||
'capacity': 2,
|
||||
'amenities': ['Free WiFi', 'Air Conditioning', 'TV', 'Minibar', 'Safe']
|
||||
},
|
||||
{
|
||||
'name': 'Superior Room',
|
||||
'description': 'Spacious room with enhanced amenities and better views',
|
||||
'base_price': 200.00,
|
||||
'capacity': 2,
|
||||
'amenities': ['Free WiFi', 'Air Conditioning', 'Smart TV', 'Minibar', 'Safe', 'Coffee Maker']
|
||||
},
|
||||
{
|
||||
'name': 'Deluxe Room',
|
||||
'description': 'Luxurious room with premium furnishings and amenities',
|
||||
'base_price': 280.00,
|
||||
'capacity': 3,
|
||||
'amenities': ['Free WiFi', 'Air Conditioning', 'Smart TV', 'Netflix', 'Minibar', 'Safe', 'Coffee Maker', 'Premium Toiletries']
|
||||
},
|
||||
{
|
||||
'name': 'Executive Suite',
|
||||
'description': 'Elegant suite with separate living area and premium amenities',
|
||||
'base_price': 400.00,
|
||||
'capacity': 4,
|
||||
'amenities': ['Free WiFi', 'Air Conditioning', 'Smart TV', 'Netflix', 'Minibar', 'Safe', 'Espresso Machine', 'Premium Toiletries', 'Bathrobes', 'Work Desk']
|
||||
},
|
||||
{
|
||||
'name': 'Presidential Suite',
|
||||
'description': 'The ultimate in luxury with expansive space and exclusive amenities',
|
||||
'base_price': 800.00,
|
||||
'capacity': 6,
|
||||
'amenities': ['Free WiFi', 'Air Conditioning', 'Smart TV', 'Netflix', 'Private Bar', 'Jacuzzi', 'Butler Service', 'Premium Toiletries', 'Bathrobes', 'Private Terrace']
|
||||
}
|
||||
]
|
||||
|
||||
import json
|
||||
for rt_data in room_types_data:
|
||||
existing = db.query(RoomType).filter(RoomType.name == rt_data['name']).first()
|
||||
if existing:
|
||||
print(f' ✓ Room type "{rt_data["name"]}" already exists')
|
||||
else:
|
||||
amenities = rt_data.pop('amenities')
|
||||
room_type = RoomType(**rt_data, amenities=json.dumps(amenities))
|
||||
db.add(room_type)
|
||||
print(f' ✓ Created room type: {rt_data["name"]} (€{rt_data["base_price"]:.2f}/night)')
|
||||
|
||||
db.commit()
|
||||
print('✓ Room types seeded successfully!\n')
|
||||
|
||||
def seed_admin_user(db: Session):
|
||||
print('=' * 80)
|
||||
print('SEEDING ADMIN USER')
|
||||
print('=' * 80)
|
||||
|
||||
admin_role = db.query(Role).filter(Role.name == 'admin').first()
|
||||
if not admin_role:
|
||||
print(' ❌ Admin role not found! Please seed roles first.')
|
||||
return
|
||||
|
||||
admin_email = 'admin@hotel.com'
|
||||
existing_admin = db.query(User).filter(User.email == admin_email).first()
|
||||
|
||||
if existing_admin:
|
||||
print(f' ✓ Admin user "{admin_email}" already exists')
|
||||
else:
|
||||
password = 'admin123' # Default password - should be changed in production
|
||||
password_bytes = password.encode('utf-8')
|
||||
salt = bcrypt.gensalt()
|
||||
hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8')
|
||||
|
||||
admin_user = User(
|
||||
email=admin_email,
|
||||
password=hashed_password,
|
||||
full_name='Administrator',
|
||||
role_id=admin_role.id,
|
||||
is_active=True,
|
||||
currency='EUR'
|
||||
)
|
||||
db.add(admin_user)
|
||||
db.commit()
|
||||
print(f' ✓ Created admin user: {admin_email}')
|
||||
print(f' ⚠️ Default password: admin123 (please change in production!)')
|
||||
|
||||
print('✓ Admin user seeded successfully!\n')
|
||||
|
||||
def main():
|
||||
db = get_db()
|
||||
try:
|
||||
seed_roles(db)
|
||||
seed_room_types(db)
|
||||
seed_admin_user(db)
|
||||
print('=' * 80)
|
||||
print('✅ Initial data seeding completed successfully!')
|
||||
print('=' * 80)
|
||||
except Exception as e:
|
||||
print(f'\n❌ Error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
165
Backend/seed_users.py
Normal file
165
Backend/seed_users.py
Normal file
@@ -0,0 +1,165 @@
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from sqlalchemy.orm import Session
|
||||
from src.config.database import SessionLocal
|
||||
from src.models.role import Role
|
||||
from src.models.user import User
|
||||
import bcrypt
|
||||
from datetime import datetime
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
return db
|
||||
finally:
|
||||
pass
|
||||
|
||||
def seed_users(db: Session):
|
||||
print('=' * 80)
|
||||
print('SEEDING USERS')
|
||||
print('=' * 80)
|
||||
|
||||
# Get roles
|
||||
admin_role = db.query(Role).filter(Role.name == 'admin').first()
|
||||
staff_role = db.query(Role).filter(Role.name == 'staff').first()
|
||||
customer_role = db.query(Role).filter(Role.name == 'customer').first()
|
||||
|
||||
if not admin_role or not staff_role or not customer_role:
|
||||
print(' ❌ Roles not found! Please seed roles first.')
|
||||
return
|
||||
|
||||
users_data = [
|
||||
{
|
||||
'email': 'gnxsoft@gnxsoft.com',
|
||||
'password': 'gnxsoft123',
|
||||
'full_name': 'GNXSoft Admin',
|
||||
'phone': '+1 (555) 111-2222',
|
||||
'role': 'admin',
|
||||
'currency': 'EUR',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'admin@gnxsoft.com',
|
||||
'password': 'admin123',
|
||||
'full_name': 'Administrator',
|
||||
'phone': '+1 (555) 222-3333',
|
||||
'role': 'admin',
|
||||
'currency': 'EUR',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'staff@gnxsoft.com',
|
||||
'password': 'staff123',
|
||||
'full_name': 'Staff Member',
|
||||
'phone': '+1 (555) 333-4444',
|
||||
'role': 'staff',
|
||||
'currency': 'EUR',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'customer@gnxsoft.com',
|
||||
'password': 'customer123',
|
||||
'full_name': 'Customer User',
|
||||
'phone': '+1 (555) 444-5555',
|
||||
'role': 'customer',
|
||||
'currency': 'EUR',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'john.doe@gnxsoft.com',
|
||||
'password': 'customer123',
|
||||
'full_name': 'John Doe',
|
||||
'phone': '+1 (555) 555-6666',
|
||||
'role': 'customer',
|
||||
'currency': 'USD',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'jane.smith@gnxsoft.com',
|
||||
'password': 'customer123',
|
||||
'full_name': 'Jane Smith',
|
||||
'phone': '+1 (555) 666-7777',
|
||||
'role': 'customer',
|
||||
'currency': 'EUR',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'robert.wilson@gnxsoft.com',
|
||||
'password': 'customer123',
|
||||
'full_name': 'Robert Wilson',
|
||||
'phone': '+1 (555) 777-8888',
|
||||
'role': 'customer',
|
||||
'currency': 'GBP',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'email': 'maria.garcia@gnxsoft.com',
|
||||
'password': 'customer123',
|
||||
'full_name': 'Maria Garcia',
|
||||
'phone': '+1 (555) 888-9999',
|
||||
'role': 'customer',
|
||||
'currency': 'EUR',
|
||||
'is_active': True
|
||||
}
|
||||
]
|
||||
|
||||
role_map = {
|
||||
'admin': admin_role.id,
|
||||
'staff': staff_role.id,
|
||||
'customer': customer_role.id
|
||||
}
|
||||
|
||||
created_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
for user_data in users_data:
|
||||
existing = db.query(User).filter(User.email == user_data['email']).first()
|
||||
if existing:
|
||||
print(f' ⚠️ User "{user_data["email"]}" already exists, skipping...')
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
password = user_data.pop('password')
|
||||
role_name = user_data.pop('role')
|
||||
role_id = role_map[role_name]
|
||||
|
||||
password_bytes = password.encode('utf-8')
|
||||
salt = bcrypt.gensalt()
|
||||
hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8')
|
||||
|
||||
user = User(
|
||||
email=user_data['email'],
|
||||
password=hashed_password,
|
||||
full_name=user_data['full_name'],
|
||||
phone=user_data.get('phone'),
|
||||
role_id=role_id,
|
||||
currency=user_data.get('currency', 'EUR'),
|
||||
is_active=user_data.get('is_active', True)
|
||||
)
|
||||
db.add(user)
|
||||
print(f' ✓ Created user: {user_data["email"]} ({role_name}) - Password: {password}')
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
print(f'\n✓ Users seeded successfully!')
|
||||
print(f' - Created: {created_count} user(s)')
|
||||
print(f' - Skipped: {skipped_count} user(s) (already exist)')
|
||||
print('=' * 80)
|
||||
|
||||
def main():
|
||||
db = get_db()
|
||||
try:
|
||||
seed_users(db)
|
||||
except Exception as e:
|
||||
print(f'\n❌ Error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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__)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user