diff --git a/docs/需求文档-PRD.md b/docs/需求文档-PRD.md index a3aa8bd..a5f3bd5 100644 --- a/docs/需求文档-PRD.md +++ b/docs/需求文档-PRD.md @@ -129,8 +129,49 @@ **验收标准**: - [ ] 能正确解密AES加密的request参数 - [ ] 能正确解析解密后的参数(type、code、mac) +- [ ] 幂等验证:相同权益码(code)状态为「服务已预约(200)」时,直接返回预约成功 +- [ ] 幂等验证:相同权益码(code)状态为「服务未预约(100)」时,继续执行后续流程 +- [ ] 幂等验证:相同权益码(code)状态为其他状态时,返回"服务已预约" +- [ ] 服务编码(type)不存在时,返回"暂不支持此服务" +- [ ] 权益码过期且渠道为CRM(41)时,返回"二维码20分钟内有效,现已超时失效,请联系理财经理重新生成二维码" +- [ ] 权益码过期且渠道为手机银行(12)时,返回"当前页面停置时间过长,请您重新进入该页面" +- [ ] 订单创建/更新时初始状态为「服务未预约(100)」 +- [ ] 邮储预约成功或返回161010(交易已预约)时,继续获取券码 +- [ ] 邮储预约失败时,订单状态保持「服务未预约(100)」,返回预约失败 +- [ ] 蓝色兄弟券码获取成功后,订单状态更新为「服务已预约(200)」 +- [ ] 蓝色兄弟券码获取异常时,订单状态保持「服务未预约(100)」,返回预约失败 - [ ] 预约成功后返回蓝色兄弟兑换地址(url) -- [ ] 响应正确透传tranChnl、instType、backUrl +- [ ] 响应正确透传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 | 并发幂等测试 | 同一权益码 | 同时发起多个请求 | 仅一个成功创建订单,其他返回幂等结果 | --- @@ -139,29 +180,65 @@ **功能描述**:接收邮储银行服务开放平台的取消请求,取消已预约的服务 **业务规则**: -1. 校验订单状态必须为"已预约"(200) -2. 调用蓝色兄弟API作废券码 -3. 更新订单状态为"已取消"(400) -4. 返回取消成功响应 +1. 对request进行AES解密,解析出type(服务编码)、code(权益码)、mac(客户id) +2. 检查订单状态必须是已预约状态才能取消,否则提示"服务已生效无法取消" +3. 调用高端客户权益积分预约服务状态查询接口查询状态: + - 如果不是已预约状态且不是已取消状态,提示"服务已生效,无法取消" + - 如果是已取消状态,直接返回取消成功 +4. 调用蓝色兄弟作废接口发起作废: + - 只有当业务码返回作废成功才算成功 + - 其他情况(如HTTP响应超时)均视为作废失败 + - 作废失败后调用蓝色兄弟券码查询接口查询券码状态,如果是已作废则按作废成功处理,否则提示"服务取消失败,请重试" +5. 调用邮储接口发起预约取消,业务码明确返回取消成功才算成功,否则提示"服务取消失败" +6. 订单状态更新为"已取消"(400) **输入**: | 字段 | 类型 | 必填 | 说明 | |-----|------|-----|------| -| rightsCode | String | M | 兑换预约码 | -| serviceType | String | M | 服务类型编码 | -| providerCode | String | M | 服务厂商编号 | +| request | String | M | AES加密字符串,解密后格式:type=服务编码&code=权益码&mac=加密后的客户id | +| channel | String | M | 渠道标识:12-手机银行,17-电话银行,41-CRM零售 | +| tranChnl | String | M | 渠道标识:12-手机银行,17-电话银行,41-CRM零售 | +| backUrl | String | C | 返回手机银行的地址,可为空 | +| instType | String | M | 客户自营代理属性:01-自营,02-代理 | +| provinceInstNo | String | M | 客户归属一分机构号 | **输出**(data字段内容): | 字段 | 类型 | 必填 | 说明 | |-----|------|-----|------| -| tradeRespCode | String | M | 业务响应码 | -| tradeRespMsg | String | M | 业务响应码描述 | +| tranChnl | String | M | 渠道标识 | +| instType | String | M | 客户自营代理属性 | +| backUrl | String | C | 返回手机银行的地址 | **验收标准**: -- [ ] 非“已预约”状态订单返回错误(161024) -- [ ] 已完成订单不允许取消(161014) -- [ ] 取消成功后蓝色兄弟券码状态为已作废(3) -- [ ] 取消成功后订单状态为400 +- [ ] 正确解析AES加密的request参数,提取type、code、mac字段 +- [ ] 本地订单状态非"已预约"时返回"服务已生效无法取消" +- [ ] 调用邮储预约服务状态查询接口,非已预约且非已取消状态时返回"服务已生效,无法取消" +- [ ] 调用邮储预约服务状态查询接口,已取消状态时直接返回取消成功 +- [ ] 蓝色兄弟作废接口返回作废成功时正常处理 +- [ ] 蓝色兄弟作废接口超时或失败后,查询券码状态为已作废时按成功处理 +- [ ] 蓝色兄弟作废接口失败且券码状态非已作废时返回"服务取消失败,请重试" +- [ ] 邮储预约取消接口返回成功时正常处理 +- [ ] 邮储预约取消接口返回失败时提示"服务取消失败" +- [ ] 取消成功后订单状态更新为400 + +**测试用例**: + +| 用例编号 | 测试场景 | 前置条件 | 输入数据 | 预期结果 | +|---------|---------|---------|---------|----------| +| 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, 直接返回取消成功 | --- @@ -790,7 +867,83 @@ ycjfsc:token:psbc ### 6.1 服务预约流程 -TODO +```plantuml +@startuml 服务预约流程 +skinparam ActivityDiamondFontSize 12 +skinparam ActivityFontSize 12 + +start + +:AES解密request; +:解析 type(服务编码)、code(权益码)、mac(客户id); + +:查询订单状态(幂等验证); + +if (订单状态?) then (服务已预约 200) + :返回预约成功; + stop +elseif (其他状态) then + :返回"服务已预约"; + stop +else (服务未预约 100 或 订单不存在) +endif + +:查询数据库验证服务编码(type); + +if (服务编码是否存在?) then (不存在) + :返回"暂不支持此服务"; + stop +else (存在) +endif + +:请求邮储服务开放平台\n验证权益码有效性; + +if (权益码是否过期?) then (过期) + if (渠道类型?) then (CRM渠道) + :返回"二维码20分钟内有效,\n现已超时失效,请联系理财经理\n重新生成二维码"; + else (手机银行渠道) + :返回"当前页面停置时间过长,\n请您重新进入该页面"; + endif + stop +else (未过期) +endif + +:创建/更新订单记录\n(状态: 服务未预约 100); + +:请求邮储服务开放平台\n发起预约; + +if (预约结果?) then (成功 或 161010已预约) + :请求蓝色兄弟营销平台\n获取券码链接; + + if (获取券码结果?) then (成功) + :更新订单状态为\n「服务已预约 200」; + :返回预约成功\n(包含券码链接url); + stop + else (异常) + :订单状态保持\n「服务未预约 100」; + :返回预约失败; + stop + endif +else (其他情况) + :订单状态保持\n「服务未预约 100」; + :返回预约失败; + stop +endif + +@enduml +``` + +**流程步骤说明:** + +| 步骤 | 操作 | 说明 | +|-----|------|------| +| 1 | AES解密 | 对request进行AES解密,解析出type、code、mac | +| 2 | 幂等验证 | 根据订单状态决定后续流程 | +| 3 | 验证服务编码 | 查询数据库验证服务编码是否存在 | +| 4 | 验证权益码 | 调用邮储平台验证权益码有效性 | +| 5 | 创建/更新订单 | 订单状态设为「服务未预约(100)」| +| 6 | 发起预约 | 调用邮储平台发起预约 | +| 7 | 获取券码 | 调用蓝色兄弟获取券码链接,更新最终状态 | --- @@ -802,7 +955,80 @@ TODO ### 6.3 服务取消流程 -TODO +```plantuml +@startuml 服务取消流程 +start + +:接收取消请求; + +:AES解密request; +note right: 解析type、code、mac + +if (解密成功?) then (否) + :返回参数错误; + stop +endif + +:查询本地订单; + +if (订单存在?) then (否) + :返回订单不存在; + stop +endif + +if (订单状态=已预约?) then (否) + :返回"服务已生效无法取消"; + stop +endif + +:调用邮储预约服务状态查询接口; + +if (邮储状态=已取消?) then (是) + :更新本地订单状态为已取消; + :返回取消成功; + stop +endif + +if (邮储状态=已预约?) then (否) + :返回"服务已生效,无法取消"; + stop +endif + +:调用蓝色兄弟作废接口; + +if (作废成功?) then (否) + :调用蓝色兄弟券码查询接口; + if (券码状态=已作废?) then (否) + :返回"服务取消失败,请重试"; + stop + endif +endif + +:调用邮储预约取消接口; + +if (取消成功?) then (否) + :返回"服务取消失败"; + stop +endif + +:更新订单状态为已取消(400); +:返回取消成功; + +stop + +@enduml +``` + +**流程步骤说明:** + +| 步骤 | 操作 | 说明 | +|-----|------|------| +| 1 | AES解密 | 对request进行AES解密,解析出type、code、mac | +| 2 | 本地订单校验 | 查询订单是否存在且状态为已预约 | +| 3 | 邮储状态查询 | 调用邮储预约服务状态查询接口,确认可取消 | +| 4 | 蓝色兄弟作废 | 调用作废接口,失败时查询券码状态确认 | +| 5 | 邮储预约取消 | 调用邮储预约取消接口,确认取消成功 | +| 6 | 更新订单状态 | 更新本地订单状态为已取消(400) | ---