import datetime import brewman.schemas.reports as schemas from fastapi import APIRouter, Depends, Request, Security from sqlalchemy.orm import Session from sqlalchemy.orm.util import aliased from sqlalchemy.sql.expression import desc, func from ...core.security import get_current_active_user as get_user from ...core.session import get_finish_date, get_start_date, set_period from ...db.session import SessionLocal from ...models.master import AccountBase, AccountType from ...models.voucher import Journal, Voucher, VoucherType from ...schemas.auth import UserToken router = APIRouter() # Dependency def get_db() -> Session: try: db = SessionLocal() yield db finally: db.close() @router.get("", response_model=schemas.CashFlow) def report_blank( request: Request, user: UserToken = Security(get_user, scopes=["cash-flow"]), ): return { "startDate": get_start_date(request.session), "finishDate": get_finish_date(request.session), "body": {"operating": [], "investing": [], "financing": [], "details": []}, "footer": None, } @router.get("/data") def report_data( request: Request, s: str = None, f: str = None, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["cash-flow"]), ): body, footer = build_report(s, f, db) set_period(s, f, request.session) return { "startDate": s, "finishDate": f, "body": body, "footer": footer, } @router.get("/{id_}") def report_id( id_: int, request: Request, s: str = None, f: str = None, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["cash-flow"]), ): details, footer = build_report_id(id_, s, f, db) set_period(s, f, request.session) return { "startDate": s, "finishDate": f, "body": {"details": details}, "footer": footer, } def build_report(start_date, finish_date, db): sub_voucher = aliased(Voucher) sub_journal = aliased(Journal) sub_account = aliased(AccountBase) sub_query = ( db.query(sub_voucher.id) .join(sub_journal, sub_voucher.journals) .join(sub_account, sub_journal.account) .filter(sub_account.type == AccountType.by_name("Cash").id) .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) .subquery() ) query = ( db.query(AccountBase.type, func.sum(Journal.signed_amount)) .join(Journal, Voucher.journals) .join(AccountBase, Journal.account) .filter(Voucher.id.in_(sub_query)) .filter(AccountBase.type != AccountType.by_name("Cash").id) .group_by(AccountBase.type) .order_by(func.sum(Journal.signed_amount)) .all() ) total_amount = 0 cf = {"operating": [], "investing": [], "financing": []} for account_type, amount in query: lt = AccountType.by_id(account_type) total_amount += amount * -1 cf[lt.cash_flow_classification.lower()].append( { "name": lt.name, "url": ["/", "cash-flow", str(lt.id)], "amount": amount * -1, } ) opening = ( db.query(func.sum(Journal.amount * Journal.debit)) .join(Journal.voucher) .join(Journal.account) .filter(Voucher.date < start_date) .filter(Voucher.type != VoucherType.by_name("Issue").id) .filter(AccountBase.type == AccountType.by_name("Cash").id) .scalar() ) closing = ( db.query(func.sum(Journal.amount * Journal.debit)) .join(Journal.voucher) .join(Journal.account) .filter(Voucher.date <= finish_date) .filter(Voucher.type != VoucherType.by_name("Issue").id) .filter(AccountBase.type == AccountType.by_name("Cash").id) .scalar() ) return ( cf, [ { "name": "Net increase in cash and cash equivalents", "amount": total_amount, }, { "name": "Cash and cash equivalents at beginning of period", "amount": opening, }, {"name": "Cash and cash equivalents at end of period", "amount": closing}, ], ) def build_report_id(account_type, start_date, finish_date, db): details = [] sub_voucher = aliased(Voucher) sub_journal = aliased(Journal) sub_account = aliased(AccountBase) sub_query = ( db.query(sub_voucher.id) .join(sub_journal, sub_voucher.journals) .join(sub_account, sub_journal.account) .filter(sub_account.type == AccountType.by_name("Cash").id) .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) .subquery() ) query = ( db.query(AccountBase, func.sum(Journal.signed_amount)) .join(Journal, Voucher.journals) .join(AccountBase, Journal.account) .filter(Voucher.id.in_(sub_query)) .filter(AccountBase.type == account_type) .group_by(AccountBase) .order_by(desc(func.sum(Journal.amount))) .all() ) total_amount = 0 for account, amount in query: total_amount += amount * -1 details.append( { "name": account.name, "url": ["/", "ledger", str(account.id)], "amount": amount * -1, } ) return details, [{"name": "total", "amount": total_amount}]