""" Printing 模块信号处理函数 监听 stateflow 信号,在流程完成时执行业务逻辑。 """ import logging from decimal import Decimal, InvalidOperation from django.conf import settings from django.db import transaction logger = logging.getLogger(__name__) def on_printing_job_process_completed(sender, **kwargs): """ PrintingJob 流程完成时的处理 当 PrintingJob 的工艺流程全部完成时,自动创建 SalesItem(销售品)。 数量和单位从指定的流程节点参数中获取(通过 settings 配置)。 配置项: AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER: 是否启用自动创建销售品(默认 True) PRINTING_SALES_ITEM_SOURCE_STATE_ID: 指定从哪个 State 获取参数 PRINTING_SALES_ITEM_QUANTITY_KEY: 数量参数的 key PRINTING_SALES_ITEM_UNIT_KEY: 单位参数的 key Args: sender: PrintingJob 类 content_object: PrintingJob 实例 business_object: BusinessObject 实例 last_completed_by: 最后步骤操作人 其他参数见 stateflow.signals.process_completed """ # 检查是否启用自动创建销售品 if not getattr(settings, 'AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER', True): logger.debug('[printing.handlers] AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER=False,跳过销售品创建') return from shipment.models import SalesItem, UnitChoices logger.info( f'[printing.handlers] 收到 process_completed 信号: ' f'sender={sender}, kwargs keys={list(kwargs.keys())}' ) content_object = kwargs.get('content_object') business_object = kwargs.get('business_object') last_completed_by = kwargs.get('last_completed_by') if content_object is None or business_object is None: logger.warning('process_completed 信号缺少 content_object 或 business_object') return printing_job = content_object logger.info(f'[printing.handlers] 处理 PrintingJob #{printing_job.id}') # 从 settings 获取配置 source_state_id = getattr(settings, 'PRINTING_SALES_ITEM_SOURCE_STATE_ID', None) quantity_key = getattr(settings, 'PRINTING_SALES_ITEM_QUANTITY_KEY', '米数') if source_state_id is None: logger.debug( f'PrintingJob #{printing_job.id} 流程完成,' f'但 PRINTING_SALES_ITEM_SOURCE_STATE_ID 未配置,跳过销售品创建' ) return # 从 business_object 的状态流转记录中找到指定 state_id 的记录 state_log = business_object.state_logs.filter( state_id=source_state_id, is_cancelled=False ).first() if state_log is None: logger.warning( f'PrintingJob #{printing_job.id} 流程完成,' f'但未找到 state_id={source_state_id} 的已完成记录,跳过销售品创建' ) return # 获取参数汇总 params = state_log.get_all_parameters_summary() # 获取数量 quantity_raw = params.get(quantity_key) if quantity_raw is None: logger.warning( f'PrintingJob #{printing_job.id} 流程完成,' f'但 state_id={source_state_id} 的参数中缺少 {quantity_key},跳过销售品创建' ) return # 转换数量为 Decimal try: quantity = Decimal(str(quantity_raw)) except (InvalidOperation, ValueError, TypeError) as e: logger.warning( f'PrintingJob #{printing_job.id} 流程完成,' f'但 {quantity_key}={quantity_raw} 无法转换为数字: {e},跳过销售品创建' ) return # 单位固定为"米" sales_unit = UnitChoices.METER # 获取产品名称 product_name = printing_job.product.name if printing_job.product else '未知产品' # 获取客户ID(从主订单获取) customer_id = None if printing_job.printing_order and printing_job.printing_order.customer: customer_id = printing_job.printing_order.customer_id try: with transaction.atomic(): sales_item = SalesItem.objects.create( shipment=None, # 暂不关联出货单,待后续分配 name=product_name, quantity=quantity, unit=sales_unit, created_by=last_completed_by, printing_job_id=printing_job.id, customer_id=customer_id, ) logger.info( f'PrintingJob #{printing_job.id} 流程完成,' f'已创建销售品 SalesItem #{sales_item.id}: ' f'{product_name} x {quantity} {sales_item.get_unit_display()}' ) except Exception as e: logger.error( f'PrintingJob #{printing_job.id} 流程完成后创建销售品失败: {e}', exc_info=True )