Fix drill-down logic and structure in dashboard
This commit is contained in:
@@ -176,14 +176,17 @@ async def inventory_drilldown(
|
||||
brand_id=None,
|
||||
specs_hash=None,
|
||||
) -> dict:
|
||||
"""Stock quantity as a three-level tree; each aggregate keyed by unit code
|
||||
so incompatible units never merge into one number."""
|
||||
"""Stock quantity as a three-level tree: Material -> Project -> Warehouse."""
|
||||
stmt = (
|
||||
select(
|
||||
Project.id,
|
||||
Project.name,
|
||||
Warehouse.id,
|
||||
Warehouse.name,
|
||||
Material.id.label("mid"),
|
||||
Material.name.label("mname"),
|
||||
Brand.name.label("bname"),
|
||||
InventoryItem.specs,
|
||||
Project.id.label("pid"),
|
||||
Project.name.label("pname"),
|
||||
Warehouse.id.label("wid"),
|
||||
Warehouse.name.label("wname"),
|
||||
Unit.code,
|
||||
Unit.name_fa,
|
||||
func.sum(InventoryItem.quantity).label("qty"),
|
||||
@@ -194,9 +197,8 @@ async def inventory_drilldown(
|
||||
.join(Project, Project.id == Warehouse.project_id)
|
||||
.join(Material, Material.id == InventoryItem.material_id)
|
||||
.join(Unit, Unit.id == InventoryItem.unit_id)
|
||||
.where(InventoryItem.quantity > 0)
|
||||
.group_by(Project.id, Project.name, Warehouse.id, Warehouse.name, Unit.code, Unit.name_fa)
|
||||
.order_by(Project.name, Warehouse.name)
|
||||
.outerjoin(Brand, Brand.id == InventoryItem.brand_id)
|
||||
.group_by(Material.id, Material.name, Brand.name, InventoryItem.specs, Project.id, Project.name, Warehouse.id, Warehouse.name, Unit.code, Unit.name_fa)
|
||||
)
|
||||
stmt = _stock_filters(
|
||||
stmt, category_id=category_id, material_id=material_id, brand_id=brand_id, specs_hash=specs_hash
|
||||
@@ -207,33 +209,59 @@ async def inventory_drilldown(
|
||||
units_legend: dict[str, str] = {}
|
||||
total_by_unit: dict[str, float] = {}
|
||||
total_rows = 0
|
||||
projects_tree: dict[uuid.UUID, dict] = {}
|
||||
for pid, pname, wid, wname, ucode, uname_fa, qty, row_count in rows:
|
||||
|
||||
materials_tree: dict[str, dict] = {}
|
||||
|
||||
for mid, mname, bname, specs, pid, pname, wid, wname, ucode, uname_fa, qty, row_count in rows:
|
||||
q = _qty(qty)
|
||||
units_legend[ucode] = uname_fa
|
||||
total_by_unit[ucode] = round(total_by_unit.get(ucode, 0.0) + q, 4)
|
||||
total_rows += row_count
|
||||
proj = projects_tree.setdefault(
|
||||
|
||||
# Build full material name
|
||||
parts = [mname]
|
||||
if bname:
|
||||
parts.append(bname)
|
||||
if specs:
|
||||
parts.extend(str(v) for v in specs.values() if v)
|
||||
full_name = " ".join(parts)
|
||||
# Use full_name + unit as unique key for material level, or just full_name
|
||||
mat_key = f"{mid}_{full_name}"
|
||||
|
||||
mat = materials_tree.setdefault(
|
||||
mat_key,
|
||||
{"id": mat_key, "name": full_name, "qty_by_unit": {}, "rows": 0, "_projects": {}},
|
||||
)
|
||||
mat["qty_by_unit"][ucode] = round(mat["qty_by_unit"].get(ucode, 0.0) + q, 4)
|
||||
mat["rows"] += row_count
|
||||
|
||||
proj = mat["_projects"].setdefault(
|
||||
pid,
|
||||
{"id": str(pid), "name": pname, "qty_by_unit": {}, "rows": 0, "_warehouses": {}},
|
||||
)
|
||||
proj["qty_by_unit"][ucode] = round(proj["qty_by_unit"].get(ucode, 0.0) + q, 4)
|
||||
proj["rows"] += row_count
|
||||
|
||||
wh = proj["_warehouses"].setdefault(wid, {"id": str(wid), "name": wname, "qty_by_unit": {}, "rows": 0})
|
||||
wh["qty_by_unit"][ucode] = round(wh["qty_by_unit"].get(ucode, 0.0) + q, 4)
|
||||
wh["rows"] += row_count
|
||||
|
||||
projects = []
|
||||
for proj in projects_tree.values():
|
||||
warehouses = sorted(proj.pop("_warehouses").values(), key=lambda w: w["name"])
|
||||
projects.append({**proj, "warehouses": warehouses})
|
||||
projects.sort(key=lambda p: p["name"])
|
||||
materials = []
|
||||
for mat in materials_tree.values():
|
||||
projects_list = []
|
||||
for proj in mat.pop("_projects").values():
|
||||
warehouses = sorted(proj.pop("_warehouses").values(), key=lambda w: w["name"])
|
||||
projects_list.append({**proj, "warehouses": warehouses})
|
||||
projects_list.sort(key=lambda p: p["name"])
|
||||
materials.append({**mat, "projects": projects_list})
|
||||
|
||||
materials.sort(key=lambda m: m["name"])
|
||||
|
||||
return {
|
||||
"data": {
|
||||
"units": units_legend,
|
||||
"total": {"qty_by_unit": total_by_unit, "rows": total_rows},
|
||||
"projects": projects,
|
||||
"materials": materials,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user