brewman/brewman/brewman/routers/reports/stock_movement.py

145 lines
4.8 KiB
Python

from datetime import date, datetime
from decimal import Decimal
import brewman.schemas.reports as schemas
from fastapi import APIRouter, Depends, Request, Security
from sqlalchemy.orm import Session
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.StockMovement)
def report_blank(
request: Request,
user: UserToken = Security(get_user, scopes=["stock-movement"]),
):
return {
"startDate": get_start_date(request.session),
"finishDate": get_finish_date(request.session),
"body": [],
}
@router.get("/{start}/{finish}", response_model=schemas.StockMovement)
def report_data(
start: str,
finish: str,
request: Request,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["stock-movement"]),
):
body = build_stock_movement(
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}
def build_stock_movement(start_date: date, finish_date: date, db: Session):
dict_ = {}
quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity")
openings = (
db.query(Product, quantity_sum)
.join(Product.inventories)
.join(Inventory.voucher)
.join(Voucher.journals)
.filter(Voucher.date < start_date)
.filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase())
.group_by(Product)
.all()
)
for product, quantity in openings:
dict_[product.id] = {
"id": product.id,
"name": product.full_name,
"group": product.product_group.name,
"opening": Decimal(round(quantity, 2)),
"url": ["/", "product-ledger", str(product.id)],
}
purchases = (
db.query(Product, quantity_sum)
.join(Product.inventories)
.join(Inventory.voucher)
.join(Voucher.journals)
.filter(Voucher.date >= start_date)
.filter(Voucher.date <= finish_date)
.filter(Voucher.type != VoucherType.by_name("Issue").id)
.filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase())
.group_by(Product)
.all()
)
for product, quantity in purchases:
if product.id in dict_:
dict_[product.id]["purchase"] = Decimal(round(quantity, 2))
else:
dict_[product.id] = {
"id": product.id,
"name": product.full_name,
"group": product.product_group.name,
"purchase": Decimal(round(quantity, 2)),
"url": ["/", "product-ledger", str(product.id)],
}
issues = (
db.query(Product, quantity_sum)
.join(Product.inventories)
.join(Inventory.voucher)
.join(Voucher.journals)
.filter(Voucher.date >= start_date)
.filter(Voucher.date <= finish_date)
.filter(Voucher.type == VoucherType.by_name("Issue").id)
.filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase())
.group_by(Product)
.all()
)
for product, quantity in issues:
if product.id in dict_:
dict_[product.id]["issue"] = Decimal(round(quantity * -1, 2))
else:
dict_[product.id] = {
"id": product.id,
"name": product.full_name,
"group": product.product_group.name,
"issue": Decimal(round(quantity * -1, 2)),
"url": ["/", "product-ledger", str(product.id)],
}
list_ = [value for key, value in dict_.items()]
list_ = sorted(list_, key=lambda x: x["name"].lower())
list_ = sorted(list_, key=lambda x: x["group"].lower())
for i in range(len(list_), 0, -1):
item = list_[i - 1]
if "opening" not in item:
item["opening"] = 0
opening = item["opening"]
if "purchase" not in item:
item["purchase"] = 0
purchase = item["purchase"]
if "issue" not in item:
item["issue"] = 0
issue = item["issue"]
closing = round(opening + purchase - issue, 2)
if opening == 0 and purchase == 0 and issue == 0:
list_.remove(item)
else:
item["closing"] = closing
return list_