diff --git a/docs/接口文档/openapi.yaml b/docs/接口文档/openapi.yaml new file mode 100644 index 0000000..a9ec936 --- /dev/null +++ b/docs/接口文档/openapi.yaml @@ -0,0 +1,1057 @@ +openapi: 3.0.3 +info: + title: 虚拟商品充值服务商系统 - 对外接口 + description: | + 服务商系统对外提供的接口,被邮储银行服务开放平台调用。 + + ## 接口列表 + - 服务预约接口:接收预约请求,获取券码链接 + - 服务取消接口:接收取消请求,作废券码 + - 订单过期积分查询接口:查询过期幸福点信息 + - 服务详情查询接口:获取券码链接展示服务详情 + - 对账单下载接口:GET方式直接下载对账文件 + - 批量补推接口:手动批量触发服务完成通知 + + ## 公共响应结构 + 所有接口统一使用以下响应结构: + ```json + { + "code": 0, + "msg": "成功", + "traceId": "请求追踪ID", + "data": {} + } + ``` + + ## 公共响应码 + | 响应码 | 描述 | + |-------|------| + | 0 | 成功 | + | 1 | 系统异常 | + | 2 | 参数错误 | + | 3 | 签名错误 | + | 4 | 业务错误 | + + ## 时间格式 + 系统统一使用 `yyyyMMddHHmmss` 格式存储和传输时间字段。 + version: 1.0.0 + contact: + name: 服务商系统技术支持 + +servers: + - url: https://api.example.com + description: 生产环境 + - url: https://api-test.example.com + description: 测试环境 + +tags: + - name: 服务预约 + description: 服务预约相关接口 + - name: 服务取消 + description: 服务取消相关接口 + - name: 积分查询 + description: 积分查询相关接口 + - name: 服务详情 + description: 服务详情查询接口 + - name: 对账管理 + description: 对账管理相关接口 + +paths: + /api/v1/service/appointment: + post: + tags: + - 服务预约 + summary: 服务预约接口 + description: | + 接收邮储银行服务开放平台的预约请求,为客户预约虚拟商品充值服务。 + + ## 业务规则 + 1. 查询数据库验证服务编码(type)是否存在 + 2. 使用AES解密request参数,解析出type、code、mac + 3. 基于权益码(code)获取分布式锁,防止重复请求 + 4. 对code(权益码)进行幂等验证 + 5. 验证权益码是否过期 + 6. 创建/更新订单记录 + 7. 请求邮储服务开放平台发起预约 + 8. 请求蓝色兄弟营销平台获取券码链接 + operationId: serviceAppointment + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AppointmentRequest' + examples: + normal: + summary: 正常预约请求 + value: + type: "310001" + request: "AES加密字符串" + channel: "12" + tranChnl: "12" + backUrl: "https://mobile.psbc.com/back" + instType: "01" + provinceInstNo: "100000" + responses: + '200': + description: 预约成功 + content: + application/json: + schema: + $ref: '#/components/schemas/AppointmentResponse' + examples: + success: + summary: 预约成功 + value: + code: 0 + msg: "成功" + traceId: "26031314253001000001" + data: + url: "https://lsb.example.com/redeem/abc123" + tranChnl: "12" + instType: "01" + backUrl: "https://mobile.psbc.com/back" + '400': + description: 参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + paramError: + summary: 参数错误 + value: + code: 2 + msg: "参数错误" + traceId: "26031314253001000002" + serviceNotFound: + summary: 服务编码不存在 + value: + code: 4 + msg: "暂不支持此服务" + traceId: "26031314253001000003" + '500': + description: 系统异常 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + systemError: + summary: 系统异常 + value: + code: 1 + msg: "系统异常" + traceId: "26031314253001000004" + + /api/v1/service/cancel: + post: + tags: + - 服务取消 + summary: 服务取消接口 + description: | + 接收邮储银行服务开放平台的取消请求,取消已预约的服务。 + + ## 业务规则 + 1. 对request进行AES解密,解析出type、code、mac + 2. 基于权益码(code)获取分布式锁,防止重复请求 + 3. 检查订单状态必须是已预约状态才能取消 + 4. 调用邮储预约服务状态查询接口查询状态 + 5. 调用蓝色兄弟作废接口发起作废 + 6. 调用邮储接口发起预约取消 + 7. 订单状态更新为"已取消"(400) + operationId: serviceCancel + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CancelRequest' + examples: + normal: + summary: 正常取消请求 + value: + type: "310001" + request: "AES加密字符串" + channel: "12" + tranChnl: "12" + backUrl: "https://mobile.psbc.com/back" + instType: "01" + provinceInstNo: "100000" + responses: + '200': + description: 取消成功 + content: + application/json: + schema: + $ref: '#/components/schemas/CancelResponse' + examples: + success: + summary: 取消成功 + value: + code: 0 + msg: "成功" + traceId: "26031314253001000005" + data: + tranChnl: "12" + instType: "01" + backUrl: "https://mobile.psbc.com/back" + '400': + description: 参数错误或业务错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + paramError: + summary: 参数错误 + value: + code: 2 + msg: "参数错误" + traceId: "26031314253001000006" + serviceNotFound: + summary: 服务编码不存在 + value: + code: 4 + msg: "暂不支持此服务" + traceId: "26031314253001000007" + serviceExpired: + summary: 服务已过期 + value: + code: 4 + msg: "服务已过期" + traceId: "26031314253001000008" + serviceCompleted: + summary: 服务已生效无法取消 + value: + code: 4 + msg: "服务已生效无法取消" + traceId: "26031314253001000009" + '500': + description: 系统异常 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + systemError: + summary: 系统异常 + value: + code: 1 + msg: "系统异常" + traceId: "26031314253001000010" + + /api/v1/order/expired-points: + post: + tags: + - 积分查询 + summary: 订单过期积分查询接口 + description: | + 查询订单退还时已过期的幸福点信息,用于取消前提醒客户。 + + ## 业务规则 + 1. 验证服务编码(type),查询数据库获取AES解密密钥 + 2. 服务编码不存在返回"暂不支持此服务" + 3. 解密request参数获取服务编码、权益码、客户ID + 4. 调用邮储「高端客户权益订单退还时已过期积分查询」接口 + 5. 返回邮储接口查询结果 + operationId: queryExpiredPoints + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExpiredPointsRequest' + examples: + normal: + summary: 正常查询请求 + value: + type: "310001" + request: "AES加密字符串" + channel: "12" + tranChnl: "12" + backUrl: "https://mobile.psbc.com/back" + instType: "01" + provinceInstNo: "100000" + responses: + '200': + description: 查询成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ExpiredPointsResponse' + examples: + success: + summary: 查询成功 + value: + code: 0 + msg: "成功" + traceId: "26031314253001000011" + data: + tranIntglNum: 1000 + ovdueIntglNum: 200 + noticeMsg: "您有200幸福点已过期,取消后将无法退回" + '400': + description: 参数错误或业务错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + paramError: + summary: 参数错误 + value: + code: 2 + msg: "参数错误" + traceId: "26031314253001000012" + serviceNotFound: + summary: 服务编码不存在 + value: + code: 4 + msg: "暂不支持此服务" + traceId: "26031314253001000013" + '500': + description: 系统异常 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + systemError: + summary: 系统异常 + value: + code: 1 + msg: "查询失败,请重试" + traceId: "26031314253001000014" + + /api/v1/service/detail: + post: + tags: + - 服务详情 + summary: 服务详情查询接口 + description: | + 提供给邮储银行跳转服务详情页面,根据参数获取上游券码链接展示服务详情。 + + ## 业务规则 + 1. 验证服务编码(type),查询数据库获取AES解密密钥 + 2. 服务编码不存在返回"暂不支持此服务" + 3. 解密request参数获取服务编码、权益码、客户ID + 4. 根据权益码查询订单获取券码链接 + 5. 返回券码链接用于页面展示 + operationId: queryServiceDetail + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceDetailRequest' + examples: + normal: + summary: 正常查询请求 + value: + type: "310001" + request: "AES加密字符串" + channel: "12" + tranChnl: "12" + backUrl: "https://mobile.psbc.com/back" + instType: "01" + provinceInstNo: "100000" + responses: + '200': + description: 查询成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceDetailResponse' + examples: + success: + summary: 查询成功 + value: + code: 0 + msg: "成功" + traceId: "26031314253001000015" + data: + codeUrl: "https://lsb.example.com/redeem/abc123" + backUrl: "https://mobile.psbc.com/back" + '400': + description: 参数错误或业务错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + paramError: + summary: 参数错误 + value: + code: 2 + msg: "参数错误" + traceId: "26031314253001000016" + serviceNotFound: + summary: 服务编码不存在 + value: + code: 4 + msg: "暂不支持此服务" + traceId: "26031314253001000017" + orderNotFound: + summary: 订单不存在 + value: + code: 1 + msg: "订单不存在" + traceId: "26031314253001000018" + '500': + description: 系统异常 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + systemError: + summary: 系统异常 + value: + code: 1 + msg: "系统异常" + traceId: "26031314253001000019" + + /api/v1/reconciliation/download: + get: + tags: + - 对账管理 + summary: 对账单下载接口 + description: | + 提供GET方式直接下载对账文件,用于管理员或运营人员获取本地处理后的对账数据。 + + ## 业务规则 + 1. 每月3号生成上月服务状态为「服务已完成(300)」的权益订单对账文件 + 2. 对账月份规则:服务完成时间所在月份为对账月份 + 3. 对账文件名称格式:RIGHTS_SERVICE_CHK_{providerCode}_{reconMonth}.csv + 4. 支持按对账月份查询和下载 + 5. 文件格式为CSV,编码UTF-8-BOM(兼容Excel中文显示) + + ## 对账文件内容字段 + | 序号 | 字段名 | 说明 | + |-----|-------|------| + | 1 | 统计月份 | YYYYMM | + | 2 | 一分机构序号 | province_inst_no | + | 3 | 一分机构名称 | 根据机构号映射 | + | 4 | 网点机构属性 | 01-自营,02-代理 | + | 5 | 积分客户服务编码 | type字段 | + | 6 | 服务内容 | 服务名称 | + | 7 | 预约时间 | yyyyMMddHHmmss | + | 8 | 实际完成时间 | yyyyMMddHHmmss | + | 9 | 权益兑换码 | code字段 | + | 10 | 订单号 | order_no | + | 11 | 券码状态 | 1-正常,2-已核销,3-已作废,4-已过期 | + operationId: downloadReconciliation + parameters: + - name: reconMonth + in: query + required: true + description: 对账月份,格式:YYYYMM,例如:202512 + schema: + type: string + pattern: '^\d{6}$' + example: "202512" + - name: providerCode + in: query + required: false + description: 服务厂商编号,默认为当前服务商编号,例如:A101 + schema: + type: string + example: "A101" + maxLength: 4 + responses: + '200': + description: 下载成功 + content: + text/csv: + schema: + type: string + format: binary + headers: + Content-Disposition: + description: 文件名 + schema: + type: string + example: 'attachment; filename="RIGHTS_SERVICE_CHK_A101_202512.csv"' + '400': + description: 参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + paramError: + summary: 参数错误 + value: + code: 2 + msg: "参数错误" + traceId: "26031314253001000020" + monthExceed: + summary: 对账月份超过当前月 + value: + code: 4 + msg: "对账月份不能超过上月" + traceId: "26031314253001000021" + noData: + summary: 无对账数据 + value: + code: 4 + msg: "暂无对账数据" + traceId: "26031314253001000022" + '500': + description: 系统异常 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + systemError: + summary: 系统异常 + value: + code: 1 + msg: "系统异常" + traceId: "26031314253001000023" + + /api/v1/reconciliation/batch-repush: + post: + tags: + - 对账管理 + summary: 批量补推接口 + description: | + 手动批量触发服务完成通知,用于处理蓝色兄弟已核销但邮储银行未收到服务完成通知的订单。 + + ## 业务规则 + 1. 查询本地订单状态为「服务已预约(200)」且券码状态为「已核销(2)」的订单 + 2. 批量创建服务完成通知任务(task_type=1) + 3. 支持按时间范围、权益码列表筛选(二选一) + 4. 单次补推数量限制:最多100笔 + 5. 幂等处理:已存在相同类型的待处理任务时跳过 + 6. 支持试运行模式(dryRun),只查询不创建任务 + operationId: batchRepush + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BatchRepushRequest' + examples: + byCodes: + summary: 按权益码列表补推 + value: + codes: + - "16800G-VN4724-NX874-30VHR" + - "16800G-VN4724-NX874-30VHS" + dryRun: false + byTimeRange: + summary: 按时间范围补推 + value: + startTime: "20251201000000" + endTime: "20251231235959" + dryRun: false + dryRunMode: + summary: 试运行模式 + value: + startTime: "20251201000000" + endTime: "20251231235959" + dryRun: true + responses: + '200': + description: 补推成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BatchRepushResponse' + examples: + success: + summary: 补推成功 + value: + code: 0 + msg: "成功" + traceId: "26031314253001000024" + data: + totalCount: 3 + createdCount: 2 + skippedCount: 1 + dryRunSuccess: + summary: 试运行成功 + value: + code: 0 + msg: "成功" + traceId: "26031314253001000025" + data: + totalCount: 3 + createdCount: 0 + skippedCount: 0 + orders: + - orderNo: "26031314253001000001" + code: "16800G-VN4724-NX874-30VHR" + status: 200 + keyStatus: 2 + keyUsageTime: "20251215143000" + hasTask: false + - orderNo: "26031314253001000002" + code: "16800G-VN4724-NX874-30VHS" + status: 200 + keyStatus: 2 + keyUsageTime: "20251216101530" + hasTask: true + '400': + description: 参数错误或业务错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + paramError: + summary: 参数错误 + value: + code: 2 + msg: "参数错误:权益码列表和时间范围必须二选一" + traceId: "26031314253001000026" + exceedLimit: + summary: 超过数量限制 + value: + code: 2 + msg: "单次补推数量不能超过100笔" + traceId: "26031314253001000027" + tooManyOrders: + summary: 符合条件订单超过限制 + value: + code: 4 + msg: "符合条件的订单超过100笔,请缩小时间范围或使用权益码列表" + traceId: "26031314253001000028" + '500': + description: 系统异常 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + systemError: + summary: 系统异常 + value: + code: 1 + msg: "系统异常" + traceId: "26031314253001000029" + +components: + schemas: + # ============ 请求参数 ============ + BaseRequest: + type: object + required: + - type + - request + - channel + - tranChnl + - instType + - provinceInstNo + properties: + type: + type: string + description: 服务编码,用于查询数据库获取AES解密密钥 + example: "310001" + maxLength: 6 + request: + type: string + description: | + AES加密字符串 + 解密后格式:type=服务编码&code=权益码&mac=加密后的客户id + 加密算法:AES/CBC/PKCS5Padding + Key长度:16位 + IV长度:16位 + 编码方式:Base64 + example: "U2FsdGVkX1+abc123..." + channel: + type: string + description: 渠道标识 + enum: + - "12" + - "17" + - "41" + x-enum-descriptions: + - 手机银行 + - 电话银行 + - CRM零售 + example: "12" + maxLength: 4 + tranChnl: + type: string + description: 渠道标识 + enum: + - "12" + - "17" + - "41" + x-enum-descriptions: + - 手机银行 + - 电话银行 + - CRM零售 + example: "12" + maxLength: 4 + backUrl: + type: string + description: 返回手机银行的地址,可为空 + example: "https://mobile.psbc.com/back" + maxLength: 256 + instType: + type: string + description: 客户自营代理属性 + enum: + - "01" + - "02" + x-enum-descriptions: + - 自营 + - 代理 + example: "01" + maxLength: 2 + provinceInstNo: + type: string + description: 客户归属一分机构号 + example: "100000" + maxLength: 20 + + AppointmentRequest: + allOf: + - $ref: '#/components/schemas/BaseRequest' + description: 服务预约请求参数 + + CancelRequest: + allOf: + - $ref: '#/components/schemas/BaseRequest' + description: 服务取消请求参数 + + ExpiredPointsRequest: + allOf: + - $ref: '#/components/schemas/BaseRequest' + description: 订单过期积分查询请求参数 + + ServiceDetailRequest: + allOf: + - $ref: '#/components/schemas/BaseRequest' + description: 服务详情查询请求参数 + + BatchRepushRequest: + type: object + description: | + 批量补推请求参数 + 注意:codes 和 startTime/endTime 必须二选一 + properties: + codes: + type: array + description: 权益码列表,最多100个,与时间范围二选一 + items: + type: string + maxItems: 100 + example: + - "16800G-VN4724-NX874-30VHR" + - "16800G-VN4724-NX874-30VHS" + startTime: + type: string + description: 开始时间,格式:yyyyMMddHHmmss,与codes二选一 + pattern: '^\d{14}$' + example: "20251201000000" + endTime: + type: string + description: 结束时间,格式:yyyyMMddHHmmss,与codes二选一 + pattern: '^\d{14}$' + example: "20251231235959" + dryRun: + type: boolean + description: 是否试运行,默认false。true时只返回待补推订单列表,不实际创建任务 + default: false + example: false + + # ============ 响应参数 ============ + BaseResponse: + type: object + required: + - code + - msg + - traceId + properties: + code: + type: integer + description: | + 公共响应码 + - 0: 成功 + - 1: 系统异常 + - 2: 参数错误 + - 3: 签名错误 + - 4: 业务错误 + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + example: 0 + msg: + type: string + description: 响应描述信息,当code!=0时为错误信息 + example: "成功" + traceId: + type: string + description: 请求追踪ID,用于问题排查。使用雪花算法或UUID确保全局唯一 + example: "26031314253001000001" + maxLength: 32 + + AppointmentResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + description: 业务数据 + required: + - url + - tranChnl + - instType + properties: + url: + type: string + description: 蓝色兄弟营销平台的兑换地址 + example: "https://lsb.example.com/redeem/abc123" + maxLength: 125 + tranChnl: + type: string + description: 渠道标识 + example: "12" + maxLength: 4 + instType: + type: string + description: 客户自营代理属性 + example: "01" + maxLength: 2 + backUrl: + type: string + description: 返回手机银行的地址 + example: "https://mobile.psbc.com/back" + maxLength: 256 + + CancelResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + description: 业务数据 + required: + - tranChnl + - instType + properties: + tranChnl: + type: string + description: 渠道标识 + example: "12" + maxLength: 4 + instType: + type: string + description: 客户自营代理属性 + example: "01" + maxLength: 2 + backUrl: + type: string + description: 返回手机银行的地址 + example: "https://mobile.psbc.com/back" + maxLength: 256 + + ExpiredPointsResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + description: 业务数据 + properties: + tranIntglNum: + type: integer + description: 交易总幸福点 + example: 1000 + ovdueIntglNum: + type: integer + description: 已过期的幸福点 + example: 200 + noticeMsg: + type: string + description: 提醒信息文本 + example: "您有200幸福点已过期,取消后将无法退回" + + ServiceDetailResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + description: 业务数据 + required: + - codeUrl + - backUrl + properties: + codeUrl: + type: string + description: 券码链接,用于展示服务详情 + example: "https://lsb.example.com/redeem/abc123" + maxLength: 125 + backUrl: + type: string + description: 返回手机银行的地址 + example: "https://mobile.psbc.com/back" + maxLength: 256 + + ErrorResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + description: 错误响应 + + BatchRepushResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + description: 业务数据 + required: + - totalCount + - createdCount + - skippedCount + properties: + totalCount: + type: integer + description: 符合条件的订单总数 + example: 3 + createdCount: + type: integer + description: 新创建的任务数(dryRun=true时为0) + example: 2 + skippedCount: + type: integer + description: 跳过的订单数(已有待处理任务) + example: 1 + orders: + type: array + description: 订单列表(dryRun=true时返回) + items: + $ref: '#/components/schemas/RepushOrderItem' + + RepushOrderItem: + type: object + description: 补推订单信息 + required: + - orderNo + - code + - status + - keyStatus + - hasTask + properties: + orderNo: + type: string + description: 订单号 + example: "26031314253001000001" + maxLength: 32 + code: + type: string + description: 权益码 + example: "16800G-VN4724-NX874-30VHR" + maxLength: 32 + status: + type: integer + description: |订单状态 + - 100: 服务未预约 + - 200: 服务已预约 + - 300: 服务已完成 + - 400: 服务已取消 + - 500: 服务已过期 + example: 200 + keyStatus: + type: integer + description: |券码状态 + - 0: 待生成 + - 1: 正常 + - 2: 已核销 + - 3: 已作废 + - 4: 已过期 + example: 2 + keyUsageTime: + type: string + description: 核销时间,格式:yyyyMMddHHmmss + example: "20251215143000" + hasTask: + type: boolean + description: 是否已有待处理任务 + example: false + + # ============ 枚举定义 ============ + Channel: + type: string + description: 渠道标识 + enum: + - "12" + - "17" + - "41" + x-enum-descriptions: + - 手机银行 + - 电话银行 + - CRM零售 + + InstType: + type: string + description: 客户自营代理属性 + enum: + - "01" + - "02" + x-enum-descriptions: + - 自营 + - 代理 + + ResponseCode: + type: integer + description: 公共响应码 + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + x-enum-descriptions: + - 成功 + - 系统异常 + - 参数错误 + - 签名错误 + - 业务错误 + + OrderStatus: + type: integer + description: 订单状态 + enum: + - 100 + - 200 + - 300 + - 400 + - 500 + x-enum-descriptions: + - 服务未预约 + - 服务已预约 + - 服务已完成 + - 服务已取消 + - 服务已过期 + + KeyCodeStatus: + type: integer + description: 券码状态 + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + x-enum-descriptions: + - 待生成 + - 正常 + - 已核销 + - 已作废 + - 已过期 diff --git a/docs/需求文档-PRD.md b/docs/需求文档-PRD.md index 71692dd..782e710 100644 --- a/docs/需求文档-PRD.md +++ b/docs/需求文档-PRD.md @@ -10,6 +10,9 @@ | 服务取消接口 | 接收取消请求,作废券码 | [3.1.2](#312-服务取消接口) | | 订单过期积分查询接口 | 查询过期幸福点信息 | [3.1.4](#314-订单过期积分查询接口) | | 服务详情查询接口 | 获取券码链接展示服务详情 | [3.1.6](#316-服务详情查询接口) | +| 对账文件查询接口 | 查询可用的对账文件列表 | [3.4.3](#343-对账文件查询接口) | +| 对账文件下载接口 | 根据文件ID下载对账文件 | [3.4.4](#344-对账文件下载接口) | +| 批量补推接口 | 手动批量触发服务完成通知 | [3.4.5](#345-批量补推接口) | ### 调用下游的接口(调用邮储银行API) @@ -730,6 +733,132 @@ --- +#### 3.4.3 对账单下载接口 + +**功能描述**:提供GET方式直接下载对账文件,用于管理员或运营人员获取本地处理后的对账数据 + +**接口信息**: +- 请求方式:GET +- 接口路径:/api/v1/reconciliation/download + +**业务规则**: +1. 每月3号生成上月服务状态为「服务已完成(300)」的权益订单对账文件 +2. 对账月份规则:服务完成时间所在月份为对账月份 + - 例如:服务完成时间 202512210000,对账月份为 2025年12月,对账文件在 2026年1月3日生成 +3. 对账文件名称格式:`RIGHTS_SERVICE_CHK_{providerCode}_{reconMonth}.csv` + - 例如:`RIGHTS_SERVICE_CHK_A101_202512.csv` +4. 支持按对账月份查询和下载 +5. 文件格式为CSV,内容与邮储对账文件格式一致 + +**输入**: +| 字段 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| reconMonth | String | M | 对账月份,格式:YYYYMM,例如:202512 | +| providerCode | String | C | 服务厂商编号,默认为当前服务商编号,例如:A101 | + +**输出**: +直接返回文件流,Content-Type: text/csv,Content-Disposition: attachment; filename="RIGHTS_SERVICE_CHK_A101_202512.csv" + +**对账文件内容字段**: +| 序号 | 字段名 | 说明 | +|-----|-------|------| +| 1 | 统计月份 | YYYYMM | +| 2 | 一分机构序号 | province_inst_no | +| 3 | 一分机构名称 | 根据机构号映射 | +| 4 | 网点机构属性 | 01-自营,02-代理 | +| 5 | 积分客户服务编码 | type字段 | +| 6 | 服务内容 | 服务名称 | +| 7 | 预约时间 | appointment_time,格式:yyyyMMddHHmmss | +| 8 | 实际完成时间 | key_usage_time,格式:yyyyMMddHHmmss | +| 9 | 权益兑换码 | code字段 | +| 10 | 订单号 | order_no | +| 11 | 券码状态 | key_status:1-正常,2-已核销,3-已作废,4-已过期 | + +**验收标准**: +- [ ] GET请求能正确下载对账文件 +- [ ] 对账月份参数校验:格式必须为YYYYMM,且不能超过当前月份 +- [ ] 对账文件只包含status=300(服务已完成)的订单 +- [ ] 对账文件按服务完成时间所在月份归档 +- [ ] 文件名格式正确:RIGHTS_SERVICE_CHK_{providerCode}_{reconMonth}.csv +- [ ] 对账月份不存在数据时返回空文件或提示"暂无对账数据" +- [ ] 文件内容编码为UTF-8-BOM(兼容Excel中文显示) + +**测试用例**: + +| 用例编号 | 测试场景 | 前置条件 | 输入数据 | 预期结果 | +|---------|---------|---------|---------|----------| +| TC-3.4.3-001 | 正常下载对账文件 | 2025年12月有已完成订单 | reconMonth=202512 | 返回CSV文件流,文件名正确 | +| TC-3.4.3-002 | 对账月份格式错误 | - | reconMonth=2025-12 | code=2, msg="参数错误" | +| TC-3.4.3-003 | 对账月份超过当前月 | 当前为2026年1月 | reconMonth=202602 | code=4, msg="对账月份不能超过上月" | +| TC-3.4.3-004 | 对账月份无数据 | 2025年11月无已完成订单 | reconMonth=202511 | code=4, msg="暂无对账数据" | +| TC-3.4.3-005 | 指定服务商编号 | A101有数据,B101无数据 | reconMonth=202512, providerCode=B101 | code=4, msg="暂无对账数据" | + +--- + +#### 3.4.4 批量补推接口 + +**功能描述**:手动批量触发服务完成通知,用于处理蓝色兄弟已核销但邮储银行未收到服务完成通知的订单 + +**接口信息**: +- 请求方式:POST +- 接口路径:/api/v1/reconciliation/batch-repush + +**业务规则**: +1. 查询本地订单状态为「服务已预约(200)」且券码状态为「已核销(2)」的订单 +2. 批量创建服务完成通知任务(task_type=1) +3. 支持按时间范围、权益码列表筛选 +4. 单次补推数量限制:最多100笔 +5. 幂等处理:已存在相同类型的待处理任务时跳过 + +**输入**: +| 字段 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| codes | String[] | C | 权益码列表,最多100个,与时间范围二选一 | +| startTime | String | C | 开始时间,格式:yyyyMMddHHmmss,与codes二选一 | +| endTime | String | C | 结束时间,格式:yyyyMMddHHmmss,与codes二选一 | +| dryRun | boolean | C | 是否试运行,默认false。true时只返回待补推订单列表,不实际创建任务 | + +**输出**(data字段内容): +| 字段 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| totalCount | int | M | 符合条件的订单总数 | +| createdCount | int | M | 新创建的任务数(dryRun=true时为0) | +| skippedCount | int | M | 跳过的订单数(已有待处理任务) | +| orders | Object[] | C | 订单列表(dryRun=true时返回) | +| orders[].orderNo | String | M | 订单号 | +| orders[].code | String | M | 权益码 | +| orders[].status | int | M | 订单状态 | +| orders[].keyStatus | int | M | 券码状态 | +| orders[].keyUsageTime | String | C | 核销时间 | +| orders[].hasTask | boolean | M | 是否已有待处理任务 | + +**验收标准**: +- [ ] 只处理本地status=200(已预约)且key_status=2(已核销)的订单 +- [ ] 权益码列表和时间范围必须二选一 +- [ ] 权益码列表最多100个,超过返回"单次补推数量不能超过100笔" +- [ ] 时间范围查询结果超过100笔时返回"符合条件的订单超过100笔,请缩小时间范围或使用权益码列表" +- [ ] 幂等处理:订单已有task_type=1且status!=2(已完成)的任务时跳过 +- [ ] dryRun=true时只查询不创建任务 +- [ ] 创建的任务trigger_source=2(主动查询/手动触发) +- [ ] 补推成功后返回创建的任务数和跳过的订单数 + +**测试用例**: + +| 用例编号 | 测试场景 | 前置条件 | 输入数据 | 预期结果 | +|---------|---------|---------|---------|----------| +| TC-3.4.4-001 | 按权益码批量补推 | 3笔订单status=200,key_status=2 | codes=["code1","code2","code3"] | code=0, createdCount=3 | +| TC-3.4.4-002 | 按时间范围批量补推 | 2笔订单符合条件 | startTime=20251201000000, endTime=20251231235959 | code=0, createdCount=2 | +| TC-3.4.4-003 | 试运行模式 | 2笔订单符合条件 | codes=["code1","code2"], dryRun=true | code=0, createdCount=0, orders返回2笔 | +| TC-3.4.4-004 | 权益码超过100个 | - | codes=[101个权益码] | code=2, msg="单次补推数量不能超过100笔" | +| TC-3.4.4-005 | 时间范围结果超100笔 | 150笔订单符合条件 | startTime/endTime | code=4, msg="符合条件的订单超过100笔" | +| TC-3.4.4-006 | 参数缺失 | - | 不传codes和时间范围 | code=2, msg="参数错误:权益码列表和时间范围必须二选一" | +| TC-3.4.4-007 | 幂等-已有待处理任务 | code1已有task_type=1,status=0的任务 | codes=["code1"] | code=0, createdCount=0, skippedCount=1 | +| TC-3.4.4-008 | 订单状态不符合 | 订单status=300(已完成) | codes=["code1"] | code=0, totalCount=0 | +| TC-3.4.4-009 | 券码状态不符合 | 订单key_status=1(正常) | codes=["code1"] | code=0, totalCount=0 | +| TC-3.4.4-010 | 混合场景 | 2笔符合,1笔已有任务,1笔状态不符 | codes=[4个权益码] | code=0, totalCount=2, createdCount=1, skippedCount=1 | + +--- + ### 3.5 安全与加密模块 #### 3.5.1 邮储银行加解密(SM2/SM4/AES) @@ -1415,7 +1544,154 @@ stop ### 6.4 月度对账流程 -TODO +```plantuml +@startuml 月度对账流程 +start + +:定时任务触发(每月3号); + +:查询上月status=300(已完成)的订单; +note right: 对账月份=服务完成时间所在月 + +if (有订单数据?) then (无) + :跳过,不生成对账文件; + stop +endif + +:生成对账文件; +note right: RIGHTS_SERVICE_CHK_{providerCode}_{reconMonth}.csv + +:调用邮储对账文件查询接口; +note right: 5s超时 + +if (获取文件列表成功?) then (否) + :记录错误,等待重试; + stop +endif + +:调用邮储对账文件下载接口; +note right: 5s超时 + +if (下载成功?) then (否) + :记录错误,等待重试; + stop +endif + +:SM4解密对账文件; + +:解析对账文件内容; + +while (遍历邮储对账记录?) is (有) + :根据权益码查询本地订单; + + if (本地订单存在?) then (否) + :记录差异-本地缺失; + elseif (状态一致?) then (否) + :记录差异-状态不一致; + :创建服务完成通知任务; + else (是) + :标记为已对账; + endif +endwhile (无) + +:保存对账结果; + +if (有差异?) then (是) + :发送告警通知; +endif + +:生成对账报告; + +stop + +@enduml +``` + +**流程步骤说明**: + +| 步骤 | 操作 | 说明 | +|-----|------|------| +| 1 | 定时触发 | 每月3号执行 | +| 2 | 查询本地订单 | 查询上月status=300(已完成)的订单 | +| 3 | 生成对账文件 | 生成CSV格式对账文件 | +| 4 | 获取邮储对账文件 | 调用邮储查询和下载接口(5s超时) | +| 5 | SM4解密 | 使用SM4密钥解密对账文件 | +| 6 | 数据核对 | 逐笔对比邮储和本地数据 | +| 7 | 差异处理 | 本地缺失或状态不一致时创建补推任务 | +| 8 | 生成报告 | 保存对账结果,有差异时发送告警 | + +**对账月份规则**: + +| 服务完成时间 | 对账月份 | 对账文件生成时间 | 对账文件名 | +|--------------|---------|--------------|----------| +| 202512210000 | 202512 | 2026年1月3日 | RIGHTS_SERVICE_CHK_A101_202512.csv | +| 202601010000 | 202601 | 2026年2月3日 | RIGHTS_SERVICE_CHK_A101_202601.csv | + +### 6.4.1 批量补推流程 + +```plantuml +@startuml 批量补推流程 +start + +:接收补推请求; + +if (参数校验?) then (失败) + :返回参数错误; + stop +endif + +if (传入codes?) then (是) + if (codes数量>100?) then (是) + :返回"单次补推不能超过100笔"; + stop + endif + :按权益码列表查询订单; +else (否) + :按时间范围查询订单; + if (结果数量>100?) then (是) + :返回"符合条件订单超过100笔"; + stop + endif +endif + +:筛选status=200且key_status=2的订单; + +if (dryRun=true?) then (是) + :返回待补推订单列表; + stop +endif + +while (遍历订单?) is (有) + :检查是否已有待处理任务; + + if (已有任务?) then (是) + :skippedCount++; + else (否) + :创建服务完成通知任务; + note right: task_type=1\ntrigger_source=2 + :createdCount++; + endif +endwhile (无) + +:返回补推结果; +note right: totalCount, createdCount, skippedCount + +stop + +@enduml +``` + +**流程步骤说明**: + +| 步骤 | 操作 | 说明 | +|-----|------|------| +| 1 | 参数校验 | codes和时间范围必须二选一 | +| 2 | 数量校验 | 单次最多处理100笔 | +| 3 | 查询订单 | 筛选status=200且key_status=2的订单 | +| 4 | 试运行判断 | dryRun=true时只查询不创建任务 | +| 5 | 幂等检查 | 已有待处理任务的订单跳过 | +| 6 | 创建任务 | task_type=1, trigger_source=2 | +| 7 | 返回结果 | 包含创建数量和跳过数量 | ---