diff --git a/brewman/routers/reports/stock_movement.py b/brewman/routers/reports/stock_movement.py index 03d17d2a..ee090ef4 100644 --- a/brewman/routers/reports/stock_movement.py +++ b/brewman/routers/reports/stock_movement.py @@ -1,4 +1,5 @@ -import datetime +from datetime import datetime, date +from decimal import Decimal from fastapi import APIRouter, Depends, Security, Request from sqlalchemy.orm import Session @@ -9,6 +10,7 @@ from ...core.security import get_current_active_user as get_user from ...db.session import SessionLocal from brewman.models.master import Product, CostCentre from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory +import brewman.schemas.reports as schemas from ...core.session import ( set_period, get_start_date, @@ -27,7 +29,7 @@ def get_db() -> Session: db.close() -@router.get("") +@router.get("", response_model=schemas.StockMovement) def report_blank( request: Request, user: UserToken = Security(get_user, scopes=["stock-movement"]), @@ -39,7 +41,7 @@ def report_blank( } -@router.get("/{start}/{finish}") +@router.get("/{start}/{finish}", response_model=schemas.StockMovement) def report_data( start: str, finish: str, @@ -47,14 +49,12 @@ def report_data( db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["stock-movement"]), ): - body = build_stock_movement(start, finish, db) + 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, finish_date, db): - start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") - finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") +def build_stock_movement(start_date: date, finish_date: date, db: Session): dict_ = {} quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity") openings = ( @@ -72,7 +72,8 @@ def build_stock_movement(start_date, finish_date, db): "id": product.id, "name": product.full_name, "group": product.product_group.name, - "opening": quantity, + "opening": Decimal(round(quantity, 2)), + "url": ['/', 'product-ledger', str(product.id)], } purchases = ( db.query(Product, quantity_sum) @@ -88,13 +89,14 @@ def build_stock_movement(start_date, finish_date, db): ) for product, quantity in purchases: if product.id in dict_: - dict_[product.id]["purchase"] = quantity + 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": quantity, + "purchase": Decimal(round(quantity, 2)), + "url": ['/', 'product-ledger', str(product.id)], } issues = ( db.query(Product, quantity_sum) @@ -110,13 +112,14 @@ def build_stock_movement(start_date, finish_date, db): ) for product, quantity in issues: if product.id in dict_: - dict_[product.id]["issue"] = quantity * -1 + 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": quantity * -1, + "issue": Decimal(round(quantity * -1, 2)), + "url": ['/', 'product-ledger', str(product.id)], } list_ = [value for key, value in dict_.items()] @@ -124,10 +127,16 @@ def build_stock_movement(start_date, finish_date, db): list_ = sorted(list_, key=lambda x: x["group"].lower()) for i in range(len(list_), 0, -1): item = list_[i - 1] - opening = item["opening"] if "opening" in item else 0 - purchase = item["purchase"] if "purchase" in item else 0 - issue = item["issue"] if "issue" in item else 0 - closing = opening + purchase - issue + 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: diff --git a/brewman/schemas/reports.py b/brewman/schemas/reports.py index 9eba41bc..fe7879e6 100644 --- a/brewman/schemas/reports.py +++ b/brewman/schemas/reports.py @@ -413,3 +413,41 @@ class RawMaterialCost(BaseModel): if isinstance(value, date): return value return datetime.strptime(value, "%d-%b-%Y").date() + + +class StockMovementItem(BaseModel): + id_: uuid.UUID + group: str + name: str + opening: Decimal + purchase: Decimal + issue: Decimal + closing: Decimal + url: List[str] + + class Config: + anystr_strip_whitespace = True + alias_generator = to_camel + + +class StockMovement(BaseModel): + start_date: date + finish_date: date + body: List[StockMovementItem] + + class Config: + anystr_strip_whitespace = True + alias_generator = to_camel + json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")} + + @validator("start_date", pre=True) + def parse_start_date(cls, value): + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() + + @validator("finish_date", pre=True) + def parse_finish_date(cls, value): + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() diff --git a/overlord/src/app/stock-movement/stock-movement.component.html b/overlord/src/app/stock-movement/stock-movement.component.html index e9a17783..b34ececd 100644 --- a/overlord/src/app/stock-movement/stock-movement.component.html +++ b/overlord/src/app/stock-movement/stock-movement.component.html @@ -32,7 +32,11 @@ Name - {{row.name}} + + + {{row.name}} + + diff --git a/overlord/src/app/stock-movement/stock-movement.ts b/overlord/src/app/stock-movement/stock-movement.ts index 25a3b8f9..32bd2c47 100644 --- a/overlord/src/app/stock-movement/stock-movement.ts +++ b/overlord/src/app/stock-movement/stock-movement.ts @@ -1,11 +1,13 @@ export class StockMovementItem { + id: string; group: string; name: string; opening: number; purchase: number; issue: number; closing: number; + url: string[]; } export class StockMovement {