Files
wyndham-ARR/arr_web/services.py
2026-08-06 22:40:18 +08:00

128 lines
3.7 KiB
Python

"""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