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, get_opening_stock 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.ProfitLoss) def report_blank( request: Request, user: UserToken = Security(get_user, scopes=["profit-&-loss"]), ): return { "startDate": get_start_date(request.session), "finishDate": get_finish_date(request.session), "body": [], "footer": None, } @router.get("/{start}/{finish}", response_model=schemas.ProfitLoss) def report_data( start: str, finish: str, request: Request, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["profit-&-loss"]), ): body, footer = build_profit_loss( datetime.strptime(start, "%d-%b-%Y"), datetime.strptime(finish, "%d-%b-%Y"), db ) set_period(start, finish, request.session) return { "startDate": start, "finishDate": finish, "body": body, "footer": footer, } def build_profit_loss(start_date: date, finish_date: date, db: Session): profit_type_list = [i.id for i in AccountType.list() if i.balance_sheet == False] report = [] groups = {} amount_sum = func.sum(Journal.amount * Journal.debit) query = ( db.query(AccountBase, amount_sum) .join(Journal.voucher) .join(Journal.account) .filter(Voucher.date >= start_date) .filter(Voucher.date <= finish_date) .filter(Voucher.type != VoucherType.by_name("Issue").id) .filter(AccountBase.type.in_(profit_type_list)) .group_by(AccountBase) .order_by(AccountBase.type) .order_by(desc(func.abs(amount_sum))) .all() ) # Get opening / closing stock opening_stock = get_opening_stock(start_date, db) closing_stock = get_closing_stock(finish_date, db) total_amount = (opening_stock - closing_stock) * -1 report.append( {"name": "Opening Stock", "amount": opening_stock * -1, "order": 200001} ) report.append({"name": "Closing Stock", "amount": closing_stock, "order": 290000}) purchase_group = AccountType.by_id(2) groups[purchase_group.id] = { "group": purchase_group.name, "total": total_amount, "order": purchase_group.order, } counter = 0 for account, amount in query: # Add Items amount *= -1 account_type = AccountType.by_id(account.type) total_amount += amount if amount != 0: counter += 10 report.append( { "name": account.name, "amount": amount, "order": account_type.order + counter, } ) if account_type.id in groups: groups[account_type.id]["total"] += amount else: groups[account_type.id] = { "group": account_type.name, "total": amount, "order": account_type.order, } # Add Subtotals for item in groups.values(): report.append(item) # Add Net footer = { "group": "Net Profit" if total_amount > 0 else "Net Loss", "total": total_amount, "order": 1000000, } return sorted(report, key=lambda d: d["order"]), footer def get_accumulated_profit(finish_date, db): type_list = [i.id for i in AccountType.list() if i.balance_sheet is False] accumulated_profit = ( 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.in_(type_list)) .scalar() ) return 0 if accumulated_profit is None else accumulated_profit