from __future__ import annotations import csv from pathlib import Path from uuid import uuid4 from playwright.sync_api import Page, expect from tests.e2e.helpers import download_via_action, expect_flash, expect_path, login, upload_file def _unique_suffix() -> str: return uuid4().hex[:8] def _read_csv_text(file_path: Path) -> str: return file_path.read_text(encoding="utf-8-sig") def test_admin_can_download_export_preview_and_confirm_csv_import( page: Page, base_url: str, admin_credentials: dict[str, str], tmp_path: Path, ) -> None: suffix = _unique_suffix() household_code = f"CSV-{suffix}".upper() head_name = f"CSV导入户{suffix}" login( page, base_url, username=admin_credentials["username"], password=admin_credentials["password"], expected_path="/", ) template_path = tmp_path / f"template-{suffix}.csv" download_via_action( page, lambda: page.get_by_role("link", name="下载 CSV 模板").click(), template_path, ) template_content = _read_csv_text(template_path) assert "household_code,head_name,phone,side,invite_status" in template_content export_all_path = tmp_path / f"export-all-{suffix}.csv" download_via_action( page, lambda: page.get_by_role("link", name="导出全部").click(), export_all_path, ) export_all_content = _read_csv_text(export_all_path) assert "李阿姨" in export_all_content assert "陈老师" in export_all_content page.locator("#main-search").fill("李阿姨") page.locator("#main-search").press("Enter") export_filtered_path = tmp_path / f"export-filtered-{suffix}.csv" download_via_action( page, lambda: page.get_by_role("link", name="导出当前筛选").click(), export_filtered_path, ) export_filtered_content = _read_csv_text(export_filtered_path) assert "李阿姨" in export_filtered_content assert "陈老师" not in export_filtered_content page.get_by_role("link", name="导入 CSV").click() expect_path(page, base_url, "/csv/households/import") expect(page.get_by_role("heading", name="CSV 导入导出")).to_be_visible() import_file_path = tmp_path / f"import-{suffix}.csv" with import_file_path.open("w", encoding="utf-8", newline="") as csv_file: writer = csv.writer(csv_file) writer.writerow( [ "household_code", "head_name", "phone", "side", "invite_status", "attendance_status", "expected_attendee_count", "actual_attendee_count", "child_count", "red_packet_child_count", "total_gift_amount", "gift_method_option_code", "gift_scene_option_code", "favor_status", "candy_status", "child_red_packet_status", "note", ], ) writer.writerow( [ household_code, head_name, "13600136000", "groom_side", "confirmed", "attending", "4", "4", "1", "1", "999.00", "cash", "wedding_day", "given", "given", "partial", "CSV 导入创建", ], ) upload_file(page, "#csv-file", import_file_path) page.get_by_role("button", name="生成导入预览").click() expect_flash(page, "CSV 预览已生成,请先检查无效行和冲突行。") expect(page.get_by_role("heading", name="导入预览")).to_be_visible() expect(page.get_by_text(head_name)).to_be_visible() expect(page.get_by_text(household_code)).to_be_visible() expect(page.get_by_text("新增候选")).to_be_visible() page.locator("#conflict-mode").select_option("update_by_code") page.get_by_role("button", name="确认导入").click() expect_path(page, base_url, "/") expect_flash(page, "CSV 导入完成:新增 1 户,更新 0 户,跳过 0 行,无效 0 行。") page.locator("#main-search").fill(head_name) page.locator("#main-search").press("Enter") results_table = page.locator("#household-results-region table") expect(results_table.get_by_text(head_name)).to_be_visible() expect(results_table.get_by_text(household_code)).to_be_visible()