From 8ae67863eb96fb713f6c0cf969a2333550fbee79 Mon Sep 17 00:00:00 2001 From: tanshu <git@tanshu.com> Date: Sat, 30 May 2020 12:06:37 +0530 Subject: [PATCH] Voucher Post and Delete working!! Also figured out why a lot of exceptions are generating 500 errors. Those errors are again caught by the general exception catcher in the end and re thrown. Need to fix this. --- brewman/main.py | 2 + brewman/routers/db_image.py | 4 + brewman/routers/journal.py | 7 + brewman/routers/purchase_return.py | 2 - .../{voucher/__init__.py => voucher.py} | 181 ++++++++---------- overlord/src/app/core/voucher.service.ts | 19 +- 6 files changed, 104 insertions(+), 111 deletions(-) rename brewman/routers/{voucher/__init__.py => voucher.py} (78%) diff --git a/brewman/main.py b/brewman/main.py index 091b02e5..fdfce19a 100644 --- a/brewman/main.py +++ b/brewman/main.py @@ -31,6 +31,7 @@ from .routers import ( journal, purchase, purchase_return, + voucher, ) from .routers.auth import client, user, role from .routers.reports import ( @@ -135,6 +136,7 @@ app.include_router( ) 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(voucher.router, prefix="/api", tags=["vouchers"]) app.include_router( lock_information.router, prefix="/api/lock-information", tags=["settings"] diff --git a/brewman/routers/db_image.py b/brewman/routers/db_image.py index 463ca174..7fce33e0 100644 --- a/brewman/routers/db_image.py +++ b/brewman/routers/db_image.py @@ -39,11 +39,15 @@ def db_image( def save_files(voucher_id: uuid.UUID, i: List[bytes], t: List[bytes], db: Session): + i = i or [] + t = t or [] for index, value in enumerate(i): db.add(DbImage(voucher_id, "voucher", i[index], t[index])) def update_files(voucher_id: uuid.UUID, data: List[output.ImageUpload], i: List[bytes], t: List[bytes], db: Session): + i = i or [] + t = t or [] 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]: diff --git a/brewman/routers/journal.py b/brewman/routers/journal.py index 2be2e691..24cada14 100644 --- a/brewman/routers/journal.py +++ b/brewman/routers/journal.py @@ -178,7 +178,14 @@ def get_id( ): try: item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() + if item is None: + raise ValueError("Voucher not found") return voucher_info(item, db) + except ValueError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail=str(e), + ) except SQLAlchemyError as e: db.rollback() raise HTTPException( diff --git a/brewman/routers/purchase_return.py b/brewman/routers/purchase_return.py index 067b5582..ba839ecd 100644 --- a/brewman/routers/purchase_return.py +++ b/brewman/routers/purchase_return.py @@ -53,8 +53,6 @@ def save_route( user: UserToken = Security(get_user, scopes=["purchase-return"]), ): try: - i = i or [] - t = t or [] item: Voucher = save(data, user, db) save_inventories(item, data.inventories, db) save_journals(item, data.vendor, db) diff --git a/brewman/routers/voucher/__init__.py b/brewman/routers/voucher.py similarity index 78% rename from brewman/routers/voucher/__init__.py rename to brewman/routers/voucher.py index 63fd335b..dd9f12fd 100644 --- a/brewman/routers/voucher/__init__.py +++ b/brewman/routers/voucher.py @@ -1,11 +1,20 @@ +import traceback +import uuid from typing import Optional from datetime import datetime, date -import uuid from decimal import Decimal + +from fastapi import ( + APIRouter, + HTTPException, + status, + Depends, + Security, +) from sqlalchemy import func, or_ +from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session -from brewman.models.auth import User from brewman.models.master import ( AccountBase, CostCentre, @@ -14,7 +23,6 @@ from brewman.models.master import ( Account, ) from brewman.models.voucher import ( - Voucher, VoucherType, Inventory, DbImage, @@ -22,97 +30,81 @@ from brewman.models.voucher import ( Journal, ) from brewman.routers import get_lock_info -from ...core.session import get_first_day - -from fastapi import APIRouter, Depends, Security, Request, HTTPException, status - -from ...schemas.auth import UserToken +from brewman.core.session import get_first_day +from ..schemas import to_camel +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 +import brewman.schemas.voucher as output router = APIRouter() -@router.post("/api/voucher/{id}") # , request_param="p" "Post Vouchers" -def voucher_post(request): - user = ( - request.dbsession.query(User) - .filter(User.id == uuid.UUID(request.authenticated_userid)) - .one() - ) - voucher = ( - request.dbsession.query(Voucher) - .filter(Voucher.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - start, finish = get_lock_info(request.dbsession) - if start is not None and start > voucher.date: - raise ValidationError( - f"Vouchers before {start.strftime('%d-%b-%Y')} have been locked." - ) - elif finish is not None and finish < voucher.date: - raise ValidationError( - f"Vouchers after {finish.strftime('%d-%b-%Y')} have been locked." - ) - voucher.posted = True - voucher.poster_id = user.id - transaction.commit() - new_voucher = ( - request.dbsession.query(Voucher).filter(Voucher.id == voucher.id).first() - ) - return voucher_info(new_voucher, request) +# Dependency +def get_db() -> Session: + try: + db = SessionLocal() + yield db + finally: + db.close() -def check_delete_permissions(request, voucher): - user = ( - request.dbsession.query(User) - .filter(User.id == uuid.UUID(request.authenticated_userid)) - .one() - ) - - if voucher.posted and not request.has_permission("Edit Posted Vouchers"): - response = Response("You are not allowed to edit posted vouchers") - response.status_int = 403 - return response - elif voucher.user_id != user.id and not request.has_permission( - "Edit Other User's Vouchers" - ): - response = Response("You are not allowed to edit other user's vouchers") - response.status_int = 403 - return response - elif not request.has_permission(VoucherType.by_id(voucher.type).name): - response = Response( - f"You are not allowed ({VoucherType.by_id(voucher.type).name}) vouchers" +@router.post("/post-voucher/{id_}", response_model=output.Voucher) +def post_voucher( + id_: uuid.UUID, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["post-vouchers"]), +): + try: + voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() + check_voucher_lock_info(voucher.date, voucher.date, db) + voucher.posted = True + voucher.poster_id = user.id_ + db.commit() + return voucher_info(voucher, db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), ) - response.status_int = 403 - return response - start, finish = get_lock_info(request.dbsession) - if start is not None and start > voucher.date: - response = Response( - f"Vouchers before {start.strftime('%d-%b-%Y')} have been locked." + except Exception: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=traceback.format_exc(), ) - response.status_int = 403 - return response - elif finish is not None and finish < voucher.date: - response = Response( - f"Vouchers after {finish.strftime('%d-%b-%Y')} have been locked." - ) - response.status_int = 403 - return response -@router.delete("/api/voucher/{id}") -def delete(request): - voucher = ( - request.dbsession.query(Voucher) - .filter(Voucher.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - images = ( - request.dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all() - ) - permission = check_delete_permissions(request, voucher) - if permission is not None: - return permission - json_voucher = voucher_info(voucher, request) +def check_delete_permissions(voucher: Voucher, user: UserToken): + voucher_type = VoucherType.by_id(voucher.type).name.replace(" ", "-").lower() + if voucher_type in ["payment", "purchase"]: + voucher_type = "journal" + if voucher.posted and "edit-posted-vouchers" not in user.permissions: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to edit posted vouchers", + ) + elif voucher.user_id != user.id_ and "edit-other-user's-vouchers" not in user.permissions: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to edit other user's vouchers", + ) + elif voucher_type not in user.permissions: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail=f"You are not allowed ({VoucherType.by_id(voucher.type).name}) vouchers", + ) + + +@router.delete("/delete/{id_}") +def delete_voucher( + id_: uuid.UUID, + db: Session = Depends(get_db), + user: UserToken = Security(get_user), +): + voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first() + images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all() + check_delete_permissions(voucher, user) + check_voucher_lock_info(None, voucher.date, db) + json_voucher = voucher_info(voucher, db) batches_to_delete = [] if voucher.type == VoucherType.by_name("Issue").id: for item in voucher.journals: @@ -142,7 +134,7 @@ def delete(request): elif voucher.type == VoucherType.by_name("Purchase").id: for item in voucher.inventories: uses = ( - request.dbsession.query(func.count(Inventory.id)) + db.query(func.count(Inventory.id)) .filter(Inventory.batch_id == item.batch.id) .filter(Inventory.id != item.id) .scalar() @@ -156,21 +148,12 @@ def delete(request): for item in voucher.inventories: item.batch.quantity_remaining += item.quantity for b in batches_to_delete: - request.dbsession.delete(b) - request.dbsession.delete(voucher) + db.delete(b) + db.delete(voucher) for image in images: - request.dbsession.delete(image) - transaction.commit() - return blank_voucher(info=json_voucher, dbsession=request.dbsession) - - -@router.get("/api/voucher/{id}") -def get_old(request): - id_ = request.matchdict.get("id", None) - voucher = ( - request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(id_)).first() - ) - return voucher_info(voucher, request) + db.delete(image) + db.commit() + return blank_voucher(info=json_voucher, db=db) def voucher_info(voucher, db): diff --git a/overlord/src/app/core/voucher.service.ts b/overlord/src/app/core/voucher.service.ts index 2f92351b..a606fdc3 100644 --- a/overlord/src/app/core/voucher.service.ts +++ b/overlord/src/app/core/voucher.service.ts @@ -24,7 +24,7 @@ export class VoucherService { const endpoint = type.replace(/ /g, '-').toLowerCase(); return <Observable<Voucher>>this.http.get<Voucher>(`${url}/${endpoint}/${id}`) .pipe( - catchError(this.log.handleError(serviceName, 'get')) + catchError(this.log.handleError(serviceName, 'Get Voucher')) ); } @@ -36,7 +36,7 @@ export class VoucherService { } return <Observable<Voucher>>this.http.get<Voucher>(`${url}/${endpoint}`, options) .pipe( - catchError(this.log.handleError(serviceName, 'getOfType')) + catchError(this.log.handleError(serviceName, 'Get Voucher of Type')) ); } @@ -44,22 +44,21 @@ export class VoucherService { const options = {params: new HttpParams().set('d', date)}; return <Observable<Voucher>>this.http.get<Voucher>(`${url}/incentive`, options) .pipe( - catchError(this.log.handleError(serviceName, 'list')) + catchError(this.log.handleError(serviceName, 'Get Incentive')) ); } post(id: string): Observable<Voucher> { - const options = {params: new HttpParams().set('p', '')}; - return <Observable<Voucher>>this.http.post<Voucher>(`${url}/${id}`, {}, options) + return <Observable<Voucher>>this.http.post<Voucher>(`${url}/post-voucher/${id}`, {}) .pipe( - catchError(this.log.handleError(serviceName, 'list')) + catchError(this.log.handleError(serviceName, 'Post Voucher')) ); } delete(id: string): Observable<Voucher> { - return <Observable<Voucher>>this.http.delete<Voucher>(`${url}/${id}`, httpOptions) + return <Observable<Voucher>>this.http.delete<Voucher>(`${url}/delete/${id}`, httpOptions) .pipe( - catchError(this.log.handleError(serviceName, 'delete')) + catchError(this.log.handleError(serviceName, 'Delete Voucher')) ); } @@ -82,7 +81,7 @@ export class VoucherService { fd.append('data', JSON.stringify(voucher)); return <Observable<Voucher>>this.http.post<Voucher>(`${url}/${endpoint}`, fd) .pipe( - catchError(this.log.handleError(serviceName, 'save')) + catchError(this.log.handleError(serviceName, 'Save Voucher')) ); } @@ -96,7 +95,7 @@ export class VoucherService { fd.append('data', JSON.stringify(voucher)); return <Observable<Voucher>>this.http.put<Voucher>(`${url}/${endpoint}/${voucher.id}`, fd) .pipe( - catchError(this.log.handleError(serviceName, 'update')) + catchError(this.log.handleError(serviceName, 'Update Voucher')) ); }