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()