From 0fcbaf8079b127dcbe0f34ec1b027b3d0f3462f3 Mon Sep 17 00:00:00 2001 From: zhouyonggao <1971162852@qq.com> Date: Fri, 13 Mar 2026 15:07:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(order):=20=E4=BC=98=E5=8C=96=E9=A2=84?= =?UTF-8?q?=E7=BA=A6=E4=B8=8E=E5=8F=96=E6=B6=88=E6=B5=81=E7=A8=8B=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=B9=82=E7=AD=89=E4=B8=8E=E9=94=81=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 对预约流程新增数据库校验服务编码,提取对应AES密钥解密请求参数 - 新增基于权益码的分布式锁,防止并发重复提交,锁未获取时返回错误 - 调整幂等校验逻辑,准确区分已预约、已取消、已完成等状态返回对应响应 - 调整权益码过期及渠道相关的错误返回信息,提升用户提示准确性 - 增加预约流程中锁的defer释放,确保流程结束自动释放锁资源 - 预约流程新增调用蓝色兄弟券码接口,支持幂等和超时处理 - 取消流程新增分布式锁控制,对订单状态进行更细化判定及返回 - 取消作废逻辑完善,失败时查询券码状态确认后续处理 - 完善预约和取消流程步骤及验收标准,新增并发和锁竞争等测试用例 - 更新相关API文档及流程图,补充异常场景处理说明 - 在docs中新增AES加解密算法支持AES,完善对账及安全模块说明 --- docs/需求文档-PRD.md | 224 +++++++++++++++++++++++++++---------------- 1 file changed, 143 insertions(+), 81 deletions(-) diff --git a/docs/需求文档-PRD.md b/docs/需求文档-PRD.md index a5f3bd5..be246ae 100644 --- a/docs/需求文档-PRD.md +++ b/docs/需求文档-PRD.md @@ -27,7 +27,7 @@ │ ├── 对账文件下载 │ └── 对账数据核对 └── 安全与加密模块 - ├── SM2/SM4加解密(邮储银行) + ├── SM2/SM4/AES加解密(邮储银行) ├── RSA/AES加解密(蓝色兄弟) └── 签名验签 ``` @@ -89,28 +89,36 @@ **功能描述**:接收邮储银行服务开放平台的预约请求,为客户预约虚拟商品充值服务 **业务规则**: -1. 对request进行AES解密,解析出type(服务编码)、code(权益码)、mac(客户id) -2. 对code(权益码)进行幂等验证: +1. 查询数据库验证服务编码(type)是否存在(数据库中维护邮储服务编码与营销平台活动的映射关系) + - 如果不存在:返回"暂不支持此服务" + - 如果存在:获取对应的AES加密密钥(aes_key)和向量(aes_iv),用于后续解密 +2. 使用从数据库查询到的aes_key和aes_iv对request进行AES解密,解析出type(服务编码)、code(权益码)、mac(客户id) + - 解密失败:返回"参数错误" +3. 基于权益码(code)获取分布式锁,防止重复请求: + - 获取锁成功:继续执行后续流程 + - 获取锁失败:返回"请勿重复提交" +4. 对code(权益码)进行幂等验证: - 若订单状态为「服务已预约(200)」,直接返回预约成功(与正常请求返回一致) - 若订单状态为「服务未预约(100)」,继续执行后续流程(更新订单,不新增) - - 若订单状态为其他状态,返回服务已预约 -3. 查询数据库验证服务编码(type)是否存在(数据库中维护邮储服务编码与营销平台活动的映射关系) - 如果不存在 返回暂不支持此服务 -4. 请求邮储服务开放平台接口验证权益码是否过期 + - 若订单状态为「服务已取消(400)」,返回"服务已取消" + - 若订单状态为「服务已完成(300)」,返回"服务已生效" +5. 请求邮储服务开放平台接口验证权益码是否过期 如果过期: 1、CRM渠道返回 "二维码20分钟内有效,现已超时失效,请联系理财经理重新生成二维码! - 2、手机银行渠道返回 “当前页面停置时间过长,请您重新进入该页面” -5. 创建/更新订单记录(订单状态:服务未预约) -6. 请求邮储服务开放平台接口发起预约: - - 预约成功或返回161010(交易已预约):继续执行步骤7 + 2、手机银行渠道返回 "当前页面停置时间过长,请您重新进入该页面" +6. 创建/更新订单记录(订单状态:服务未预约) +7. 请求邮储服务开放平台接口发起预约: + - 预约成功或返回161010(交易已预约):继续执行步骤8 - 其他情况:订单状态保持「服务未预约(100)」,返回预约失败 -7. 请求蓝色兄弟营销平台获取券码链接(使用相同交易号和参数请求): +8. 请求蓝色兄弟营销平台获取券码链接(使用相同交易号和参数请求): - 请求成功:更新订单状态为「服务已预约(200)」,返回预约成功响应 - 请求异常:订单状态保持「服务未预约(100)」,返回预约失败 +9. 释放分布式锁 **输入**: | 字段 | 类型 | 必填 | 说明 | |-----|------|-----|------| +| type | String | M | 服务编码,用于查询数据库获取AES解密密钥 | | request | String | M | AES加密字符串,解密后格式:type=服务编码&code=权益码&mac=加密后的客户id | | channel | String | M | 渠道标识:12-手机银行,17-电话银行,41-CRM零售 | | tranChnl | String | M | 渠道标识:12-手机银行,17-电话银行,41-CRM零售 | @@ -127,12 +135,15 @@ | backUrl | String | C | 返回手机银行的地址 | **验收标准**: -- [ ] 能正确解密AES加密的request参数 +- [ ] 入参type(服务编码)为必填字段,缺失时返回"参数错误" +- [ ] 根据入参type查询数据库获取对应的aes_key和aes_iv +- [ ] 服务编码(type)不存在时,返回"暂不支持此服务"(在AES解密之前校验) +- [ ] 使用数据库查询到的aes_key和aes_iv能正确解密AES加密的request参数 - [ ] 能正确解析解密后的参数(type、code、mac) - [ ] 幂等验证:相同权益码(code)状态为「服务已预约(200)」时,直接返回预约成功 - [ ] 幂等验证:相同权益码(code)状态为「服务未预约(100)」时,继续执行后续流程 -- [ ] 幂等验证:相同权益码(code)状态为其他状态时,返回"服务已预约" -- [ ] 服务编码(type)不存在时,返回"暂不支持此服务" +- [ ] 幂等验证:相同权益码(code)状态为「已取消(400)」时,返回"服务已取消" +- [ ] 幂等验证:相同权益码(code)状态为「已完成(300)」时,返回"服务已生效" - [ ] 权益码过期且渠道为CRM(41)时,返回"二维码20分钟内有效,现已超时失效,请联系理财经理重新生成二维码" - [ ] 权益码过期且渠道为手机银行(12)时,返回"当前页面停置时间过长,请您重新进入该页面" - [ ] 订单创建/更新时初始状态为「服务未预约(100)」 @@ -142,36 +153,41 @@ - [ ] 蓝色兄弟券码获取异常时,订单状态保持「服务未预约(100)」,返回预约失败 - [ ] 预约成功后返回蓝色兄弟兑换地址(url) - [ ] 响应正确透传tranChnl、instType、backUrl字段 +- [ ] 并发请求时,基于权益码获取分布式锁,获取失败返回"请勿重复提交" **测试用例**: | 用例编号 | 测试场景 | 前置条件 | 输入数据 | 预期结果 | |---------|---------|---------|---------|----------| -| TC-3.1.1-001 | 正常预约成功 | 服务编码存在、权益码有效、订单不存在 | request=有效加密参数, channel=12 | code=0, 返回url、tranChnl、instType、backUrl | -| TC-3.1.1-002 | AES解密失败 | - | request=无效加密字符串 | code=2, msg="参数错误" | -| TC-3.1.1-003 | 参数解析失败-缺少type | - | request解密后无type字段 | code=2, msg="参数错误" | -| TC-3.1.1-004 | 参数解析失败-缺少code | - | request解密后无code字段 | code=2, msg="参数错误" | -| TC-3.1.1-005 | 幂等-已预约状态 | 订单状态=200(已预约) | 相同权益码再次请求 | code=0, 返回原预约成功响应 | -| TC-3.1.1-006 | 幂等-未预约状态 | 订单状态=100(未预约) | 相同权益码再次请求 | 继续执行流程,最终返回预约结果 | -| TC-3.1.1-007 | 幂等-已完成状态 | 订单状态=300(已完成) | 相同权益码再次请求 | code=4, msg="服务已预约" | -| TC-3.1.1-008 | 幂等-已取消状态 | 订单状态=400(已取消) | 相同权益码再次请求 | code=4, msg="服务已预约" | -| TC-3.1.1-009 | 服务编码不存在 | 数据库无该服务编码映射 | type=999999 | code=4, msg="暂不支持此服务" | -| TC-3.1.1-010 | 权益码过期-CRM渠道 | 邮储返回权益码已过期 | channel=41 | code=4, msg含"二维码20分钟内有效" | -| TC-3.1.1-011 | 权益码过期-手机银行 | 邮储返回权益码已过期 | channel=12 | code=4, msg含"当前页面停置时间过长" | -| TC-3.1.1-012 | 权益码过期-电话银行 | 邮储返回权益码已过期 | channel=17 | code=4, msg含"当前页面停置时间过长" | -| TC-3.1.1-013 | 邮储预约成功 | 权益码有效 | 正常请求 | 继续调用蓝色兄弟获取券码 | -| TC-3.1.1-014 | 邮储返回已预约(161010) | 权益码有效 | 正常请求 | 继续调用蓝色兄弟获取券码 | -| TC-3.1.1-015 | 邮储预约失败 | 邮储返回其他错误 | 正常请求 | code!=0, 订单状态=100 | -| TC-3.1.1-016 | 券码获取成功 | 邮储预约成功 | 正常请求 | code=0, 订单状态=200, 返回url | -| TC-3.1.1-017 | 券码获取失败 | 蓝色兄弟返回异常 | 正常请求 | code!=0, 订单状态=100 | -| TC-3.1.1-018 | 券码获取超时 | 蓝色兄弟接口超时 | 正常请求 | code!=0, 订单状态=100 | -| TC-3.1.1-019 | backUrl为空 | backUrl参数未传 | backUrl=空 | code=0, 响应中backUrl为空 | -| TC-3.1.1-020 | 必填参数缺失-channel | - | 不传channel | code=2, msg="参数错误" | -| TC-3.1.1-021 | 必填参数缺失-tranChnl | - | 不传tranChnl | code=2, msg="参数错误" | -| TC-3.1.1-022 | 必填参数缺失-instType | - | 不传instType | code=2, msg="参数错误" | -| TC-3.1.1-023 | 邮储服务不可用 | 邮储平台异常 | 正常请求 | code=1, msg="系统异常" | -| TC-3.1.1-024 | 蓝色兄弟服务不可用 | 蓝色兄弟平台异常 | 正常请求 | code=1, 订单状态=100 | -| TC-3.1.1-025 | 并发幂等测试 | 同一权益码 | 同时发起多个请求 | 仅一个成功创建订单,其他返回幂等结果 | +| TC-3.1.1-001 | 正常预约成功 | 服务编码存在、权益码有效、订单不存在 | type=有效服务编码, request=有效加密参数, channel=12 | code=0, 返回url、tranChnl、instType、backUrl | +| TC-3.1.1-002 | 必填参数缺失-type | - | 不传type | code=2, msg="参数错误" | +| TC-3.1.1-003 | 服务编码不存在 | 数据库无该服务编码映射 | type=999999 | code=4, msg="暂不支持此服务"(在AES解密前返回) | +| TC-3.1.1-004 | AES解密失败-密钥不匹配 | 服务编码存在但request用其他密钥加密 | type=有效服务编码, request=用错误密钥加密 | code=2, msg="参数错误" | +| TC-3.1.1-005 | AES解密失败-格式错误 | 服务编码存在 | type=有效服务编码, request=无效加密字符串 | code=2, msg="参数错误" | +| TC-3.1.1-006 | 参数解析失败-解密后缺少type | 服务编码存在,AES解密成功 | request解密后无type字段 | code=2, msg="参数错误" | +| TC-3.1.1-007 | 参数解析失败-解密后缺少code | 服务编码存在,AES解密成功 | request解密后无code字段 | code=2, msg="参数错误" | +| TC-3.1.1-008 | 幂等-已预约状态 | 订单状态=200(已预约) | 相同权益码再次请求 | code=0, 返回原预约成功响应 | +| TC-3.1.1-009 | 幂等-未预约状态 | 订单状态=100(未预约) | 相同权益码再次请求 | 继续执行流程,最终返回预约结果 | +| TC-3.1.1-010 | 幂等-已完成状态 | 订单状态=300(已完成) | 相同权益码再次请求 | code=4, msg="服务已生效" | +| TC-3.1.1-011 | 幂等-已取消状态 | 订单状态=400(已取消) | 相同权益码再次请求 | code=4, msg="服务已取消" | +| TC-3.1.1-012 | 权益码过期-CRM渠道 | 邮储返回权益码已过期 | channel=41 | code=4, msg含"二维码20分钟内有效" | +| TC-3.1.1-013 | 权益码过期-手机银行 | 邮储返回权益码已过期 | channel=12 | code=4, msg含"当前页面停置时间过长" | +| TC-3.1.1-014 | 权益码过期-电话银行 | 邮储返回权益码已过期 | channel=17 | code=4, msg含"当前页面停置时间过长" | +| TC-3.1.1-015 | 邮储预约成功 | 权益码有效 | 正常请求 | 继续调用蓝色兄弟获取券码 | +| TC-3.1.1-016 | 邮储返回已预约(161010) | 权益码有效 | 正常请求 | 继续调用蓝色兄弟获取券码 | +| TC-3.1.1-017 | 邮储预约失败 | 邮储返回其他错误 | 正常请求 | code!=0, 订单状态=100 | +| TC-3.1.1-018 | 券码获取成功 | 邮储预约成功 | 正常请求 | code=0, 订单状态=200, 返回url | +| TC-3.1.1-019 | 券码获取失败 | 蓝色兄弟返回异常 | 正常请求 | code!=0, 订单状态=100 | +| TC-3.1.1-020 | 券码获取超时 | 蓝色兄弟接口超时 | 正常请求 | code!=0, 订单状态=100 | +| TC-3.1.1-021 | backUrl为空 | backUrl参数未传 | backUrl=空 | code=0, 响应中backUrl为空 | +| TC-3.1.1-022 | 必填参数缺失-channel | - | 不传channel | code=2, msg="参数错误" | +| TC-3.1.1-023 | 必填参数缺失-tranChnl | - | 不传tranChnl | code=2, msg="参数错误" | +| TC-3.1.1-024 | 必填参数缺失-instType | - | 不传instType | code=2, msg="参数错误" | +| TC-3.1.1-025 | 邮储服务不可用 | 邮储平台异常 | 正常请求 | code=1, msg="系统异常" | +| TC-3.1.1-026 | 蓝色兄弟服务不可用 | 蓝色兄弟平台异常 | 正常请求 | code=1, 订单状态=100 | +| TC-3.1.1-027 | 并发幂等测试 | 同一权益码 | 同时发起多个请求 | 仅一个成功创建订单,其他返回幂等结果 | +| TC-3.1.1-028 | 并发锁竞争-获取锁失败 | 同一权益码并发请求 | 第二个请求 | code=1, msg="请勿重复提交" | +| TC-3.1.1-029 | 不同服务编码使用不同密钥 | 数据库存在多个服务编码配置 | type=服务A, request=用服务A密钥加密 | code=0, 使用服务A的aes_key/aes_iv解密成功 | --- @@ -181,16 +197,22 @@ **业务规则**: 1. 对request进行AES解密,解析出type(服务编码)、code(权益码)、mac(客户id) -2. 检查订单状态必须是已预约状态才能取消,否则提示"服务已生效无法取消" -3. 调用高端客户权益积分预约服务状态查询接口查询状态: +2. 基于权益码(code)获取分布式锁,防止重复请求: + - 获取锁成功:继续执行后续流程 + - 获取锁失败:返回"请勿重复提交" +3. 检查订单状态必须是已预约状态才能取消: + - 如果是已取消状态,直接返回取消成功 + - 其他非已预约状态,提示"服务已生效无法取消" +4. 调用高端客户权益积分预约服务状态查询接口查询状态: - 如果不是已预约状态且不是已取消状态,提示"服务已生效,无法取消" - 如果是已取消状态,直接返回取消成功 -4. 调用蓝色兄弟作废接口发起作废: +5. 调用蓝色兄弟作废接口发起作废: - 只有当业务码返回作废成功才算成功 - 其他情况(如HTTP响应超时)均视为作废失败 - 作废失败后调用蓝色兄弟券码查询接口查询券码状态,如果是已作废则按作废成功处理,否则提示"服务取消失败,请重试" -5. 调用邮储接口发起预约取消,业务码明确返回取消成功才算成功,否则提示"服务取消失败" -6. 订单状态更新为"已取消"(400) +6. 调用邮储接口发起预约取消,业务码明确返回取消成功才算成功,否则提示"服务取消失败" +7. 订单状态更新为"已取消"(400) +8. 释放分布式锁 **输入**: | 字段 | 类型 | 必填 | 说明 | @@ -211,7 +233,8 @@ **验收标准**: - [ ] 正确解析AES加密的request参数,提取type、code、mac字段 -- [ ] 本地订单状态非"已预约"时返回"服务已生效无法取消" +- [ ] 本地订单状态为已取消时,直接返回取消成功 +- [ ] 本地订单状态非已预约且非已取消时,返回"服务已生效无法取消" - [ ] 调用邮储预约服务状态查询接口,非已预约且非已取消状态时返回"服务已生效,无法取消" - [ ] 调用邮储预约服务状态查询接口,已取消状态时直接返回取消成功 - [ ] 蓝色兄弟作废接口返回作废成功时正常处理 @@ -220,6 +243,7 @@ - [ ] 邮储预约取消接口返回成功时正常处理 - [ ] 邮储预约取消接口返回失败时提示"服务取消失败" - [ ] 取消成功后订单状态更新为400 +- [ ] 并发请求时,基于权益码获取分布式锁,获取失败返回"请勿重复提交" **测试用例**: @@ -227,18 +251,20 @@ |---------|---------|---------|---------|----------| | TC-3.1.2-001 | 正常取消成功 | 订单状态=已预约(200),邮储状态=已预约,蓝色兄弟作废成功,邮储取消成功 | request=有效加密参数 | code=0, 订单状态=400 | | TC-3.1.2-002 | AES解密失败 | - | request=无效加密字符串 | code=2, msg="参数错误" | -| TC-3.1.2-003 | 本地订单状态非已预约 | 订单状态=已完成(300) | request=有效加密参数 | code=1, msg="服务已生效无法取消" | -| TC-3.1.2-004 | 本地订单不存在 | 订单不存在 | request=有效加密参数 | code=1, msg="订单不存在" | -| TC-3.1.2-005 | 邮储查询状态-已取消 | 订单状态=已预约(200),邮储状态=已取消 | request=有效加密参数 | code=0, 直接返回取消成功 | -| TC-3.1.2-006 | 邮储查询状态-已生效 | 订单状态=已预约(200),邮储状态=已生效 | request=有效加密参数 | code=1, msg="服务已生效,无法取消" | -| TC-3.1.2-007 | 蓝色兄弟作废成功 | 邮储状态=已预约,蓝色兄弟作废返回成功 | request=有效加密参数 | 继续执行邮储取消流程 | -| TC-3.1.2-008 | 蓝色兄弟作废超时后查询已作废 | 蓝色兄弟作废超时,券码查询状态=已作废(3) | request=有效加密参数 | 按作废成功处理,继续执行 | -| TC-3.1.2-009 | 蓝色兄弟作废失败后查询已作废 | 蓝色兄弟作废返回失败,券码查询状态=已作废(3) | request=有效加密参数 | 按作废成功处理,继续执行 | -| TC-3.1.2-010 | 蓝色兄弟作废失败且券码未作废 | 蓝色兄弟作废失败,券码查询状态=未作废 | request=有效加密参数 | code=1, msg="服务取消失败,请重试" | -| TC-3.1.2-011 | 邮储预约取消成功 | 蓝色兄弟作废成功,邮储取消返回成功 | request=有效加密参数 | code=0, 订单状态=400 | -| TC-3.1.2-012 | 邮储预约取消失败 | 蓝色兄弟作废成功,邮储取消返回失败 | request=有效加密参数 | code=1, msg="服务取消失败" | -| TC-3.1.2-013 | 邮储预约取消超时 | 蓝色兄弟作废成功,邮储取消超时 | request=有效加密参数 | code=1, msg="服务取消失败" | -| TC-3.1.2-014 | 幂等性测试-已取消订单 | 订单状态=已取消(400) | 重复发起取消请求 | code=0, 直接返回取消成功 | +| TC-3.1.2-003 | 本地订单状态已取消 | 订单状态=已取消(400) | request=有效加密参数 | code=0, 直接返回取消成功 | +| TC-3.1.2-004 | 本地订单状态非已预约 | 订单状态=已完成(300) | request=有效加密参数 | code=1, msg="服务已生效无法取消" | +| TC-3.1.2-005 | 本地订单不存在 | 订单不存在 | request=有效加密参数 | code=1, msg="订单不存在" | +| TC-3.1.2-006 | 邮储查询状态-已取消 | 订单状态=已预约(200),邮储状态=已取消 | request=有效加密参数 | code=0, 直接返回取消成功 | +| TC-3.1.2-007 | 邮储查询状态-已生效 | 订单状态=已预约(200),邮储状态=已生效 | request=有效加密参数 | code=1, msg="服务已生效,无法取消" | +| TC-3.1.2-008 | 蓝色兄弟作废成功 | 邮储状态=已预约,蓝色兄弟作废返回成功 | request=有效加密参数 | 继续执行邮储取消流程 | +| TC-3.1.2-009 | 蓝色兄弟作废超时后查询已作废 | 蓝色兄弟作废超时,券码查询状态=已作废(3) | request=有效加密参数 | 按作废成功处理,继续执行 | +| TC-3.1.2-010 | 蓝色兄弟作废失败后查询已作废 | 蓝色兄弟作废返回失败,券码查询状态=已作废(3) | request=有效加密参数 | 按作废成功处理,继续执行 | +| TC-3.1.2-011 | 蓝色兄弟作废失败且券码未作废 | 蓝色兄弟作废失败,券码查询状态=未作废 | request=有效加密参数 | code=1, msg="服务取消失败,请重试" | +| TC-3.1.2-012 | 邮储预约取消成功 | 蓝色兄弟作废成功,邮储取消返回成功 | request=有效加密参数 | code=0, 订单状态=400 | +| TC-3.1.2-013 | 邮储预约取消失败 | 蓝色兄弟作废成功,邮储取消返回失败 | request=有效加密参数 | code=1, msg="服务取消失败" | +| TC-3.1.2-014 | 邮储预约取消超时 | 蓝色兄弟作废成功,邮储取消超时 | request=有效加密参数 | code=1, msg="服务取消失败" | +| TC-3.1.2-015 | 幂等性测试-已取消订单 | 订单状态=已取消(400) | 重复发起取消请求 | code=0, 直接返回取消成功 | +| TC-3.1.2-016 | 并发锁竞争-获取锁失败 | 同一权益码并发请求 | 第二个请求 | code=1, msg="请勿重复提交" | --- @@ -874,28 +900,48 @@ skinparam ActivityFontSize 12 start -:AES解密request; +:根据入参type(服务编码)\n查询数据库; + +if (服务编码是否存在?) then (不存在) + :返回"暂不支持此服务"; + stop +else (存在) + :获取对应的aes_key和aes_iv; +endif + +:使用aes_key和aes_iv\n对request进行AES解密; + +if (解密成功?) then (否) + :返回"参数错误"; + stop +endif + :解析 type(服务编码)、code(权益码)、mac(客户id); +:基于权益码(code)获取分布式锁; + +if (获取锁成功?) then (否) + :返回"请勿重复提交"; + stop +endif + +:defer 释放分布式锁; +note right: 使用defer机制确保锁在流程结束时释放 + :查询订单状态(幂等验证); if (订单状态?) then (服务已预约 200) :返回预约成功; stop -elseif (其他状态) then - :返回"服务已预约"; +elseif (服务已取消 400) then + :返回"服务已取消"; + stop +elseif (服务已完成 300) then + :返回"服务已生效"; stop else (服务未预约 100 或 订单不存在) endif -:查询数据库验证服务编码(type); - -if (服务编码是否存在?) then (不存在) - :返回"暂不支持此服务"; - stop -else (存在) -endif - :请求邮储服务开放平台\n验证权益码有效性; if (权益码是否过期?) then (过期) @@ -937,13 +983,15 @@ endif | 步骤 | 操作 | 说明 | |-----|------|------| -| 1 | AES解密 | 对request进行AES解密,解析出type、code、mac | -| 2 | 幂等验证 | 根据订单状态决定后续流程 | -| 3 | 验证服务编码 | 查询数据库验证服务编码是否存在 | -| 4 | 验证权益码 | 调用邮储平台验证权益码有效性 | -| 5 | 创建/更新订单 | 订单状态设为「服务未预约(100)」| -| 6 | 发起预约 | 调用邮储平台发起预约 | -| 7 | 获取券码 | 调用蓝色兄弟获取券码链接,更新最终状态 | +| 1 | 验证服务编码 | 根据入参type查询数据库,获取对应的aes_key和aes_iv | +| 2 | AES解密 | 使用数据库查询到的aes_key和aes_iv对request进行解密,解析出type、code、mac | +| 3 | 获取分布式锁 | 基于权益码(code)获取锁,防止重复请求 | +| 4 | defer释放锁 | 使用defer机制注册锁释放,确保流程结束时自动释放 | +| 5 | 幂等验证 | 根据订单状态决定后续流程:已预约→返回成功,已取消→返回"服务已取消",已完成→返回"服务已生效" | +| 6 | 验证权益码 | 调用邮储平台验证权益码有效性(前置校验,5s超时) | +| 7 | 创建/更新订单 | 订单状态设为「服务未预约(100)」| +| 8 | 发起预约 | 调用邮储平台发起预约(5s超时) | +| 9 | 获取券码 | 调用蓝色兄弟获取券码链接(幂等,5s超时),更新最终状态 | --- @@ -969,6 +1017,13 @@ if (解密成功?) then (否) stop endif +:基于权益码(code)获取分布式锁; + +if (获取锁成功?) then (否) + :返回"请勿重复提交"; + stop +endif + :查询本地订单; if (订单存在?) then (否) @@ -976,6 +1031,11 @@ if (订单存在?) then (否) stop endif +if (订单状态=已取消?) then (是) + :返回取消成功; + stop +endif + if (订单状态=已预约?) then (否) :返回"服务已生效无法取消"; stop @@ -1024,11 +1084,13 @@ stop | 步骤 | 操作 | 说明 | |-----|------|------| | 1 | AES解密 | 对request进行AES解密,解析出type、code、mac | -| 2 | 本地订单校验 | 查询订单是否存在且状态为已预约 | -| 3 | 邮储状态查询 | 调用邮储预约服务状态查询接口,确认可取消 | -| 4 | 蓝色兄弟作废 | 调用作废接口,失败时查询券码状态确认 | -| 5 | 邮储预约取消 | 调用邮储预约取消接口,确认取消成功 | -| 6 | 更新订单状态 | 更新本地订单状态为已取消(400) | +| 2 | 获取分布式锁 | 基于权益码(code)获取锁,防止重复请求 | +| 3 | 本地订单校验 | 查询订单是否存在,已取消直接返回成功,非已预约返回失败 | +| 4 | 邮储状态查询 | 调用邮储预约服务状态查询接口,确认可取消 | +| 5 | 蓝色兄弟作废 | 调用作废接口,失败时查询券码状态确认 | +| 6 | 邮储预约取消 | 调用邮储预约取消接口,确认取消成功 | +| 7 | 更新订单状态 | 更新本地订单状态为已取消(400) | +| 8 | 释放锁 | 释放分布式锁 | ---