brewman/brewman/brewman/routers/reports/balance_sheet.py

131 lines
4.0 KiB
Python

from datetime import date, datetime
import brewman.schemas.reports as schemas
from fastapi import APIRouter, Depends, Request, Security
from sqlalchemy.orm import Session
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 ...routers.reports.closing_stock import get_closing_stock
from ...routers.reports.profit_loss import get_accumulated_profit
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.BalanceSheet)
def report_blank(
request: Request,
user: UserToken = Security(get_user, scopes=["balance-sheet"]),
):
return {"date": get_finish_date(request.session), "body": [], "footer": None}
@router.get("/{date_}", response_model=schemas.BalanceSheet)
def report_data(
date_: str,
request: Request,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["balance-sheet"]),
):
body, footer = build_balance_sheet(datetime.strptime(date_, "%d-%b-%Y"), db)
set_period(get_start_date(request.session), date_, request.session)
return {"date": date_, "body": body, "footer": footer}
def build_balance_sheet(date_: date, db: Session):
type_list = [i.id for i in AccountType.list() if i.balance_sheet]
report = []
groups = dict()
# Add Net Profit / Loss
closing_stock = round(get_closing_stock(date_, db), 2)
net_profit = round(get_accumulated_profit(date_, db), 2) - closing_stock
total_amount = net_profit
report.append(
{
"name": "Net Loss" if net_profit >= 0 else "Net Profit",
"subAmount": round(net_profit, 2),
"order": 79000,
}
)
capital_group = AccountType.by_id(5)
groups[capital_group.id] = {
"group": capital_group.name,
"amount": round(total_amount, 2),
"order": capital_group.order,
}
total_amount += closing_stock
report.append(
{"name": "Closing Stock", "subAmount": round(closing_stock, 2), "order": 20001}
)
asset_group = AccountType.by_id(4)
groups[asset_group.id] = {
"group": asset_group.name,
"amount": round(closing_stock, 2),
"order": asset_group.order,
}
amount_sum = func.sum(Journal.amount * Journal.debit)
query = (
db.query(AccountBase, amount_sum)
.join(Journal.voucher)
.join(Journal.account)
.filter(Voucher.date <= date_)
.filter(Voucher.type != VoucherType.by_name("Issue").id)
.filter(AccountBase.type.in_(type_list))
.group_by(AccountBase)
.order_by(AccountBase.type)
.order_by(desc(func.abs(amount_sum)))
.all()
)
counter = 0
for account, amount in query:
# Add Items
account_type = AccountType.by_id(account.type)
total_amount += amount
if amount != 0:
counter += 1
report.append(
{
"name": account.name,
"subAmount": round(amount, 2),
"order": account_type.order + counter,
}
)
if account_type.id in groups:
groups[account_type.id]["amount"] = round(
groups[account_type.id]["amount"] + amount, 2
)
else:
groups[account_type.id] = {
"group": account_type.name,
"amount": round(amount, 2),
"order": account_type.order,
}
# Add Subtotals
for item in groups.values():
report.append(item)
footer = {"name": "Total", "amount": round(total_amount, 2), "order": 100000}
return sorted(report, key=lambda d: d["order"]), footer