brewman/brewman/brewman/routers/employee.py

273 lines
8.4 KiB
Python

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)