JhHardwareWRS_BackPoint/scripts/backfill_product_erp_aux_values.py
2026-06-24 15:19:14 +08:00

90 lines
3.2 KiB
Python

from collections import defaultdict
from hashlib import sha256
from pathlib import Path
import sys
from sqlalchemy import select
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from app.database import SessionLocal # noqa: E402
from app.models import Product # noqa: E402
def ratio(name: str, salt: str) -> float:
digest = sha256(f"{name}|{salt}".encode("utf-8")).hexdigest()
return int(digest[:8], 16) / 0xFFFFFFFF
def generated_values(product_name: str) -> tuple[float, float, float, float]:
name = product_name or ""
if "纵梁" in name and "加强板" not in name:
net = 2.6 + ratio(name, "net") * 1.8
elif "吸能盒" in name:
net = 0.75 + ratio(name, "net") * 0.65
elif "加强板" in name:
net = 0.55 + ratio(name, "net") * 0.65
elif any(keyword in name for keyword in ("安装板", "连接板", "端板", "盖板", "封板")):
net = 0.32 + ratio(name, "net") * 0.62
else:
net = 0.85 + ratio(name, "net") * 1.05
gross_factor = 1.08 + ratio(name, "gross") * 0.1
scrap_rate = 0.012 + ratio(name, "scrap") * 0.016
waste_price = 12.0 + ratio(name, "price") * 2.6
return (
round(net, 3),
round(net * gross_factor, 3),
round(scrap_rate, 4),
round(waste_price, 2),
)
def valid_positive(value) -> float | None:
if value is None:
return None
number = float(value)
return number if number > 0 else None
def valid_waste_price(value) -> float | None:
number = valid_positive(value)
if number is None or number > 25:
return None
return number
def group_values(product_name: str, items: list[Product]) -> tuple[float, float, float, float]:
generated = generated_values(product_name)
net = next((value for item in items if (value := valid_positive(item.product_net_weight_kg)) is not None), generated[0])
gross = next((value for item in items if (value := valid_positive(item.product_gross_weight_kg)) is not None), generated[1])
scrap_rate = next((value for item in items if (value := valid_positive(item.scrap_loss_rate)) is not None), generated[2])
waste_price = next((value for item in items if (value := valid_waste_price(item.waste_price_yuan_per_kg)) is not None), generated[3])
return net, gross, scrap_rate, waste_price
def main() -> None:
with SessionLocal() as db:
products = db.scalars(select(Product).order_by(Product.product_name, Product.process_name)).all()
groups: dict[str, list[Product]] = defaultdict(list)
for product in products:
groups[product.product_name].append(product)
updated_rows = 0
for product_name, items in groups.items():
net, gross, scrap_rate, waste_price = group_values(product_name, items)
for product in items:
product.product_net_weight_kg = net
product.product_gross_weight_kg = gross
product.scrap_loss_rate = scrap_rate
product.waste_price_yuan_per_kg = waste_price
updated_rows += 1
db.commit()
print(f"backfilled {updated_rows} product rows, {len(groups)} product names")
if __name__ == "__main__":
main()