diff --git a/alembic/versions/5498fc4bf58d_rename_service_charge_to_incentive.py b/alembic/versions/5498fc4bf58d_rename_service_charge_to_incentive.py new file mode 100644 index 00000000..ea72e322 --- /dev/null +++ b/alembic/versions/5498fc4bf58d_rename_service_charge_to_incentive.py @@ -0,0 +1,46 @@ +"""Rename Service Charge to Incentive + +Revision ID: 5498fc4bf58d +Revises: eed0b382c287 +Create Date: 2020-05-12 16:39:12.157447 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.sql import table, column + +# revision identifiers, used by Alembic. +revision = '5498fc4bf58d' +down_revision = 'eed0b382c287' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('service_charges_journal_id_fkey', 'service_charges', type_='foreignkey') + op.drop_constraint('service_charges_voucher_id_fkey', 'service_charges', type_='foreignkey') + op.rename_table('service_charges', 'incentives') + op.create_foreign_key('fk_incentives_journal_id_journals', 'incentives', 'journals', ['journal_id'], ['id']) + op.create_foreign_key('fk_incentives_voucher_id_vouchers', 'incentives', 'vouchers', ['voucher_id'], ['id']) + + role = table('auth_roles', column('name', sa.String)) + op.execute(role.update().where(role.c.name == op.inline_literal('Service Charge')).values({'name': op.inline_literal('Incentive')})) + account = table('accounts', column('name', sa.String)) + op.execute(account.update().where(account.c.name == op.inline_literal('Service Charges')).values({'name': op.inline_literal('Incentives')})) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('fk_incentives_journal_id_journals', 'incentives', type_='foreignkey') + op.drop_constraint('fk_incentives_voucher_id_vouchers', 'incentives', type_='foreignkey') + op.rename_table('incentives', 'service_charges') + op.create_foreign_key('service_charges_journal_id_fkey', 'service_charges', 'journals', ['journal_id'], ['journals.id']) + op.create_foreign_key('service_charges_voucher_id_fkey', 'service_charges', 'vouchers', ['voucher_id'], ['vouchers.id']) + + role = table('auth_roles', column('name', sa.String)) + op.execute(role.update().where(role.c.name == op.inline_literal('Incentive')).values({'name': op.inline_literal('Service Charge')})) + account = table('accounts', column('name', sa.String)) + op.execute(account.update().where(account.c.name == op.inline_literal('Incentives')).values({'name': op.inline_literal('Service Charges')})) + # ### end Alembic commands ### diff --git a/brewman/models/master.py b/brewman/models/master.py index 677ec1af..b618f817 100644 --- a/brewman/models/master.py +++ b/brewman/models/master.py @@ -367,11 +367,11 @@ class AccountBase(Base): return {"id": "5c2b54d0-c174-004d-a0d5-92cdaadcefa7", "name": "Staff Salary"} @classmethod - def service_charge(cls): - return {"id": "b7eff754-e8ba-e047-ab06-9132c15c7640", "name": "Service Charges"} + def incentive(cls): + return {"id": "b7eff754-e8ba-e047-ab06-9132c15c7640", "name": "Incentives"} @classmethod - def service_charge_id(cls): + def incentive_id(cls): return uuid.UUID("b7eff754-e8ba-e047-ab06-9132c15c7640") @classmethod @@ -461,8 +461,8 @@ class Account(AccountBase): class AttendanceType: - def __init__(self, id, name, value=None): - self.id = id + def __init__(self, id_, name, value=None): + self.id = id_ self.name = name self.value = value diff --git a/brewman/models/operations.py b/brewman/models/operations.py index 2d6e75d9..f4636ba6 100644 --- a/brewman/models/operations.py +++ b/brewman/models/operations.py @@ -1,5 +1,6 @@ +from fastapi import HTTPException, status + from brewman.models.master import CostCentre -from brewman.models.validation_exception import ValidationError def validate(voucher): @@ -22,16 +23,18 @@ def validate(voucher): def check_batch_insert(voucher): if voucher.type == 9: - raise ValidationError("Verification Vouchers have been disabled") + raise HTTPException( + status_code=status.HTTP_410_GONE, + detail="Verification Vouchers have been disabled", + ) if voucher.type == 6: # Purchase Return for item in voucher.inventories: batch = item.batch if batch.quantity_remaining < item.quantity: - raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format( - item.product.name, item.product.units, batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Quantity of {item.product.name} ({item.product.units}) cannot be more than {batch.quantity_remaining}", ) if voucher.type == 3: # Issue @@ -46,10 +49,9 @@ def check_batch_insert(voucher): for item in voucher.inventories: batch = item.batch if batch.quantity_remaining < item.quantity: - raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format( - item.product.name, item.product.units, batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Quantity of {item.product.name} ({item.product.units}) cannot be more than {batch.quantity_remaining}", ) if voucher.type == 2: # Purchase @@ -64,9 +66,9 @@ def issue_new(voucher): if not len(consuming): consuming = False elif consuming[0].debit == 1: - consuming == False + consuming = False else: - consuming == True + consuming = True if not consuming: return @@ -74,10 +76,9 @@ def issue_new(voucher): for item in voucher.inventories: batch = item.batch if batch.quantity_remaining < item.quantity: - raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format( - item.product.name, item.product.units, batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Quantity of {item.product.name} ({item.product.units}) cannot be more than {batch.quantity_remaining}", ) @@ -99,10 +100,9 @@ def issue_update(voucher): for item in voucher.inventories: batch = item.batch if batch.quantity_remaining < item.quantity: - raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format( - item.product.name, item.product.units, batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Quantity of {item.product.name} ({item.product.units}) cannot be more than {batch.quantity_remaining}", ) @@ -110,10 +110,9 @@ def purchase_return_new(voucher): for item in voucher.inventories: batch = item.batch if batch.quantity_remaining < item.quantity: - raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format( - item.product.name, item.product.units, batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Quantity of {item.product.name} ({item.product.units}) cannot be more than {batch.quantity_remaining}", ) @@ -121,17 +120,19 @@ def purchase_return_update(voucher): for item in voucher.inventories: batch = item.batch if batch.quantity_remaining < item.quantity: - raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format( - item.product.name, item.product.units, batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Quantity of {item.product.name} ({item.product.units}) cannot be more than {batch.quantity_remaining}", ) def inventory_valid(voucher): if voucher.type in [2, 6, 3]: if not len(voucher.inventories): - raise ValidationError("Not enough inventories") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Not enough inventories", + ) is_distinct_inventory(voucher.inventories) @@ -140,7 +141,10 @@ def is_distinct_inventory(inventories): for item in inventories: item_hash = hash(item.product_id) if item_hash in found: - raise ValidationError("Duplicate inventories") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Duplicate inventories", + ) else: found.add(item_hash) @@ -155,14 +159,23 @@ def is_date_allowed(voucher): def journals_valid(voucher): if len(voucher.journals) < 2: - raise ValidationError("Not enough journals") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Not enough journals", + ) signed_amount = 0 for item in voucher.journals: if item.amount < 0: - raise ValidationError("Amounts cannot be negative") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Amounts cannot be negative", + ) signed_amount += item.signed_amount if not signed_amount == 0: - raise ValidationError("Journal amounts do no match") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Journal amounts do no match", + ) is_distinct_journal(voucher.journals) @@ -171,6 +184,9 @@ def is_distinct_journal(journals): for item in journals: item_hash = hash(item.account_id) ^ hash(item.cost_centre_id) if item_hash in found: - raise ValidationError("Duplicate journals") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Duplicate journals", + ) else: found.add(item_hash) diff --git a/brewman/models/validation_exception.py b/brewman/models/validation_exception.py deleted file mode 100644 index 2e80b403..00000000 --- a/brewman/models/validation_exception.py +++ /dev/null @@ -1,11 +0,0 @@ -class ValidationError(Exception): - def __init__(self, message, errors=None): - self.message = message - # Call the base class constructor with the parameters it needs - Exception.__init__(self, message) - - # Now for your custom code... - self.errors = errors - - def __str__(self): - return self.message diff --git a/brewman/models/voucher.py b/brewman/models/voucher.py index f41bde40..28fd3095 100644 --- a/brewman/models/voucher.py +++ b/brewman/models/voucher.py @@ -40,7 +40,7 @@ class VoucherType: VoucherType(10, "Opening Balance"), VoucherType(11, "Closing Balance"), VoucherType(12, "Salary Deduction"), - VoucherType(13, "Service Charge"), + VoucherType(13, "Incentive"), ] return list @@ -98,8 +98,8 @@ class Voucher(Base): cascade="delete, delete-orphan", cascade_backrefs=False, ) - service_charges = relationship( - "ServiceCharge", + incentives = relationship( + "Incentive", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False, @@ -237,8 +237,8 @@ class SalaryDeduction(Base): self.journal = journal -class ServiceCharge(Base): - __tablename__ = "service_charges" +class Incentive(Base): + __tablename__ = "incentives" id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) voucher_id = Column( "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False @@ -251,7 +251,7 @@ class ServiceCharge(Base): journal = relationship( Journal, - backref=backref("service_charge", uselist=False), + backref=backref("incentive", uselist=False), cascade=None, cascade_backrefs=False, ) diff --git a/brewman/routers/account.py b/brewman/routers/account.py index 77ea2fef..c79a5e17 100644 --- a/brewman/routers/account.py +++ b/brewman/routers/account.py @@ -69,7 +69,7 @@ def update( item: Account = db.query(Account).filter(Account.id == id_).first() if item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) if not item.type == data.type: diff --git a/brewman/routers/attendance.py b/brewman/routers/attendance.py index 09dea526..7d4aa4cd 100644 --- a/brewman/routers/attendance.py +++ b/brewman/routers/attendance.py @@ -1,25 +1,23 @@ -import datetime import uuid +from datetime import datetime, date, timedelta +from fastapi import APIRouter, HTTPException, status, Depends, Security, Request from sqlalchemy import or_ from sqlalchemy.orm import Session -from fastapi import Depends, Security - from ..schemas.auth import UserToken +from ..core.security import get_current_active_user as get_user +from ..db.session import SessionLocal from ..models.master import Employee from ..models.voucher import Attendance from ..routers.fingerprint import get_prints -from ..db.session import SessionLocal -from ..core.security import get_current_active_user as get_user from ..core.session import get_date - -from fastapi import APIRouter +import brewman.schemas.voucher as schemas router = APIRouter() # Dependency -def get_db(): +def get_db() -> Session: try: db = SessionLocal() yield db @@ -27,24 +25,27 @@ def get_db(): db.close() -@router.get("/") -def attendance_blank(db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["attendance"])): - return {"date": get_date(request), "body": []} +@router.get("") +def attendance_blank(request: Request, user: UserToken = Security(get_user, scopes=["attendance"])): + return {"date": get_date(request.session), "body": []} -@router.get("/{date}") # "Attendance" -def attendance_date(request): - date = request.matchdict.get("date", None) - return attendance_date_report(date, request.dbsession) +@router.get("/{date_}") +def attendance_date( + date_: str, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["attendance"]), +): + return attendance_date_report(date_, db) -def attendance_date_report(date, dbsession): - report = {"date": date, "body": []} - date = datetime.datetime.strptime(date, "%d-%b-%Y") +def attendance_date_report(date_: str, db): + report = {"date": date_, "body": []} + date_ = datetime.strptime(date_, "%d-%b-%Y").date() employees = ( - dbsession.query(Employee) - .filter(Employee.joining_date <= date) - .filter(or_(Employee.is_active, Employee.leaving_date >= date)) + db.query(Employee) + .filter(Employee.joining_date <= date_) + .filter(or_(Employee.is_active, Employee.leaving_date >= date_)) .order_by(Employee.cost_centre_id) .order_by(Employee.designation) .order_by(Employee.name) @@ -52,7 +53,7 @@ def attendance_date_report(date, dbsession): ) for item in employees: att = ( - dbsession.query(Attendance) + db.query(Attendance) .filter(Attendance.employee_id == item.id) .filter(Attendance.date == date) .filter(Attendance.is_valid == True) @@ -60,7 +61,7 @@ def attendance_date_report(date, dbsession): ) att = 0 if att is None else att.attendance_type - prints, hours, worked = get_prints(item.id, date, dbsession) + prints, hours, worked = get_prints(item.id, date, db) report["body"].append( { "id": item.id, @@ -77,28 +78,30 @@ def attendance_date_report(date, dbsession): return report -@router.post("/{date}") # "Attendance" -def save(request): - user_id = uuid.UUID(request.authenticated_userid) - date = request.matchdict.get("date", None) - date_object = datetime.datetime.strptime(date, "%d-%b-%Y") +@router.post("/{date_}") # "Attendance" +def save( + date_: str, + data: schemas.AttendanceIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["attendance"]), +): + date_object = datetime.strptime(date_, "%d-%b-%Y").date() - for item in request.json_body["body"]: - employee_id = uuid.UUID(item["id"]) - attendance_type = item["attendanceType"]["id"] + for item in data.body: + attendance_type = item.attendance_type.id_ if attendance_type != 0: attendance = Attendance( - employee_id=employee_id, + employee_id=item.employee_id, date=date_object, attendance_type=attendance_type, - user_id=user_id, + user_id=user.id_, ) - attendance.create(request.dbsession) - transaction.commit() - return attendance_date_report(date, request.dbsession) + attendance.create(db) + db.commit() + return attendance_date_report(date_, db) -def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False): +def date_range(start: date, stop: date, step=timedelta(days=1), inclusive=False): # inclusive=False to behave like range by default if step.days > 0: while start < stop: diff --git a/brewman/routers/attendance_report.py b/brewman/routers/attendance_report.py index 0a8d45ee..fd05e335 100644 --- a/brewman/routers/attendance_report.py +++ b/brewman/routers/attendance_report.py @@ -2,7 +2,7 @@ import datetime from sqlalchemy import or_ from ..models.master import AttendanceType, Employee from ..models.voucher import Attendance -from .attendance import daterange +from .attendance import date_range from ..core.session import get_start_date, get_finish_date from fastapi import APIRouter @@ -22,7 +22,7 @@ def get_report(request): def attendance_record(start_date, finish_date, dbsession): report = [] header = ["Code", "Name", "Designation", "Department", "Salary", "SC Points"] - for date in daterange(start_date, finish_date, inclusive=True): + for date in date_range(start_date, finish_date, inclusive=True): header.append(date.strftime("%d-%b")) not_set = AttendanceType.by_id(0) @@ -45,7 +45,7 @@ def attendance_record(start_date, finish_date, dbsession): employee.points, ] row_value = ["", "", "", "", employee.salary, employee.points] - for date in daterange(start_date, finish_date, inclusive=True): + for date in date_range(start_date, finish_date, inclusive=True): att = ( dbsession.query(Attendance) .filter(Attendance.employee_id == employee.id) diff --git a/brewman/routers/auth/role.py b/brewman/routers/auth/role.py index d96c3a97..0e8c6d5d 100644 --- a/brewman/routers/auth/role.py +++ b/brewman/routers/auth/role.py @@ -102,7 +102,7 @@ def delete( ) else: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Role deletion not implemented", ) except Exception: diff --git a/brewman/routers/auth/user.py b/brewman/routers/auth/user.py index 92a79eed..3fafa64b 100644 --- a/brewman/routers/auth/user.py +++ b/brewman/routers/auth/user.py @@ -140,7 +140,7 @@ def delete( ) else: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="User deletion not implemented", ) except Exception: diff --git a/brewman/routers/cost_centre.py b/brewman/routers/cost_centre.py index f18b8c36..d9673940 100644 --- a/brewman/routers/cost_centre.py +++ b/brewman/routers/cost_centre.py @@ -59,7 +59,7 @@ def update( item = db.query(CostCentre).filter(CostCentre.id == id_).first() if item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) item.name = data.name @@ -90,17 +90,17 @@ def delete( if item is None: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_404_NOT_FOUND, detail="Cost Centre not found", ) elif item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) else: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Cost Centre deletion not implemented", ) except Exception: diff --git a/brewman/routers/employee.py b/brewman/routers/employee.py index fe9a3b9a..69e73851 100644 --- a/brewman/routers/employee.py +++ b/brewman/routers/employee.py @@ -10,7 +10,6 @@ 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.validation_exception import ValidationError from brewman.models.voucher import Voucher, Journal, VoucherType import brewman.schemas.master as schemas @@ -71,7 +70,7 @@ def update( item: Employee = db.query(Employee).filter(Employee.id == id_).first() if item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) item.name = data.name diff --git a/brewman/routers/employee_attendance.py b/brewman/routers/employee_attendance.py index 49991958..238cb763 100644 --- a/brewman/routers/employee_attendance.py +++ b/brewman/routers/employee_attendance.py @@ -1,50 +1,70 @@ -import datetime import uuid +from datetime import datetime, date -from sqlalchemy import or_ - +from fastapi import APIRouter, HTTPException, status, Depends, Security, Request +from sqlalchemy.orm import Session +from .attendance import date_range +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 Employee -from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Attendance from brewman.routers.fingerprint import get_prints +import brewman.schemas.voucher as schemas from ..core.session import ( get_start_date, get_finish_date, ) -from fastapi import APIRouter - router = APIRouter() -@router.get("/") # "Attendance" -def employee_attendance_blank(request): +# Dependency +def get_db() -> Session: + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.get("") +def show_blank( + request: Request, + user: UserToken = Security(get_user, scopes=["attendance"]), +): return { - "startDate": get_start_date(request), - "finishDate": get_finish_date(request), + "startDate": get_start_date(request.session), + "finishDate": get_finish_date(request.session), "employee": None, "body": [], } -@router.get("/{id}") # "Attendance" -def employee_attendance_report(request): - employee = ( - request.dbsession.query(Employee) - .filter(Employee.id == uuid.UUID(request.matchdict["id"])) - .first() - ) +@router.get("/{id_}") +def employee_attendance_report( + id_: int, + request: Request, + s: str = None, + f: str = None, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["attendance"]), +): + employee: Employee = db.query(Employee).filter(Employee.id == id_).first() if employee is None: - raise ValidationError("Employee id is wrong") - start_date = request.GET.get("s", get_start_date(request)) - finish_date = request.GET.get("f", get_finish_date(request)) + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Employee not found", + ) + start_date = s if s is not None else get_start_date(request.session) + finish_date = f if f is not None else get_finish_date(request.session) info = { "startDate": start_date, "finishDate": finish_date, "employee": {"id": employee.id, "name": employee.name}, } - start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") - finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") + start_date = datetime.strptime(start_date, "%d-%b-%Y").date() + finish_date = datetime.strptime(finish_date, "%d-%b-%Y").date() start_date = ( employee.joining_date if employee.joining_date > start_date else start_date ) @@ -54,27 +74,23 @@ def employee_attendance_report(request): else finish_date ) info["body"] = employee_attendance( - employee, start_date, finish_date, request.dbsession + employee, start_date, finish_date, db ) return info -def employee_attendance(employee, start_date, finish_date, dbsession): - if not isinstance(start_date, datetime.datetime): - start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") - if not isinstance(finish_date, datetime.datetime): - finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") +def employee_attendance(employee: Employee, start_date: date, finish_date: date, db: Session): list_ = [] - for item in daterange(start_date, finish_date, inclusive=True): + for item in date_range(start_date, finish_date, inclusive=True): att = ( - dbsession.query(Attendance) + db.query(Attendance) .filter(Attendance.employee_id == employee.id) .filter(Attendance.date == item) .filter(Attendance.is_valid == True) .first() ) att = 0 if att is None else att.attendance_type - prints, hours, worked = get_prints(employee.id, item, dbsession) + prints, hours, worked = get_prints(employee.id, item, db) list_.append( { "date": item.strftime("%d-%b-%Y"), @@ -87,37 +103,34 @@ def employee_attendance(employee, start_date, finish_date, dbsession): return list_ -@router.post("/{id}") # "Attendance" -def save_employee_attendance(request): +@router.post("/{id_}") +def save_employee_attendance( + id_: uuid.UUID, + data: schemas.EmployeeAttendanceIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["attendance"]), +): start_date = None finish_date = None - user_id = uuid.UUID(request.authenticated_userid) - employee = ( - request.dbsession.query(Employee) - .filter(Employee.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - for item in request.json_body["body"]: + employee: Employee = db.query(Employee).filter(Employee.id == id_).first() + for item in data.body: if start_date is None: - start_date = item["date"] - finish_date = item["date"] + start_date = item.date + finish_date = item.date - attendance_type = item["attendanceType"]["id"] + attendance_type = item.attendance_type.id_ if attendance_type != 0: - date = datetime.datetime.strptime(item["date"], "%d-%b-%Y") attendance = Attendance( employee_id=employee.id, - date=date, + date=item.date, attendance_type=attendance_type, - user_id=user_id, + user_id=user.id_, ) - attendance.create(request.dbsession) - transaction.commit() + attendance.create(db) + db.commit() return { - "startDate": start_date, - "finishDate": finish_date, + "startDate": start_date.strftime("%d-%b-%Y"), + "finishDate": finish_date.strftime("%d-%b-%Y"), "employee": {"id": employee.id, "name": employee.name}, - "body": employee_attendance( - employee, start_date, finish_date, request.dbsession - ), + "body": employee_attendance(employee, start_date, finish_date, db), } diff --git a/brewman/routers/management/rebase.py b/brewman/routers/management/rebase.py index fbe1ea32..d1af29ea 100644 --- a/brewman/routers/management/rebase.py +++ b/brewman/routers/management/rebase.py @@ -15,7 +15,7 @@ from brewman.models.voucher import ( Fingerprint, Attendance, DbImage, - ServiceCharge, + Incentive, ) @@ -206,7 +206,7 @@ def delete_data(date, vouchers, dbsession): SalaryDeduction.__table__.delete(SalaryDeduction.voucher_id.in_(sub_query)) ) dbsession.execute( - ServiceCharge.__table__.delete(ServiceCharge.voucher_id.in_(sub_query)) + Incentive.__table__.delete(Incentive.voucher_id.in_(sub_query)) ) dbsession.execute( Journal.__table__.delete( diff --git a/brewman/routers/product.py b/brewman/routers/product.py index 8e248ce1..ea9e2e53 100644 --- a/brewman/routers/product.py +++ b/brewman/routers/product.py @@ -73,7 +73,7 @@ def update( item: Product = db.query(Product).filter(Product.id == id_).first() if item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) item.name = data.name diff --git a/brewman/routers/product_group.py b/brewman/routers/product_group.py index 3d186726..6dc9b03b 100644 --- a/brewman/routers/product_group.py +++ b/brewman/routers/product_group.py @@ -59,7 +59,7 @@ def update( item = db.query(ProductGroup).filter(ProductGroup.id == id_).first() if item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) item.name = data.name @@ -90,17 +90,17 @@ def delete( if item is None: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_404_NOT_FOUND, detail="Product Group not found", ) elif item.is_fixture: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", ) else: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Product Group deletion not implemented", ) except Exception: diff --git a/brewman/routers/recipe.py b/brewman/routers/recipe.py index be856e14..dbed394b 100644 --- a/brewman/routers/recipe.py +++ b/brewman/routers/recipe.py @@ -5,7 +5,6 @@ from decimal import Decimal, InvalidOperation from sqlalchemy import desc, or_, func from brewman.models.master import Recipe, Product, RecipeItem, CostCentre -from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Voucher, Inventory, VoucherType, Journal from ..core.session import ( get_start_date, diff --git a/brewman/routers/voucher/__init__.py b/brewman/routers/voucher/__init__.py index a80a0b36..3b2b4733 100644 --- a/brewman/routers/voucher/__init__.py +++ b/brewman/routers/voucher/__init__.py @@ -11,7 +11,6 @@ from brewman.models.master import ( AttendanceType, Account, ) -from brewman.models.validation_exception import ValidationError from brewman.models.voucher import ( Voucher, VoucherType, @@ -24,8 +23,8 @@ from brewman.routers import get_lock_info from .issue import issue_create_voucher, issue_update_voucher from .journal import journal_update_voucher, journal_create_voucher from .purchase import purchase_create_voucher, purchase_update_voucher -from .service_charge import service_charge_create_voucher, service_charge_update_voucher -from ..session import get_first_day +from .incentive import incentive_create_voucher, incentive_update_voucher +from ...core.session import get_first_day from fastapi import APIRouter, Depends, Security, Request @@ -47,13 +46,9 @@ def voucher_post(request): ) start, finish = get_lock_info(request.dbsession) if start is not None and start > voucher.date: - raise ValidationError( - "Vouchers before {0} have been locked.".format(start.strftime("%d-%b-%Y")) - ) + raise ValidationError(f"Vouchers before {start.strftime('%d-%b-%Y')} have been locked.") elif finish is not None and finish < voucher.date: - raise ValidationError( - "Vouchers after {0} have been locked.".format(finish.strftime("%d-%b-%Y")) - ) + raise ValidationError(f"Vouchers after {finish.strftime('%d-%b-%Y')} have been locked.") voucher.posted = True voucher.poster_id = user.id transaction.commit() @@ -81,24 +76,16 @@ def check_delete_permissions(request, voucher): response.status_int = 403 return response elif not request.has_permission(VoucherType.by_id(voucher.type).name): - response = Response( - "You are not allowed (0) vouchers".format( - VoucherType.by_id(voucher.type).name - ) - ) + response = Response(f"You are not allowed ({VoucherType.by_id(voucher.type).name}) vouchers") response.status_int = 403 return response start, finish = get_lock_info(request.dbsession) if start is not None and start > voucher.date: - response = Response( - "Vouchers before {0} have been locked.".format(start.strftime("%d-%b-%Y")) - ) + response = Response(f"Vouchers before {start.strftime('%d-%b-%Y')} have been locked.") response.status_int = 403 return response elif finish is not None and finish < voucher.date: - response = Response( - "Vouchers after {0} have been locked.".format(finish.strftime("%d-%b-%Y")) - ) + response = Response(f"Vouchers after {finish.strftime('%d-%b-%Y')} have been locked.") response.status_int = 403 return response @@ -236,7 +223,7 @@ def voucher_info(voucher, request): }, } ) - for item in voucher.service_charges: + for item in voucher.incentives: employee = ( request.dbsession.query(Employee) .filter(Employee.id == item.journal.account_id) @@ -256,7 +243,7 @@ def voucher_info(voucher, request): json_voucher["incentive"] = [ x.amount for x in voucher.journals - if x.account_id == Account.service_charge_id() + if x.account_id == Account.incentive_id() ][0] for item in voucher.inventories: text = "{0} ({1}) {2:.2f}@{3:.2f} from {4}".format( @@ -406,17 +393,17 @@ def blank_voucher(info, dbsession): elif type_ == "Salary Deduction": json_voucher["employeeBenefits"] = [] - elif type_ == "Service Charge": + elif type_ == "Incentive": json_voucher["incentives"], json_voucher[ "incentive" - ] = service_charge_employees(info["date"], dbsession) + ] = incentive_employees(info["date"], dbsession) else: raise ValidationError('Voucher of type "{0}" does not exist.'.format(type_)) json_voucher["files"] = [] return json_voucher -def service_charge_employees(date, dbsession): +def incentive_employees(date, dbsession): date = datetime.datetime.strptime(date, "%d-%b-%Y") start_date = get_first_day(date) finish_date = date + datetime.timedelta(1) @@ -456,29 +443,8 @@ def service_charge_employees(date, dbsession): .join(Journal.voucher) .filter(Voucher.date < finish_date) .filter(Voucher.type != VoucherType.by_name("Issue").id) - .filter(Journal.account_id == Account.service_charge_id()) + .filter(Journal.account_id == Account.incentive_id()) .scalar() ) amount = 0 if amount is None else amount * Decimal(0.9) * -1 return details, amount - - -def get_edit_url(voucher, request): - if voucher.type == 1: - return request.route_url("journal_id", id=voucher.id) - elif voucher.type == 2: - return request.route_url("purchase_id", id=voucher.id) - elif voucher.type == 3: - return request.route_url("issue_id", id=voucher.id) - elif voucher.type == 4: - return request.route_url("payment_id", id=voucher.id) - elif voucher.type == 5: - return request.route_url("receipt_id", id=voucher.id) - elif voucher.type == 6: - return request.route_url("purchase_return_id", id=voucher.id) - elif voucher.type == 12: - return request.route_url("employee_benefits_id", id=voucher.id) - elif voucher.type == 13: - return request.route_url("incentive_id", id=voucher.id) - else: - return "#" diff --git a/brewman/routers/voucher/batch.py b/brewman/routers/voucher/batch.py index 141d0d39..8498cb43 100644 --- a/brewman/routers/voucher/batch.py +++ b/brewman/routers/voucher/batch.py @@ -28,7 +28,7 @@ def batch_term( db: Session = Depends(get_db), current_user: UserToken = Depends(get_user), ): - filter_ = q if q is not None and q.strip() is not "" else None + filter_ = q if q is not None and q.strip() != "" else None date = None if not d else datetime.datetime.strptime(d, "%d-%b-%Y") list_ = [] for index, item in enumerate( diff --git a/brewman/routers/voucher/emptyvoucher.py b/brewman/routers/voucher/emptyvoucher.py index 885c445c..08181012 100644 --- a/brewman/routers/voucher/emptyvoucher.py +++ b/brewman/routers/voucher/emptyvoucher.py @@ -51,8 +51,8 @@ class EmptyVoucher(object): else: return self.get_blank() - @router.get("/api/voucher", request_param="t=Service Charge") # "Service Charge" - def service_charge(self): + @router.get("/api/voucher", request_param="t=Incentive") # "Incentive" + def incentive(self): voucher_type = self.request.GET.get("t", None) date = self.request.GET.get("d", None) if date is not None: diff --git a/brewman/routers/voucher/service_charge.py b/brewman/routers/voucher/incentive.py similarity index 89% rename from brewman/routers/voucher/service_charge.py rename to brewman/routers/voucher/incentive.py index 76eeb655..068bac05 100644 --- a/brewman/routers/voucher/service_charge.py +++ b/brewman/routers/voucher/incentive.py @@ -11,12 +11,12 @@ from brewman.models.voucher import ( Voucher, VoucherType, Attendance, - ServiceCharge, + Incentive, ) -from brewman.routers.services.session import get_first_day +from brewman.core.session import get_first_day -def service_charge_create_voucher(json, user, dbsession): +def incentive_create_voucher(json, user, dbsession): date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher = Voucher(date=date, user_id=user.id, type=VoucherType.by_id(13)) @@ -45,18 +45,18 @@ def service_charge_create_voucher(json, user, dbsession): account_id=employee.id, cost_centre_id=employee.cost_centre_id, ) - sc = ServiceCharge( + inc = Incentive( journal=journal, days_worked=item["daysWorked"], points=item["points"] ) voucher.journals.append(journal) - voucher.service_charges.append(sc) + voucher.incentives.append(inc) dbsession.add(journal) - dbsession.add(sc) + dbsession.add(inc) total_amount += item_amount sc = ( dbsession.query(Account) - .filter(Account.id == Account.service_charge_id()) + .filter(Account.id == Account.incentive_id()) .first() ) journal = Journal( @@ -68,7 +68,7 @@ def service_charge_create_voucher(json, user, dbsession): return voucher -def service_charge_update_voucher(voucher, json, user, dbsession): +def incentive_update_voucher(voucher, json, user, dbsession): date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher.date = date voucher.user_id = user.id @@ -90,7 +90,7 @@ def service_charge_update_voucher(voucher, json, user, dbsession): point_value = round(amount / total_points, 2) total_amount = 0 - for item in voucher.service_charges: + for item in voucher.incentives: employee = [ e for e in employees if e["employee"].id == item.journal.account_id ][0] @@ -101,7 +101,7 @@ def service_charge_update_voucher(voucher, json, user, dbsession): total_amount += item_amount journal = [ - j for j in voucher.journals if j.account_id == Account.service_charge_id() + j for j in voucher.journals if j.account_id == Account.incentive_id() ][0] journal.amount = total_amount @@ -149,7 +149,7 @@ def balance(date, voucher_id=None, dbsession=None): .join(Journal.voucher) .filter(Voucher.date < date + datetime.timedelta(1)) .filter(Voucher.type != VoucherType.by_name("Issue").id) - .filter(Journal.account_id == Account.service_charge_id()) + .filter(Journal.account_id == Account.incentive_id()) ) if voucher_id is not None: amount = amount.filter(Voucher.id != voucher_id) @@ -165,7 +165,7 @@ def check_if_employees_changed(json, db, voucher): [ x.account_id for x in voucher - if x.account_id != Account.service_charge_id() + if x.account_id != Account.incentive_id() ] ) if voucher is not None diff --git a/brewman/routers/voucher/issue.py b/brewman/routers/voucher/issue.py index bd566afa..0d32a8a6 100644 --- a/brewman/routers/voucher/issue.py +++ b/brewman/routers/voucher/issue.py @@ -1,9 +1,11 @@ import datetime from decimal import Decimal import uuid + +from fastapi import HTTPException, status + from brewman.models.master import CostCentre, AccountBase from brewman.models.operations import journals_valid, inventory_valid -from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory, Journal @@ -23,7 +25,10 @@ def issue_create_voucher(json, user, dbsession): else: source = uuid.UUID(item["costCentre"]["id"]) if source == destination: - raise ValidationError("Source cannot be the same as destination") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Source cannot be the same as destination", + ) if source == CostCentre.cost_centre_purchase(): batch_consumed = True elif destination == CostCentre.cost_centre_purchase(): @@ -52,16 +57,19 @@ def issue_create_inventory(voucher, item, batch_consumed, dbsession): quantity = round(Decimal(item["quantity"]), 2) if quantity <= 0: - raise ValidationError( - "Quantity of {0} cannot be zero".format(item.product.name) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Quantity of {item.product.name} cannot be zero", ) if batch_consumed == True and quantity > batch.quantity_remaining: - raise ValidationError( - "Quantity available is {0} only".format(batch.quantity_remaining) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Quantity available is {batch.quantity_remaining} only", ) if batch.name > voucher.date: - raise ValidationError( - "Batch of {0} was purchased after the issue date".format(batch.product.name) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Batch of {batch.product.name} was purchased after the issue date", ) if batch_consumed is None: pass @@ -127,7 +135,10 @@ def issue_update_voucher(voucher, json, user, dbsession): else: source = uuid.UUID(item["costCentre"]["id"]) if source == destination: - raise ValidationError("Source cannot be the same as destination") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Source cannot be the same as destination", + ) if source == CostCentre.cost_centre_purchase(): new_batch_consumed = True @@ -137,7 +148,10 @@ def issue_update_voucher(voucher, json, user, dbsession): new_batch_consumed = None if new_batch_consumed != old_batch_consumed: - raise ValidationError("Purchase cost centre cannot be changed") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Purchase cost centre cannot be changed", + ) issue_update_inventory(voucher, json["inventories"], old_batch_consumed, dbsession) issue_update_journals(voucher, source, destination) @@ -160,28 +174,30 @@ def issue_update_inventory(voucher, new_inventories, batch_consumed, dbsession): ) found = True if item.batch_id != batch.id: - raise ValidationError("Product / Batch cannot be changed") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Product / Batch cannot be changed", + ) new_quantity = round(Decimal(i["quantity"]), 2) old_quantity = round(Decimal(item.quantity), 2) quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2) if new_quantity <= 0: - raise ValidationError( - "Quantity of {0} cannot be zero".format(item.product.name) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Quantity of {item.product.name} cannot be zero", ) if ( batch_consumed is True and new_quantity - old_quantity > quantity_remaining ): - raise ValidationError( - "Maximum quantity available for {0} is {1}".format( - item.product.full_name, old_quantity + quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Maximum quantity available for {item.product.full_name} is {old_quantity + quantity_remaining}", ) if item.batch.name > voucher.date: - raise ValidationError( - "Batch of {0} was purchased after the issue date".format( - item.product.name - ) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Batch of {item.product.name} was purchased after the issue date", ) if batch_consumed is None: @@ -205,10 +221,9 @@ def issue_update_inventory(voucher, new_inventories, batch_consumed, dbsession): item.batch.quantity_remaining += item.quantity else: if item.batch.quantity_remaining < item.quantity: - raise ValidationError( - "Product {0} cannot be removed, minimum quantity is {1}".format( - item.product.name, item.batch.quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Product {item.product.name} cannot be removed, minimum quantity is {item.batch.quantity_remaining}", ) item.batch.quantity_remaining -= item.quantity dbsession.delete(item) diff --git a/brewman/routers/voucher/purchase.py b/brewman/routers/voucher/purchase.py index edbb4c56..645d3708 100644 --- a/brewman/routers/voucher/purchase.py +++ b/brewman/routers/voucher/purchase.py @@ -2,11 +2,11 @@ import datetime import uuid from decimal import Decimal +from fastapi import HTTPException, status from sqlalchemy import func from brewman.models.master import Product, AccountBase from brewman.models.operations import journals_valid, inventory_valid -from brewman.models.validation_exception import ValidationError from brewman.models.voucher import ( Voucher, VoucherType, @@ -44,14 +44,20 @@ def purchase_create_voucher(json, files, user, dbsession): def purchase_create_inventory(voucher, item, date, dbsession): if "product" not in item or "id" not in item["product"]: - raise ValidationError("No Product in item") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="No Product in item", + ) product = ( dbsession.query(Product) .filter(Product.id == uuid.UUID(item["product"]["id"])) .first() ) if product is None: - raise ValidationError("No Product in item") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="No Product in item", + ) inventory_id = ( uuid.UUID(item["id"]) if "id" in item and item["id"] is not None else None ) @@ -151,21 +157,24 @@ def purchase_update_inventory(voucher, new_inventories, dbsession): ) found = True if item.product_id != product.id: - raise ValidationError("Product cannot be changed") + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Product cannot be changed", + ) new_quantity = round(Decimal(i["quantity"]), 2) old_quantity = round(Decimal(item.quantity), 2) quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2) if new_quantity <= 0: - raise ValidationError( - "Quantity of {0} cannot be zero".format(item.product.name) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Quantity of {item.product.name} cannot be zero", ) if old_quantity > new_quantity and quantity_remaining < ( old_quantity - new_quantity ): - raise ValidationError( - "{0} has been issued, minimum quantity is".format( - old_quantity - quantity_remaining - ) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"{old_quantity - quantity_remaining} has been issued, minimum quantity is", ) item.batch.quantity_remaining -= old_quantity - new_quantity item.quantity = new_quantity @@ -195,10 +204,9 @@ def purchase_update_inventory(voucher, new_inventories, dbsession): .scalar() ) if uses > 0: - raise ValidationError( - "{0} has been issued, it cannot be deleted".format( - item.product.name - ) + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"{item.product.name} has been issued, it cannot be deleted", ) else: dbsession.delete(item.batch) diff --git a/brewman/routers/voucher/purchase_return.py b/brewman/routers/voucher/purchase_return.py index 11bae7a8..c3bdccdc 100644 --- a/brewman/routers/voucher/purchase_return.py +++ b/brewman/routers/voucher/purchase_return.py @@ -52,17 +52,11 @@ def purchase_return_create_inventory(voucher, item, dbsession): quantity = Decimal(item["quantity"]) if quantity <= 0: - raise ValidationError( - "Quantity of {0} cannot be zero".format(item.product.name) - ) + raise ValidationError(f"Quantity of {item.product.name} cannot be zero") if quantity > batch.quantity_remaining: - raise ValidationError( - "Quantity available is {0} only".format(batch.quantity_remaining) - ) + raise ValidationError(f"Quantity available is {batch.quantity_remaining} only") if batch.name > voucher.date: - raise ValidationError( - "Batch of {0} was purchased after the issue date".format(batch.product.name) - ) + raise ValidationError("Batch of {batch.product.name} was purchased after the issue date") batch.quantity_remaining -= quantity diff --git a/brewman/routers/voucher/savevoucher.py b/brewman/routers/voucher/savevoucher.py index 18b2147e..d2412b27 100644 --- a/brewman/routers/voucher/savevoucher.py +++ b/brewman/routers/voucher/savevoucher.py @@ -12,7 +12,7 @@ from . import ( purchase_create_voucher, issue_create_voucher, ) -from . import service_charge_create_voucher +from . import incentive_create_voucher from .purchase_return import purchase_return_create_voucher from .salary_deduction import salary_deduction_create_voucher @@ -73,8 +73,8 @@ class SaveVoucher(object): def salary_deduction(self): return self.save() - @router.get("/api/voucher", request_param="t=Service Charge") # "Service Charge" - def salary_deduction(self): + @router.get("/api/voucher", request_param="t=Incentive") # "Incentive" + def incentive(self): return self.save() def save(self): @@ -109,8 +109,8 @@ class SaveVoucher(object): voucher = salary_deduction_create_voucher( self.json, self.user, self.request.dbsession ) - elif self.json["type"] in ["Service Charge"]: - voucher = service_charge_create_voucher( + elif self.json["type"] in ["Incentive"]: + voucher = incentive_create_voucher( self.json, self.user, self.request.dbsession ) transaction.commit() diff --git a/brewman/routers/voucher/updatevoucher.py b/brewman/routers/voucher/updatevoucher.py index 58ed2b2a..f0c4cf01 100644 --- a/brewman/routers/voucher/updatevoucher.py +++ b/brewman/routers/voucher/updatevoucher.py @@ -7,18 +7,18 @@ from pyramid.response import Response from brewman.models.auth import User from brewman.models.voucher import Voucher from brewman.routers import get_lock_info -from ....core.session import set_date +from ...core.session import set_date from . import ( voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher, ) -from . import service_charge_update_voucher -from brewman.routers.services.voucher.purchase_return import ( +from . import incentive_update_voucher +from brewman.routers.voucher.purchase_return import ( purchase_return_update_voucher, ) -from brewman.routers.services.voucher.salary_deduction import ( +from brewman.routers.voucher.salary_deduction import ( salary_deduction_update_voucher, ) @@ -70,21 +70,13 @@ class UpdateVoucher(object): elif self.start is not None and ( self.start > self.voucher_date or self.start > self.voucher.date ): - response = Response( - "Vouchers before {0} have been locked.".format( - self.start.strftime("%d-%b-%Y") - ) - ) + response = Response(f"Vouchers before {self.start.strftime('%d-%b-%Y')} have been locked.") response.status_int = 403 self.error = response elif self.finish is not None and ( self.finish < self.voucher_date or self.finish < self.voucher.date ): - response = Response( - "Vouchers after {0} have been locked.".format( - self.finish.strftime("%d-%b-%Y") - ) - ) + response = Response(f"Vouchers after {self.finish.strftime('%d-%b-%Y')} have been locked.") response.status_int = 403 self.error = response else: @@ -118,8 +110,8 @@ class UpdateVoucher(object): def salary_deduction(self): return self.update() - @router.get("/api/voucher/{id}", request_param="t=Service Charge") # "Service Charge" - def service_charge(self): + @router.get("/api/voucher/{id}", request_param="t=Incentive") # "Incentive" + def incentive(self): return self.update() def update(self): @@ -145,8 +137,8 @@ class UpdateVoucher(object): voucher = salary_deduction_update_voucher( self.voucher, self.json, self.user, self.request.dbsession ) - elif self.json["type"] in ["Service Charge"]: - voucher = service_charge_update_voucher( + elif self.json["type"] in ["Incentive"]: + voucher = incentive_update_voucher( self.voucher, self.json, self.user, self.request.dbsession ) transaction.commit() diff --git a/brewman/schemas/voucher.py b/brewman/schemas/voucher.py index 47ea001c..eaba7f98 100644 --- a/brewman/schemas/voucher.py +++ b/brewman/schemas/voucher.py @@ -1,7 +1,7 @@ import uuid from datetime import datetime, date from decimal import Decimal - +from typing import List from pydantic import BaseModel @@ -41,7 +41,7 @@ class SalaryDeduction(BaseModel): pf_er: int -class ServiceCharge(BaseModel): +class Incentive(BaseModel): id: uuid.UUID voucher_id: uuid.UUID journal_id: uuid.UUID @@ -70,17 +70,36 @@ class Batch(BaseModel): discount: Decimal -class Attendance(BaseModel): +class AttendanceType(BaseModel): + id_: int + name: str + value: Decimal + + +class AttendanceItem(BaseModel): id: uuid.UUID employee_id: uuid.UUID date: date - attendance_type: int + attendance_type: AttendanceType amount: Decimal creation_date: datetime user_id: uuid.UUID is_valid: bool +class AttendanceIn(BaseModel): + body: List[AttendanceItem] + + +class EmployeeAttendanceItem(BaseModel): + date: date + attendance_type: AttendanceType + + +class EmployeeAttendanceIn(BaseModel): + body: List[EmployeeAttendanceItem] + + class Fingerprint(BaseModel): id: uuid.UUID employee_id: uuid.UUID @@ -91,6 +110,6 @@ class DbImage(BaseModel): id: uuid.UUID resource_id: uuid.UUID resource_type: str - image: bytearray - thumbnail: bytearray + image: bytes + thumbnail: bytes creation_date: datetime diff --git a/brewman/scripts/initializedb.py b/brewman/scripts/initializedb.py index 280f8bba..7549b44c 100644 --- a/brewman/scripts/initializedb.py +++ b/brewman/scripts/initializedb.py @@ -38,7 +38,7 @@ from brewman.models.voucher import ( Product, SalaryDeduction, Voucher, - ServiceCharge, + Incentive, DbImage, ) @@ -137,7 +137,7 @@ def main(argv=sys.argv): Role("Stock Movement", uuid.UUID("20b707ee-2b59-41ad-be87-76d5fe1efca8")), Role("Purchases", uuid.UUID("cf7019c8-3fd3-45b0-9a42-601029ce5b71")), Role("Dashboard", uuid.UUID("53eecc09-bd06-4890-b6f5-6885dda762d4")), - Role("Service Charge", uuid.UUID("99b56390-96c2-4f3d-8b0f-5ae3c868594f")), + Role("Incentive", uuid.UUID("99b56390-96c2-4f3d-8b0f-5ae3c868594f")), Role("Maintenance", uuid.UUID("770532e4-21de-4712-8a6b-4ff9fd63a503")), ] @@ -229,7 +229,7 @@ def main(argv=sys.argv): ), Account( 2, - "Service Charges", + "Incentives", 11, False, True, diff --git a/overlord/src/app/app-routing.module.ts b/overlord/src/app/app-routing.module.ts index 574e02f6..228562a0 100644 --- a/overlord/src/app/app-routing.module.ts +++ b/overlord/src/app/app-routing.module.ts @@ -119,7 +119,7 @@ const appRoutes: Routes = [ loadChildren: () => import('./receipt/receipt.module').then(mod => mod.ReceiptModule) }, { - path: 'return', + path: 'purchase-return', loadChildren: () => import('./purchase-return/purchase-return.module').then(mod => mod.PurchaseReturnModule) }, { diff --git a/overlord/src/app/core/voucher.service.ts b/overlord/src/app/core/voucher.service.ts index 38446269..cf04eebf 100644 --- a/overlord/src/app/core/voucher.service.ts +++ b/overlord/src/app/core/voucher.service.ts @@ -40,7 +40,7 @@ export class VoucherService { } getIncentive(date: string): Observable { - const options = {params: new HttpParams().set('t', 'Service Charge').set('d', date)}; + const options = {params: new HttpParams().set('t', 'Incentive').set('d', date)}; return >this.http.get(url, options) .pipe( catchError(this.log.handleError(serviceName, 'list')) diff --git a/overlord/src/app/incentive/incentive-resolver.service.ts b/overlord/src/app/incentive/incentive-resolver.service.ts index b8491836..50c97191 100644 --- a/overlord/src/app/incentive/incentive-resolver.service.ts +++ b/overlord/src/app/incentive/incentive-resolver.service.ts @@ -16,7 +16,7 @@ export class IncentiveResolver implements Resolve { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { const id = route.paramMap.get('id'); if (id === null) { - return this.ser.getOfType('Service Charge'); + return this.ser.getOfType('Incentive'); } else { return this.ser.get(id); } diff --git a/overlord/src/app/incentive/incentive-routing.module.ts b/overlord/src/app/incentive/incentive-routing.module.ts index 75d21d40..cca745d2 100644 --- a/overlord/src/app/incentive/incentive-routing.module.ts +++ b/overlord/src/app/incentive/incentive-routing.module.ts @@ -11,7 +11,7 @@ const incentiveRoutes: Routes = [ component: IncentiveComponent, canActivate: [AuthGuard], data: { - permission: 'Service Charge' + permission: 'Incentive' }, resolve: { voucher: IncentiveResolver @@ -23,7 +23,7 @@ const incentiveRoutes: Routes = [ component: IncentiveComponent, canActivate: [AuthGuard], data: { - permission: 'Service Charge' + permission: 'Incentive' }, resolve: { voucher: IncentiveResolver diff --git a/overlord/src/app/incentive/incentive.component.html b/overlord/src/app/incentive/incentive.component.html index c5e192fe..dfeead7c 100644 --- a/overlord/src/app/incentive/incentive.component.html +++ b/overlord/src/app/incentive/incentive.component.html @@ -13,7 +13,7 @@
- Total Service Charge: {{voucher.incentive | number:'1.2-2'}} + Total Incentive: {{voucher.incentive | number:'1.2-2'}} Total Points: {{totalPoints() | number:'1.2-2'}} Point Value: {{pointValue() | number:'1.2-2'}}