Commit cc8c217c by luoqi

W4: 治疗事实信号源切到 EMR(treat_plan→actual / plan→planned),settlement 退出

语义修正背景(真实数据验证):
- EMR.treat_plan = 本次实际治疗(actual),字段名误导但语义就是 actual
- EMR.plan        = 未来计划(planned),2023+ host 启用
- settlement      = 财务事件,不是临床事件;颗粒度 1:N、0% 带牙位

改造前:
- treat_plan(actual)被当成 planned 
- plan 字段完全没消费 
- settlement 反推 treatment_actual,跟 EMR 双源混叠

改造后:
- treat_plan 真治疗 → treatment_actual_rows kind=actual  带 48.7% 牙位
- plan       真治疗 → treatment_planned_rows kind=planned  带牙位
- settlement 不再产 treatment_record,职责单一(LTV/退费)

文件改动:
- manifest.yaml § C:treat_plan + plan 双源 split + route(MVP:plan 的复查/建议暂 drop)
- manifest.yaml § D:删除 settlement → _treatment_actual_raw / treatment_actual_rows 派生
- assemblers/treatment_actual.yaml:source 切到 EMR,字典复用 treatment_planned.yaml 同款(200+ entries)
- assemblers/treatment_planned.yaml:仅头部注释更新(源切到 plan 字段)
- assemblers/refund.yaml / payment.yaml:不动(settlement 继续走这两路)

不动的下游:
- treatment.parser.ts:kind 由 emits.action 决定,yaml 改完自动正确
- chain-composer.service.ts / treatment-initiation-recall.scenario.ts:读 fact.kind 抽象层,自动受益

