"""Small active Web mutation ports for ARR2.0.""" from __future__ import annotations import threading from dataclasses import dataclass from datetime import date from typing import Any, Dict, Protocol from arr_web.contracts import PortalError from monthly_reports.service import MonthlyReportService, RunRequest class UploadCoordinator(Protocol): def submit(self, original_filename: str, payload: bytes) -> Dict[str, Any]: ... class MonthlyCoordinator(Protocol): def generate(self, month_key: str, as_of_date: date) -> Dict[str, Any]: ... class UnavailableUploadCoordinator: def submit(self, original_filename: str, payload: bytes) -> Dict[str, Any]: raise PortalError( "PROCESSING_GATEWAY_UNAVAILABLE", "文件接收服务尚未完成生产接线", 503, ) class UnavailableMonthlyCoordinator: def generate(self, month_key: str, as_of_date: date) -> Dict[str, Any]: raise PortalError( "MONTHLY_GENERATOR_UNAVAILABLE", "月报生成服务暂不可用", 503, ) @dataclass class ProgramMonthlyCoordinator: """Run the deterministic monthly database program.""" service: MonthlyReportService def __post_init__(self) -> None: self._lock = threading.Lock() def generate(self, month_key: str, as_of_date: date) -> Dict[str, Any]: year, month = (int(part) for part in month_key.split("-")) request = RunRequest(year, month, as_of_date) try: request.validate() except Exception: raise PortalError("MONTHLY_REQUEST_INVALID", "月报日期范围无效") from None if not self._lock.acquire(blocking=False): raise PortalError("MONTHLY_ALREADY_RUNNING", "该服务正在生成月报", 409) try: result = self.service.run(request) finally: self._lock.release() payload = result.to_dict() if result.status != "success": error = payload.get("errors", [{}])[0] code = str(error.get("code") or "MONTHLY_GENERATION_FAILED") raise PortalError(code, "月报生成未完成", 422) return payload