brewman/brewman/brewman/routers/reports/raw_material_cost.py

187 lines
5.3 KiB
Python

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"])