多渠道的支付系统之退款模块(三)
1.Overview/背景介绍
我们的商品在用户支付成功后, 允许用户发起退款申请, 或者我们后台对用户的订单发起退款。这里就涉及到退款操作的安全和权限问题。
另外, 退款和支付的证书, 必须隔离开来(因为退款的安全性要求更高), 生产和非生产环境不能共用证书。在发布程序的时候, 需要解决的是如何测试验证线上功能。此外, 还需要考虑部署方面的安全。
2.Goals and Product Requirements/目标和产品需求
业务目标
- 财务人员 | 提供可操作的退款界面,具备审计功能 | 避免误退款,资金可追溯 |
- 业务方 | 支持自动退款和单笔退款 | 增强用户的产品体验 |
- 用户 | 在终端可发起退款申请 | 提升退款的便捷 |
- 测试 | 增加数据层的灰度,在对用户开放前,充分测试支付和退款等功能 | 有证书的新增或支付的路由切换情况下的验证
3.ASR/关键架构需求
技术约束
| 请求退款需要双向证书 |
| 请求频次的限制(每人每分钟 100次) |
| 校验验证码的错误频次不能超过5次(每人每分钟 5次) |
| 错误或无效请求频次限制(每人每分钟 10次) |
业务约束
| 交易时间超过一年的订单无法提交退款 | 微信 |
| 总退款金额不能超过用户实际支付金额 | 微信 |
| 每个支付订单的部分退款次数不能超过5次 | 平台 |
架构设计
image.png
在支付服务前,增加一个api网关(安装Open证书),用于安全认证。
另外便于蓝绿部署。
增加测试bizId
为了对迭代的服务和支付证书的完全测试(在非生产环境,我们使用的是不同于线上的商户证书和支付环境),从数据层面,增加测试业务bizId,对真实用户不可见。
只有在测试业务测试通过后,才让线上的真实业务切换到该支付账户或环境下。
4.Out of Scope/范围
本方案中的退款功能, 着重于执行退款的安全, 业务上的退款流程的审批功能不在本方案中.
5.Open Questions/开放性问题
发布上线环节, 涉及新增证书的时候, 相关流程在操作时的安全,比如谁导出证书,怎么把证书给到运维。(目前的解决办法是:证书文件、密码等由财务人员直接给到线上,不经过开发/测试/预发环境)
6.Design/设计实现
业务场景一
一个订单多次部分退款,先创建一个退款计划,待退款操作完成,再创建第二个退款计划。
业务场景二
用户重复付款,当业务方识别,并由财务确定是重复付款情况属实,可以发起实时退款请求。
业务场景三
当业务方发现之前的退款申请操作有误,允许在未执行退款前,撤销退款计划。这里的opType=1(撤销)。
退款操作采用两阶段提交机制, 主要流程见下:
image.png
Tips: 这里的验证码发送形式, 可以是短信, 也可以是内部邮件等其他工具。
允许操作退款的人员,必须事先在数据库中录入,并由支付服务维护。
退款人员支持多个,起到互备的作用,保证退款收取token的高可用。
数模设计
image.png
数模变更脚本:
`CREATE` `TABLE` ``refund_plan` (`
``id` ``int``(10) ``NOT` `NULL` `COMMENT ``'主键ID'``,`
``biz_type` ``int``(4) ``NOT` `NULL` `COMMENT ``'业务类型'``,`
``batch_no` ``varchar``(64) ``NOT` `NULL` `COMMENT ``'批次号'``,`
``pay_trade_no` ``varchar``(64) ``NOT` `NULL` `COMMENT ``'平台支付流水号'``,`
``user_id` ``bigint``(20) ``NOT` `NULL` `COMMENT ``'用户ID'``,`
``user_name` ``varchar``(32) ``DEFAULT` `NULL` `COMMENT ``'用户姓名'``,`
``plan_date` datetime ``NOT` `NULL` `COMMENT ``'计划退款时间'``,`
``refund_amt` ``int``(10) ``NOT` `NULL` `COMMENT ``'退款金额(单位:分)'``,`
``status` ``smallint``(6) ``NOT` `NULL` `DEFAULT` `0 COMMENT ``'状态:0--待执行; 1--已执行; 2--已撤销;'``,`
``refund_reason` ``varchar``(256) ``DEFAULT` `NULL` `COMMENT ``'退款原因'``,`
``refund_way` ``smallint``(6) ``NOT` `NULL` `DEFAULT` `1 COMMENT ``'退回路径:0-线下转账; 1-原路退回'``,`
``client_ip` ``varchar``(32) ``DEFAULT` `NULL` `COMMENT ``'客户端IP'``,`
``device` ``varchar``(32) ``DEFAULT` `NULL` `COMMENT ``'设备'``,`
``notify_url` ``varchar``(255) ``DEFAULT` `NULL` `COMMENT ``'退款回调url'``,`
``create_by` ``varchar``(64) ``NOT` `NULL` `COMMENT ``'创建人'``,`
``create_gmt` datetime ``DEFAULT` `current_timestamp``() COMMENT ``'创建时间'``,`
``modified_by` ``varchar``(64) ``DEFAULT` `NULL` `COMMENT ``'更新人'``,`
``modified_gmt` datetime ``DEFAULT` `current_timestamp``() COMMENT ``'更新时间'``,`
`PRIMARY` `KEY` `(`id`) USING BTREE,`
`UNIQUE` `KEY` ``idx_RefundPlan_payTradeNo_batchNo` (`pay_trade_no`,`batch_no`),`
`KEY` ``idx_RefundPlan_plan_date` (`plan_date`),`
`KEY` ``idx_RefundPlan_payTradeNo_status` (`pay_trade_no`,`status`)`
`) ENGINE=InnoDB ``DEFAULT` `CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT=``'退款计划表(一笔支付订单同时只能创建一次退款计划)'``;`
`CREATE` `TABLE` ``operate_user` (`
``id` ``int``(10) ``NOT` `NULL` `COMMENT ``'主键ID'``,`
``biz_type` ``int``(4) ``NOT` `NULL` `COMMENT ``'业务类型'``,`
``opt_user_id` ``bigint``(20) ``NOT` `NULL` `COMMENT ``'操作员ID'``,`
``opt_user_name` ``varchar``(32) ``DEFAULT` `NULL` `COMMENT ``'操作员姓名'``,`
``mobile` ``varchar``(16) ``NOT` `NULL` `DEFAULT` `''` `COMMENT ``'手机号'``,`
``create_by` ``varchar``(64) ``NOT` `NULL` `COMMENT ``'创建人'``,`
``create_gmt` datetime ``DEFAULT` `current_timestamp``() COMMENT ``'创建时间'``,`
``modified_by` ``varchar``(64) ``DEFAULT` `NULL` `COMMENT ``'更新人'``,`
``modified_gmt` datetime ``DEFAULT` `current_timestamp``() COMMENT ``'更新时间'``,`
`PRIMARY` `KEY` `(`id`) USING BTREE`
`) ENGINE=InnoDB ``DEFAULT` `CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT=``'操作人员表'``;`
接口设计
1) 获取退款token
token将以短信或邮箱等方式发送至申请退款人,token有效期为10分钟。
第一步、校验申请退款人员的token是否已存在,如果存在,则返回。
第二步、校验optUserId是否合法,然后生成对应的token,最后将token发送到申请人。
image.png
2) 确认退款
退款计划支持新增和撤销,在未到执行时间前,允许管理人员对计划撤销。
第一步、判断token是否合法
第二步、执行退款逻辑
判断支付订单是否满足退款条件。
一笔支付订单同时只能创建一次退款计划,除非计划已执行或已撤销,才能发起第二次退款。
退款计划时间,必须是大于当前时间。
每次最多申请1000条记录。
image.png
image.png
双向证书
将支付服务的部署和其他服务分开部署,要求调用端必须安装open私有证书。
7.Deployment/部署
7.1 支持蓝绿发布
蓝绿发布的作用主要是在支付和退款回调这块,服务在重启前,先切流量(暂不接收第三方支付的回调),再优雅停机,重启后,再将流量切换回来。
7.2 增加双向认证
支付服务需要单独部署,对接的业务方(包括管理后台) 需要安装由支付网关颁发的私有证书,才能发起退款。
8.Monitoring and Logging/监控和日志埋点
监控退款成功的QP 1m 的量
打印请求退款的入参
打印确认退款的入参
9.Metrics/业务指标
请求退款的次数(按业务、按渠道类型、按人)
发送验证码的次数(按业务、按渠道类型、按人)
确认退款的次数(按业务、按渠道类型、按人)
校验验证码通过的次数(按业务、按渠道类型、按人)
校验验证码非法的次数(按业务、按渠道类型、按人)