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 from sqlalchemy.sql.expression import case, 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, CostCentre, Product, ProductGroup from ...models.voucher import Inventory, Journal, Voucher 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.RawMaterialCost) def report_blank( request: Request, user: UserToken = Security(get_user, scopes=["raw-material-cost"]), ): return { "startDate": get_start_date(request.session), "finishDate": get_finish_date(request.session), "body": [], "footer": None, } @router.get("/data", response_model=schemas.RawMaterialCost) def report_data( request: Request, s: str = None, f: str = None, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["raw-material-cost"]), ): body, footer = build_report( datetime.strptime(s, "%d-%b-%Y"), datetime.strptime(f, "%d-%b-%Y"), db ) set_period(s, f, request.session) return { "startDate": s, "finishDate": f, "body": body, "footer": footer, } @router.get("/{id_}", response_model=schemas.RawMaterialCost) def report_id( id_: uuid.UUID, request: Request, s: str = None, f: str = None, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["raw-material-cost"]), ): body = build_report_id( id_, datetime.strptime(s, "%d-%b-%Y"), datetime.strptime(f, "%d-%b-%Y"), db ) set_period(s, f, request.session) return { "id": id_, "startDate": s, "finishDate": f, "body": body, } def build_report(start_date: date, finish_date: date, db: Session): body = [] sum_issue = func.sum( case([(AccountBase.type == 2, Journal.signed_amount)], else_=0) ).label("issue") sum_sale = func.sum( case([(AccountBase.type == 3, Journal.signed_amount * -1)], else_=0) ).label("sale") query = ( db.query(CostCentre, sum_issue, sum_sale) .join(CostCentre.journals) .join(Journal.voucher) .join(Journal.account) .filter(Voucher.date >= start_date) .filter(Voucher.date <= finish_date) .filter(Journal.cost_centre_id != CostCentre.cost_centre_purchase()) .filter(AccountBase.type.in_([2, 3])) .group_by(CostCentre) .order_by(sum_sale.desc()) .all() ) issues = 0 sales = 0 for cost_centre, issue, sale in query: issues += issue sales += sale rmc = 0 if sale == 0 else issue / sale body.append( { "name": cost_centre.name, "issue": issue, "sale": sale, "rmc": rmc, "url": ["/", "raw-material-cost", str(cost_centre.id)], } ) rmc = 0 if sales == 0 else issues / sales return body, {"name": "Total", "issue": issues, "sale": sales, "rmc": rmc} def build_report_id( cost_centre_id: uuid.UUID, start_date: date, finish_date: date, db: Session ): sum_quantity = func.sum(Inventory.quantity * Journal.debit).label("quantity") sum_net = func.sum(Inventory.rate * Inventory.quantity * Journal.debit).label("net") sum_gross = func.sum(Inventory.amount * Journal.debit).label("gross") query = ( db.query(Product, sum_quantity, sum_net, sum_gross) .join(Product.inventories) .join(Inventory.voucher) .join(Voucher.journals) .join(Product.product_group) .filter(Voucher.date >= start_date) .filter(Voucher.date <= finish_date) .filter(Voucher.type == 3) .filter(Journal.cost_centre_id == cost_centre_id) .group_by(Product) .group_by(Journal.debit) .group_by(ProductGroup.name) .order_by(ProductGroup.name) .order_by(sum_net.desc()) .all() ) groups = {} counter = 0 list_ = [] for product, quantity, net, gross in query: if product.product_group_id in groups: group = groups[product.product_group_id] group["net"] += net group["gross"] += gross else: counter += 500 group = { "group": product.product_group.name, "net": net, "gross": gross, "order": counter, "heading": True, } groups[product.product_group_id] = group counter += 1 list_.append( { "name": product.full_name, "quantity": quantity, "net": net, "gross": gross, "order": counter, "heading": False, } ) for item in groups.values(): list_.append(item) return sorted(list_, key=lambda d: d["order"])