import uuid import brewman.schemas.master as schemas from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import desc from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session, joinedload_all from ..core.security import get_current_active_user as get_user from ..db.session import SessionLocal from ..models.master import Account, AccountBase, CostCentre, Employee from ..models.voucher import Journal, Voucher, VoucherType from ..schemas.auth import UserToken router = APIRouter() # Dependency def get_db(): try: db = SessionLocal() yield db finally: db.close() @router.post("", response_model=schemas.Employee) def save( data: schemas.EmployeeIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["employees"]), ): try: item = Employee( name=data.name, is_starred=data.is_starred, is_active=data.is_active, cost_centre_id=data.cost_centre.id_, designation=data.designation, salary=data.salary, points=data.points, joining_date=data.joining_date, leaving_date=None if data.is_active else data.leaving_date, ).create(db) db.commit() return employee_info(item.id, db) except SQLAlchemyError as e: db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), ) except Exception: db.rollback() raise @router.put("/{id_}", response_model=schemas.Employee) def update( id_: uuid.UUID, data: schemas.EmployeeIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["employees"]), ): try: item: Employee = db.query(Employee).filter(Employee.id == id_).first() if item.is_fixture: raise HTTPException( status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) item.name = data.name item.cost_centre_id = data.cost_centre.id_ item.designation = data.designation item.salary = data.salary item.points = data.points item.joining_date = data.joining_date item.is_starred = data.is_starred item.is_active = data.is_active item.leaving_date = data.leaving_date db.commit() return employee_info(item.id, db) except SQLAlchemyError as e: db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), ) except Exception: db.rollback() raise @router.delete("/{id_}") def delete( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["employees"]), ): employee: Employee = db.query(Employee).filter(Employee.id == id_).first() can_delete, reason = employee.can_delete("advanced-delete" in user.permissions) if can_delete: delete_with_data(employee, db) db.commit() return employee_info(None, db) else: db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Cannot delete account because {reason}", ) @router.get("") def show_blank( db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["employees"]), ): return employee_info(None, db) @router.get("/list") async def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): return [ { "id": item.id, "code": item.code, "name": item.name, "designation": item.designation, "salary": item.salary, "points": item.points, "isActive": item.is_active, "costCentre": item.cost_centre.name, "joiningDate": item.joining_date.strftime("%d-%b-%Y"), "leavingDate": "" if item.is_active else item.leaving_date.strftime("%d-%b-%Y"), "isStarred": item.is_starred, } for item in db.query(Employee) .order_by(desc(Employee.is_active)) .order_by(Account.cost_centre_id) .order_by(Employee.designation) .order_by(Employee.name) .all() ] @router.get("/query") async def show_term( q: str, c: int = None, db: Session = Depends(get_db), current_user: UserToken = Depends(get_user), ): list_ = [] for index, item in enumerate(AccountBase.query(q=q, type_=10, db=db)): list_.append( { "id": item.id, "name": item.name, "designation": item.designation, "costCentre": { "id": item.cost_centre.id, "name": item.cost_centre.name, }, } ) if c is not None and index == c - 1: break return list_ @router.get("/{id_}") def show_id( id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["employees"]), ): return employee_info(id_, db) def employee_info(id_, db): if id_ is None: employee = { "code": "(Auto)", "isStarred": False, "isActive": True, "costCentre": CostCentre.overall(), } else: employee = db.query(Employee).filter(Employee.id == id_).first() if employee is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Employee not found", ) employee = { "id": employee.id, "code": employee.code, "name": employee.name, "isActive": employee.is_active, "isStarred": employee.is_starred, "designation": employee.designation, "salary": employee.salary, "points": employee.points, "joiningDate": employee.joining_date.strftime("%d-%b-%Y"), "leavingDate": None if employee.is_active else employee.leaving_date.strftime("%d-%b-%Y"), "costCentre": { "id": employee.cost_centre_id, "name": employee.cost_centre.name, }, "isFixture": employee.is_fixture, } return employee def delete_with_data(employee, db): suspense_account = ( db.query(Account).filter(Account.id == Account.suspense()).first() ) query = ( db.query(Voucher) .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) .filter(Voucher.journals.any(Journal.account_id == employee.id)) .all() ) for voucher in query: others, sus_jnl, acc_jnl = False, None, None for journal in voucher.journals: if journal.account_id == employee.id: acc_jnl = journal elif journal.account_id == Account.suspense(): sus_jnl = journal else: others = True if not others: db.delete(voucher) else: if sus_jnl is None: acc_jnl.account = suspense_account voucher.narration += ( f"\nSuspense \u20B9 {acc_jnl.amount:,.2f} is {employee.name}" ) else: amount = (sus_jnl.debit * sus_jnl.amount) + ( acc_jnl.debit * acc_jnl.amount ) if acc_jnl.employee_benefit is not None: db.delete(acc_jnl.employee_benefit) db.delete(acc_jnl) if amount == 0: db.delete(sus_jnl) else: sus_jnl.amount = abs(amount) sus_jnl.debit = -1 if amount < 0 else 1 voucher.narration += f"\nDeleted \u20B9 {acc_jnl.amount * acc_jnl.debit:,.2f} of {employee.name}" if voucher.type in ( VoucherType.by_name("Payment").id, VoucherType.by_name("Receipt").id, ): voucher.type = VoucherType.by_name("Journal") for fingerprint in employee.fingerprints: db.delete(fingerprint) for attendance in employee.attendances: db.delete(attendance) db.delete(employee)