brewman/brewman/brewman/routers/reports/cash_flow.py

194 lines
5.6 KiB
Python

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}]