""" Printing module business logic services """ from typing import Dict, Any, Tuple from django.conf import settings from django.db import transaction from django.contrib.contenttypes.models import ContentType from printing import models as printing_models from stateflow import models as stateflow_models from stateflow import services as stateflow_services class PrintingOrderService: """印染订单业务逻辑服务""" @staticmethod def get_default_process(): """获取默认流程""" process_id = getattr(settings, 'PRINTING_DEFAULT_PROCESS_ID', None) if not process_id: return None try: return stateflow_models.Process.objects.get(id=process_id) except stateflow_models.Process.DoesNotExist: return None @staticmethod def create_printing_order(data: Dict[str, Any], user) -> printing_models.PrintingOrder: """ 创建印染订单 Args: data: 订单数据 user: 当前用户 Returns: 创建的订单实例 """ # 如果未指定 process,使用默认值 if 'process' not in data or data['process'] is None: default_process = PrintingOrderService.get_default_process() if default_process: data['process'] = default_process # 绑定创建人 data['created_by'] = user # 绑定商户(从当前用户的 employee 获取) if hasattr(user, 'employee') and user.employee and user.employee.merchant: data['merchant'] = user.employee.merchant order = printing_models.PrintingOrder.objects.create(**data) # domain event: printing order created # handler will ensure transaction.on_commit for external side effects (e.g. WeCom notify) try: from printing.signals import printing_order_created printing_order_created.send( sender=printing_models.PrintingOrder, instance=order, created_by=user, ) except Exception: # signal should never break core create flow import logging logging.getLogger(__name__).exception( "[api_v1.views.printing.services] 触发 printing_order_created signal 失败(已忽略)" ) return order @staticmethod def update_printing_order( printing_order: printing_models.PrintingOrder, data: Dict[str, Any], user ) -> Tuple[bool, str, printing_models.PrintingOrder]: """ 更新印染订单 Args: printing_order: 订单实例 data: 更新数据 user: 当前用户 Returns: (success, message, updated_order) """ # 如果要修改 process,需要验证并同步 relink 所有 jobs 的 BusinessObject if 'process' in data and data['process'] != printing_order.process: new_process = data.get('process') if new_process is None: return False, '流程不能为空,无法修改流程', printing_order # 只要存在任意 job 已开始(有未撤销进度)则拒绝 if not printing_order.can_change_process(): return False, '存在已开始的印染任务,无法修改流程', printing_order from stateflow.services import relink_business_object_for_instance try: with transaction.atomic(): # relink 所有 jobs(jobs 未开始,允许重建并重新绑定 BO) for job in printing_order.printing_jobs.select_related('business_object').all(): relinked = relink_business_object_for_instance( instance=job, new_process=new_process, default_name=f"PrintingJob-{job.pk}", default_description=f"印染任务 {job.pk} 的流程实例", ) if relinked is None: raise RuntimeError(f'印染任务 {job.pk} 已存在有效进度,无法修改流程') # 最后更新订单流程 printing_order.process = new_process printing_order.save(update_fields=['process']) except RuntimeError as e: return False, str(e), printing_order # process 已处理完毕,避免后续通用字段更新再次覆盖 data = {k: v for k, v in data.items() if k != 'process'} # 更新字段 for field, value in data.items(): setattr(printing_order, field, value) printing_order.save() return True, '更新成功', printing_order @staticmethod def can_change_process(printing_order: printing_models.PrintingOrder) -> bool: """ 检查订单是否可以修改流程 Args: printing_order: 订单实例 Returns: 是否可以修改 """ return printing_order.can_change_process() @staticmethod def get_order_progress(printing_order: printing_models.PrintingOrder) -> int: """ 计算订单完成进度 Args: printing_order: 订单实例 Returns: 完成百分比 (0-100) """ return printing_order.progress class PrintingJobService: """印染任务业务逻辑服务""" @staticmethod @transaction.atomic def create_printing_job(data: Dict[str, Any], user) -> printing_models.PrintingJob: """ 创建印染任务 自动创建关联的 BusinessObject 实例 Args: data: 任务数据 user: 当前用户 Returns: 创建的任务实例 """ printing_order = data.get('printing_order') # 绑定创建人 data['created_by'] = user # 绑定商户(从当前用户的 employee 获取) if hasattr(user, 'employee') and user.employee and user.employee.merchant: data['merchant'] = user.employee.merchant # 创建 PrintingJob job = printing_models.PrintingJob.objects.create(**data) # 如果 PrintingOrder 有关联的流程,创建 BusinessObject if printing_order and printing_order.process: # 将流程实例绑定到该 PrintingJob(便于跨模块定位与审计) ct = ContentType.objects.get_for_model(printing_models.PrintingJob) business_object = stateflow_models.BusinessObject.objects.create( name=f"PrintingJob-{job.id}", process=printing_order.process, description=f"印染任务 {job.id} 的流程实例", content_type=ct, object_id=job.id, ) job.business_object = business_object job.save() return job @staticmethod def update_printing_job( printing_job: printing_models.PrintingJob, data: Dict[str, Any], user ) -> Tuple[bool, str, printing_models.PrintingJob]: """ 更新印染任务 Args: printing_job: 任务实例 data: 更新数据 user: 当前用户 Returns: (success, message, updated_job) """ # 更新字段 for field, value in data.items(): # 不允许直接修改 business_object if field == 'business_object': continue setattr(printing_job, field, value) printing_job.save() return True, '更新成功', printing_job @staticmethod def get_job_status(printing_job: printing_models.PrintingJob) -> Dict[str, Any]: """ 获取任务状态信息 Args: printing_job: 任务实例 Returns: 状态信息字典 """ return { 'status': printing_job.status, 'status_id': printing_job.status_id, 'is_completed': printing_job.is_completed, 'has_started': printing_job.has_started, }