fix: 归一化报工归属工时分配

This commit is contained in:
souplearn
2026-07-25 03:25:42 +08:00
parent 65fd7f85ff
commit fbbea51d5c
2 changed files with 58 additions and 0 deletions
+34
View File
@@ -11,6 +11,7 @@ from app.services.metrics import (
SHIFT_BUCKETS,
SHIFT_LABELS,
_blank_overtime_intervals,
_device_segment_ranges,
_iter_shift_base_dates,
_overlap_minutes,
_schedule_interval,
@@ -126,6 +127,38 @@ def _item_reference_wage(item) -> float:
return as_float(getattr(item, "good_qty", 0)) * as_float(getattr(item, "process_unit_price_yuan", 0))
def _minutes_total(rows: dict[date, dict[str, float]]) -> float:
return sum(sum(minutes.get(key, 0.0) for key in SHIFT_BUCKETS) for minutes in rows.values())
def _target_effective_minutes(report, schedule: WorkScheduleConfig | None = None) -> float:
start_at = getattr(report, "start_at")
end_at = getattr(report, "end_at")
segment_ranges = _device_segment_ranges(start_at, end_at, _report_devices(report))
if segment_ranges:
return sum(
_minutes_total(_range_allocation_minutes(segment_start, segment_end, schedule))
for ranges in segment_ranges.values()
for segment_start, segment_end in ranges
)
return _minutes_total(_range_allocation_minutes(start_at, end_at, schedule))
def _scale_minutes_to_target(
minutes_by_item: dict[int, dict[date, dict[str, float]]],
target_effective_minutes: float,
) -> None:
raw_total = sum(_minutes_total(item_minutes) for item_minutes in minutes_by_item.values())
if raw_total <= 0 or abs(raw_total - target_effective_minutes) <= 0.000001:
return
scale = target_effective_minutes / raw_total
for item_minutes in minutes_by_item.values():
for minutes in item_minutes.values():
for key in SHIFT_BUCKETS:
minutes[key] = minutes.get(key, 0.0) * scale
def _fallback_row(report, item) -> ReportAllocationDraft:
return ReportAllocationDraft(
report_id=getattr(report, "id", None),
@@ -179,6 +212,7 @@ def build_report_allocation_drafts(report, schedule: WorkScheduleConfig | None =
target[allocation_date][key] += minutes.get(key, 0.0) * as_float(
getattr(item_range, "allocation_weight", 1.0)
)
_scale_minutes_to_target(minutes_by_item, _target_effective_minutes(report, schedule))
rows: list[ReportAllocationDraft] = []
for item in items: