# 会员余额变动（GetMemberCardBalanceChange） → member_balance_changes 字段映射

> 生成时间：2026-02-14

## 端点信息

| 属性 | 值 |
|------|-----|
| 接口路径 | `MemberProfile/GetMemberCardBalanceChange` |
| 请求方法 | POST |
| ODS 对应表 | `ods.member_balance_changes` |
| JSON 数据路径 | `data.tenantMemberCardLogs` |

## 字段映射

| JSON 字段 | ODS 列名 | 类型转换 | 说明 |
|-----------|----------|----------|------|
| tenant_id | tenant_id | int→BIGINT（`parse_int`） | 租户/商户 ID，本数据中是固定值（同一品牌/商户） |
| site_id | site_id | int→BIGINT（`parse_int`） | 非 0：记录所属的具体门店 ID（与其他 JSON 内的 site_id 一致） |
| register_site_id | register_site_id | int→BIGINT（`parse_int`） | 会员卡的“注册门店 ID”，即办卡所在门店 |
| registerSiteName | registerSiteName | string→TEXT（原样） | 卡片的注册门店名称（办卡地点），和 register_site_id 配套 |
| paySiteName | paySiteName | string→TEXT（原样） | 发生本次余额变更的门店名称（即本次消费/充值所在门店） |
| id | id | int→BIGINT（`parse_int`） | 余额变更记录的主键 ID，唯一标识这一条“账户余额变化事件” |
| tenant_member_id | tenant_member_id | int→BIGINT（`parse_int`） | 商户维度的会员 ID（租户内会员主键） |
| tenant_member_card_id | tenant_member_card_id | int→BIGINT（`parse_int`） | 会员卡账户 ID，在租户内唯一标识某张卡 |
| system_member_id | system_member_id | int→BIGINT（`parse_int`） | 系统级（全局）会员 ID |
| memberName | memberName | string→TEXT（原样） | 会员姓名或称呼（非昵称字段） |
| memberMobile | memberMobile | string→TEXT（原样） | 会员手机号 |
| card_type_id | card_type_id | int→BIGINT（`parse_int`） | 卡种类型 ID，用于区分不同卡种 |
| memberCardTypeName | memberCardTypeName | string→TEXT（原样） | 卡种名称，与 card_type_id 一一对应，是一个 卡种枚举名称 |
| account_data | account_data | float→NUMERIC(18,2)（`parse_decimal`） | 本次变动的金额（元），正数表示增加，负数表示减少 |
| before | before | float→NUMERIC(18,2)（`parse_decimal`） | 本次变动前，该卡账户的余额（元） |
| after | after | float→NUMERIC(18,2)（`parse_decimal`） | 本次变动后，该卡账户的余额（元） |
| refund_amount | refund_amount | float→NUMERIC(18,2)（`parse_decimal`） | 可能用于标记“其中有多少金额是以‘退款’形式回流的”，或区分“退回余额”和“原路退回”两种模式 |
| from_type | from_type | int→INT（`parse_int`） | 来自 JSON 导出的原始字段，用于保留业务取值 |
| payment_method | payment_method | int→INT（`parse_int`） | 来自 JSON 导出的原始字段，用于保留业务取值 |
| relate_id | relate_id | int→BIGINT（`parse_int`） | 例如某次充值记录的 ID、某张订单/结算单 ID、某次活动抵用券核销记录 ID 等 |
| remark | remark | string→TEXT（原样） | 当为空时，说明这条变动没有额外备注说明 |
| operator_id | operator_id | int→BIGINT（`parse_int`） | 执行此次余额变更操作的员工 ID |
| operator_name | operator_name | string→TEXT（原样） | 操作员姓名（带职位前缀），是对 operator_id 的可读冗余字段 |
| is_delete | is_delete | int→INT（`parse_int`） | 逻辑删除标记（0=否，1=是） |
| create_time | create_time | string→TIMESTAMP（`parse_timestamp`） | 本条余额变更记录的创建时间，通常接近交易发生时间 |
| principal_after | principal_after | float→NUMERIC(18,2)（`parse_decimal`） | 变动后本金余额（新增字段） |
| principal_before | principal_before | float→NUMERIC(18,2)（`parse_decimal`） | 变动前本金余额（新增字段） |
| principal_data | principal_data | string→TEXT（原样） | 本金变动金额（新增字段） |

## ETL 补充字段

| ODS 列名 | 生成逻辑 |
|-----------|----------|
| content_hash | 对业务字段（排除 ETL 元数据列）计算 SHA-256，用于变更检测与去重 |
| source_file | 固定值：`member_balance_changes.json`，标识原始导出文件 |
| source_endpoint | API 端点路径，如 `MemberProfile/GetMemberCardBalanceChange` |
| fetched_at | ETL 入库时间戳（`TIMESTAMPTZ DEFAULT now()`） |
| payload | 完整原始 JSON 记录快照（`JSONB NOT NULL`），用于回溯与二次解析 |

## 类型转换规则

- **时间戳**：通过 `TypeParser.parse_timestamp()` 转换，支持 ISO 字符串和 Unix 毫秒时间戳，自动处理时区
- **金额**：通过 `TypeParser.parse_decimal(value, scale=2)` 转换，`ROUND_HALF_UP` 四舍五入
- **整数**：通过 `TypeParser.parse_int()` 转换，`None` 保持为 `NULL`
- **字符串**：原样保留，`None` / 空字符串均存为 `NULL` 或空文本
- **布尔值**：API 返回 `true/false`，ODS 存为 `BOOLEAN` 或 `INT`（0/1）
- **JSONB**：`siteProfile`、`payload` 等复合对象直接以 `JSONB` 类型存储
