"""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 DailyPriceReviewCoordinator(Protocol): def get_price_review(self, job_id: str, limit: int, offset: int) -> Dict[str, Any]: ... def update_price_review_item( self, job_id: str, item_id: int, case_id: str, revision: int, real_price: str, actor_username: str, ) -> Dict[str, Any]: ... def finalize_price_review( self, job_id: str, case_id: str, revision: int, actor_username: str, ) -> Dict[str, Any]: ... def cancel_price_review( self, job_id: str, case_id: str, revision: int, actor_username: str, ) -> 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 UnavailableDailyPriceReviewCoordinator: @staticmethod def _raise() -> None: raise PortalError("PROCESSING_GATEWAY_UNAVAILABLE", "人工价格复核服务暂不可用", 503) def get_price_review(self, job_id: str, limit: int, offset: int) -> Dict[str, Any]: self._raise() def update_price_review_item( self, job_id: str, item_id: int, case_id: str, revision: int, real_price: str, actor_username: str ) -> Dict[str, Any]: self._raise() def finalize_price_review( self, job_id: str, case_id: str, revision: int, actor_username: str ) -> Dict[str, Any]: self._raise() def cancel_price_review( self, job_id: str, case_id: str, revision: int, actor_username: str ) -> Dict[str, Any]: self._raise() 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