1
0
forked from erp-dev/erp
Files
erpnew/docs/2026-01-23_summary.md

5.9 KiB
Raw Blame History

2026-01-23 工作记录

1) 新增:企业微信机器人 Webhooktext 消息util 与测试命令

  • settings
    • flower/settings.py 新增 WECOM_WEBHOOK_BASE_URL / WECOM_WEBHOOK_KEY
    • WECOM_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:必填,消息内容
      • --msgtype:可选,text(默认)或 markdown
      • --key:可选,临时覆盖 .envWECOM_WEBHOOK_KEY
      • --timeout可选HTTP 超时秒数(默认 10

2) 新增PrintingJob 每次状态推进state_advanced发送企业微信 markdown 通知

  • 信号来源:stateflow.signals.state_advanced(每次推进都会触发,发送点在 stateflow.services.advance_to_next_state() 内)
  • 监听注册:printing/apps.pystate_advanced.connect(..., sender=PrintingJob)
  • handlerprinting/handlers.py::on_printing_job_state_advanced
    • 使用 transaction.on_commit(...),确保事务提交后再发送企业微信(避免回滚导致通知不一致)
    • 发送内容markdown包含
      • PrintingOrder.id
      • PrintingJob.id
      • state.name
      • 推进时间(取 state_log.completed_at
      • 发送者(默认取推进人 completed_by 的员工姓名/username兜底为“系统自动发送”
  • 模板位置(便于后续改文案):flower/settings.py
    • PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE
    • 开关:PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED(默认测试环境关闭,非测试环境开启)
    • 模板已增加字段:{sender}(发送者)
    • 跟进地址:
      • .envPRINTING_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.py
    • send_printing_job_latest_state_wecom(printing_job_id, sender_label, ...)
    • render_printing_job_state_markdown(...)
  • commandprinting/management/commands/wecom_notify_printing_job_latest_state.py
    • 发送者强制为“系统自动发送”(后续 API 化可传入基于 request.user 的 sender_label
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 出网 + 配置 .envWECOM_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
  • 参数:
    • printing_job_id必填PrintingJob.id
    • --dry-run:仅输出 markdown不调用企业微信 webhook
    • --key:可选,临时覆盖 .envWECOM_WEBHOOK_KEY
    • --timeout可选HTTP 超时秒数(默认 10

4) 排查PrintingJob 查询 APIlist / retrieve均返回 “No PrintingJob matches the given query”

现象:

  • api_v1 的 PrintingJob 查询接口(列表/单体)提示 “No PrintingJob matches the given query”但数据库中确有数据。

排查路径与结论(仅排查,未改动代码):

  • PrintingJobViewSetapi_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 都“查不到”。
  • 佐证:
    • 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 的回归测试覆盖该历史数据场景。