Bundle pending backend/web-admin feature updates, data-migration scripts, and related docs so the V1.5 branch on the Tencent Cloud Gogs matches the current workspace (excluding local secrets). Co-authored-by: Cursor <cursoragent@cursor.com>
113 lines
3.3 KiB
Python
113 lines
3.3 KiB
Python
"""计划归档按品牌数量校验与持久化"""
|
|
from decimal import Decimal
|
|
from typing import Any, Optional
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.utils import generate_uuid
|
|
from app.models.pl_models import PlPlanProductBrandQty
|
|
|
|
|
|
def load_brand_qtys_by_plan_product_ids(
|
|
db: Session,
|
|
*,
|
|
tenant_no: str,
|
|
plan_product_ids: list[str],
|
|
) -> dict[str, list[dict[str, Any]]]:
|
|
"""按计划产品明细 ID 批量加载归档品牌数量(brandId/brandName/qty)。"""
|
|
ids = [pid for pid in plan_product_ids if pid]
|
|
if not ids:
|
|
return {}
|
|
rows = (
|
|
db.query(PlPlanProductBrandQty)
|
|
.filter(
|
|
PlPlanProductBrandQty.plan_product_id.in_(ids),
|
|
PlPlanProductBrandQty.tenant_no == tenant_no,
|
|
PlPlanProductBrandQty.del_flag == 0,
|
|
)
|
|
.order_by(PlPlanProductBrandQty.order_num.asc())
|
|
.all()
|
|
)
|
|
grouped: dict[str, list[dict[str, Any]]] = {}
|
|
for row in rows:
|
|
qty = Decimal(str(row.qty or 0))
|
|
if qty <= 0:
|
|
continue
|
|
grouped.setdefault(row.plan_product_id, []).append(
|
|
{
|
|
"brandId": row.brand_id or "",
|
|
"brandName": row.brand_name,
|
|
"qty": qty,
|
|
}
|
|
)
|
|
return grouped
|
|
|
|
|
|
def validate_brand_qty_rows(
|
|
*,
|
|
brand_mode: Optional[str],
|
|
required_brand_id: Optional[str],
|
|
actual_qty: Decimal,
|
|
rows: list[dict],
|
|
) -> None:
|
|
actual_qty = Decimal(str(actual_qty))
|
|
if not brand_mode:
|
|
return
|
|
if brand_mode in ("required", "any"):
|
|
total = sum((Decimal(str(r.get("qty") or 0)) for r in rows), Decimal("0"))
|
|
if total != actual_qty:
|
|
raise ValueError("各品牌数量合计必须等于归档实际数量")
|
|
return
|
|
raise ValueError("无效的 brand_mode")
|
|
|
|
|
|
def persist_plan_product_brand_qtys(
|
|
db: Session,
|
|
*,
|
|
tenant_no: str,
|
|
plan_id: str,
|
|
plan_product_id: str,
|
|
brand_mode: Optional[str],
|
|
rows: list[dict[str, Any]],
|
|
user_id: str,
|
|
dept_id: str = "",
|
|
) -> None:
|
|
"""软删旧品牌量行后按归档结果插入;无品牌约定则只软删不插入。"""
|
|
existing = (
|
|
db.query(PlPlanProductBrandQty)
|
|
.filter(
|
|
PlPlanProductBrandQty.plan_product_id == plan_product_id,
|
|
PlPlanProductBrandQty.tenant_no == tenant_no,
|
|
PlPlanProductBrandQty.del_flag == 0,
|
|
)
|
|
.all()
|
|
)
|
|
for row in existing:
|
|
row.del_flag = 1
|
|
row.update_by = user_id
|
|
|
|
if not brand_mode:
|
|
return
|
|
|
|
for idx, item in enumerate(rows):
|
|
qty = Decimal(str(item.get("qty") or 0))
|
|
if qty <= 0:
|
|
continue
|
|
brand_id = item.get("brandId") or item.get("brand_id") or ""
|
|
brand_name = item.get("brandName") or item.get("brand_name")
|
|
db.add(
|
|
PlPlanProductBrandQty(
|
|
id=generate_uuid(),
|
|
tenant_no=tenant_no,
|
|
plan_id=plan_id,
|
|
plan_product_id=plan_product_id,
|
|
brand_id=brand_id,
|
|
brand_name=brand_name,
|
|
qty=qty,
|
|
order_num=idx,
|
|
create_by=user_id,
|
|
create_dept_id=dept_id or "",
|
|
update_by=user_id,
|
|
)
|
|
)
|