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