1
0
forked from erp-dev/erp

feat: notification sending for printing order created

This commit is contained in:
2026-01-27 16:40:09 +08:00
parent 44557f3d0c
commit dffb4a3e03
8 changed files with 213 additions and 1 deletions

View File

@@ -12,8 +12,9 @@ class PrintingConfig(AppConfig):
def ready(self):
"""注册信号处理函数"""
from stateflow.signals import process_completed, state_advanced
from .models import PrintingJob
from .models import PrintingJob, PrintingOrder
from . import handlers
from .signals import printing_order_created
# 监听 PrintingJob 流程完成信号
process_completed.connect(
@@ -26,6 +27,13 @@ class PrintingConfig(AppConfig):
handlers.on_printing_job_state_advanced,
sender=PrintingJob
)
# 监听 PrintingOrder 创建事件(领域 signal
printing_order_created.connect(
handlers.on_printing_order_created,
sender=PrintingOrder,
dispatch_uid="printing.on_printing_order_created",
)
logger.info(
f'[printing.apps] 已注册 process_completed 信号处理器, '
@@ -34,4 +42,8 @@ class PrintingConfig(AppConfig):
logger.info(
f'[printing.apps] 已注册 state_advanced 信号处理器, '
f'sender={PrintingJob}, handler={handlers.on_printing_job_state_advanced}'
)
logger.info(
f'[printing.apps] 已注册 printing_order_created 信号处理器, '
f'sender={PrintingOrder}, handler={handlers.on_printing_order_created}'
)

View File

@@ -242,3 +242,88 @@ def on_printing_job_state_advanced(sender, **kwargs):
# 在事务提交后再发送,避免事务回滚但通知已发出
transaction.on_commit(_send_wecom)
def on_printing_order_created(sender, **kwargs):
"""
PrintingOrder 创建时的处理(领域 signalprinting.signals.printing_order_created
需求:
- 在事务提交后发送企业微信机器人通知markdown
- 消息字段(中文):
- 印染订单ID / human_id
- 创建时间
- 发送者(优先 created_by.employee.name / created_by.username
- 客户、面料、出货日期(可选字段,缺省展示为 '-'
"""
# 测试环境默认关闭,避免单测出网/刷屏
if not getattr(settings, "PRINTING_ORDER_CREATED_WECOM_NOTIFY_ENABLED", True):
return
if getattr(settings, "TESTING", False):
return
order = kwargs.get("instance")
created_by = kwargs.get("created_by")
if order is None:
logger.warning("[printing.handlers] printing_order_created 信号缺少 instance跳过通知")
return
try:
from printing.services import render_printing_order_created_markdown
created_at_dt = getattr(order, "created_at", None)
created_at = (
timezone.localtime(created_at_dt).strftime("%Y-%m-%d %H:%M:%S")
if created_at_dt is not None
else timezone.localtime(timezone.now()).strftime("%Y-%m-%d %H:%M:%S")
)
emp = getattr(created_by, "employee", None) if created_by else None
sender_label = getattr(emp, "name", None) if emp is not None else None
sender_label = sender_label or getattr(created_by, "username", None) if created_by else None
sender_label = sender_label or "系统自动发送"
customer_name = None
try:
customer = getattr(order, "customer", None)
customer_name = getattr(customer, "name", None) if customer else None
except Exception:
customer_name = None
outgoing_dt = getattr(order, "outgoing_date", None)
outgoing_date = (
timezone.localtime(outgoing_dt).strftime("%Y-%m-%d %H:%M:%S")
if outgoing_dt is not None
else "-"
)
message = render_printing_order_created_markdown(
printing_order_id=str(getattr(order, "id", "-") or "-"),
printing_order_human_id=str(getattr(order, "human_id", "-") or "-"),
created_at=str(created_at),
sender_label=str(sender_label),
customer_name=str(customer_name or "-"),
fabric=str(getattr(order, "fabric", "-") or "-"),
outgoing_date=str(outgoing_date),
)
except Exception:
logger.exception("[printing.handlers] 渲染企业微信消息失败,跳过通知")
return
def _send_wecom():
try:
from api_v1.utils.wecom_webhook import send_wecom_webhook_message
resp = send_wecom_webhook_message(content=message, msgtype="markdown")
if not resp.ok:
logger.warning(
"[printing.handlers] WeCom webhook 返回失败errcode=%s, errmsg=%s, raw=%s",
resp.errcode,
resp.errmsg,
resp.raw,
)
except Exception:
logger.exception("[printing.handlers] 发送 WeCom webhook 失败(已忽略,不影响主流程)")
# 在事务提交后再发送,避免事务回滚但通知已发出
transaction.on_commit(_send_wecom)

View File

@@ -254,3 +254,39 @@ def send_printing_job_latest_state_wecom(
"errcode": resp.errcode,
"errmsg": resp.errmsg,
}
def render_printing_order_created_markdown(
*,
printing_order_id: str,
printing_order_human_id: str,
created_at: str,
sender_label: str,
customer_name: str,
fabric: str,
outgoing_date: str,
) -> str:
template = getattr(
settings,
"PRINTING_ORDER_CREATED_WECOM_MARKDOWN_TEMPLATE",
(
"### 印染订单创建\n"
"\n"
"- **印染订单ID**`{printing_order_id}`\n"
"- **订单编号**`{printing_order_human_id}`\n"
"- **创建时间**`{created_at}`\n"
"- **发送者**{sender}\n"
"- **客户**{customer_name}\n"
"- **面料**{fabric}\n"
"- **出货日期**`{outgoing_date}`\n"
),
)
return template.format(
printing_order_id=str(printing_order_id),
printing_order_human_id=str(printing_order_human_id),
created_at=str(created_at),
sender=str(sender_label or "系统自动发送"),
customer_name=str(customer_name or "-"),
fabric=str(fabric or "-"),
outgoing_date=str(outgoing_date or "-"),
)

17
printing/signals.py Normal file
View File

@@ -0,0 +1,17 @@
"""
Printing domain signals.
We use domain-level signals (instead of model post_save) to:
- keep semantics clean (only fire on business "create" flow)
- allow passing explicit actor (created_by / sender_label)
- keep integration (e.g. WeCom notify) in handlers
"""
from django.dispatch import Signal
# Fired when a PrintingOrder is created via business service.
# Payload:
# - instance: PrintingOrder
# - created_by: Django User (may be None)
printing_order_created = Signal()