diff --git a/brewman/main.py b/brewman/main.py index dc1740f3..20bc5a33 100644 --- a/brewman/main.py +++ b/brewman/main.py @@ -10,6 +10,8 @@ from .routers import ( attendance, batch, cost_centre, + credit_salary, + db_image, db_integrity, employee, employee_attendance, @@ -61,7 +63,7 @@ app = FastAPI() app.add_middleware(SessionMiddleware, secret_key="c982367648") -# app.include_router(brewman.routers, prefix="/api/db-image", tags=["db-image"]) +app.include_router(db_image.router, prefix="/db-image", tags=["db-image"]) app.include_router(login.router, tags=["login"]) app.include_router(account.router, prefix="/api/accounts", tags=["accounts"]) app.include_router(account_types.router, prefix="/api/account-types", tags=["accounts"]) @@ -134,6 +136,7 @@ app.include_router( employee_benefit.router, prefix="/api/employee-benefit", tags=["vouchers"] ) app.include_router(incentive.router, prefix="/api/incentive", tags=["vouchers"]) +app.include_router(credit_salary.router, prefix="/api/credit-salary", tags=["vouchers"]) app.include_router( lock_information.router, prefix="/api/lock-information", tags=["settings"] diff --git a/brewman/models/master.py b/brewman/models/master.py index d1fc1baa..0dbb3131 100644 --- a/brewman/models/master.py +++ b/brewman/models/master.py @@ -366,6 +366,10 @@ class AccountBase(Base): def salary(cls): return {"id": "5c2b54d0-c174-004d-a0d5-92cdaadcefa7", "name": "Staff Salary"} + @classmethod + def salary_id(cls): + return uuid.UUID("5c2b54d0-c174-004d-a0d5-92cdaadcefa7") + @classmethod def incentive(cls): return {"id": "b7eff754-e8ba-e047-ab06-9132c15c7640", "name": "Incentives"} diff --git a/brewman/models/voucher.py b/brewman/models/voucher.py index 49dac44f..9a73d8bc 100644 --- a/brewman/models/voucher.py +++ b/brewman/models/voucher.py @@ -14,7 +14,7 @@ from sqlalchemy import ( ) from sqlalchemy.dialects.postgresql import BYTEA from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy.orm import relationship, synonym, backref +from sqlalchemy.orm import relationship, synonym, backref, Session from brewman.models.guidtype import GUID from brewman.models.master import Product @@ -176,14 +176,14 @@ class Journal(Base): def __init__( self, - id=None, + id_=None, debit=None, amount=None, voucher_id=None, account_id=None, cost_centre_id=None, ): - self.id = id + self.id = id_ self.debit = debit self.amount = amount self.voucher_id = voucher_id @@ -357,14 +357,14 @@ class Batch(Base): ) @classmethod - def list(cls, name, include_nil, date, dbsession): - query = dbsession.query(Batch).join(Batch.product) + def list(cls, name, include_nil, date, db: Session): + query = db.query(Batch).join(Batch.product) if not include_nil: query = query.filter(cls.quantity_remaining > 0) if date is not None: query = query.filter(cls.name <= date) for item in name.split(): - query = query.filter(Product.name.ilike("%" + item + "%")) + query = query.filter(Product.name.ilike(f"%{item}%")) return query.order_by(Product.name).order_by(cls.name).all() @classmethod @@ -388,7 +388,7 @@ class Attendance(Base): def __init__( self, - id=None, + id_=None, employee_id=None, date=None, attendance_type=None, @@ -397,20 +397,18 @@ class Attendance(Base): user_id=None, is_valid=None, ): - self.id = id + self.id = id_ self.employee_id = employee_id self.date = date self.attendance_type = attendance_type self.amount = amount if amount is not None else 0 - self.creation_date = ( - datetime.utcnow() if creation_date is None else creation_date - ) + self.creation_date = creation_date or datetime.utcnow() self.user_id = user_id self.is_valid = is_valid if is_valid is not None else True - def create(self, dbsession): + def create(self, db: Session): old = ( - dbsession.query(Attendance) + db.query(Attendance) .filter(Attendance.date == self.date) .filter(Attendance.employee_id == self.employee_id) .filter(Attendance.is_valid == True) @@ -453,13 +451,11 @@ class DbImage(Base): image=None, thumbnail=None, creation_date=None, - id=None, + id_=None, ): self.resource_id = resource_id self.resource_type = resource_type self.image = image self.thumbnail = thumbnail - self.creation_date = ( - datetime.utcnow() if creation_date is None else creation_date - ) - self.id = id + self.creation_date = creation_date or datetime.utcnow() + self.id = id_ diff --git a/brewman/routers/__init__.py b/brewman/routers/__init__.py index ed365775..0fd8e94b 100644 --- a/brewman/routers/__init__.py +++ b/brewman/routers/__init__.py @@ -5,6 +5,8 @@ from decimal import Decimal from io import BytesIO from typing import Optional +from sqlalchemy.orm import Session + from brewman.models.master import DbSetting from brewman.models.voucher import DbImage @@ -13,26 +15,10 @@ from fastapi import APIRouter router = APIRouter() -@router.get("/{id}/{type}") -def db_image(request): - item = ( - request.dbsession.query(DbImage) - .filter(DbImage.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if request.matchdict["type"] == "thumbnail": - item = BytesIO(item.thumbnail) - else: - item = BytesIO(item.image) - response = Response(content_type="image/jpeg") - response.app_iter = item - return response - - -def get_lock_info(dbsession) -> (Optional[date], Optional[date]): +def get_lock_info(db: Session) -> (Optional[date], Optional[date]): start: Optional[date] finish: Optional[date] - data = dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first() + data = db.query(DbSetting).filter(DbSetting.name == "Lock Info").first() if data is None: return None, None diff --git a/brewman/routers/credit_salary.py b/brewman/routers/credit_salary.py new file mode 100644 index 00000000..3b52ec55 --- /dev/null +++ b/brewman/routers/credit_salary.py @@ -0,0 +1,101 @@ +from calendar import monthrange +from datetime import datetime, date + +from fastapi import APIRouter, Depends, Security, Body, HTTPException, status +from sqlalchemy import or_ +from sqlalchemy.orm import Session + +from ..core.session import get_first_day, get_last_day +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 Account, Employee, AttendanceType +from ..models.voucher import Voucher, Journal, VoucherType, Attendance + +router = APIRouter() + + +# Dependency +def get_db() -> Session: + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("") +def credit_salary( + month: str = Body(..., embed=True), + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["attendance"]), +): + month = datetime.strptime(month, "%d-%b-%Y").date() + + start_date = get_first_day(month) + finish_date = get_last_day(month) + voucher = Voucher( + date=finish_date, + narration="Auto Generated Salary Entry", + user_id=user.id_, + type_=VoucherType.by_name("Journal"), + posted=True, + poster_id=user.id_, + ) + db.add(voucher) + for item in salary_journals(start_date, finish_date, db): + voucher.journals.append(item) + db.add(item) + db.commit() + return {"message": "Salary Entry created"} + + +def salary_journals(start_date: date, finish_date: date, db: Session): + days = monthrange(start_date.year, start_date.month)[1] + amount = 0 + journals = [] + employees = ( + db.query(Employee) + .filter(Employee.joining_date <= finish_date) + .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) + .order_by(Employee.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) + for employee in employees: + att = ( + db.query(Attendance) + .filter(Attendance.employee_id == employee.id) + .filter(Attendance.date >= start_date) + .filter(Attendance.date <= finish_date) + .filter(Attendance.is_valid == True) + .all() + ) + att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att)) + att = round(att * employee.salary / days) + if att != 0: + amount += att + journals.append( + Journal( + amount=att, + debit=-1, + account_id=employee.id, + cost_centre_id=employee.cost_centre_id, + ) + ) + salary = db.query(Account).filter(Account.id == Account.salary_id()).first() + if amount == 0: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="No salaries to credit", + ) + journals.append( + Journal( + amount=amount, + debit=1, + account_id=salary.id, + cost_centre_id=salary.cost_centre_id, + ) + ) + return journals diff --git a/brewman/routers/db_image.py b/brewman/routers/db_image.py new file mode 100644 index 00000000..650b6acb --- /dev/null +++ b/brewman/routers/db_image.py @@ -0,0 +1,36 @@ +import uuid +from io import BytesIO + +from fastapi import APIRouter, Depends, Security +from fastapi.responses import StreamingResponse +from sqlalchemy.orm import Session + +from ..core.security import get_user +from ..models.voucher import DbImage +from ..db.session import SessionLocal +from ..schemas.auth import UserToken + +router = APIRouter() + + +# Dependency +def get_db() -> Session: + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.get("/{id_}/{type_}") +def db_image( + id_: uuid.UUID, + type_: str, + db: Session = Depends(get_db) +): + item = db.query(DbImage).filter(DbImage.id == id_).first() + if type_ == "thumbnail": + item = BytesIO(item.thumbnail) + else: + item = BytesIO(item.image) + return StreamingResponse(item, media_type="image/jpeg") diff --git a/brewman/routers/journal.py b/brewman/routers/journal.py index 77c4154f..766a0423 100644 --- a/brewman/routers/journal.py +++ b/brewman/routers/journal.py @@ -26,7 +26,7 @@ from ..models import AccountBase from ..schemas.auth import UserToken from ..core.security import get_current_active_user as get_user from ..db.session import SessionLocal -from ..models.voucher import Voucher, VoucherType, Journal +from ..models.voucher import Voucher, VoucherType, Journal, DbImage import brewman.schemas.voucher as output import brewman.schemas.input as schema_in @@ -47,15 +47,14 @@ def save_route( request: Request, data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form), db: Session = Depends(get_db), - i: List[UploadFile] = File(None), - t: List[UploadFile] = File(None), + i: List[bytes] = File(None), + t: List[bytes] = File(None), user: UserToken = Security(get_user, scopes=["journal"]), ): try: - i = i or [] - t = t or [] item: Voucher = save(data, user, db) - save_files(i + t, db) + db.flush() + save_files(item.id, i, t, db) db.commit() set_date(data.date_.strftime("%d-%b-%Y"), request.session) info = voucher_info(item, db) @@ -66,11 +65,7 @@ def save_route( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), ) except Exception: - db.rollback() - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=traceback.format_exc(), - ) + raise def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher: @@ -88,7 +83,6 @@ def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher: AccountBase.id == item.account.id_ ).first() journal = Journal( - id=item.id_, amount=item.amount, debit=item.debit, account_id=account.id, @@ -99,10 +93,9 @@ def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher: return voucher -def save_files(files: List[UploadFile], db: Session): - # for key, value in files.items(): - # db.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) - pass +def save_files(voucher_id: uuid.UUID, i: List[bytes], t: List[bytes], db: Session): + for index, value in enumerate(i): + db.add(DbImage(voucher_id, "voucher", i[index], t[index])) @router.put("/{id_}", response_model=output.Voucher) @@ -111,15 +104,13 @@ def update_route( request: Request, data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form), db: Session = Depends(get_db), - i: List[UploadFile] = File(None), - t: List[UploadFile] = File(None), + i: List[bytes] = File(None), + t: List[bytes] = File(None), user: UserToken = Security(get_user, scopes=["journal"]), ): try: - i = i or [] - t = t or [] item: Voucher = update(id_, data, user, db) - update_files(data, i + t, db) + update_files(item.id, data.files, i, t, db) db.commit() set_date(data.date_.strftime("%d-%b-%Y"), request.session) return voucher_info(item, db) @@ -174,7 +165,6 @@ def update( db.query(AccountBase).filter(AccountBase.id == new_item.account.id_).first() ) journal = Journal( - id=None, amount=new_item.amount, debit=new_item.debit, account_id=account.id, @@ -185,16 +175,13 @@ def update( return voucher -def update_files(data: schema_in.VoucherIn, files: List[UploadFile], db: Session): - pass - # old_files = [ - # uuid.UUID(f["id"]) for f in json["files"] if "id" in f and f["id"] is not None - # ] - # images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all() - # for image in [i for i in images if i.id not in old_files]: - # db.delete(image) - # for key, value in files.items(): - # db.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) +def update_files(voucher_id: uuid.UUID, data: List[output.ImageUpload], i: List[bytes], t: List[bytes], db: Session): + old = [f.id_ for f in data if f.id_] + images = db.query(DbImage).filter(DbImage.resource_id == voucher_id).all() + for image in [i for i in images if i.id not in old]: + db.delete(image) + for index, value in enumerate(i): + db.add(DbImage(voucher_id, "voucher", i[index], t[index])) @router.get("/{id_}", response_model=output.Voucher) diff --git a/brewman/routers/login.py b/brewman/routers/login.py index 94d7d3a6..364f550b 100644 --- a/brewman/routers/login.py +++ b/brewman/routers/login.py @@ -7,9 +7,10 @@ from ..core.security import ( Token, authenticate_user, ACCESS_TOKEN_EXPIRE_MINUTES, - create_access_token, + create_access_token, get_user, ) from ..db.session import SessionLocal +from ..schemas.auth import UserToken router = APIRouter() @@ -54,3 +55,21 @@ async def login_for_access_token( expires_delta=access_token_expires, ) return {"access_token": access_token, "token_type": "bearer"} + + +@router.post("/refresh", response_model=Token) +async def refresh_token( + db: Session = Depends(get_db), + user: UserToken = Depends(get_user) +): + access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={ + "sub": user.name, + "scopes": user.permissions, + "userId": str(user.id_), + "lockedOut": user.locked_out, + }, + expires_delta=access_token_expires, + ) + return {"access_token": access_token, "token_type": "bearer"} diff --git a/brewman/routers/voucher/__init__.py b/brewman/routers/voucher/__init__.py index 6dd46ede..63fd335b 100644 --- a/brewman/routers/voucher/__init__.py +++ b/brewman/routers/voucher/__init__.py @@ -283,7 +283,7 @@ def voucher_info(voucher, db): ) images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all() for image in images: - json_voucher["files"].append({"id": image.id, "resized": "", "thumbnail": ""}) + json_voucher["files"].append({"id": image.id, "resized": f"/db-image/{image.id}/resized", "thumbnail": f"/db-image/{image.id}/thumbnail"}) return json_voucher @@ -301,6 +301,7 @@ def blank_voucher(info, db): "narration": "", "journals": [], "inventories": [], + "employeeBenefits": [], } if type_ == "Journal": pass diff --git a/brewman/routers/voucher/credit_salary.py b/brewman/routers/voucher/credit_salary.py deleted file mode 100644 index 15a3a24c..00000000 --- a/brewman/routers/voucher/credit_salary.py +++ /dev/null @@ -1,87 +0,0 @@ -import calendar -import datetime -import uuid - -from sqlalchemy import or_ -from ....models.auth import User -from ....models.master import Employee, AttendanceType, Account -from ....models.voucher import Voucher, VoucherType, Attendance, Journal -from ..session import get_first_day, get_last_day - - -@router.post("/api/credit-salary") # "Attendance" -def credit_salary(request): - user = ( - request.dbsession.query(User) - .filter(User.id == uuid.UUID(request.authenticated_userid)) - .one() - ) - month = datetime.datetime.strptime(request.json_body["month"], "%d-%b-%Y") - - start_date = get_first_day(month) - finish_date = get_last_day(month) - voucher = Voucher( - date=finish_date, - narration="Auto Generated Salary Entry", - user_id=user.id, - type=VoucherType.by_name("Journal"), - posted=True, - poster_id=user.id, - ) - request.dbsession.add(voucher) - for item in salary_journals(start_date, finish_date, request.dbsession): - voucher.journals.append(item) - request.dbsession.add(item) - transaction.commit() - return {"message": "Salary Entry created"} - - -def salary_journals(start_date, finish_date, dbsession): - days = calendar.monthrange(start_date.year, start_date.month)[1] - finish_date = finish_date + datetime.timedelta(1) - amount = 0 - journals = [] - employees = ( - dbsession.query(Employee) - .filter(Employee.joining_date <= finish_date) - .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) - .order_by(Employee.cost_centre_id) - .order_by(Employee.designation) - .order_by(Employee.name) - .all() - ) - for employee in employees: - att = ( - dbsession.query(Attendance) - .filter(Attendance.employee_id == employee.id) - .filter(Attendance.date >= start_date) - .filter(Attendance.date < finish_date) - .filter(Attendance.is_valid == True) - .all() - ) - att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att)) - att = round(att * employee.salary / days) - if att != 0: - amount += att - journals.append( - Journal( - amount=att, - debit=-1, - account_id=employee.id, - cost_centre_id=employee.cost_centre_id, - ) - ) - salary = ( - dbsession.query(Account) - .filter(Account.id == uuid.UUID(Account.salary()["id"])) - .first() - ) - journals.append( - Journal( - amount=amount, - debit=1, - account_id=salary.id, - cost_centre_id=salary.cost_centre_id, - ) - ) - return journals diff --git a/brewman/routers/voucher/emptyvoucher.py b/brewman/routers/voucher/emptyvoucher.py deleted file mode 100644 index f41fde38..00000000 --- a/brewman/routers/voucher/emptyvoucher.py +++ /dev/null @@ -1,27 +0,0 @@ -from ....core.session import get_date -from brewman.routers.services.voucher import blank_voucher - - -class EmptyVoucher(object): - def __init__(self, request): - self.request = request - - @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: - return blank_voucher( - {"type": voucher_type, "date": date}, self.request.dbsession - ) - else: - return self.get_blank() - - def get_blank(self, additional_info=None): - voucher_type = self.request.GET.get("t", None) - if additional_info is None: - additional_info = {} - additional_info["date"] = get_date(self.request) - additional_info["type"] = voucher_type - - return blank_voucher(additional_info, self.request.dbsession) diff --git a/brewman/schemas/voucher.py b/brewman/schemas/voucher.py index 8a150ec9..173a2185 100644 --- a/brewman/schemas/voucher.py +++ b/brewman/schemas/voucher.py @@ -16,6 +16,15 @@ from brewman.schemas.master import ( ) +class ImageUpload(BaseModel): + id_: Optional[uuid.UUID] + resized: Optional[str] + thumbnail: Optional[str] + + class Config: + alias_generator = to_camel + + class UserLink(BaseModel): id_: uuid.UUID name: str @@ -94,6 +103,7 @@ class VoucherIn(BaseModel): narration: str is_starred: bool type_: str + files: List[ImageUpload] @classmethod def load_form(cls, data: str = Form(...)): @@ -118,7 +128,7 @@ class Voucher(VoucherIn): incentives: Optional[List[Incentive]] incentive: Optional[Decimal] employee_benefits: List[EmployeeBenefit] - files: List[Any] + files: List[ImageUpload] class Config: anystr_strip_whitespace = True diff --git a/overlord/src/app/account/account-detail/account-detail.component.ts b/overlord/src/app/account/account-detail/account-detail.component.ts index 52e16e35..80f5f324 100644 --- a/overlord/src/app/account/account-detail/account-detail.component.ts +++ b/overlord/src/app/account/account-detail/account-detail.component.ts @@ -78,7 +78,7 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/accounts'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -91,7 +91,7 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/accounts'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/attendance/attendance.component.ts b/overlord/src/app/attendance/attendance.component.ts index 3f7439e9..92024542 100644 --- a/overlord/src/app/attendance/attendance.component.ts +++ b/overlord/src/app/attendance/attendance.component.ts @@ -82,7 +82,7 @@ export class AttendanceComponent implements OnInit { this.toaster.show('Success', ''); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/client/client-detail/client-detail.component.ts b/overlord/src/app/client/client-detail/client-detail.component.ts index 87df2c0b..5c13e9d5 100644 --- a/overlord/src/app/client/client-detail/client-detail.component.ts +++ b/overlord/src/app/client/client-detail/client-detail.component.ts @@ -69,7 +69,7 @@ export class ClientDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/clients'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -82,7 +82,7 @@ export class ClientDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/clients'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/core/error-logger.service.ts b/overlord/src/app/core/error-logger.service.ts index 1bba940c..d246cbd6 100644 --- a/overlord/src/app/core/error-logger.service.ts +++ b/overlord/src/app/core/error-logger.service.ts @@ -22,7 +22,7 @@ export class ErrorLoggerService { console.error(error); // log to console instead // TODO: better job of transforming error for user consumption - this.log(serviceName, `${operation} failed: ${error.message}`); + this.log(serviceName, `${operation} failed: ${error}`); // // Let the app keep running by returning an empty result. // return of(result as T); diff --git a/overlord/src/app/cost-centre/cost-centre-detail/cost-centre-detail.component.ts b/overlord/src/app/cost-centre/cost-centre-detail/cost-centre-detail.component.ts index 8ad96512..137fdc71 100644 --- a/overlord/src/app/cost-centre/cost-centre-detail/cost-centre-detail.component.ts +++ b/overlord/src/app/cost-centre/cost-centre-detail/cost-centre-detail.component.ts @@ -60,7 +60,7 @@ export class CostCentreDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/cost-centres'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/employee-attendance/employee-attendance.component.ts b/overlord/src/app/employee-attendance/employee-attendance.component.ts index c8d72ead..8857c029 100644 --- a/overlord/src/app/employee-attendance/employee-attendance.component.ts +++ b/overlord/src/app/employee-attendance/employee-attendance.component.ts @@ -129,7 +129,7 @@ export class EmployeeAttendanceComponent implements OnInit, AfterViewInit { this.toaster.show('Success', ''); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/employee-benefits/employee-benefits.component.ts b/overlord/src/app/employee-benefits/employee-benefits.component.ts index 8592d3ee..11fbcac9 100644 --- a/overlord/src/app/employee-benefits/employee-benefits.component.ts +++ b/overlord/src/app/employee-benefits/employee-benefits.component.ts @@ -185,7 +185,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit { this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -198,7 +198,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit { this.router.navigate(['/employee-benefits', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -217,7 +217,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit { this.router.navigate(['/employee-benefits'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/employee-functions/employee-functions.component.ts b/overlord/src/app/employee-functions/employee-functions.component.ts index 215ab2a8..51bede8b 100644 --- a/overlord/src/app/employee-functions/employee-functions.component.ts +++ b/overlord/src/app/employee-functions/employee-functions.component.ts @@ -79,7 +79,8 @@ export class EmployeeFunctionsComponent implements OnInit { this.toaster.show('Success', 'Salaries Credited'); }, (error) => { - this.toaster.show('Danger', error.error); + console.log('Error:', error); + this.toaster.show('Danger', error); } ); } @@ -109,7 +110,7 @@ export class EmployeeFunctionsComponent implements OnInit { this.toaster.show('Success', 'Fingerprints uploaded'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/employee/employee-detail/employee-detail.component.ts b/overlord/src/app/employee/employee-detail/employee-detail.component.ts index b75c5641..b147708a 100644 --- a/overlord/src/app/employee/employee-detail/employee-detail.component.ts +++ b/overlord/src/app/employee/employee-detail/employee-detail.component.ts @@ -90,7 +90,7 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/employees'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -103,7 +103,7 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/employees'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/incentive/incentive.component.ts b/overlord/src/app/incentive/incentive.component.ts index 6d9726de..0317c1e8 100644 --- a/overlord/src/app/incentive/incentive.component.ts +++ b/overlord/src/app/incentive/incentive.component.ts @@ -140,7 +140,7 @@ export class IncentiveComponent implements OnInit { this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -153,7 +153,7 @@ export class IncentiveComponent implements OnInit { this.router.navigate(['/incentive', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -176,7 +176,7 @@ export class IncentiveComponent implements OnInit { this.router.navigate(['/incentive'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/issue/issue.component.ts b/overlord/src/app/issue/issue.component.ts index e3b2c9ff..79ec2ac5 100644 --- a/overlord/src/app/issue/issue.component.ts +++ b/overlord/src/app/issue/issue.component.ts @@ -223,7 +223,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/issue', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -249,7 +249,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/issue'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/journal/journal.component.ts b/overlord/src/app/journal/journal.component.ts index 9cbc8e17..9750ba81 100644 --- a/overlord/src/app/journal/journal.component.ts +++ b/overlord/src/app/journal/journal.component.ts @@ -218,7 +218,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy { this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -232,7 +232,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/journal', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -252,7 +252,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/journal'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/payment/payment.component.ts b/overlord/src/app/payment/payment.component.ts index d0491b14..6273fd8f 100644 --- a/overlord/src/app/payment/payment.component.ts +++ b/overlord/src/app/payment/payment.component.ts @@ -222,7 +222,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy { this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -236,7 +236,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/payment', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -257,7 +257,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/payment'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/product-group/product-group-detail/product-group-detail.component.ts b/overlord/src/app/product-group/product-group-detail/product-group-detail.component.ts index a1b3c284..4a0315ad 100644 --- a/overlord/src/app/product-group/product-group-detail/product-group-detail.component.ts +++ b/overlord/src/app/product-group/product-group-detail/product-group-detail.component.ts @@ -60,7 +60,7 @@ export class ProductGroupDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/product-groups'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/product/product-detail/product-detail.component.ts b/overlord/src/app/product/product-detail/product-detail.component.ts index b538c1bf..7287dd42 100644 --- a/overlord/src/app/product/product-detail/product-detail.component.ts +++ b/overlord/src/app/product/product-detail/product-detail.component.ts @@ -87,7 +87,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/products'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -100,7 +100,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/products'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/purchase-return/purchase-return.component.ts b/overlord/src/app/purchase-return/purchase-return.component.ts index 0c7c5c8d..b9dedc92 100644 --- a/overlord/src/app/purchase-return/purchase-return.component.ts +++ b/overlord/src/app/purchase-return/purchase-return.component.ts @@ -209,7 +209,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -223,7 +223,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy this.router.navigate(['/purchase-return', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -244,7 +244,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy this.router.navigate(['/purchase-return'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/purchase/purchase.component.ts b/overlord/src/app/purchase/purchase.component.ts index 910c351e..018bc111 100644 --- a/overlord/src/app/purchase/purchase.component.ts +++ b/overlord/src/app/purchase/purchase.component.ts @@ -222,7 +222,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy { this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -236,7 +236,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/purchase', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -257,7 +257,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/purchase'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/receipt/receipt.component.ts b/overlord/src/app/receipt/receipt.component.ts index 25374596..532ed675 100644 --- a/overlord/src/app/receipt/receipt.component.ts +++ b/overlord/src/app/receipt/receipt.component.ts @@ -221,7 +221,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy { this.toaster.show('Success', 'Voucher Posted'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -235,7 +235,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/receipt', result.id]); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -256,7 +256,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy { this.router.navigate(['/receipt'], {replaceUrl: true}); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/role/role-detail/role-detail.component.ts b/overlord/src/app/role/role-detail/role-detail.component.ts index 624a88e1..52f95734 100644 --- a/overlord/src/app/role/role-detail/role-detail.component.ts +++ b/overlord/src/app/role/role-detail/role-detail.component.ts @@ -65,7 +65,7 @@ export class RoleDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/roles'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -78,7 +78,7 @@ export class RoleDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/roles'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/settings/settings.component.ts b/overlord/src/app/settings/settings.component.ts index f4ad9734..904f575f 100644 --- a/overlord/src/app/settings/settings.component.ts +++ b/overlord/src/app/settings/settings.component.ts @@ -132,7 +132,7 @@ export class SettingsComponent implements OnInit { this.toaster.show('Success', 'Lock information Updated'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -162,7 +162,7 @@ export class SettingsComponent implements OnInit { this.toaster.show('Success', 'Data has been rebased!'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -213,7 +213,7 @@ export class SettingsComponent implements OnInit { this.toaster.show('Success', 'Stock has been reset!'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -227,7 +227,7 @@ export class SettingsComponent implements OnInit { this.toaster.show('Success', 'Database checked, it is fine!'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/overlord/src/app/user/user-detail/user-detail.component.ts b/overlord/src/app/user/user-detail/user-detail.component.ts index ddb53653..5e064896 100644 --- a/overlord/src/app/user/user-detail/user-detail.component.ts +++ b/overlord/src/app/user/user-detail/user-detail.component.ts @@ -76,7 +76,7 @@ export class UserDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/users'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } @@ -89,7 +89,7 @@ export class UserDetailComponent implements OnInit, AfterViewInit { this.router.navigateByUrl('/users'); }, (error) => { - this.toaster.show('Danger', error.error); + this.toaster.show('Danger', error); } ); } diff --git a/requirements.txt b/requirements.txt index 6efc5749..9b9bdcad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,8 @@ fastapi environs python-jose[cryptography] passlib[bcrypt] -psycopg2 +psycopg2-binary +sqlalchemy python-multipart pyjwt alembic