from pathlib import Path import re import sys from sqlalchemy import select, text ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) from app.database import SessionLocal, engine # noqa: E402 from app.models import DeviceQRCode, Product, ProductionReportItem, WorkSessionDevice # noqa: E402 from app.services.cleaning import CLEANING_STAMPING_METHOD, LEGACY_CLEANING_PROCESS_NAME # noqa: E402 def _column_exists(conn, table_name: str, column_name: str) -> bool: return bool(conn.execute( text(""" SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = :table_name AND column_name = :column_name """), {"table_name": table_name, "column_name": column_name}, ).scalar_one()) def _sequence_number(process_name: str) -> int | None: matched = re.search(r"\d+", str(process_name or "")) return int(matched.group(0)) if matched else None def _next_process_name(products: list[Product]) -> str: existing = {str(product.process_name or "").strip() for product in products} max_number = max( (number for number in (_sequence_number(value) for value in existing) if number is not None), default=0, ) number = max_number + 1 while f"{number}序" in existing: number += 1 return f"{number}序" def main() -> None: with engine.begin() as conn: if not _column_exists(conn, "production_report_items", "stamping_method"): conn.execute(text(""" ALTER TABLE production_report_items ADD COLUMN stamping_method VARCHAR(128) NULL AFTER process_name """)) with SessionLocal() as db: cleaning_products = db.scalars( select(Product).where(Product.process_name == LEGACY_CLEANING_PROCESS_NAME) ).all() migrated_products = 0 for product in cleaning_products: old_process_name = product.process_name siblings = db.scalars( select(Product).where( Product.project_no == product.project_no, Product.product_name == product.product_name, Product.device_no == product.device_no, ) ).all() next_process_name = _next_process_name(siblings) old_qr = db.get(DeviceQRCode, { "device_no": product.product_name, "process_name": old_process_name, }) if old_qr is not None: old_qr.process_name = next_process_name for session_device in db.scalars( select(WorkSessionDevice).where( WorkSessionDevice.device_no == product.product_name, WorkSessionDevice.process_name == old_process_name, ) ).all(): session_device.process_name = next_process_name for report_item in db.scalars( select(ProductionReportItem).where( ProductionReportItem.project_no == product.project_no, ProductionReportItem.product_name == product.product_name, ProductionReportItem.process_name == old_process_name, ) ).all(): report_item.process_name = next_process_name report_item.stamping_method = CLEANING_STAMPING_METHOD report_item.standard_beat = 0 report_item.standard_workload = 0 report_item.allocated_minutes = 0 product.process_name = next_process_name product.stamping_method = CLEANING_STAMPING_METHOD product.standard_beat = 0 product.standard_workload = 0 migrated_products += 1 for product in db.scalars( select(Product).where(Product.stamping_method == CLEANING_STAMPING_METHOD) ).all(): product.standard_beat = 0 product.standard_workload = 0 for report_item in db.scalars(select(ProductionReportItem)).all(): if report_item.stamping_method: continue product = db.scalar( select(Product).where( Product.project_no == report_item.project_no, Product.product_name == report_item.product_name, Product.process_name == (report_item.process_name or ""), Product.device_no == "", ) ) if product is not None: report_item.stamping_method = product.stamping_method db.commit() print(f"cleaning migrated to stamping_method, products={migrated_products}") if __name__ == "__main__": main()