2026-10-22-basic-experiment-delivery-remind-design.md 6.1 KB

基础实验交付日前一天 · 服务号微信提醒设计

日期:2026-10-22
工程:backend(定时任务 + 服务号模板消息)
相关:docs/superpowers/specs/2026-08-13-oa-wechat-service-notify-design.md
范围:仅 基础实验申请单(biz_type=basic_experiment)交付计划


1. 背景与目标

1.1 现状

  • 基础实验申请单创建时,每行细胞产品独立生成一条交付计划;交付时间存于 biz_pilot_infusion_schedule.infusion_time(前端字段 pickupTime,界面文案「交付时间」)。
  • 服务号模板消息发送链路已存在(wechat_mp_message._send_template、wx_mp_openid 绑定),目前仅 OA 事件驱动使用。
  • APScheduler 已启动,但无业务 Job。

1.2 目标

在交付时间前一天固定 10:00,向创建该基础实验申请单的人发送微信服务号模板消息,提醒次日交付/出库。

1.3 非目标

  • 中试服务 / 临床应用申请单。
  • 向客户、渠道等非系统用户推送。
  • 点击消息跳转小程序详情(首期纯模板通知即可;可选带 miniprogram,失败则降级,与 OA 一致)。
  • 按「交付时间 − 24 小时」精确推送。

2. 已确认决策

决策点 结论
触发方式 每日 10:00(服务器本地时区)定时扫描
扫描条件 biz_type=basic_experiment;交付日 = 明天;计划未删除;计划状态非已取消(schedule_status != yqx)
接收人 申请单 create_by → sys_user.wx_mp_openid;未绑定则 skip + 日志
模板 ID oQNU3t0Q5kwc4KPJ8Z6yPA-k6qlsH9pikSCIb4eAwgM(配置可覆盖)
出库时间 细胞产品行的交付时间(infusion_time)
产品名称 projectName 拼接 规格 specText、产品包装 packageText,格式:名称(规格、包装);缺段时省略空括号内容
件数 产品 quantity
客户名称 / 收货联系人 申请单 customer_name / customer_contact
幂等 按「交付计划 ID + 提醒日(交付日前一天的日期)」记发送成功记录,防多实例/重跑重复推
开关 沿用 WX_MP_NOTIFY_ENABLED;另需本模板 ID 配置非空才发送

3. 模板字段映射

模板 ID:oQNU3t0Q5kwc4KPJ8Z6yPA-k6qlsH9pikSCIb4eAwgM

模板字段 业务含义 数据来源
thing6 客户名称 biz_pilot_application.customer_name
thing10 产品名称 project_name(spec_text、package_text),见 §2;thing 约 20 字截断
character_string8 产品件数 biz_pilot_infusion_schedule_product.quantity(字符串)
thing7 收货联系人 biz_pilot_application.customer_contact
time14 出库时间 biz_pilot_infusion_schedule.infusion_time,格式 YYYY-MM-DD HH:MM

产品名称拼接规则(空段跳过):

  • 三者皆有:{projectName}({specText}、{packageText})
  • 仅名称+规格:{projectName}({specText})
  • 仅名称+包装:{projectName}({packageText})
  • 仅名称:{projectName}

基础实验一产品一行计划,取该计划下唯一(或首条)产品明细。


4. 架构与数据流

APScheduler Cron 每天 10:00
  → job: basic_experiment_delivery_remind
  → 查询:明天有 infusion_time 的基础实验交付计划(未取消)
  → 对每条计划:
       查申请单 create_by → wx_mp_openid
       查幂等记录,已成功则 skip
       组装模板 data → _send_template
       成功则写幂等记录

4.1 新增配置(Settings / env)

配置项 说明 默认
WX_MP_TEMPLATE_BASIC_EXPERIMENT_DELIVERY 模板 ID 空;部署填入给定 ID
WX_MP_TPL_BE_DELIVERY_FIELD_CUSTOMER 客户名称字段 thing6
WX_MP_TPL_BE_DELIVERY_FIELD_PRODUCT 产品名称字段 thing10
WX_MP_TPL_BE_DELIVERY_FIELD_QTY 件数字段 character_string8
WX_MP_TPL_BE_DELIVERY_FIELD_CONTACT 联系人字段 thing7
WX_MP_TPL_BE_DELIVERY_FIELD_TIME 时间字段 time14

发送前提与 OA 一致:WX_MP_NOTIFY_ENABLED=true、服务号 appid/secret、接收人已绑 openid、已关注服务号。

4.2 幂等表

表名建议:biz_wx_notify_log(若首期未建 OA 日志表,本需求一并落地;若已有则复用)。

最小字段:

  • id、tenant_no
  • biz_type:如 basic_experiment_delivery_remind
  • biz_id:交付计划 schedule_id
  • notify_date:提醒日 YYYY-MM-DD(交付日前一天)
  • user_id、status(success/fail)、errcode、errmsg
  • 公共字段:create_by、create_time、del_flag 等(符合 database-conventions)

唯一约束:(tenant_no, biz_type, biz_id, notify_date) 或等价业务唯一键。

4.3 代码落点

模块 职责
app/services/wechat_mp_message.py 新增 send_basic_experiment_delivery_remind(...)
app/services/basic_experiment_delivery_remind.py 扫描、组装、幂等、调用发送
app/tasks/ 注册 Cron hour=10, minute=0
docs/sql/migrations/ 幂等表 DDL
backend/tests/ 拼接规则、扫描日界、幂等、跳过未绑定

5. 错误处理

  • 发送失败:记日志 + 幂等表 fail(可选);次日不再针对同一提醒日重试(提醒日已过);同日 Job 重跑可再试未 success 的记录。
  • 无 openid / 无交付时间 / 已取消:skip,不写 success。
  • 推送失败不影响申请单业务读写。

6. 测试要点

  • 产品名称拼接与截断。
  • 仅 basic_experiment;交付日 = 明天才命中。
  • 已取消计划不发。
  • 同一 schedule + notify_date 第二次不发。
  • 无 wx_mp_openid 不发。

7. 部署注意

  1. 执行幂等表迁移 SQL。
  2. 配置 WX_MP_TEMPLATE_BASIC_EXPERIMENT_DELIVERY 与 WX_MP_NOTIFY_ENABLED=true。
  3. 确认创建人已走服务号绑定(与 OA 同一套)。
  4. 多实例部署时依赖幂等表防重;若生产多 worker,仅一实例跑 scheduler 或接受幂等冲突吞掉重复。