You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
7.3 KiB
Python

from app.api.v1.module_common.file.crud import FileCRUD
from app.api.v1.module_energy.report_template.crud import EnergyReportTemplateCRUD
from app.api.v1.module_system.user.crud import UserCRUD
from app.core.base_schema import AuthSchema
from app.core.exceptions import CustomException
from .crud import EnergyReportReviewCRUD
from .schema import (
EnergyReportReviewCreateSchema,
EnergyReportReviewOutSchema,
EnergyReportReviewQueryParam,
EnergyReportReviewStatsSchema,
EnergyReportReviewUpdateSchema,
)
ENERGY_REPORT_REVIEW_BUSINESS_TYPE = "energy_report_review"
class EnergyReportReviewService:
"""能源报告审核任务服务。"""
def __init__(self, auth: AuthSchema) -> None:
self.auth = auth
async def detail(self, id: int) -> EnergyReportReviewOutSchema:
review = await EnergyReportReviewCRUD(self.auth).get_or_404(id=id)
return self._to_out_schema(review)
async def page(
self,
page_no: int,
page_size: int,
search: EnergyReportReviewQueryParam | None = None,
order_by: list[dict[str, str]] | None = None,
) -> dict:
search_dict = vars(search) if search else None
stats = await self._stats(search_dict=self._build_stats_search(search_dict))
offset = (page_no - 1) * page_size
page_result = await EnergyReportReviewCRUD(self.auth).page(
offset=offset,
limit=page_size,
order_by=order_by or [{"id": "desc"}],
search=search_dict,
out_schema=EnergyReportReviewOutSchema,
)
items = [self._fill_out_dict(item) for item in page_result.items]
return {
"page_no": page_result.page_no,
"page_size": page_result.page_size,
"total": page_result.total,
"has_next": page_result.has_next,
"stats": stats.model_dump(),
"items": items,
}
async def create(self, data: EnergyReportReviewCreateSchema) -> EnergyReportReviewOutSchema:
await self._validate_template(template_id=data.template_id)
await self._validate_file(file_id=data.file_id)
await self._validate_reviewer(reviewer_id=data.reviewer_id)
review = await EnergyReportReviewCRUD(self.auth).create(data=data)
await self._bind_file(file_id=data.file_id, review_id=review.id)
return self._to_out_schema(review)
async def update(self, id: int, data: EnergyReportReviewUpdateSchema) -> EnergyReportReviewOutSchema:
old_review = await EnergyReportReviewCRUD(self.auth).get_or_404(id=id, msg="更新失败,能源报告审核任务不存在")
await self._validate_template(template_id=data.template_id)
await self._validate_file(file_id=data.file_id, current_review_id=id)
await self._validate_reviewer(reviewer_id=data.reviewer_id)
review = await EnergyReportReviewCRUD(self.auth).update(id=id, data=data)
if old_review.file_id != data.file_id:
await self._unbind_file(file_id=old_review.file_id, review_id=id)
await self._bind_file(file_id=data.file_id, review_id=id)
return self._to_out_schema(review)
async def delete(self, ids: list[int]) -> None:
if len(ids) < 1:
raise CustomException(msg="删除失败,删除对象不能为空")
reviews = await EnergyReportReviewCRUD(self.auth).get_list(search={"id": ("in", ids)})
review_map = {review.id: review for review in reviews}
for review_id in ids:
if review_id not in review_map:
raise CustomException(msg="删除失败,能源报告审核任务不存在")
for review in reviews:
await self._unbind_file(file_id=review.file_id, review_id=review.id)
await EnergyReportReviewCRUD(self.auth).delete(ids=ids)
async def _stats(self, search_dict: dict | None = None) -> EnergyReportReviewStatsSchema:
records = await EnergyReportReviewCRUD(self.auth).get_list(search=search_dict or {})
return EnergyReportReviewStatsSchema(
submitted_count=len(records),
reviewed_count=len([record for record in records if record.status == 1]),
pending_count=len([record for record in records if record.status == 0]),
failed_count=len([record for record in records if record.status == 2]),
)
def _build_stats_search(self, search_dict: dict | None = None) -> dict:
if not search_dict:
return {}
stats_keys = {"created_time", "updated_time", "tenant_id", "created_id", "updated_id"}
return {key: value for key, value in search_dict.items() if key in stats_keys and value is not None}
def _to_out_schema(self, review) -> EnergyReportReviewOutSchema:
review_out = EnergyReportReviewOutSchema.model_validate(review)
if review_out.template:
review_out.template_name = review_out.template.template_name
if review_out.file:
review_out.file_url = review_out.file.file_url
review_out.original_name = review_out.file.original_name
if hasattr(review, "reviewer") and review.reviewer:
review_out.reviewer_name = review.reviewer.name
return review_out
def _fill_out_dict(self, item: dict) -> dict:
template_info = item.get("template") or {}
file_info = item.get("file") or {}
reviewer_info = item.get("reviewer") or {}
item["template_name"] = template_info.get("template_name")
item["file_url"] = file_info.get("file_url")
item["original_name"] = file_info.get("original_name")
item["reviewer_name"] = reviewer_info.get("name")
return item
async def _validate_template(self, template_id: int) -> None:
template = await EnergyReportTemplateCRUD(self.auth).get(id=template_id)
if not template:
raise CustomException(msg="能源报告模板不存在")
async def _validate_file(self, file_id: int, current_review_id: int | None = None) -> None:
file_record = await FileCRUD(self.auth).get(id=file_id)
if not file_record:
raise CustomException(msg="文件记录不存在")
if file_record.business_type and file_record.business_type != ENERGY_REPORT_REVIEW_BUSINESS_TYPE:
raise CustomException(msg="文件已绑定到其他业务类型")
if file_record.business_id and file_record.business_id != current_review_id:
raise CustomException(msg="文件已绑定到其他能源报告审核任务")
async def _validate_reviewer(self, reviewer_id: int | None) -> None:
if reviewer_id is None:
return
reviewer = await UserCRUD(self.auth).get(id=reviewer_id)
if not reviewer:
raise CustomException(msg="审查人不存在")
async def _bind_file(self, file_id: int, review_id: int) -> None:
await FileCRUD(self.auth).set(
ids=[file_id],
business_type=ENERGY_REPORT_REVIEW_BUSINESS_TYPE,
business_id=review_id,
)
async def _unbind_file(self, file_id: int, review_id: int) -> None:
file_record = await FileCRUD(self.auth).get(id=file_id)
if not file_record:
return
if file_record.business_type == ENERGY_REPORT_REVIEW_BUSINESS_TYPE and file_record.business_id == review_id:
await FileCRUD(self.auth).set(ids=[file_id], business_id=None)