import uuid from datetime import date, datetime import brewman.schemas.reports as schemas from fastapi import APIRouter, Depends, Request, Security from sqlalchemy.orm import Session, joinedload from sqlalchemy.sql.expression import 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 CostCentre, Product from ...models.voucher import Inventory, 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.ProductLedger) def show_blank( request: Request, user: UserToken = Security(get_user, scopes=["product-ledger"]), ): return { "startDate": get_start_date(request.session), "finishDate": get_finish_date(request.session), "product": None, "body": [], } @router.get("/{id_}", response_model=schemas.ProductLedger) def show_data( id_: uuid.UUID, request: Request, s: str = None, f: str = None, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["product-ledger"]), ): product = db.query(Product).filter(Product.id == id_).first() start_date = s if s is not None else get_start_date(request.session) finish_date = f if f is not None else get_finish_date(request.session) body = build_report( product.id, datetime.strptime(start_date, "%d-%b-%Y"), datetime.strptime(finish_date, "%d-%b-%Y"), db, ) set_period(start_date, finish_date, request.session) return { "startDate": start_date, "finishDate": finish_date, "product": {"id": product.id, "name": product.name}, "body": body, } def build_report( product_id: uuid.UUID, start_date: date, finish_date: date, db: Session ): body = [] running_total_q, running_total_a, opening = opening_balance( product_id, start_date, db ) body.append(opening) query = ( db.query(Voucher, Inventory, Journal) .options( joinedload(Journal.account, innerjoin=True), joinedload(Journal.cost_centre, innerjoin=True), ) .filter(Voucher.id == Inventory.voucher_id) .filter(Voucher.id == Journal.voucher_id) .filter(Inventory.product_id == product_id) .filter(Journal.cost_centre_id != CostCentre.cost_centre_purchase()) .filter(Voucher.date >= start_date) .filter(Voucher.date <= finish_date) .order_by(Voucher.date) .order_by(Voucher.last_edit_date) .all() ) for row in query: journal_debit = row.Journal.debit * -1 name = ( row.Journal.cost_centre.name if row.Voucher.type == VoucherType.by_name("Issue").id else row.Journal.account.name ) debit_q = row.Inventory.quantity if journal_debit == 1 else None debit_a = row.Inventory.amount if journal_debit == 1 else None credit_q = row.Inventory.quantity if journal_debit != 1 else None credit_a = row.Inventory.amount if journal_debit != 1 else None running_total_q += row.Inventory.quantity * journal_debit running_total_a += row.Inventory.amount * journal_debit body.append( { "id": row.Voucher.id, "date": row.Voucher.date.strftime("%d-%b-%Y"), "name": name, "url": [ "/", VoucherType.by_id(row.Voucher.type).name.replace(" ", "-").lower(), str(row.Voucher.id), ], "type": VoucherType.by_id(row.Voucher.type).name, "narration": row.Voucher.narration, "posted": row.Voucher.posted or VoucherType.by_id(row.Voucher.type).name == "Issue", "debitQuantity": debit_q, "debitAmount": debit_a, "creditQuantity": credit_q, "creditAmount": credit_a, "runningQuantity": running_total_q, "runningAmount": running_total_a, } ) return body def opening_balance(product_id: uuid.UUID, start_date: date, db: Session): quantity, amount = ( db.query( func.sum(Inventory.quantity * Journal.debit), func.sum(Inventory.amount * Journal.debit), ) .join(Inventory.voucher) .join(Voucher.journals) .filter(Voucher.id == Inventory.voucher_id) .filter(Voucher.id == Journal.voucher_id) .filter(Inventory.product_id == product_id) .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) .filter(Voucher.date < start_date) .one() ) if quantity and quantity > 0: debit_quantity = quantity debit_amount = amount else: debit_quantity = None debit_amount = None if quantity is None: quantity = 0 amount = 0 return ( quantity, amount, { "id": None, "date": start_date.strftime("%d-%b-%Y"), "name": "Opening Balance", "url": [], "type": "Opening Balance", "narration": "", "posted": True, "debitQuantity": debit_quantity, "debitAmount": debit_amount, "creditQuantity": 0, "creditAmount": 0, "runningQuantity": quantity, "runningAmount": amount, }, )