2020-05-21 19:45:25 +00:00
|
|
|
import uuid
|
2020-10-07 15:18:43 +00:00
|
|
|
|
|
|
|
from datetime import date, datetime
|
2020-05-22 04:40:45 +00:00
|
|
|
from math import ceil
|
2020-05-21 19:45:25 +00:00
|
|
|
from typing import List
|
2020-10-07 15:18:43 +00:00
|
|
|
|
|
|
|
import brewman.schemas.input as schema_in
|
|
|
|
import brewman.schemas.voucher as output
|
|
|
|
|
|
|
|
from fastapi import APIRouter, Depends, File, HTTPException, Request, Security, status
|
2020-05-21 19:45:25 +00:00
|
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
2020-10-07 15:18:43 +00:00
|
|
|
from ..core.security import get_current_active_user as get_user
|
|
|
|
from ..core.session import get_date, get_last_day, set_date
|
|
|
|
from ..db.session import SessionLocal
|
|
|
|
from ..models import AccountBase, Employee
|
|
|
|
from ..models.voucher import EmployeeBenefit, Journal, Voucher, VoucherType
|
|
|
|
from ..schemas.auth import UserToken
|
2020-05-30 05:39:19 +00:00
|
|
|
from .db_image import save_files, update_files
|
2020-05-22 04:40:45 +00:00
|
|
|
from .voucher import (
|
|
|
|
blank_voucher,
|
2020-10-07 15:18:43 +00:00
|
|
|
check_voucher_edit_allowed,
|
|
|
|
check_voucher_lock_info,
|
|
|
|
voucher_info,
|
2020-05-22 04:40:45 +00:00
|
|
|
)
|
2020-10-07 15:18:43 +00:00
|
|
|
|
2020-05-21 19:45:25 +00:00
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
# Dependency
|
|
|
|
def get_db() -> Session:
|
|
|
|
try:
|
|
|
|
db = SessionLocal()
|
|
|
|
yield db
|
|
|
|
finally:
|
|
|
|
db.close()
|
|
|
|
|
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
@router.post("", response_model=output.Voucher)
|
2020-05-21 19:45:25 +00:00
|
|
|
def save_route(
|
|
|
|
request: Request,
|
2020-05-22 04:40:45 +00:00
|
|
|
data: schema_in.EmployeeBenefitIn = Depends(schema_in.EmployeeBenefitIn.load_form),
|
2020-05-21 19:45:25 +00:00
|
|
|
db: Session = Depends(get_db),
|
2020-05-30 05:39:19 +00:00
|
|
|
i: List[bytes] = File(None),
|
|
|
|
t: List[bytes] = File(None),
|
2020-05-22 04:40:45 +00:00
|
|
|
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
2020-05-21 19:45:25 +00:00
|
|
|
):
|
|
|
|
try:
|
2020-05-22 04:40:45 +00:00
|
|
|
dt = get_last_day(data.date_)
|
|
|
|
days_in_month = dt.day
|
|
|
|
item: Voucher = save(data, dt, user, db)
|
2020-10-07 16:59:24 +00:00
|
|
|
exp, total = save_employee_benefits(
|
|
|
|
item, data.employee_benefits, days_in_month, db
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
save_journals(item, exp, total, db)
|
2020-05-30 05:39:19 +00:00
|
|
|
save_files(item.id, i, t, db)
|
2020-05-21 19:45:25 +00:00
|
|
|
db.commit()
|
2020-05-22 04:40:45 +00:00
|
|
|
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
|
|
|
info = voucher_info(item, db)
|
|
|
|
return info
|
2020-05-21 19:45:25 +00:00
|
|
|
except SQLAlchemyError as e:
|
|
|
|
db.rollback()
|
|
|
|
raise HTTPException(
|
2020-10-07 15:18:43 +00:00
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
detail=str(e),
|
2020-05-21 19:45:25 +00:00
|
|
|
)
|
|
|
|
except Exception:
|
|
|
|
db.rollback()
|
2020-06-01 03:31:31 +00:00
|
|
|
raise
|
2020-05-21 19:45:25 +00:00
|
|
|
|
|
|
|
|
2020-10-07 16:59:24 +00:00
|
|
|
def save(
|
|
|
|
data: schema_in.EmployeeBenefitIn, date_: date, user: UserToken, db: Session
|
|
|
|
) -> Voucher:
|
2020-05-22 04:40:45 +00:00
|
|
|
check_voucher_lock_info(None, date_, db)
|
|
|
|
voucher = Voucher(
|
|
|
|
date=date_,
|
|
|
|
narration=data.narration,
|
|
|
|
is_starred=data.is_starred,
|
|
|
|
user_id=user.id_,
|
|
|
|
type_=VoucherType.by_name(data.type_),
|
|
|
|
)
|
|
|
|
db.add(voucher)
|
2020-05-21 19:45:25 +00:00
|
|
|
return voucher
|
|
|
|
|
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
def save_employee_benefits(
|
2020-10-07 15:18:43 +00:00
|
|
|
voucher: Voucher,
|
|
|
|
employee_benefits: List[schema_in.EmployeeBenefit],
|
|
|
|
days_in_month: int,
|
|
|
|
db: Session,
|
2020-05-22 04:40:45 +00:00
|
|
|
):
|
|
|
|
total_exp, total_total = 0, 0
|
|
|
|
for item in employee_benefits:
|
2020-05-23 04:15:02 +00:00
|
|
|
account = db.query(Employee).filter(Employee.id == item.employee.id_).first()
|
2020-05-22 04:40:45 +00:00
|
|
|
gross_salary = item.gross_salary
|
|
|
|
days_worked = item.days_worked
|
2020-10-07 16:59:24 +00:00
|
|
|
esi_ee, esi_er, esi_both = esi_contribution(
|
|
|
|
gross_salary, days_worked, days_in_month
|
|
|
|
)
|
|
|
|
pf_ee, pf_er, pf_both = pf_contribution(
|
|
|
|
gross_salary, days_worked, days_in_month
|
|
|
|
)
|
2020-10-07 15:18:43 +00:00
|
|
|
journal = Journal(
|
|
|
|
amount=esi_ee + pf_ee,
|
|
|
|
debit=1,
|
|
|
|
account_id=account.id,
|
|
|
|
cost_centre_id=account.cost_centre_id,
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
sd = EmployeeBenefit(
|
|
|
|
journal=journal,
|
|
|
|
gross_salary=gross_salary,
|
|
|
|
days_worked=days_worked,
|
|
|
|
esi_ee=esi_ee,
|
|
|
|
pf_ee=pf_ee,
|
|
|
|
esi_er=esi_er,
|
|
|
|
pf_er=pf_er,
|
|
|
|
)
|
|
|
|
voucher.journals.append(journal)
|
|
|
|
voucher.employee_benefits.append(sd)
|
|
|
|
db.add(journal)
|
|
|
|
db.add(sd)
|
|
|
|
total_exp += esi_er + pf_er
|
|
|
|
total_total += esi_both + pf_both
|
|
|
|
return total_exp, total_total
|
|
|
|
|
|
|
|
|
|
|
|
def save_journals(voucher: Voucher, exp: int, total: int, db: Session):
|
2020-10-07 16:59:24 +00:00
|
|
|
account = (
|
|
|
|
db.query(AccountBase)
|
|
|
|
.filter(AccountBase.id == AccountBase.esi_pf_expense())
|
|
|
|
.first()
|
|
|
|
)
|
2020-10-07 15:18:43 +00:00
|
|
|
journal = Journal(
|
|
|
|
amount=exp,
|
|
|
|
debit=1,
|
|
|
|
account_id=account.id,
|
|
|
|
cost_centre_id=account.cost_centre_id,
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
db.add(journal)
|
|
|
|
voucher.journals.append(journal)
|
2020-10-07 16:59:24 +00:00
|
|
|
account = (
|
|
|
|
db.query(AccountBase)
|
|
|
|
.filter(AccountBase.id == AccountBase.esi_pf_payable())
|
|
|
|
.first()
|
|
|
|
)
|
2020-10-07 15:18:43 +00:00
|
|
|
journal = Journal(
|
|
|
|
amount=total,
|
|
|
|
debit=-1,
|
|
|
|
account_id=account.id,
|
|
|
|
cost_centre_id=account.cost_centre_id,
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
db.add(journal)
|
|
|
|
voucher.journals.append(journal)
|
|
|
|
|
|
|
|
|
|
|
|
@router.put("/{id_}", response_model=output.Voucher)
|
2020-05-21 19:45:25 +00:00
|
|
|
def update_route(
|
|
|
|
id_: uuid.UUID,
|
|
|
|
request: Request,
|
2020-05-22 04:40:45 +00:00
|
|
|
data: schema_in.EmployeeBenefitIn = Depends(schema_in.EmployeeBenefitIn.load_form),
|
2020-05-21 19:45:25 +00:00
|
|
|
db: Session = Depends(get_db),
|
2020-05-30 05:39:19 +00:00
|
|
|
i: List[bytes] = File(None),
|
|
|
|
t: List[bytes] = File(None),
|
2020-05-22 04:40:45 +00:00
|
|
|
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
2020-05-21 19:45:25 +00:00
|
|
|
):
|
|
|
|
try:
|
2020-05-22 04:40:45 +00:00
|
|
|
dt = get_last_day(data.date_)
|
|
|
|
days_in_month = dt.day
|
|
|
|
item: Voucher = update(id_, data, user, db)
|
|
|
|
if dt != item.date:
|
2020-10-07 14:07:28 +00:00
|
|
|
raise HTTPException(
|
2020-10-07 15:18:43 +00:00
|
|
|
status_code=status.HTTP_423_LOCKED,
|
|
|
|
detail="Date Cannot be changed for Employee Benefit voucher!",
|
2020-10-07 14:07:28 +00:00
|
|
|
)
|
2020-10-07 16:59:24 +00:00
|
|
|
exp, total = update_employee_benefits(
|
|
|
|
item, data.employee_benefits, days_in_month, db
|
|
|
|
)
|
2020-05-23 04:15:02 +00:00
|
|
|
update_journals(item, exp, total)
|
2020-05-22 04:40:45 +00:00
|
|
|
# journals_valid(voucher)
|
2020-05-30 05:39:19 +00:00
|
|
|
update_files(item.id, data.files, i, t, db)
|
2020-05-21 19:45:25 +00:00
|
|
|
db.commit()
|
2020-05-22 04:40:45 +00:00
|
|
|
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
2020-05-21 19:45:25 +00:00
|
|
|
return voucher_info(item, db)
|
|
|
|
except SQLAlchemyError as e:
|
|
|
|
db.rollback()
|
|
|
|
raise HTTPException(
|
2020-10-07 15:18:43 +00:00
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
detail=str(e),
|
2020-05-21 19:45:25 +00:00
|
|
|
)
|
|
|
|
except Exception:
|
|
|
|
db.rollback()
|
2020-06-01 03:31:31 +00:00
|
|
|
raise
|
2020-05-21 19:45:25 +00:00
|
|
|
|
|
|
|
|
2020-10-07 16:59:24 +00:00
|
|
|
def update(
|
|
|
|
id_: uuid.UUID, data: schema_in.EmployeeBenefitIn, user: UserToken, db: Session
|
|
|
|
) -> Voucher:
|
2020-05-22 04:40:45 +00:00
|
|
|
voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
|
|
|
|
check_voucher_lock_info(voucher.date, data.date_, db)
|
|
|
|
check_voucher_edit_allowed(voucher, user)
|
|
|
|
voucher.is_starred = data.is_starred
|
|
|
|
voucher.narration = data.narration
|
|
|
|
voucher.user_id = user.id_
|
|
|
|
voucher.posted = False
|
|
|
|
voucher.last_edit_date = datetime.utcnow()
|
2020-05-21 19:45:25 +00:00
|
|
|
return voucher
|
2020-05-22 04:40:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
def update_employee_benefits(
|
2020-10-07 15:18:43 +00:00
|
|
|
voucher: Voucher,
|
|
|
|
employee_benefits: List[schema_in.EmployeeBenefit],
|
|
|
|
days_in_month: int,
|
|
|
|
db: Session,
|
2020-05-22 04:40:45 +00:00
|
|
|
):
|
|
|
|
exp, total = 0, 0
|
|
|
|
for i in range(len(voucher.employee_benefits), 0, -1):
|
|
|
|
item = voucher.employee_benefits[i - 1]
|
|
|
|
found = False
|
|
|
|
for j in range(len(employee_benefits), 0, -1):
|
|
|
|
new_item = employee_benefits[j - 1]
|
|
|
|
if new_item.id_ == item.id:
|
|
|
|
exp += item.esi_er + item.pf_er
|
|
|
|
total += item.esi_ee + item.pf_ee + item.esi_er + item.pf_er
|
|
|
|
employee_benefits.remove(new_item)
|
|
|
|
break
|
|
|
|
if not found:
|
|
|
|
voucher.employee_benefits.remove(item)
|
|
|
|
voucher.journals.remove(item.journal)
|
2020-10-07 16:59:24 +00:00
|
|
|
new_exp, new_total = save_employee_benefits(
|
|
|
|
voucher, employee_benefits, days_in_month, db
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
return exp + new_exp, total + new_total
|
|
|
|
|
|
|
|
|
|
|
|
def update_journals(voucher: Voucher, exp: int, total: int):
|
2020-10-07 16:59:24 +00:00
|
|
|
journal = next(
|
|
|
|
i for i in voucher.journals if i.account_id == AccountBase.esi_pf_expense()
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
journal.amount = exp
|
2020-10-07 16:59:24 +00:00
|
|
|
journal = next(
|
|
|
|
i for i in voucher.journals if i.account_id == AccountBase.esi_pf_payable()
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
journal.amount = total
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/{id_}", response_model=output.Voucher)
|
|
|
|
def get_id(
|
2020-10-07 15:18:43 +00:00
|
|
|
id_: uuid.UUID,
|
|
|
|
db: Session = Depends(get_db),
|
|
|
|
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
2020-05-22 04:40:45 +00:00
|
|
|
):
|
|
|
|
try:
|
|
|
|
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
|
|
|
|
return voucher_info(item, db)
|
|
|
|
except SQLAlchemyError as e:
|
|
|
|
db.rollback()
|
|
|
|
raise HTTPException(
|
2020-10-07 15:18:43 +00:00
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
detail=str(e),
|
2020-05-22 04:40:45 +00:00
|
|
|
)
|
|
|
|
except Exception:
|
|
|
|
db.rollback()
|
2020-06-01 03:31:31 +00:00
|
|
|
raise
|
2020-05-22 04:40:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
@router.get("", response_model=output.Voucher)
|
|
|
|
def show_blank(
|
2020-10-07 15:18:43 +00:00
|
|
|
request: Request,
|
|
|
|
db: Session = Depends(get_db),
|
|
|
|
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
2020-05-22 04:40:45 +00:00
|
|
|
):
|
|
|
|
additional_info = {"date": get_date(request.session), "type": "Employee Benefit"}
|
|
|
|
return blank_voucher(additional_info, db)
|
|
|
|
|
|
|
|
|
|
|
|
def esi_contribution(gross_salary, days_worked, days_in_month):
|
|
|
|
limit = 21000
|
|
|
|
employee_rate = 0.0175
|
|
|
|
employer_rate = 0.0475
|
2020-10-07 16:59:24 +00:00
|
|
|
employee = (
|
|
|
|
0
|
|
|
|
if gross_salary > limit
|
|
|
|
else ceil(employee_rate * gross_salary * days_worked / days_in_month)
|
|
|
|
)
|
|
|
|
employer = (
|
|
|
|
0
|
|
|
|
if gross_salary > limit
|
|
|
|
else ceil(employer_rate * gross_salary * days_worked / days_in_month)
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
return employee, employer, employee + employer
|
|
|
|
|
|
|
|
|
|
|
|
def pf_contribution(gross_salary, days_worked, days_in_month):
|
|
|
|
limit = 15000
|
|
|
|
employee_rate = 0.12
|
|
|
|
employer_rate = 0.12 + 0.011 + 0.005 + 0.0001
|
2020-10-07 16:59:24 +00:00
|
|
|
employee = (
|
|
|
|
0
|
|
|
|
if gross_salary > limit
|
|
|
|
else ceil(employee_rate * gross_salary * days_worked / days_in_month)
|
|
|
|
)
|
|
|
|
employer = (
|
|
|
|
0
|
|
|
|
if gross_salary > limit
|
|
|
|
else ceil(employer_rate * gross_salary * days_worked / days_in_month)
|
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
return employee, employer, employee + employer
|