forked from erp-dev/erp
5.9 KiB
5.9 KiB
2026-01-23 工作记录
1) 新增:企业微信机器人 Webhook(text 消息)util 与测试命令
- settings:
flower/settings.py新增WECOM_WEBHOOK_BASE_URL/WECOM_WEBHOOK_KEYWECOM_WEBHOOK_KEY已改为从.env读取(默认空);若为空,发送时会报错(不会静默吞掉)- 仓库内提供
env.example(等价于常见的.env.example),可用cp env.example .env生成本地.env
- util:
api_v1/utils/wecom_webhook.py- 提供
send_wecom_webhook_message(content=..., msgtype=..., key=..., timeout_seconds=...)msgtype支持:text(默认)、markdown
- command(通用测试发送):
api_v1/management/commands/wecom_webhook_send_text.py- 用法:
- text(默认):
uv run python manage.py wecom_webhook_send_text "hello world"
- markdown:
uv run python manage.py wecom_webhook_send_text "**bold**\n> hello" --msgtype markdown
- text(默认):
- 参数:
text:必填,消息内容--msgtype:可选,text(默认)或markdown--key:可选,临时覆盖.env的WECOM_WEBHOOK_KEY--timeout:可选,HTTP 超时秒数(默认 10)
2) 新增:PrintingJob 每次状态推进(state_advanced)发送企业微信 markdown 通知
- 信号来源:
stateflow.signals.state_advanced(每次推进都会触发,发送点在stateflow.services.advance_to_next_state()内) - 监听注册:
printing/apps.py里state_advanced.connect(..., sender=PrintingJob) - handler:
printing/handlers.py::on_printing_job_state_advanced- 使用
transaction.on_commit(...),确保事务提交后再发送企业微信(避免回滚导致通知不一致) - 发送内容(markdown)包含:
PrintingOrder.idPrintingJob.idstate.name- 推进时间(取
state_log.completed_at) - 发送者(默认取推进人
completed_by的员工姓名/username;兜底为“系统自动发送”)
- 使用
- 模板位置(便于后续改文案):
flower/settings.pyPRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE- 开关:
PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED(默认测试环境关闭,非测试环境开启) - 模板已增加字段:
{sender}(发送者) - 跟进地址:
.env:PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE(默认空)- 若为空则消息中省略“跟进地址”字段,但消息仍然发送
- 模板占位符:
{followup_line}(由 service 渲染:有 url 才会输出“跟进地址”行)
- 模板已增加字段:
{process_params_markdown}(工序参数,来自state_log.get_all_parameters_summary()) - 工序参数渲染增强:当参数值是 http/https URL(如图片链接)时,自动渲染为 markdown Link:
[url](url),便于点击查看
3) 重构:提取“发送最新状态到企业微信”逻辑为可复用 service(便于后续 API 化)
- 新增:
printing/services.pysend_printing_job_latest_state_wecom(printing_job_id, sender_label, ...)render_printing_job_state_markdown(...)
- command:
printing/management/commands/wecom_notify_printing_job_latest_state.py- 发送者强制为“系统自动发送”(后续 API 化可传入基于
request.user的 sender_label)
- 发送者强制为“系统自动发送”(后续 API 化可传入基于
3.1) command:发送某个 PrintingJob 的“最新状态”通知(可 dry-run)
- 文件:
printing/management/commands/wecom_notify_printing_job_latest_state.py - 用法:
- 预览(不发请求,适合只有 http 出网的机器):
uv run python manage.py wecom_notify_printing_job_latest_state <printing_job_id> --dry-run
- 实际发送(需要 https 出网 + 配置
.env的WECOM_WEBHOOK_KEY):uv run python manage.py wecom_notify_printing_job_latest_state <printing_job_id>
- 可选覆盖 key / timeout:
uv run python manage.py wecom_notify_printing_job_latest_state <printing_job_id> --key xxx --timeout 5
- 预览(不发请求,适合只有 http 出网的机器):
- 参数:
printing_job_id:必填,PrintingJob.id--dry-run:仅输出 markdown,不调用企业微信 webhook--key:可选,临时覆盖.env的WECOM_WEBHOOK_KEY--timeout:可选,HTTP 超时秒数(默认 10)
4) 排查:PrintingJob 查询 API(list / retrieve)均返回 “No PrintingJob matches the given query”
现象:
api_v1的 PrintingJob 查询接口(列表/单体)提示 “No PrintingJob matches the given query”,但数据库中确有数据。
排查路径与结论(仅排查,未改动代码):
PrintingJobViewSet:api_v1/views/printing/views.py::PrintingJobViewSet- 继承
CustomerVisibilityFilterMixin,其get_queryset()会先做 merchant 隔离,再做 客户可见性过滤。
- 继承
CustomerVisibilityFilterMixin.filter_by_merchant():api_v1/views/printing/mixins.py- 当前逻辑对非 superuser 强制
queryset.filter(merchant=emp.merchant)。 - 当历史数据存在
PrintingJob.merchant = NULL(或不等于当前员工 merchant)时,会被直接过滤掉,导致 list/retrieve 都“查不到”。
- 当前逻辑对非 superuser 强制
- 佐证:
api_v1/views/printing/test_printing_job_api.py中明确把测试用户设为superuser,并注释说明: “PrintingJobViewSet 默认做 merchant 隔离;本测试集不关注该隔离逻辑,设为 superuser 以避免因测试数据未设置 merchant 导致的 404/列表为空。”- 这与线上“明明有数据但 API 查不到”的现象一致(典型是 merchant 字段为空/不一致导致隔离过滤)。
建议方案(未实施):
- 保持多租户隔离前提下,对
merchant=NULL的历史数据做兼容:- 若模型自身
merchant为空,则可回退使用关联 customer 的 merchant(对 PrintingJob 可通过printing_order__customer__merchant)判断归属。 - 并补充非 superuser 的回归测试覆盖该历史数据场景。
- 若模型自身