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

194 lines
5.6 KiB
Python
Raw Normal View History

import datetime
2020-10-07 15:18:43 +00:00
import brewman.schemas.reports as schemas
from fastapi import APIRouter, Depends, Request, Security
from sqlalchemy.orm import Session
from sqlalchemy.orm.util import aliased
2020-10-07 15:18:43 +00:00
from sqlalchemy.sql.expression import desc, func
from ...core.security import get_current_active_user as get_user
2020-10-07 15:18:43 +00:00
from ...core.session import get_finish_date, get_start_date, set_period
from ...db.session import SessionLocal
2020-10-07 15:18:43 +00:00
from ...models.master import AccountBase, AccountType
from ...models.voucher import Journal, Voucher, VoucherType
from ...schemas.auth import UserToken
2012-10-16 18:51:43 +00:00
router = APIRouter()
2012-10-16 18:51:43 +00:00
# Dependency
def get_db() -> Session:
try:
db = SessionLocal()
yield db
finally:
db.close()
@router.get("", response_model=schemas.CashFlow)
def report_blank(
2020-10-07 15:18:43 +00:00
request: Request,
user: UserToken = Security(get_user, scopes=["cash-flow"]),
):
return {
2020-05-12 04:25:33 +00:00
"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)
2020-05-12 04:25:33 +00:00
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)
2020-05-12 04:25:33 +00:00
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(
2020-10-07 15:18:43 +00:00
{
"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,
[
2020-10-07 15:18:43 +00:00
{
"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(
2020-10-07 15:18:43 +00:00
{
"name": account.name,
"url": ["/", "ledger", str(account.id)],
"amount": amount * -1,
}
)
return details, [{"name": "total", "amount": total_amount}]