1
0
forked from erp-dev/erp

feat: mission replied calling task

This commit is contained in:
2026-04-17 23:26:33 +08:00
parent e109c00837
commit 8b1afc64c5
22 changed files with 1056 additions and 95 deletions

View File

@@ -41,49 +41,27 @@
### 3.1 Notifier
`Notifier` 负责“怎么发”:
- `merchant`
- `name`
- `channel`
- `template_key`
- `is_enabled`
- `config`
- `description`
当前 `Notifier` 已不再直接持有 `event_key`
### 3.2 NotifierRoute
`NotifierRoute` 负责“何时发、发给谁”:
- `merchant`
- `notifier`
- `event_key`
- `mission_category`
- `is_enabled`
- `description`
其中:
- `mission_category = null` 表示该事件的通配路由
- `mission_category != null` 表示任务分类专用路由
### 3.3 约束设计
当前约束:
- `Notifier` 在同商户下 `name` 唯一
- `NotifierRoute` 在同一 `notifier + event_key + mission_category` 下唯一
- `NotifierRoute` 额外限制同一 `notifier + event_key` 只能有一条通配路由
## 4. 路由匹配规则
当前 `dispatch_notification_event(...)` 的匹配规则为:
1. 先按 `merchant + event_key + route.is_enabled=True + notifier.is_enabled=True` 查路由
2. 如果 payload 中带有 `category_id`
- 匹配该分类的专用路由
- 也允许匹配通配路由
3. 如果 payload 中没有 `category_id`
- 只匹配通配路由
@@ -91,11 +69,6 @@
- 只保留一条
- 优先保留专用路由
这样可以同时满足:
- 分类专用通知
- 默认兜底通知
- 多群并发通知
- 同一通知器不重复发送
## 5. 当前调用链
@@ -103,32 +76,14 @@
通知链路如下:
1. `mission.services` 在事务提交后发 signal
2. `mission.handlers` 构造 payload
3. payload 中已包含 `category_id``category_name`
4. handler 调用 `enqueue_notification_event(...)`
5. Celery task 调用 `dispatch_notification_event(...)`
6. notifier 根据 route 匹配命中的 `Notifier`
7. 渲染模板并调用 backend 发送
8. 记录路由日志和发送日志
## 6. 已接入的事件
当前 `mission` 已接入:
- `mission.created`
- `mission.replied`
- `mission.completed`
- `mission.reply_rejected`
- `mission.reopened`
- `mission.cancelled`
这些事件全部支持按任务分类路由。
- `mission.unreplied`
- `mission.unreplied` 并非由业务 signal 直接触发,而是由后台每分钟一次的扫描任务按任务对象上的提醒配置触发
## 7. 日志策略
当前日志覆盖以下节点:
- 事件入队
- 没有命中任何可用路由
- 路由命中成功
- backend 发送成功
@@ -146,26 +101,26 @@
当前后台提供两个对象:
- `Notifier`
- `NotifierRoute`
并且:
- `Notifier` 页面支持 inline 维护其下路由
- `NotifierRoute` 也支持单独管理
`Notifier` inline 场景下route 的 `merchant` 会自动同步为当前 notifier 的商户,避免管理人员重复录入。
## 11. Mission 上的未回复提醒状态字段
## 9. 迁移策略
当前未回复提醒的核心状态全部放在 `Mission` 对象自身:
本次从旧结构迁到新结构时,做了自动回填:
- `notify_if_unreplied`
- `unreplied_notify_interval_minutes`
- `unreplied_notify_max_count`
- `unreplied_notify_sent_count`
- `unreplied_last_notified_at`
- 对每条旧 `Notifier(event_key=...)`
- 自动创建一条 `NotifierRoute`
- `event_key` 原样继承
- `mission_category = null`
- `description` 标记为自动迁移生成
这样做的原因是:
- 配置和运行态统一放在任务对象上,最容易排查
- 不需要额外的提醒计划表或提醒历史表就能支撑当前需求
- 最大提醒次数和上次提醒时间都能直接在任务详情中观察到
这样旧配置不会因为结构调整而丢失。
## 10. 测试覆盖重点