From 6765f0a93e3cc8c7baa8906a4c5f8d162885cd64 Mon Sep 17 00:00:00 2001 From: tanshu <tanshu@gmail.com> Date: Fri, 8 May 2020 16:18:50 +0530 Subject: [PATCH] Account done --- brewman/routers/account.py | 187 ++++++++++++++++++------------- brewman/routers/account_types.py | 16 +-- brewman/routers/cost_centre.py | 9 +- brewman/schemas/master.py | 9 +- 4 files changed, 129 insertions(+), 92 deletions(-) diff --git a/brewman/routers/account.py b/brewman/routers/account.py index ea91e0b2..86e6e65c 100644 --- a/brewman/routers/account.py +++ b/brewman/routers/account.py @@ -1,17 +1,19 @@ +import traceback import uuid +from typing import List from datetime import datetime -from fastapi import APIRouter, Depends, Security -from pydantic import ValidationError +from fastapi import APIRouter, HTTPException, status, Depends, Security from sqlalchemy import func +from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import joinedload_all, Session from ..core.security import User, get_current_active_user as get_user from ..db.session import SessionLocal from ..models.master import CostCentre, Account, AccountType, AccountBase -from ..models.validation_exception import ValidationError from ..models.voucher import Voucher, Journal, VoucherType -from ..schemas.master import Account as AccountSchema +import brewman.schemas.master as schemas + router = APIRouter() @@ -24,11 +26,14 @@ def get_db(): db.close() -@router.post("/") -def save(data: AccountSchema, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])): +@router.post("/", response_model=schemas.Account) +def save( + data: schemas.AccountSaveUpdate, + db: Session = Depends(get_db), + user: User = Security(get_user, scopes=["accounts"]), +): try: item = Account( - code=0, name=data.name, type=data.type, is_starred=data.is_starred, @@ -38,56 +43,85 @@ def save(data: AccountSchema, db: Session = Depends(get_db), user: User = Securi ).create(db) db.commit() return account_info(item.id, db) - except: + except SQLAlchemyError as e: db.rollback() - finally: - db.close() - - -@router.put("/{id_}") -def update(id_: uuid.UUID, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])): - item = ( - db.query(Account) - .filter(Account.id == id_) - .first() - ) - if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.name) + raise HTTPException( + 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(), ) - new_type = int(request.json_body["type"]) - if not item.type == new_type: - item.code = Account.get_code(new_type, request.dbsession) - item.type = new_type - item.name = request.json_body["name"] - item.is_active = request.json_body["isActive"] - item.is_reconcilable = request.json_body["isReconcilable"] - item.is_starred = request.json_body["isStarred"] - item.cost_centre_id = uuid.UUID(request.json_body["costCentre"]["id"]) - transaction.commit() - return account_info(item.id, request.dbsession) -@router.delete("/{id}") # "Accounts" -def delete(id_: uuid.UUID, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])): - account = ( - db.query(Account) - .filter(Account.id == id_) - .first() - ) - can_delete, reason = account.can_delete(request.has_permission("Advanced Delete")) +@router.put("/{id_}", response_model=schemas.Account) +def update( + id_: uuid.UUID, + data: schemas.AccountSaveUpdate, + db: Session = Depends(get_db), + user: User = Security(get_user, scopes=["accounts"]), +): + try: + item: Account = db.query(Account).filter(Account.id == id_).first() + if item.is_fixture: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"{item.name} is a fixture and cannot be edited or deleted.", + ) + if not item.type == data.type: + item.code = Account.get_code(data.type, db) + item.type = data.type + item.name = data.name + item.is_active = data.is_active + item.is_reconcilable = data.is_reconcilable + item.is_starred = data.is_starred + item.cost_centre_id = data.cost_centre.id_ + db.commit() + return account_info(item.id, db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=traceback.format_exc(), + ) + + +@router.delete("/{id}") +def delete( + id_: uuid.UUID, + db: Session = Depends(get_db), + user: User = Security(get_user, scopes=["accounts"]), +): + account: Account = db.query(Account).filter(Account.id == id_).first() + can_delete, reason = account.can_delete("Advanced Delete" in user.permissions) if can_delete: delete_with_data(account, db) - transaction.commit() + db.commit() return account_info(None, db) else: - transaction.abort() - response = Response("Cannot delete account because {0}".format(reason)) - response.status_int = 500 - return response + db.abort() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Cannot delete account because {reason}", + ) -@router.get("/list") # "Authenticated" +@router.get("/") +def show_blank( + db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"]) +): + return account_info(None, db) + + +@router.get("/list") async def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)): list_ = ( db.query(Account) @@ -113,9 +147,16 @@ async def show_list(db: Session = Depends(get_db), user: User = Depends(get_user return accounts -@router.get("/query") # "Authenticated" -async def show_term(q: str, t: int = None, r: bool = None, a: bool = None, c: int = None, - db: Session = Depends(get_db), current_user: User = Depends(get_user)): +@router.get("/query") +async def show_term( + q: str, + t: int = None, + r: bool = None, + a: bool = None, + c: int = None, + db: Session = Depends(get_db), + current_user: User = Depends(get_user), +): count = c list_ = [] @@ -126,29 +167,32 @@ async def show_term(q: str, t: int = None, r: bool = None, a: bool = None, c: in return {"user": current_user.name, "list": list_} -@router.get("/{id_}/balance") # "Authenticated" -async def show_balance(id_: uuid.UUID, d: str = None, db: Session = Depends(get_db), user: User = Depends(get_user)): - date = ( - None - if d is None or d == "" - else datetime.datetime.strptime(d, "%d-%b-%Y") - ) +@router.get("/{id_}/balance") +async def show_balance( + id_: uuid.UUID, + d: str = None, + db: Session = Depends(get_db), + user: User = Depends(get_user), +): + date = None if d is None or d == "" else datetime.datetime.strptime(d, "%d-%b-%Y") return {"date": balance(id_, date, db), "total": balance(id_, None, db)} -@router.get("/{id_}") # "Accounts" -def show_id(id_: uuid.UUID, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])): +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, + db: Session = Depends(get_db), + user: User = Security(get_user, scopes=["accounts"]), +): return account_info(id_, db) -def balance(id_: uuid.UUID, date, dbsession: Session): - account = dbsession.query(AccountBase).filter(AccountBase.id == id_).first() +def balance(id_: uuid.UUID, date, db: Session): + account = db.query(AccountBase).filter(AccountBase.id == id_).first() if not account.type_object.balance_sheet: return 0 - bal = dbsession.query(func.sum(Journal.amount * Journal.debit)).join( - Journal.voucher - ) + bal = db.query(func.sum(Journal.amount * Journal.debit)).join(Journal.voucher) if date is not None: bal = bal.filter(Voucher.date <= date) @@ -160,11 +204,6 @@ def balance(id_: uuid.UUID, date, dbsession: Session): return 0 if bal is None else bal -@router.get("/") # "Accounts" -def show_blank(db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])): - return account_info(None, db) - - def account_info(id_, db): if id_ is None: account = { @@ -198,7 +237,7 @@ def delete_with_data(account, db): suspense_account = ( db.query(Account).filter(Account.id == Account.suspense()).first() ) - query = ( + query: List[Voucher] = ( db.query(Voucher) .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) .filter(Voucher.journals.any(Journal.account_id == account.id)) @@ -219,8 +258,8 @@ def delete_with_data(account, db): else: if sus_jnl is None: acc_jnl.account = suspense_account - voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format( - acc_jnl.amount, account.name + voucher.narration += ( + f"\nSuspense \u20B9{acc_jnl.amount:,.2f} is {account.name}" ) else: amount = (sus_jnl.debit * sus_jnl.amount) + ( @@ -232,9 +271,7 @@ def delete_with_data(account, db): else: sus_jnl.amount = abs(amount) sus_jnl.debit = -1 if amount < 0 else 1 - voucher.narration += "\nDeleted \u20B9{0:,.2f} of {1}".format( - acc_jnl.amount * acc_jnl.debit, account.name - ) + voucher.narration += f"\nDeleted \u20B9{acc_jnl.amount * acc_jnl.debit:,.2f} of {account.name}" if voucher.type in ( VoucherType.by_name("Payment").id, VoucherType.by_name("Receipt").id, diff --git a/brewman/routers/account_types.py b/brewman/routers/account_types.py index b188bbf2..7f5bc5e8 100644 --- a/brewman/routers/account_types.py +++ b/brewman/routers/account_types.py @@ -1,12 +1,14 @@ +from fastapi import APIRouter, Depends + +from ..core.security import User, get_current_active_user as get_user from brewman.models.master import AccountType -from fastapi import APIRouter router = APIRouter() -@router.get("/") # "Authenticated" -def account_type_list(request): - account_types = [] - for item in AccountType.list(): - account_types.append({"id": item.id, "name": item.name}) - return account_types +@router.get("/") +def account_type_list(user: User = Depends(get_user)): + return [ + {"id": item.id, "name": item.name} + for item in AccountType.list() + ] diff --git a/brewman/routers/cost_centre.py b/brewman/routers/cost_centre.py index 85a05941..18e7e0ee 100644 --- a/brewman/routers/cost_centre.py +++ b/brewman/routers/cost_centre.py @@ -1,19 +1,14 @@ import traceback import uuid from typing import List, Optional - -from sqlalchemy.exc import SQLAlchemyError - -import brewman.schemas.master as schemas - from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session +import brewman.schemas.master as schemas from ..core.security import User, get_current_active_user as get_user from ..db.session import SessionLocal from ..models.master import CostCentre - - router = APIRouter() diff --git a/brewman/schemas/master.py b/brewman/schemas/master.py index 06198bf5..146a3377 100644 --- a/brewman/schemas/master.py +++ b/brewman/schemas/master.py @@ -62,15 +62,18 @@ class CostCentre(CostCentreSaveUpdate): is_fixture: bool = Field(alias="isFixture") -class Account(BaseModel): - id_: uuid.UUID - code: int +class AccountSaveUpdate(BaseModel): name: str type: int is_starred: bool is_active: bool is_reconcilable: bool cost_centre: CostCentre + + +class Account(AccountSaveUpdate): + id_: uuid.UUID = Field(alias="id") + code: int is_fixture: bool