forked from erp-dev/erp
feat: improved wecomm message field
This commit is contained in:
@@ -36,6 +36,8 @@
|
|||||||
- `PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE`
|
- `PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE`
|
||||||
- 开关:`PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED`(默认测试环境关闭,非测试环境开启)
|
- 开关:`PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED`(默认测试环境关闭,非测试环境开启)
|
||||||
- 模板已增加字段:`{sender}`(发送者)
|
- 模板已增加字段:`{sender}`(发送者)
|
||||||
|
- 模板已增加字段:`{followup_url}`(跟进地址,来自 `PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE`)
|
||||||
|
- 模板已增加字段:`{process_params_markdown}`(工序参数,来自 `state_log.get_all_parameters_summary()`)
|
||||||
|
|
||||||
#### 3) 重构:提取“发送最新状态到企业微信”逻辑为可复用 service(便于后续 API 化)
|
#### 3) 重构:提取“发送最新状态到企业微信”逻辑为可复用 service(便于后续 API 化)
|
||||||
|
|
||||||
|
|||||||
@@ -270,6 +270,11 @@ else:
|
|||||||
# PrintingJob:状态推进时的企业微信通知(markdown)
|
# PrintingJob:状态推进时的企业微信通知(markdown)
|
||||||
# - 默认:测试环境关闭(避免单测出网/刷屏),非测试环境开启
|
# - 默认:测试环境关闭(避免单测出网/刷屏),非测试环境开启
|
||||||
PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED = (not TESTING)
|
PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED = (not TESTING)
|
||||||
|
# PrintingJob 跟进地址(用于企业微信通知里展示/点击)
|
||||||
|
# orderId 使用 PrintingOrder.id
|
||||||
|
PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE = (
|
||||||
|
"https://app.yuwen.cloud/workstation/production/batch-advance?orderId={order_id}"
|
||||||
|
)
|
||||||
PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE = (
|
PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE = (
|
||||||
"### 印染任务状态推进\n"
|
"### 印染任务状态推进\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -278,6 +283,10 @@ PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE = (
|
|||||||
"- **推进状态**:**{state_name}**\n"
|
"- **推进状态**:**{state_name}**\n"
|
||||||
"- **推进时间**:`{advanced_at}`\n"
|
"- **推进时间**:`{advanced_at}`\n"
|
||||||
"- **发送者**:{sender}\n"
|
"- **发送者**:{sender}\n"
|
||||||
|
"- **跟进地址**:[{followup_url}]({followup_url})\n"
|
||||||
|
"\n"
|
||||||
|
"**工序参数**:\n"
|
||||||
|
"{process_params_markdown}\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -191,18 +191,6 @@ def on_printing_job_state_advanced(sender, **kwargs):
|
|||||||
else timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M:%S')
|
else timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
)
|
)
|
||||||
|
|
||||||
template = getattr(
|
|
||||||
settings,
|
|
||||||
'PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE',
|
|
||||||
(
|
|
||||||
"### PrintingJob 状态推进\n"
|
|
||||||
"\n"
|
|
||||||
"- **PrintingOrder.id**: `{printing_order_id}`\n"
|
|
||||||
"- **PrintingJob.id**: `{printing_job_id}`\n"
|
|
||||||
"- **State**: **{state_name}**\n"
|
|
||||||
"- **AdvancedAt**: `{advanced_at}`\n"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
sender_label = None
|
sender_label = None
|
||||||
completed_by = kwargs.get('completed_by')
|
completed_by = kwargs.get('completed_by')
|
||||||
if completed_by:
|
if completed_by:
|
||||||
@@ -212,13 +200,33 @@ def on_printing_job_state_advanced(sender, **kwargs):
|
|||||||
else:
|
else:
|
||||||
sender_label = '系统自动发送'
|
sender_label = '系统自动发送'
|
||||||
|
|
||||||
message = template.format(
|
# 工序参数:取该 state_log 的最新汇总
|
||||||
printing_order_id=str(printing_order_id) if printing_order_id is not None else '-',
|
try:
|
||||||
printing_job_id=str(printing_job_id) if printing_job_id is not None else '-',
|
params = state_log.get_all_parameters_summary(include_cancelled=False) if state_log else {}
|
||||||
state_name=str(state_name),
|
except Exception:
|
||||||
advanced_at=str(advanced_at),
|
logger.exception('[printing.handlers] 读取工序参数失败,降级为空')
|
||||||
sender=str(sender_label),
|
params = {}
|
||||||
)
|
|
||||||
|
try:
|
||||||
|
from printing.services import (
|
||||||
|
build_printing_job_followup_url,
|
||||||
|
render_printing_job_state_markdown,
|
||||||
|
render_process_params_markdown,
|
||||||
|
)
|
||||||
|
followup_url = build_printing_job_followup_url(printing_order_id=printing_order_id)
|
||||||
|
process_params_markdown = render_process_params_markdown(params=params)
|
||||||
|
message = render_printing_job_state_markdown(
|
||||||
|
printing_order_id=str(printing_order_id) if printing_order_id is not None else '-',
|
||||||
|
printing_job_id=str(printing_job_id) if printing_job_id is not None else '-',
|
||||||
|
state_name=str(state_name),
|
||||||
|
advanced_at=str(advanced_at),
|
||||||
|
sender_label=str(sender_label),
|
||||||
|
followup_url=str(followup_url),
|
||||||
|
process_params_markdown=str(process_params_markdown),
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
logger.exception('[printing.handlers] 渲染企业微信消息失败,跳过通知')
|
||||||
|
return
|
||||||
|
|
||||||
def _send_wecom():
|
def _send_wecom():
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -24,6 +24,49 @@ class PrintingJobLatestState:
|
|||||||
advanced_at: str
|
advanced_at: str
|
||||||
|
|
||||||
|
|
||||||
|
def build_printing_job_followup_url(*, printing_order_id: int | None) -> str:
|
||||||
|
tmpl = getattr(
|
||||||
|
settings,
|
||||||
|
"PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE",
|
||||||
|
"https://app.yuwen.cloud/workstation/production/batch-advance?orderId={order_id}",
|
||||||
|
)
|
||||||
|
oid = printing_order_id if printing_order_id is not None else ""
|
||||||
|
try:
|
||||||
|
return str(tmpl).format(order_id=str(oid))
|
||||||
|
except Exception:
|
||||||
|
# template mis-config should not crash critical flows
|
||||||
|
return f"https://app.yuwen.cloud/workstation/production/batch-advance?orderId={oid}"
|
||||||
|
|
||||||
|
|
||||||
|
def _truncate_text(s: str, max_len: int) -> str:
|
||||||
|
s = s or ""
|
||||||
|
if len(s) <= max_len:
|
||||||
|
return s
|
||||||
|
return s[: max(0, int(max_len) - 6)] + "...(截断)"
|
||||||
|
|
||||||
|
|
||||||
|
def render_process_params_markdown(*, params: dict, max_items: int = 60, max_value_len: int = 200) -> str:
|
||||||
|
"""
|
||||||
|
Render process params as markdown lines.
|
||||||
|
Example:
|
||||||
|
- **温度**:25
|
||||||
|
"""
|
||||||
|
if not params:
|
||||||
|
return "- (无)"
|
||||||
|
|
||||||
|
items = []
|
||||||
|
for k in sorted(params.keys(), key=lambda x: str(x)):
|
||||||
|
v = params.get(k)
|
||||||
|
kk = _truncate_text(str(k), 80)
|
||||||
|
vv = _truncate_text(str(v), int(max_value_len))
|
||||||
|
items.append(f"- **{kk}**:{vv}")
|
||||||
|
|
||||||
|
if len(items) > int(max_items):
|
||||||
|
remain = len(items) - int(max_items)
|
||||||
|
items = items[: int(max_items)] + [f"- ……(其余 {remain} 项已省略)"]
|
||||||
|
return "\n".join(items)
|
||||||
|
|
||||||
|
|
||||||
def _user_label(user) -> str:
|
def _user_label(user) -> str:
|
||||||
"""
|
"""
|
||||||
Format a human-readable sender label from Django User.
|
Format a human-readable sender label from Django User.
|
||||||
@@ -71,6 +114,8 @@ def render_printing_job_state_markdown(
|
|||||||
state_name: str,
|
state_name: str,
|
||||||
advanced_at: str,
|
advanced_at: str,
|
||||||
sender_label: str,
|
sender_label: str,
|
||||||
|
followup_url: str,
|
||||||
|
process_params_markdown: str,
|
||||||
) -> str:
|
) -> str:
|
||||||
template = getattr(
|
template = getattr(
|
||||||
settings,
|
settings,
|
||||||
@@ -83,6 +128,10 @@ def render_printing_job_state_markdown(
|
|||||||
"- **推进状态**:**{state_name}**\n"
|
"- **推进状态**:**{state_name}**\n"
|
||||||
"- **推进时间**:`{advanced_at}`\n"
|
"- **推进时间**:`{advanced_at}`\n"
|
||||||
"- **发送者**:{sender}\n"
|
"- **发送者**:{sender}\n"
|
||||||
|
"- **跟进地址**:[{followup_url}]({followup_url})\n"
|
||||||
|
"\n"
|
||||||
|
"**工序参数**:\n"
|
||||||
|
"{process_params_markdown}\n"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return template.format(
|
return template.format(
|
||||||
@@ -91,6 +140,8 @@ def render_printing_job_state_markdown(
|
|||||||
state_name=str(state_name),
|
state_name=str(state_name),
|
||||||
advanced_at=str(advanced_at),
|
advanced_at=str(advanced_at),
|
||||||
sender=str(sender_label or "系统自动发送"),
|
sender=str(sender_label or "系统自动发送"),
|
||||||
|
followup_url=str(followup_url),
|
||||||
|
process_params_markdown=str(process_params_markdown),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -113,17 +164,45 @@ def send_printing_job_latest_state_wecom(
|
|||||||
if not job:
|
if not job:
|
||||||
raise ValueError(f"PrintingJob 不存在:id={printing_job_id}")
|
raise ValueError(f"PrintingJob 不存在:id={printing_job_id}")
|
||||||
|
|
||||||
latest = get_printing_job_latest_state(job=job)
|
# latest state log for parameters
|
||||||
|
state_log = (
|
||||||
|
job.business_object.state_logs.filter(is_cancelled=False)
|
||||||
|
.select_related("state")
|
||||||
|
.order_by("-completed_at", "-id")
|
||||||
|
.first()
|
||||||
|
if job.business_object
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
if state_log is None:
|
||||||
|
state_name = "未开始"
|
||||||
|
advanced_at = "-"
|
||||||
|
params = {}
|
||||||
|
else:
|
||||||
|
state_name = getattr(state_log.state, "name", None) or str(state_log.state)
|
||||||
|
advanced_at = timezone.localtime(state_log.completed_at).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
params = state_log.get_all_parameters_summary(include_cancelled=False)
|
||||||
|
|
||||||
|
followup_url = build_printing_job_followup_url(printing_order_id=job.printing_order_id)
|
||||||
|
process_params_markdown = render_process_params_markdown(params=params)
|
||||||
msg = render_printing_job_state_markdown(
|
msg = render_printing_job_state_markdown(
|
||||||
printing_order_id=str(job.printing_order_id),
|
printing_order_id=str(job.printing_order_id),
|
||||||
printing_job_id=str(job.id),
|
printing_job_id=str(job.id),
|
||||||
state_name=latest.state_name,
|
state_name=str(state_name),
|
||||||
advanced_at=latest.advanced_at,
|
advanced_at=str(advanced_at),
|
||||||
sender_label=sender_label,
|
sender_label=sender_label,
|
||||||
|
followup_url=followup_url,
|
||||||
|
process_params_markdown=process_params_markdown,
|
||||||
)
|
)
|
||||||
|
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return {"dry_run": True, "message": msg, "state_name": latest.state_name, "advanced_at": latest.advanced_at}
|
return {
|
||||||
|
"dry_run": True,
|
||||||
|
"message": msg,
|
||||||
|
"state_name": str(state_name),
|
||||||
|
"advanced_at": str(advanced_at),
|
||||||
|
"followup_url": str(followup_url),
|
||||||
|
"process_params": params,
|
||||||
|
}
|
||||||
|
|
||||||
resp = send_wecom_webhook_message(
|
resp = send_wecom_webhook_message(
|
||||||
content=msg,
|
content=msg,
|
||||||
@@ -134,8 +213,10 @@ def send_printing_job_latest_state_wecom(
|
|||||||
return {
|
return {
|
||||||
"dry_run": False,
|
"dry_run": False,
|
||||||
"message": msg,
|
"message": msg,
|
||||||
"state_name": latest.state_name,
|
"state_name": str(state_name),
|
||||||
"advanced_at": latest.advanced_at,
|
"advanced_at": str(advanced_at),
|
||||||
|
"followup_url": str(followup_url),
|
||||||
|
"process_params": params,
|
||||||
"wecom": resp.raw,
|
"wecom": resp.raw,
|
||||||
"ok": resp.ok,
|
"ok": resp.ok,
|
||||||
"errcode": resp.errcode,
|
"errcode": resp.errcode,
|
||||||
|
|||||||
Reference in New Issue
Block a user