fix: 强化报工归属回填脚本

This commit is contained in:
souplearn 2026-07-25 05:58:27 +08:00
parent 666c26bb57
commit 6065ab031d

View File

@ -9,9 +9,9 @@ ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT))
from app.database import SessionLocal, engine # noqa: E402 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.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" 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)}") raise RuntimeError(f"{TABLE_NAME} missing foreign keys: {', '.join(missing_foreign_keys)}")
def _backfill() -> tuple[int, int]: def _read_work_schedule_config(db, attendance_point_name: str | None) -> WorkScheduleConfig:
processed = 0 point_name = str(attendance_point_name or "").strip()
skipped = 0 if not point_name:
return DEFAULT_WORK_SCHEDULE_CONFIG
query = ( point = db.get(AttendancePoint, point_name)
select(ProductionReport) if point is None:
.options( return DEFAULT_WORK_SCHEDULE_CONFIG
selectinload(ProductionReport.items),
selectinload(ProductionReport.session).selectinload(WorkSession.devices), return WorkScheduleConfig(
) day_start=point.day_start or DEFAULT_WORK_SCHEDULE_CONFIG.day_start,
.order_by(ProductionReport.id.asc()) 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: with SessionLocal() as db:
reports = db.scalars(query).all() while True:
for report in reports: query = (
if report is None: select(ProductionReport)
skipped += 1 .where(ProductionReport.id > last_id)
continue .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) for report in reports:
refresh_report_allocations(db, report, schedule=schedule, commit=False) if report is None:
processed += 1 skipped += 1
continue
if processed % 200 == 0: last_id = report.id
db.commit() 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 return processed, skipped