深色模式
eDDA 代扣入金
本页说明
讲什么:eDDA 授权生命周期、eDDI 扣款执行流程、汇丰与恒生的协议差异、异常场景与错误码 适合谁:需要理解"用户一键入金"背后完整链路的产品经理 前置阅读:入金方式总览预计阅读:5 分钟 负责人:入金产品经理
核心要点:eDDA 是授权,eDDI 是扣款——两个分离步骤实现"用户一键入金"。汇丰用 OTP 短信 + 令牌桶并发,恒生用数字证书 + 悲观锁串行,协议差异是两家银行最大的区别。
快速跳转 — 你可能想做的事:
- 用户 eDDA 授权失败,怎么办?→ 授权失败错误码 + 排障 § 场景七
- 用户 eDDA 扣款被拒,怎么办?→ 恒生扣款被拒 / 汇丰扣款被拒
- 汇丰和恒生有什么区别?→ 汇丰 vs 恒生协议差异
- 想给新银行加 eDDA?→ 变更指南 § 新增 eDDA
- 周末/维护时段能用 eDDA 吗?→ 处理时段与维护窗口
eDDA 与 eDDI 是什么
eDDA(Electronic Direct Debit Authorization)和 eDDI(Electronic Direct Debit Instruction)是两个分离的步骤:
| 概念 | 全称 | 作用 | 频率 |
|---|---|---|---|
| eDDA | 电子直接付款授权 | 用户授权 moomoo 从其银行账户扣款 | 一次性,授权后长期有效 |
| eDDI | 电子直接付款指令 | moomoo 向银行发送具体的扣款指令 | 每次入金一次 |
为什么分离:监管要求银行在执行代扣前,必须先获得账户持有人的明确授权。eDDA 解决"谁允许扣",eDDI 解决"扣多少"。
与出金无关:eDDA/eDDI 仅用于入金代扣。汇丰和恒生的出金通道是企业网银转账,不是 eDDI。
PM 视角
eDDA 入金是转化率最高的入金方式——用户无需切换到银行 App,在 moomoo 内一键完成。理解这条链路的每个环节,是优化入金体验的基础。
授权生命周期
授权状态机
| 状态码 | 常量 | 含义 | 用户感知 |
|---|---|---|---|
| 3 | EDDA_STATUS_WAITING | 等待授权——申请已创建,尚未发送到银行 | "授权处理中" |
| 1 | EDDA_STATUS_PENDING | 授权中——请求已发送,等待银行回复 | "授权处理中" |
| 2 | EDDA_STATUS_EFFECT | 授权成功——可以发起 eDDI 扣款 | "已授权" |
| 0 | EDDA_STATUS_FAIL | 授权失败——银行拒绝 | 显示具体失败原因 |
数据表:setup_eddis,按 uid + bank_card_number 唯一标识一条授权记录。
授权轮询机制
授权请求发送后,银行不会立即返回结果。系统通过 SetupEddaCheckAuthorizationJob 定时轮询银行授权状态:
| 参数 | 值 | 说明 |
|---|---|---|
| 轮询间隔 | 600 秒(10 分钟) | 每次检查一次银行端授权状态 |
| 最大重试 | ~3,000 次 | 约 20 天后停止轮询 |
| 触发时机 | 用户提交授权申请后入队 | SetupEddaCheckAuthorizationJob::enqueue() |
配置位置
- 轮询间隔:硬编码于
SetupEddaCheckAuthorizationJob的 enqueue delay - 最大重试:Job 框架的 max_attempts 配置
- 代码路径:
deposit/src/app/Business/Job/Deposit/SetupEddaCheckAuthorizationJob.php
授权失败错误码
银行返回的错误码存储在 setup_eddis.error_code 字段。以下是完整的错误码映射:
| 错误码 | 失败原因 | 用户提示 | 失败类型 |
|---|---|---|---|
MFISAC01 | 账户号码错误 | 请输入正确的账户号码 | eDDA 授权 |
MPP01005 | 证件类型/号码错误 | 请核对证件类型和号码 | eDDA 授权 |
MPP01006 | 与银行绑定手机号不一致 | 请输入正确的手机号 | eDDA 授权 |
MPP01007 | 授权账户与姓名不匹配 | 请核对账户与姓名 | eDDA 授权 |
MPP01008 | 银行未绑定手机号码 | 请联系银行绑定手机号 | eDDA 授权 |
MPP01023 | 银行绑定手机号码错误 | 请联系银行修改绑定手机号 | eDDA 授权 |
MPP02003 | 银行账户号码错误 | 请重新输入正确的账户号码 | eDDA 授权 |
MPP02011 | 银行账户号码错误 | 请重新输入正确的账户号码 | eDDA 授权 |
MPP02013 | 银行未绑定手机号码 | 请联系银行绑定手机号 | eDDA 授权 |
MPP02035 | 银行账户号码错误 | 请重新输入正确的账户号码 | eDDA 授权 |
MPP02040 | 银行账户号码错误 | 请重新输入正确的账户号码 | eDDA 授权 |
MPP03001 | 银行账户类型异常 | 请联系银行处理 | eDDA 授权 |
MPP04000 | 验证码无效 | 请重新获取 | eDDA 授权 |
MPP04003 | 验证码错误 | 请重新输入 | eDDA 授权 |
MPP04004 | 验证码已过期 | 请重新获取 | eDDA 授权 |
MPP06001 | 银行账户状态异常 | 请联系银行处理 | eDDA 授权 |
ECH09001 | 银行授权失败(通用) | 请确认信息正确后重新授权 | eDDA 授权 |
配置位置
代码路径:deposit/src/app/Business/SetupEddi.php:91-113 — errorCodeMessageDict()
扣款执行流程
任务链
用户发起 eDDA 入金后,系统通过异步 Job 链执行扣款:
| 步骤 | Job / 方法 | 职责 |
|---|---|---|
| 1 | ApplyFollowJob | 检查申请状态,路由到对应银行的 eDDI 创建逻辑 |
| 2 | Eddi::applyHsEddi() / Eddi::applyHsbcEddi() | 获取 eDDA 授权信息,标记 Apply 为已使用,创建扣款记录 |
| 3 | SBA HsEddi/HsbcEddi.create() | 向 SBA 服务发送扣款 Procedure 创建请求 |
| 4 | HsEddiResultJob / HsbcEddiResultJob | 轮询 SBA Procedure 状态,获取银行处理结果 |
| 5 | 入账 / 失败处理 | 成功:写入银行流水 + SBA 执行入账;失败:更新 setup_eddis 状态 |
防重复扣款机制
| 机制 | 实现方式 | 防护场景 |
|---|---|---|
| Apply 占用锁 | Apply::setUsed() 原子更新 | 同一申请不会被两个 Job 同时处理 |
| apply_id 唯一索引 | hsbc_eddis / hs_eddis 表的 unique index | 同一申请只生成一条扣款记录 |
| request_id 幂等 | SBA 端按 request_id 去重 | 网络重试不会导致重复扣款 |
| SBA 创建重试 | HsbcEddiSBACreateRetryJob / HsEddiSBACreateRetryJob | SBA 创建失败时延迟 60 秒重试 |
eDDI 入金类型
eDDI 入金区分为 6 种子类型,决定入金后资金是否被冻结:
| 代码 | 常量 | 含义 | 资金是否冻结 |
|---|---|---|---|
| 1 | FOUNDING_AIP | 基金定投 | 否 |
| 2 | STOCK_MP | 股票定投 | 否 |
| 3 | FUND_PURCHASE | 购买基金 | 否 |
| 11 | FUND_HOLD | 基金定投 + 冻结 | 是 |
| 21 | STOCK_HOLD | 股票定投 + 冻结 | 是 |
| 31 | FUND_PURCHASE_HOLD | 购买基金 + 冻结 | 是 |
冻结的含义:代码 11/21/31 的入金,资金到账后会被系统冻结,预留给对应的投资操作(定投扣款、基金申购)。冻结释放时机由投资侧系统控制。
对应的 DepositType 为 NORMAL_HOLD = 11(入金类型速查 → 入金规则速查 § 入金类型)。
配置位置
代码路径:deposit/src/app/Common/EddiDepositType.php
HOLD_LIST = [11, 21, 31]— 需要冻结的类型列表ALL_LIST = [1, 2, 3, 11, 21, 31]— 全部类型
如果需求变更:eDDA/eDDI 相关
| 变更 | 改动位置 | 说明 |
|---|---|---|
| 新增 eDDI 入金类型 | EddiDepositType.php + SBA 编排配置 | 加枚举值,配置是否冻结 |
| 修改扣款币种 | sba_hsbc_eddi / sba_hase_eddi 请求参数 | 当前仅支持 HKD |
| 修改轮询间隔 | sba_hsbc_eddi_worker.ini / sba_hase_eddi 配置 | 调整 rush/normal 间隔 |
| 修改令牌桶速率(汇丰) | sba_hsbc_eddi token_bucket 守护进程 | 调整 frequency 参数 |
| 更换恒生数字证书 | sba_hase_eddi/conf/ | 替换 P12 文件和密码 |
| 新增 eDDA 支持银行 | 见 入金变更指南 § 场景八 | 涉及商务+技术+SBA,数月周期 |
eDDA 支持范围
汇丰通道支持的银行(15 家)
通过汇丰通道发起的 eDDA,支持以下 15 家银行的个人账户:
| 银行 | 银行代码 | 接入日期 | 备注 |
|---|---|---|---|
| 汇丰 HSBC | 004 | 初始 | 同行扣款 |
| 恒生 Hang Seng | 024 | 初始 | 跨行扣款 |
| 中银 BOCHK | 012 | 2021-06 | 跨行扣款 |
| 南洋商业银行 | 041 | 2021-07 | 跨行扣款 |
| 富融银行 Fusion Bank | — | 2021-09 | 虚拟银行 |
| 工银亚洲 ICBC(Asia) | 072 | 2021-09 | 跨行扣款 |
| 渣打 SCB | 003 | 2021-12 | 跨行扣款 |
| 众安银行 ZA Bank | — | 2021-12 | 虚拟银行 |
| 中信银行国际 CNCBI | 018 | 2021-12 | 跨行扣款,卡号需 15 位格式(前 3 位补 0) |
| 永隆银行 CMB Wing Lung | 238 | 2021-12 | 跨行扣款 |
| 天星银行 Airstar | — | 2022-09 | 虚拟银行 |
| 建银亚洲 CCB(Asia) | 009 | 2023-10 | 跨行扣款 |
| LIVI BANK | — | 2024-01 | 虚拟银行 |
| 招商银行 | — | 2024-03 | 跨行扣款 |
| 大新银行 Dah Sing | 040 | 2024-03 | 跨行扣款 |
恒生通道支持的银行(12 家)
通过恒生通道发起的 eDDA,支持以下 12 家银行的个人账户:
两条通道均支持(7 家)——这些银行同时支持汇丰通道和恒生通道,优先推荐汇丰通道:
| 银行 | 银行代码 | 备注 |
|---|---|---|
| 恒生 Hang Seng | 024 | 同行扣款 |
| 汇丰 HSBC | 004 | 跨行扣款 |
| 中银 BOCHK | 012 | 跨行扣款 |
| 南洋商业银行 | 041 | 跨行扣款 |
| 工银亚洲 ICBC(Asia) | 072 | 跨行扣款 |
| 渣打 SCB | 003 | 跨行扣款 |
| 永隆银行 CMB Wing Lung | 238 | 跨行扣款 |
恒生通道专属(5 家)——以下银行仅能通过恒生通道使用 eDDA,不支持汇丰通道:
| 银行 | 银行代码 | 备注 |
|---|---|---|
| 花旗银行 Citibank | 250 | 跨行扣款 |
| 东亚银行 BEA | 015 | 跨行扣款,注意"每日单笔"频率限制 |
| 华侨永亨银行 OCBC Wing Hang | — | 跨行扣款 |
| 集友银行 Chiyu Banking | — | 跨行扣款 |
| 交通银行香港分行 BANKCOMM | 382 | 需柜台申请 |
支持的证件类型
eDDA 授权时需验证用户证件信息,支持的证件类型因银行而异:
| 证件类型 | 汇丰通道 | 恒生通道 | 说明 |
|---|---|---|---|
| 香港身份证(HKID) | 支持 | 支持 | 最常见,覆盖大部分用户 |
| 中国居民身份证 | 支持 | 支持 | 大陆开户用户 |
| 护照 | 支持 | 支持 | 海外用户 |
不支持的场景
以下场景不支持 eDDA 入金,PM 和运营需注意:
| 场景 | 原因 | 用户提示建议 |
|---|---|---|
| 企业账户 | eDDA 仅支持个人账户,银行侧不允许企业账户授权 | 引导使用网银转账或 FPS |
| 信银国际卡号非 15 位 | 信银国际银行卡号需补齐至 15 位(前 3 位补 0),否则授权失败 | 引导用户确认正确的卡号格式 |
| 天星银行超日限 | 天星 eDDA 单日限额 HKD 200,000,每日累计不超过 5 笔(合计 HKD 1,000,000) | 提示用户分多日入金或使用其他通道 |
汇丰 vs 恒生协议差异
| 维度 | 汇丰 HSBC | 恒生 Hang Seng |
|---|---|---|
| TransType | 303 (HSBC_EDDI) | 302 (HASE_EDDI) |
| 入金方式码 | eddaHSBC(代码 9) | edda(代码 8) |
| 通信协议 | HTTPS REST API | SM2 签名 HTTP POST |
| 加密方式 | TLS(标准 HTTPS) | 香港邮政电子证书 SM2 数字签名 |
| SBA 服务 | sba_hsbc_eddi | sba_hase_eddi |
| 数据表 | hsbc_eddis | hs_eddis |
| 授权要求(同行) | 必须预授权 | 必须预授权 |
| 授权要求(跨行+线上开户) | 允许后置授权 | 不允许,必须预授权 |
| 扣款币种 | 仅 HKD | 仅 HKD |
| 扣款结果 Job | HsbcEddiResultJob | HsEddiResultJob |
| SBA 创建重试 Job | HsbcEddiSBACreateRetryJob | HsEddiSBACreateRetryJob |
授权前置 vs 后置
PM 关注点:恒生的"必须预授权"意味着新用户首次入金的流程更长(需等待授权生效),而汇丰跨行+线上开户场景允许"先入金后授权",降低了首次入金门槛。
完整扣款流程对比
下图并排展示汇丰和恒生从用户点击到资金到账的完整链路差异:
关键差异点:
- 通信协议:汇丰用标准 HTTPS REST API;恒生用 SM2 签名 HTTP POST(国密算法)
- 数据表:汇丰写
hsbc_eddis;恒生写hs_eddis - 轮询 Job:汇丰用
HsbcEddiResultJob;恒生用HsEddiResultJob - 扣款回调时间:两家银行的处理时间相近(通常几分钟),但恒生在周日维护窗口(00:00~08:30)更短
恒生扣款被拒错误码
恒生 eDDI 扣款失败时,银行返回的错误码和对应含义:
| 错误码 | 含义 | 用户提示 |
|---|---|---|
BRC_8I1 | 余额不足 | 银行账户余额不足,银行可能收取手续费且取消授权 |
BRC_8RZ | 账户异常 | 银行账户异常,请联系银行 |
BRC_8RW + FP2414 | 未查询到授权 | 无法扣款,请联系银行 |
BRC_8RW + FP2415 | 授权未生效 | 请至银行激活 eDDA |
BRC_8RW + FP2416 | 授权已过期 | 请至银行重新授权 |
BRC_8RW + FP2417 | 超过授权限额 | 请减少金额后重新发起 |
000 | 通用失败 | 请联系银行确认原因 |
汇丰扣款被拒错误码
| 错误码 | 含义 | 用户提示 |
|---|---|---|
MPP02020 | 授权已取消/不存在 | 请联系银行重新授权 |
MPP02021 | 付款账户已关闭 | 请联系银行 |
MPP02022 | 超过 eDDA 扣款上限 | 请联系银行调整限额 |
MPP02023 | 授权已取消/不存在 | 请联系银行重新授权 |
MPP02038 | 授权已休眠 | 请联系银行重新授权 |
MPP02039 | 授权已过期 | 请联系银行重新授权 |
MPP05000 | 超过扣款上限 | 请联系银行调整限额 |
配置位置
- 恒生错误码:
deposit/src/app/Business/Eddi.php:341-377—hsRejectMessage() - 汇丰错误码:
deposit/src/app/Business/Eddi.php:379-397—hsbcRejectMessage()
处理时段与维护窗口
| 维度 | 恒生 | 汇丰 | 说明 |
|---|---|---|---|
| 工作时段 | 周一 07:00 ~ 周六 10:00 | 周一 07:00 ~ 周六 10:00 | 此时段内 SBA 会处理 eDDI 指令 |
| 周日维护 | 00:00 ~ 08:30 | 00:00 ~ 12:00 | 银行系统维护,不接受请求 |
| 非工作时段行为 | 指令进入 Blank 状态,下个工作时段自动激活 | 同左 | 用户不会感知延迟 |
| 对账暂停 | 16:05 ~ 16:10 | 16:05 ~ 16:10 | 与全局 2412 规则一致 |
非工作时段提交的处理:如果用户在周六 10:00 之后提交 eDDA 入金,系统会创建 Apply 和 setup_eddis 记录,但 SBA 的 eDDI Procedure 不会立即执行。Procedure 进入 Blank 状态,等到下周一 07:00 自动激活并发送扣款指令到银行。
配置位置
- 恒生维护窗口:
sba_hase_eddi服务常量配置 - 汇丰维护窗口:
sba_hsbc_eddi服务常量配置 - 2412 暂停规则:
deposit/src/app/Business/DepositConfigNew.php:603-641
setup_eddis 完整状态流转
eDDA 入金涉及 setup_eddis 表的状态流转,覆盖从授权到入金完成的全过程:
| 状态码 | 常量 | 含义 | 后续动作 |
|---|---|---|---|
| 0 | STATUS_PENDING | 待处理——记录已创建 | applySetupEddi() 触发处理 |
| 1 | STATUS_PROCESSING | 处理中——扣款指令已发送 | 等待银行回调 |
| 2 | STATUS_DEDUCTED | 扣款完成——银行已扣款 | SBA 执行入账 |
| 3 | STATUS_FAIL | 失败——授权失败或扣款失败 | 通知用户,记录 error_code |
| 4 | STATUS_FINISH | 入金完成——资金已到账 | 流程结束 |
特殊场景:STATUS_DEDUCTED → STATUS_FAIL(CRM 驳回)——当银行已完成扣款但后台运营终止入金时,error_code 为 REJECT_BY_CRM,此时需要人工处理退款。
eDDA 异常场景速查
| 异常 | 现象 | 排查路径 | 处理方式 |
|---|---|---|---|
| 授权长时间未生效 | 用户等待超过 24h | 查 setup_eddis.edda_status,确认是否仍在 PENDING | 引导用户联系银行确认 |
| 授权失败 | 用户看到错误提示 | 查 setup_eddis.error_code,对照上方错误码表 | 按错误码引导用户修正信息 |
| 扣款失败 | Apply 状态变为已驳回 | 查 hsbc_eddis / hs_eddis 表的 reject 信息 | 对照扣款错误码表处理 |
| 扣款成功但未入账 | 银行已扣款,余额未增加 | 查 setup_eddis.status 是否卡在 DEDUCTED(2) | 检查 SBA Procedure 状态 |
| 扣款超时 | 银行无回调 | 查 ResultJob 轮询状态 | 等待轮询完成或人工查询银行 |
| 授权失效 | 历史已授权用户突然无法入金 | 查银行端授权状态(可能被用户在银行侧取消) | 引导用户重新授权 |
详细的排障流程 → 入金排障 § eDDA 授权失败
分步 Runbook:eDDA 扣款成功但未入账(SBA Procedure 挂起)
现象:银行已扣款(setup_eddis.status = 2 DEDUCTED),但用户余额未增加。
第 1 分钟 — 定位阻塞点
- 查
setup_eddis表:确认status = 2(已扣款) - 查 SBA Procedure 状态:是 Running / Pending / Failed?
- 如果 Procedure 是 Running 且超过 10 分钟 → 异常
第 2~5 分钟 — 排查 SBA 异常 4. 查 SBA 服务日志:Procedure 是否卡在某个 Step? 5. 常见卡点:
- CRM 账户锁定(正在执行其他操作)→ 等待释放
- SBA 余额计算失败 → 检查账户数据一致性
- SBA 服务本身异常 → 检查 SBA 服务状态
第 5~15 分钟 — 处理 6. 如果 Procedure 状态是 Failed → 需要手动触发重新执行(联系技术支持) 7. 如果 Procedure 状态是 Pending → 检查是否有前置 Procedure 在排队 8. 如果 SBA 服务异常 → 等服务恢复后 Procedure 会自动继续
用户沟通:告知用户"银行已扣款成功,资金正在处理中",避免用户恐慌
超过 30 分钟未解决 → 升级到入金技术负责人
余额不足自动取消授权
恒生银行有一个特殊行为:当 eDDI 扣款因余额不足(BRC_8I1)被拒时,银行可能自动取消该用户的 eDDA 授权。这意味着:
- 用户需要先往银行账户充值
- 然后还需要重新完成 eDDA 授权才能再次使用 eDDA 入金
- 运营需要主动告知用户这个情况,否则用户会以为充值后就能继续入金
汇丰没有这个行为——余额不足被拒后,授权仍然有效,充值后可直接重试。
处理建议:如果用户反馈"之前可以用 eDDA,现在不行了",先检查是否是恒生用户 + 曾经因余额不足被拒。如果是 → 引导重新授权。
常见误解
| 误解 | 事实 |
|---|---|
| "eDDA 和 eDDI 是出金通道" | 不是。eDDA/eDDI 仅用于入金代扣。汇丰/恒生的出金走企业网银转账,与 eDDA 无关 |
| "所有银行都能用 eDDA" | 汇丰通道支持 15 家银行的个人账户,恒生通道支持 12 家(含 5 家专属)。企业账户不支持。详见 支持范围 |
| "eDDA 授权一次就永久有效" | 授权可能因为银行侧维护、用户在银行 App 取消、余额不足自动取消(恒生)而失效 |
| "eDDA 入金需要匹配引擎" | 不需要。eDDA 是系统主动发起扣款,天然知道资金归属,完全跳过匹配引擎 |
| "汇丰和恒生的 eDDA 实现是一样的" | 协议完全不同。汇丰用 HTTPS REST API,恒生用 SM2 签名。数据表、Job、SBA 服务都是独立的 |
| "周末可以用 eDDA 入金" | 周六 10:00 后到周日结束是非工作时段。提交的请求会排队到周一 07:00 才执行 |
读完之后
| 我想... | 去看 |
|---|---|
| 了解 eDDA 授权如何开启入金通道 | 银行卡绑定与入金授权 § eDDA |
| 跟着一笔 eDDA 入金走全程 | 新人导读 § eDDA 入金 |
| 看 eDDA 授权/扣款失败怎么处理 | 入金排障 |
| 看运营侧 eDDA 排障操作指引 | eDDA 排障指引 |
| 查 eDDI 类型码和状态码 | 入金规则速查 |
| 深入了解汇丰 eDDA 实现 | 汇丰 HSBC |
| 深入了解恒生 eDDA 实现 | 恒生 Hang Seng |
| 了解 SBA 编排如何执行入账 | SBA 资金编排 |
这个页面有帮助吗?