from datetime import date from io import BytesIO from types import SimpleNamespace from openpyxl import load_workbook from app.routers import dashboard from app.services.excel_export import export_dashboard_rows def test_dashboard_rows_from_allocations_groups_by_allocation_date_desc(): report_date = date(2026, 7, 25) report = SimpleNamespace( id=1, attendance_point_name="总厂", report_date=report_date, employee_phone="13800000000", employee=SimpleNamespace(name="张三", is_temporary=False), items=[], audit_logs=[], session=None, is_system_auto_submitted=False, is_voided=False, is_multi_person_assistant=False, review_remark="复核通过", ) item = SimpleNamespace( id=10, attendance_point_name="总厂", device_no="A-01", project_no="P1", product_name="23#", process_name="冲压", remark=None, raw_material_batch_no="BATCH-1", material_code="M-1", material_name="铝材", profile_no="PF-1", stamping_method="单冲", operator_count=1, process_unit_price_yuan=2, standard_beat=1, good_qty=650, defect_qty=0, scrap_qty=0, changeover_count=2, allocated_minutes=650, ) report.items = [item] allocations = [ SimpleNamespace( report=report, item=item, allocation_date=date(2026, 7, 24), night_minutes=350, overtime_minutes=0, day_minutes=0, effective_minutes=350, good_qty=350, defect_qty=0, scrap_qty=0, changeover_count=1, reference_wage=350, ), SimpleNamespace( report=report, item=item, allocation_date=date(2026, 7, 25), night_minutes=0, overtime_minutes=60, day_minutes=240, effective_minutes=300, good_qty=300, defect_qty=0, scrap_qty=0, changeover_count=1, reference_wage=300, ), ] rows = dashboard._dashboard_rows_from_allocations(allocations) assert [row.report_date for row in rows] == [date(2026, 7, 25), date(2026, 7, 24)] assert [row.source_report_dates for row in rows] == [[report_date], [report_date]] assert [row.source_report_date for row in rows] == [report_date, report_date] assert [row.report_count for row in rows] == [1, 1] current, previous = rows assert current.effective_minutes == 300 assert current.shift_day_minutes == 240 assert current.shift_overtime_minutes == 60 assert current.shift_night_minutes == 0 assert current.total_good_qty == 300 assert current.total_defect_qty == 0 assert current.total_output_qty == 300 assert current.changeover_count == 1 assert current.reference_wage == 300 assert previous.effective_minutes == 350 assert previous.shift_day_minutes == 0 assert previous.shift_overtime_minutes == 0 assert previous.shift_night_minutes == 350 assert previous.total_good_qty == 350 assert previous.total_defect_qty == 0 assert previous.total_output_qty == 350 assert previous.changeover_count == 1 assert previous.reference_wage == 350 def test_export_dashboard_rows_writes_allocation_and_source_dates_with_warning_columns(): row = SimpleNamespace( attendance_point_name="总厂", report_date=date(2026, 7, 24), source_report_dates=[date(2026, 7, 25), date(2026, 7, 23)], source_report_date=None, employee_name="张三", employee_phone="13800000000", worker_type="正式工", project_no="P1", product_name="23#", process_name="冲压", effective_minutes=60, shift_distribution_text="白班1小时", total_good_qty=50, total_defect_qty=2, expected_workload=100, actual_beat=20, standard_beat=10, profile_no="PF-1", material_code="M-1", material_name="铝材", raw_material_batch_no="BATCH-1", device_no="A-01", stamping_method="单冲", changeover_count=1, operator_count=1, process_unit_price_yuan=2, reference_wage=100, is_voided=False, is_multi_person=False, is_continuous_die=False, correction_pairs=[], review_remark="复核通过", ) workbook = load_workbook(BytesIO(export_dashboard_rows([row]))) sheet = workbook["报工看板"] assert [sheet.cell(row=1, column=index).value for index in range(1, 5)] == [ "考勤点", "统计归属日期", "原始报工日期", "员工姓名", ] assert sheet.cell(row=2, column=2).value == "2026-07-24" assert sheet.cell(row=2, column=3).value == "2026-07-23、2026-07-25" assert sheet.cell(row=2, column=12).fill.fgColor.rgb == "FFFF6666" assert sheet.cell(row=2, column=15).fill.fgColor.rgb == "FFFF6666"