From 6065ab031d71b87c8f9ce728844d25d3132ec68f Mon Sep 17 00:00:00 2001 From: souplearn Date: Sat, 25 Jul 2026 05:58:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BC=BA=E5=8C=96=E6=8A=A5=E5=B7=A5?= =?UTF-8?q?=E5=BD=92=E5=B1=9E=E5=9B=9E=E5=A1=AB=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/migrate_report_allocations.py | 73 ++++++++++++++++++--------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/scripts/migrate_report_allocations.py b/scripts/migrate_report_allocations.py index d872f3a..8ed9509 100644 --- a/scripts/migrate_report_allocations.py +++ b/scripts/migrate_report_allocations.py @@ -9,9 +9,9 @@ ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) from app.database import SessionLocal, engine # noqa: E402 -from app.models import ProductionReport, WorkSession # noqa: E402 +from app.models import AttendancePoint, ProductionReport, WorkSession # noqa: E402 from app.services.report_allocations import refresh_report_allocations # noqa: E402 -from app.services.work_schedule import get_work_schedule_config # noqa: E402 +from app.services.work_schedule import DEFAULT_WORK_SCHEDULE_CONFIG, WorkScheduleConfig # noqa: E402 TABLE_NAME = "production_report_allocations" @@ -378,34 +378,61 @@ def verify_schema(conn) -> None: raise RuntimeError(f"{TABLE_NAME} missing foreign keys: {', '.join(missing_foreign_keys)}") -def _backfill() -> tuple[int, int]: - processed = 0 - skipped = 0 +def _read_work_schedule_config(db, attendance_point_name: str | None) -> WorkScheduleConfig: + point_name = str(attendance_point_name or "").strip() + if not point_name: + return DEFAULT_WORK_SCHEDULE_CONFIG - query = ( - select(ProductionReport) - .options( - selectinload(ProductionReport.items), - selectinload(ProductionReport.session).selectinload(WorkSession.devices), - ) - .order_by(ProductionReport.id.asc()) + point = db.get(AttendancePoint, point_name) + if point is None: + return DEFAULT_WORK_SCHEDULE_CONFIG + + return WorkScheduleConfig( + day_start=point.day_start or DEFAULT_WORK_SCHEDULE_CONFIG.day_start, + day_end=point.day_end or DEFAULT_WORK_SCHEDULE_CONFIG.day_end, + lunch_start=point.lunch_start or DEFAULT_WORK_SCHEDULE_CONFIG.lunch_start, + lunch_end=point.lunch_end or DEFAULT_WORK_SCHEDULE_CONFIG.lunch_end, + dinner_start=point.dinner_start or DEFAULT_WORK_SCHEDULE_CONFIG.dinner_start, + dinner_end=point.dinner_end or DEFAULT_WORK_SCHEDULE_CONFIG.dinner_end, + overtime_start=point.overtime_start or DEFAULT_WORK_SCHEDULE_CONFIG.overtime_start, + overtime_end=point.overtime_end or DEFAULT_WORK_SCHEDULE_CONFIG.overtime_end, + night_start=point.night_start or DEFAULT_WORK_SCHEDULE_CONFIG.night_start, + night_end=point.night_end or DEFAULT_WORK_SCHEDULE_CONFIG.night_end, ) + +def _backfill(batch_size: int = 200) -> tuple[int, int]: + processed = 0 + skipped = 0 + last_id = 0 + with SessionLocal() as db: - reports = db.scalars(query).all() - for report in reports: - if report is None: - skipped += 1 - continue + while True: + query = ( + select(ProductionReport) + .where(ProductionReport.id > last_id) + .options( + selectinload(ProductionReport.items), + selectinload(ProductionReport.session).selectinload(WorkSession.devices), + ) + .order_by(ProductionReport.id.asc()) + .limit(batch_size) + ) + reports = db.scalars(query).all() + if not reports: + break - schedule = get_work_schedule_config(db, report.attendance_point_name) - refresh_report_allocations(db, report, schedule=schedule, commit=False) - processed += 1 + for report in reports: + if report is None: + skipped += 1 + continue - if processed % 200 == 0: - db.commit() + last_id = report.id + schedule = _read_work_schedule_config(db, report.attendance_point_name) + refresh_report_allocations(db, report, schedule=schedule, commit=False) + processed += 1 - db.commit() + db.commit() return processed, skipped