brewman/brewman/routers/employee.py

236 lines
7.9 KiB
Python

import uuid
from sqlalchemy import desc
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import joinedload_all, Session
from fastapi import APIRouter, HTTPException, status, Depends, Security
from ..schemas.auth import UserToken
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal
from brewman.models.master import CostCentre, Employee, AccountBase, Account
from brewman.models.voucher import Voucher, Journal, VoucherType
import brewman.schemas.master as schemas
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 ValidationError("Invalid Employee")
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)