# refund — fact_settlement_out 退费明细(独立 fact_type refund_record)
# 消费 transforms 输出表 refund_rows(SQL WHERE is_refund=1 OR settlement_status=4)
#
# 双轨判定 — host 退费两种表达方式都收:
#   ① is_refund=1            (显式标记的退费单,settlement_money 通常 > 0 表示"被退金额")
#   ② settlement_status=4    (反向结算单,settlement_money 通常 < 0 表示"金额冲减")
# refund.parser 侧 Math.abs(amount) 统一成正 cents(语义 = 患者拿回的钱)
#
# 用途:
#   - LTV 算法:value.feature.ts 已 SUM(refund.amount) 扣减 LTV
#   - 5 阶段闭环风控:chain-composer.hasPostS3Refund 查"S3 后是否有退费"决定 S5
#   - UI 时间轴:详情页"2026-03-15 退费 ¥3000(原因 X)" 独立事件
canonical: refund

emits:
  action: refund_created
  subjectType: refund
  occurredAtField: refundedAt
  kind: actual

primary:
  table: refund_rows
  key: id
  dedup_by: id   # 同 settlement_id 不应重复(SQL 已去重)

field_mapping:
  externalId:        id
  # W4 末 DW upsert:updatedAt 进 source_event_id 幂等键,host UPDATE → 新 transaction(否则永久 dedup 漏 update)
  updatedAt:         updated_date
  createdAt:         created_date
  patientExternalId: patient_id
  clinicId:          organization_id
  # 退费时间 = created_date(结算记录入库时间)— 跟 payment / treatment 口径一致
  refundedAt:        created_date
  # 金额 — yaml 直接映射 settlement_money(可能正可能负);parser 侧 Math.abs() 归一为正 cents
  amount:            settlement_money
  # 反查关联的接诊(同 registration_id 找到对应 payment)
  # 注:fact_settlement_out 没有"原 payment_id" 字段,只能靠 registration_id + 业务 reconcile
  # 后续 host 若提供 original_settlement_id 再升级 paymentExternalId 映射
  # reason 字段 host 暂无 — 待 DW 补"退费原因" 字段后映射