待办:
- 暂不重导(代码层先稳定);下一轮 TRUNCATE + cold-import 看真实效果
- recommendation_rows 双源 union(transforms 加 union op 或 parser 侧 dedup)
- treatment_review_rows 双源 union + kind 区分(actual review vs planned review)
- EMR 漏录 fallback:某些治疗只有 settlement 没 EMR.treat_plan 的兜底策略

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
parent 36686f66
# treatment_actual — 从 fact_settlement_out 反推已做治疗 # treatment_actual — EMR.treat_plan 本次实际治疗(actual)
# 消费 transforms 输出表 treatment_actual_rows(transforms.project + derive) #
# settlement_type 是闭集 ~45 个(DW 实测),enum_mapping 全枚举映射 PAC category # W4 末重大语义修正(详见 docs/dw-data-source-issues.md):
# - 原方案:从 fact_settlement_out 反推已做治疗(无牙位、颗粒度差、跟收费 1:N)
# - 新方案:从 EMR.treat_plan 字段(真实临床记录,48.7% 带牙位)取本次治疗
# - settlement 不再消费为 treatment_actual,只走 payment.yaml(LTV)+ refund.yaml(风险)
#
# 消费 transforms 输出表 treatment_actual_rows
# (来源:_treatment_actual_raw_emr ← _treat_plan_raw route 后剩下的"真治疗")
#
# 字段结构跟 treatment_planned.yaml 几乎相同(同源 _treat_plan_raw / _plan_raw 结构对称),
# 仅 kind=actual + occurredAt 用 rq(treat_plan 是已发生事实,occurredAt 准确反映)
canonical: treatment canonical: treatment
emits: emits:
...@@ -11,100 +20,254 @@ emits: ...@@ -11,100 +20,254 @@ emits:
primary: primary:
table: treatment_actual_rows table: treatment_actual_rows
key: id key: treat_external_id
dedup_by: id # settlement 表内多视角合一炸行兜底 dedup_by: treat_external_id # 炸行兜底:同 emr × treatName × tooth_position 因影像 JOIN 重复
field_mapping: field_mapping:
externalId: id externalId: treat_external_id
patientExternalId: patient_id patientExternalId: patient_id
clinicId: organization_id clinicId: organization_id
occurredAt: created_date # W3 末从 billing_date 升级 — 治疗实际发生时间最佳代理。 occurredAt: rq # treat_plan 已发生,rq=就诊日,actual 时点
# 真实语义对比: sourceEncounterExternalId: emr_id
# - billing_date = 开单/收费动作时间(团购券预付等场景在治疗前几小时,失真) category: category_raw # transforms 已带 treat_name 原文,这里 enum_mapping 翻译
# - created_date = 结算记录入库时间(治疗后医生录入,接近实际治疗时点) subtype: treat_name # 原始 treatName 留作 subtype(给 chain milestone 字典匹配)
# 全量 244 万对验证(瑞泰): toothPosition: tooth_position # ⭐ 关键升级:48.7% 带牙位,chain S3 牙位级判定可用
# - 100% created_date >= billing_date(永远是治疗时间下界) doctorId: user_id # 治疗医生(从 emr 父级继承)
# - 77% 完全相同,23% created 晚于 billing(预付场景) doctorName: doctor_name # 治疗医生名(快照)
# - settlement.created vs EMR.created p50 差 5min,51% 在 5min 内
# null/parse 失败:0(271 万行实测)。0.8% case 偏差 > 1 天是 host 后补录,本就该按 created 算。
category: category_raw # transforms.derive 已把 settlement_type 复制到这
subtype: settlement_project_name
status: settlement_type # 留原 settlement_type 文字作 status(parser 不强消费)
doctorId: doctor_id # 执行医生(医患关系信号,100% 充实)
sourceEncounterExternalId: registration_id # 反查接诊(99.999% 充实,之前漏接导致 source_encounter null)
quantity: settlement_num # 治疗份数(种植 4 颗 / 套餐 5 套…)
unitName: settlement_unit_name # 计量单位(颗/次/区/套)
# settlement_type 全枚举(实测 distinct ~45)→ PAC category # treatName 实测 21k distinct,top 100 cover 80%。下面是按实测高频 + 临床合理拼出来的白名单。
# 维护:DW 加新 settlement_type 时跑 SQL `SELECT DISTINCT settlement_type FROM fact_settlement_out` # 字典跟 treatment_planned.yaml 完全相同(同源 treat_name,只是 kind 不同)。
# 补到本表;长尾兜底 _default: '' parser 跳过 # 长尾兜底 _default: ""(parser 见空 category 跳过该 fact,数据损失换数据质量)。
#
# 维护:跑 SQL `SELECT JSONExtractString(t,'treatName') treat_name, count() FROM
# fact_emr_treatment_out ARRAY JOIN JSONExtractArrayRaw(coalesce(treat_plan,'[]')) AS t
# WHERE brand IN ('瑞泰','瑞尔') GROUP BY 1 ORDER BY 2 DESC LIMIT 200`
# 看新出现的高频 treat_name,补到对应 category。
enum_mapping: enum_mapping:
category: category:
# ── 种植(implant) # ── 牙周(periodontic)
种植手术: implant 龈上洁治: periodontic
种植耗材: implant "龈上洁治。": periodontic
种植基台: implant 龈上洁治术: periodontic
种植上部修复: prosthodontic # ⚠️ 注意:种植上部修复阶段算修复,不是种植 "龈上洁治术。": periodontic
种植体上部修复: prosthodontic "龈上洁治术/预防性洁治/洁牙/洗牙": periodontic
龈上洁治+牙周治疗: periodontic
# ── 牙髓 / 根管(endodontic) 全口龈上洁治: periodontic
根管: endodontic "全口龈上洁治、抛光。": periodontic
牙髓病: endodontic "全口龈上洁治,抛光。": periodontic
儿童-牙髓病: pediatric # 儿牙优先 "全口龈上洁治,抛光": periodontic
"全口龈上洁治。": periodontic
"全口龈上洁治术。": periodontic
全口洁治: periodontic
"全口洁治。": periodontic
全口洁牙: periodontic
全口超声洁治: periodontic
全口超声波洁治: periodontic
全口龈上超声洁治: periodontic
定期全口洁治: periodontic
"定期全口洁治\r\n": periodontic
"全口洁治\r\n": periodontic
定期洁牙: periodontic
洁牙: periodontic
洁治: periodontic
"洁治。": periodontic
洗牙: periodontic
洁治 OHI: periodontic
"洁治+OHI": periodontic
"龈上洁治;细洁": periodontic
"龈上洁治+细洁": periodontic
"龈上洁治+龈下细洁": periodontic
龈下细洁: periodontic
龈上超声洁治: periodontic
牙周基础治疗: periodontic
牙周系统治疗: periodontic
"牙周系统治疗。": periodontic
"OHI\r\n牙周系统治疗": periodontic
牙周治疗: periodontic
牙周维护: periodontic
牙周刮治: periodontic
牙周刮治术: periodontic
龈下刮治: periodontic
龈下刮治术: periodontic
"龈下刮治及根面平整术(>5mm牙周袋)/牙周刮治术/超声龈下清创术": periodontic
"龈下刮治及根面平整术(<5mm牙周袋)/牙周刮治术/超声龈下清创术": periodontic
根面平整术: periodontic
PMTC: periodontic
"PMTC+全口涂氟": periodontic
# ── 充填修复(restorative) # ── 充填修复(restorative)
充填: restorative 充填: restorative
"充填。": restorative
充填治疗: restorative
"充填治疗(乳牙单面洞)": restorative
充填术: restorative
树脂充填: restorative
光固化树脂充填: restorative
非美学区树脂充填: restorative
美学区简单树脂充填: restorative
"垫底+充填": restorative
重新充填: restorative
预防性充填: restorative
嵌体修复: restorative
嵌体: restorative 嵌体: restorative
龋病: restorative 戴嵌体: restorative
儿童-龋病: pediatric 龋齿充填: restorative
# ── 牙髓 / 根管(endodontic)
根管治疗: endodontic
"根管治疗(磨牙)": endodontic
"根管治疗(前牙及双尖牙单根管)": endodontic
"根管治疗(前牙及双尖牙多根管/显微根管)": endodontic
"根管治疗+冠修复": endodontic
"根管治疗+充填": endodontic
根管再治疗: endodontic
根管预备: endodontic
根管充填: endodontic
根充: endodontic
RCT: endodontic
牙髓治疗: endodontic
根尖诱导成形术: endodontic
拔髓: endodontic
干髓术: endodontic
盖髓术: endodontic
间接盖髓: endodontic
直接盖髓: endodontic
MTA盖髓: endodontic
冲洗上药: endodontic
# ── 种植(implant)
种植: implant
种植手术: implant
种植体植入: implant
种植修复: implant
种植戴牙: implant
种植一期: implant
种植二期: implant
种植三期: implant
种植耗材: implant
种植基台: implant
种植取模: implant
种植拆线: implant
"种植冠修复(非美学区单颗)": implant
"简单种植术(非美学区,单颗)": implant
"复杂种植术(非美学区,连续缺失/多颗)": implant
"复杂种植术(非美学区,伴同期上颌窦底内提升/同期GBR术)": implant
"复杂种植术(同期上颌窦底外提升术)": implant
"复杂种植术(美学区连续2颗以上或伴骨量不足及GBR术)": implant
即刻种植术: implant
拔除后种植修复: implant
延期种植术: implant
"延期种植术(美学区,单颗)": implant
# ── 修复(prosthodontic) # ── 修复(prostho)— 冠 / 桥 / 义齿 / 桩核
牙冠: prosthodontic 冠修复: prosthodontic
"冠修复(非美学区)": prosthodontic
"冠修复(简单美学区)": prosthodontic
全冠修复: prosthodontic
牙冠修复: prosthodontic
重新冠修复: prosthodontic
戴冠: prosthodontic
粘冠: prosthodontic
拆冠: prosthodontic
戴牙: prosthodontic
桩核: prosthodontic
桩核冠: prosthodontic
固定修复: prosthodontic 固定修复: prosthodontic
活动修复: prosthodontic 活动修复: prosthodontic
桩核: prosthodontic 重新修复: prosthodontic
儿童-牙冠: pediatric 修复: prosthodontic
预成冠修复: prosthodontic
# ── 牙周(periodontic) 牙体预备: prosthodontic
牙周: periodontic 取模: prosthodontic
调合: prosthodontic
调颌: prosthodontic
种植上部修复: prosthodontic
种植体上部修复: prosthodontic
# ── 外科(surgical) # ── 外科(surgical)— 拔除 / 智齿 / 残根残冠
牙外科: surgical 拔除: surgical
口腔外科: surgical "拔除。": surgical
儿童-牙外科: pediatric 拔除术: surgical
拔牙: surgical
牙拔除术: surgical
"牙拔除术(松动乳牙)": surgical
简单牙拔除术: surgical
松动恒牙拔除术: surgical
松动乳牙拔除术: surgical
择期拔除: surgical
阻生齿拔除术: surgical
阻生牙拔除: surgical
"智齿拔除术(正位)": surgical
"智齿拔除术(复杂)": surgical
残根拔除术: surgical
"残根(残冠)拔除术": surgical
"正畸牙拔除术(正位)": surgical
# ── 正畸(orthodontic) # ── 正畸(orthodontic)
正畸: orthodontic 正畸: orthodontic
正畸治疗: orthodontic
隐形正畸: orthodontic 隐形正畸: orthodontic
正畸矫治器: orthodontic 固定正畸: orthodontic
早期矫治: orthodontic
"合垫/预防性矫治/功能矫治/早期阻断性矫治": orthodontic
"简单前牙排齐/安氏I类非拔牙矫治": orthodontic
"安氏I类拔牙矫治(轻中度支抗)": orthodontic
"安氏II类非拔牙矫治-涉及后牙咬合关系调整": orthodontic
"安氏II类拔牙矫治(轻中度支抗)": orthodontic
"安氏II类拔牙矫治(强支抗/种植支抗)": orthodontic
"安氏III类非拔牙矫治-涉及后牙咬合关系调整": orthodontic
"安氏III类拔牙矫治(轻中度支抗)": orthodontic
保持器: orthodontic
正畸保持器: orthodontic 正畸保持器: orthodontic
正畸保持: orthodontic
正畸矫治器: orthodontic
正畸辅助治疗: orthodontic 正畸辅助治疗: orthodontic
正畸辅助附件: orthodontic 正畸加力: orthodontic
固定正畸: orthodontic "正畸加力。": orthodontic
儿童-正畸保持器: pediatric 加力: orthodontic
儿童-正畸矫治器: pediatric 粘附件: orthodontic
儿童-固定正畸: pediatric 粘接附件: orthodontic
"粘接全口附件。": orthodontic
重粘托槽: orthodontic
"重粘托槽。": orthodontic
精细调整: orthodontic
"精细调整。": orthodontic
"精调粘接附件。": orthodontic
发放矫治器: orthodontic
"发放新矫治器。": orthodontic
"去除矫正器,配戴保持器保持现有咬合关系。": orthodontic
# ── 预防(preventive)
涂氟: preventive
全口涂氟: preventive
"牙面清洁,涂氟": preventive
窝沟封闭: preventive
"窝沟封闭。": preventive
窝沟封闭术: preventive
OHI: preventive
"OHI,涂氟": preventive
"OHI,涂氟": preventive
口腔卫生宣教: preventive
口腔检查: preventive
全口检查: preventive
常规检查: preventive
脱敏: preventive
抛光: preventive
全景片: preventive
CBCT: preventive
曲面断层: preventive
根尖片: preventive
# ── 美学(cosmetic) # ── 美学(cosmetic)
美白: cosmetic
冷光美白: cosmetic
牙齿美白: cosmetic 牙齿美白: cosmetic
牙位图美白: cosmetic
贴面: cosmetic 贴面: cosmetic
贴面修复: cosmetic
# ── 预防 / 检查(preventive) # 长尾兜底:未命中 → category='',parser 跳过该 fact(silently warn)
预防: preventive # 故意不纳入(已被 transforms.route_by_pattern 分流走):
保健/预防: preventive # 常规复查 / 复查 / 定期复查 / 检查(无具体内容) / 暂观 / 观察 / 无治疗 / 重复 / 取资料 / 拆线
检查: preventive # 建议XX / 推荐XX(走 recommendation_record)
放射: preventive _default: ""
儿童-预防: pediatric
# ── 儿牙
儿科: pediatric
# ── 长尾杂项 → 不算治疗,丢 fact
麻醉: ""
儿童-麻醉: ""
诊疗服务: ""
其它收费项目: ""
其他: ""
加急费: ""
_default: "" # settlement_type 未识别 → parser 跳过(不入 fact)
# treatment_planned — EMR.treat_plan 真治疗动作(planned) # treatment_planned — EMR.plan 字段未来治疗计划(planned)
# 消费 transforms 输出表 treatment_planned_rows(route_by_pattern 后剩下的 = 排除复查/建议) #
# W4 末重大语义修正:
# - 原方案:从 EMR.treat_plan 拿"真治疗",标 planned(❌ 错!treat_plan 是 actual)
# - 新方案:从 EMR.plan 字段拿"未来计划",标 planned(✅ 字段语义对齐)
# - 字典(treat_name → category)完全跟 treatment_actual.yaml 相同,只是 kind 不同
#
# 消费 transforms 输出表 treatment_planned_rows
# (来源:_treatment_planned_raw_emr ← _plan_raw route 后剩下的"真治疗")
#
# plan 字段是 2023+ host 启用,老数据(2017-2022)plan 几乎空 → 老患者 planned 信号较少,正常
canonical: treatment canonical: treatment
emits: emits:
...@@ -17,12 +26,12 @@ field_mapping: ...@@ -17,12 +26,12 @@ field_mapping:
externalId: treat_external_id externalId: treat_external_id
patientExternalId: patient_id patientExternalId: patient_id
clinicId: organization_id clinicId: organization_id
occurredAt: rq occurredAt: rq # rq=就诊日(医生当天写的计划);plannedFor 由 parser 用此填
sourceEncounterExternalId: emr_id sourceEncounterExternalId: emr_id
category: category_raw # transforms 已带 treat_name 原文,这里 enum_mapping 翻译 category: category_raw # transforms 已带 treat_name 原文,这里 enum_mapping 翻译
subtype: treat_name # 原始 treatName 留作 subtype subtype: treat_name # 原始 treatName 留作 subtype
toothPosition: tooth_position toothPosition: tooth_position
doctorId: user_id # 计划医生(从 emr 父级继承) doctorId: user_id # 制定计划的医生(从 emr 父级继承)
doctorName: doctor_name # 计划医生名(快照) doctorName: doctor_name # 计划医生名(快照)
# treatName 实测 21k distinct,top 100 cover 80%。下面是按实测高频 + 临床合理拼出来的白名单。 # treatName 实测 21k distinct,top 100 cover 80%。下面是按实测高频 + 临床合理拼出来的白名单。
......
...@@ -233,7 +233,33 @@ transforms: ...@@ -233,7 +233,33 @@ transforms:
op: concat op: concat
parts: ['${emr_id}', '|', '${std_code_k}', '|', '${message_norm}', '|', '${tooth_position}'] parts: ['${emr_id}', '|', '${std_code_k}', '|', '${message_norm}', '|', '${tooth_position}']
# ── C. EMR.treat_plan JSON 拆行 → 治疗 / 推荐 / 流程性 三路分流 ── # ── C. EMR.treat_plan(本次治疗 actual)+ EMR.plan(未来计划 planned)双源 ──
#
# W4 末重大语义修正(真实数据 + 用户业务确认,详见 dw-data-source-issues.md):
# - `treat_plan` 字段 = **本次实际做的治疗(actual)**(字段名误导,真实是 actual)
# - `plan` 字段 = **未来计划(planned)**(2023+ host 启用,老数据空)
# - 历史上 treat_plan 是杂烩(老数据没 plan 字段,医生把"建议/暂观/复查"也塞这里)
# → 现 route_by_pattern 把这些分流走,剩下的才是真治疗 actual,合理
#
# 数据流:
# treat_plan → split → route:
# ① 建议/推荐 → recommendation_rows (kind=planned,医生当场给的健康路径)
# ② 复查/暂观 → treatment_review_rows (kind=planned,本次做的复查,chain S4 信号)
# ③ 真治疗 → treatment_actual_rows ⭐ (kind=actual,临床真实,带牙位 48.7%)
#
# plan → split → route:
# ① 建议/推荐 → drop(MVP,后续可加 union)
# ② 复查/暂观 → drop(避免 kind 冲突)
# ③ 真治疗 → treatment_planned_rows ⭐ (kind=planned,医生写好的下一步,带牙位)
#
# **settlement → treatment_actual 路径已删除**(原 § D 区段):
# - settlement = 财务事件 ≠ 临床事件;一次治疗 5-8 个收费项行 → 反推 actual 颗粒失真
# - settlement 0% 带牙位 vs EMR.treat_plan 48.7% 带牙位 → EMR 单源更精确
# - settlement 继续走 payment.yaml(LTV)+ refund.yaml(风险),职责单一
# - 边界:42% EMR 无 settlement(洁牙赠送/T+延迟)— 用 EMR 单源能正确算 actual
# - 反向 0% settlement 无 EMR(实测) — 不会丢治疗
# ── C.1 split treat_plan(本次治疗) ──
- kind: split_json_array - kind: split_json_array
input: fact_emr_treatment_out input: fact_emr_treatment_out
output: _treat_plan_raw output: _treat_plan_raw
...@@ -244,8 +270,8 @@ transforms: ...@@ -244,8 +270,8 @@ transforms:
organization_id: organization_id organization_id: organization_id
brand: brand brand: brand
rq: rq rq: rq
user_id: user_id # 计划医生(继承 emr 父级) user_id: user_id # 治疗医生(继承 emr 父级)
doctor_name: doctor_name # 计划医生名 doctor_name: doctor_name # 治疗医生名
element_fields: element_fields:
treat_name: treatName treat_name: treatName
tooth_position: toothPosition tooth_position: toothPosition
...@@ -253,16 +279,36 @@ transforms: ...@@ -253,16 +279,36 @@ transforms:
where: where:
treat_name: { not_empty: true } treat_name: { not_empty: true }
# C.1 按 treat_name 关键词分流到 3 张表 # ── C.2 split plan(未来计划)— W4 末新增 ──
- kind: split_json_array
input: fact_emr_treatment_out
output: _plan_raw
array_field: plan
parent_keys:
emr_id: id
patient_id: patient_id
organization_id: organization_id
brand: brand
rq: rq
user_id: user_id # 制定计划的医生
doctor_name: doctor_name
element_fields:
treat_name: treatName
tooth_position: toothPosition
plan_code: planCode
where:
treat_name: { not_empty: true }
# ── C.3 treat_plan 路由分流 ──
- kind: route_by_pattern - kind: route_by_pattern
input: _treat_plan_raw input: _treat_plan_raw
field: treat_name field: treat_name
routes: routes:
# 推荐建议(医生说"建议XX")→ recommendation_record(W5+ 还会接 Layer C LLM 抽取增强) # 建议/推荐(医生当场给的健康路径)→ recommendation_record
- output: _recommendation_raw - output: _recommendation_raw
when: when:
starts_with: ['建议', '推荐'] starts_with: ['建议', '推荐']
# 流程性事实(复查 / 拆线 / 观察 / 无治疗 / 重复 等)— W3 末加 review category # 流程性 / 复查 → treatment_review_rows(本次做的复查;chain S4 信号)
- output: _treatment_review_raw - output: _treatment_review_raw
when: when:
equals: equals:
...@@ -278,12 +324,42 @@ transforms: ...@@ -278,12 +324,42 @@ transforms:
- 重复 - 重复
- 取资料 - 取资料
- 暂观,必要时拔除 - 暂观,必要时拔除
# 真治疗动作 → treatment_record(planned) # 真治疗动作 → treatment_actual_rows ⭐ kind=actual(临床真实)
- output: _treatment_planned_raw - output: _treatment_actual_raw_emr
when: when:
default: true default: true
# C.2 推荐:派生 external_id + 暂时把 treat_name 当作"推荐码"原文(后续 yaml enum_mapping 翻译) # ── C.4 plan 路由分流(MVP:只取真治疗,推荐/复查暂 drop)──
- kind: route_by_pattern
input: _plan_raw
field: treat_name
routes:
# MVP:plan 的"建议"暂时 drop(transforms 无 union,合并 treat_plan 留 TODO)
- output: _drop_plan_recommendation
when:
starts_with: ['建议', '推荐']
# MVP:plan 的"复查/暂观"暂 drop(避免 kind 冲突,future review 信号待后续)
- output: _drop_plan_review
when:
equals:
- 常规复查
- 复查
- 定期复查
- 检查
- 初诊检查
- 拆线
- 暂观
- 观察
- 无治疗
- 重复
- 取资料
- 暂观,必要时拔除
# 真治疗动作 → treatment_planned_rows ⭐ kind=planned(医生写好的下一步)
- output: _treatment_planned_raw_emr
when:
default: true
# ── C.5 推荐(来自 treat_plan) ──
- kind: derive - kind: derive
input: _recommendation_raw input: _recommendation_raw
output: recommendation_rows output: recommendation_rows
...@@ -292,7 +368,7 @@ transforms: ...@@ -292,7 +368,7 @@ transforms:
op: concat op: concat
parts: ['${emr_id}', '|rec|', '${treat_name}', '|', '${tooth_position}'] parts: ['${emr_id}', '|rec|', '${treat_name}', '|', '${tooth_position}']
# C.3 复查类:treat_name 当 subtype,category 全部 'review'(yaml 里 enum_mapping 处理) # ── C.6 复查(来自 treat_plan,本次做的复查) ──
- kind: derive - kind: derive
input: _treatment_review_raw input: _treatment_review_raw
output: treatment_review_rows output: treatment_review_rows
...@@ -306,14 +382,27 @@ transforms: ...@@ -306,14 +382,27 @@ transforms:
from: __nonexistent_field__ from: __nonexistent_field__
value: _review_sentinel value: _review_sentinel
# C.4 真治疗:derive external_id,category_raw 留 treat_name 原文(yaml enum_mapping 翻译) # ── C.7 actual 治疗(来自 treat_plan)⭐ W4 末新增 ──
- kind: derive
input: _treatment_actual_raw_emr
output: treatment_actual_rows
fields:
treat_external_id:
op: concat
parts: ['${emr_id}', '|tx|act|', '${treat_name}', '|', '${tooth_position}']
category_raw:
op: default
from: treat_name
value: ''
# ── C.8 planned 治疗(来自 plan 字段)⭐ W4 末新增 ──
- kind: derive - kind: derive
input: _treatment_planned_raw input: _treatment_planned_raw_emr
output: treatment_planned_rows output: treatment_planned_rows
fields: fields:
treat_external_id: treat_external_id:
op: concat op: concat
parts: ['${emr_id}', '|tx|', '${treat_name}', '|', '${tooth_position}'] parts: ['${emr_id}', '|tx|plan|', '${treat_name}', '|', '${tooth_position}']
category_raw: category_raw:
op: default op: default
from: treat_name from: treat_name
...@@ -350,29 +439,15 @@ transforms: ...@@ -350,29 +439,15 @@ transforms:
op: concat op: concat
parts: ['${emr_id}', '|img|', '${file_path}'] parts: ['${emr_id}', '|img|', '${file_path}']
# ── D. settlement_out → treatment_actual_rows ── # ── D. settlement_out → refund_rows(退费)──
# SQL 已 WHERE is_refund=0 + status=1;此处不再拆,直接 project rename 准备 enum_mapping #
- kind: project # W4 末:settlement → treatment_actual 路径已删除(详见 § C 顶部注释)
input: fact_settlement_out # settlement 现在只服务两路:
output: _treatment_actual_raw # ① refund(本段)→ refund_rows → refund_record(LTV/风险算法)
keep: [id, organization_id, brand, patient_id, rq, billing_date, created_date, # ② payment_mode(§ E)→ payment_rows → payment_record(LTV/渠道分析)
settlement_type, doctor_id, #
settlement_project_name, settlement_money, settlement_num, settlement_unit_name, # 已治疗的"actual"信号源**只信任 EMR.treat_plan**(临床真实,带牙位),不再由 settlement 反推。
registration_id] #
rename:
settlement_id: id # 跟下游 yaml field_mapping 对齐
# D.1 settlement_type 当 category_raw,yaml enum_mapping 翻译到 PAC category(45 个枚举)
- kind: derive
input: _treatment_actual_raw
output: treatment_actual_rows
fields:
category_raw:
op: default
from: settlement_type
value: ''
# ── D.2 退费 → refund_rows ──
# SQL 已 WHERE is_refund=1 OR status=4;此处 project 准备 refund.yaml 消费。 # SQL 已 WHERE is_refund=1 OR status=4;此处 project 准备 refund.yaml 消费。
# refund.parser 侧 Math.abs(amount) 把 status=4 负 money 和 is_refund=1 正 money 都归一成"被退金额"正 cents。 # refund.parser 侧 Math.abs(amount) 把 status=4 负 money 和 is_refund=1 正 money 都归一成"被退金额"正 cents。
- kind: project - kind: project
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment