Pluxee 券类型 · 券码类型 · Validate 场景

依据 Merchant API v2.8 · POST /voucher/validate 场景 a–h

图1 · 券码类型分类(API 可识别)

文档未返回 type 字段,以下依据请求/响应行为推断

录入的券码 Body[] 普通单券 1 码 = 1 张券 输入: ["0473990306"] 响应 code 与输入一致 返回: isValid + faceValue 场景 a / b / c 组券 Group Voucher 1 组码 → 展开多张子券 输入: ["0001234567"] 组码 响应 code 变为子券码 validVoucherCodes = 子券列表 场景 f / g / h 组内子券 组券展开后的单张券 如: 7439470471 Validate 可单独出现 Redeem 时不可与组码混用 见 Redeem 场景 h
普通单券 — 输入码 = 响应码 组券 — 输入 1 码,响应 N 张子券 子券 — 组券内部成员,Redeem 有混用限制

图2 · 券类型(Product Type)与 separate 字段

API 不返回类型名称,仅通过 separate 标识批量券是否同类型

批量验券 ["code1","code2",...] Pluxee 内部比对 product type separate: true 所有券 = 同一 product type 例: 场景 a 两张普通券 例: 场景 f 组券展开子券 产品含义: 同类券,可视为一批处理 separate: false 券码 = 不同 product type 文档未给 separate:false 样例 Redeem 是否允许 — 文档未说明 产品建议: UI 提示「券类型不一致」
券类型(product type)是 Pluxee 后台配置的内部分类,API 不暴露类型 ID/名称。我方只能读 separate 做提示,不能当作核销硬性规则。

图3 · Validate 总决策树(场景 a–h 路由)

从请求进入到响应分支的完整判定流程

POST /voucher/validate Header 合法? 场景 d HTTP 401 Body 合法? 非[]/null/[null] 场景 e HTTP 400 券码类型? 普通券 组券 Group 有重复码? 全部有效? 场景 c 重复·200 场景 a 全有效·200 场景 b 部分无效·200 组码有效? 场景 g 无效组券·200 重复 组码? 场景 f 有效组券·200 场景 h 重复组券·200 场景速查 a 普通券全有效 · f 组券有效展开 b 部分无效 · c 普通重复 · h 组券重复 d Header 401 · e Body 400 · g 无效组券 HTTP 200 场景: a b c f g h(业务成败看 areAllVouchersValid) HTTP 401/400: d e(请求层失败,未进入券校验) → 仅 areAllVouchersValid=true 才可进入 Redeem

图4 · 场景 a–h 对比矩阵

一图看清输入、HTTP、核心响应、能否核销

场景 券码类型 请求 Body 示例 HTTP areAllValid totalFaceValue 能否 Redeem a 普通券["0473990306","3629327113"] 200true600 ✓ 可核销 b 普通券["0123456789","01234567"] 200false1000 ✗ 不可核销(有无效券) c 普通券["0123456789","0123456789"] 200false1000 ✗ 不可核销(重复码) d 任意Header 非法 401 ✗ 未进入验券 e 任意[] / null / [null] 400 ✗ 未进入验券 f 组券["0001234567"] 200true20000 ✓ 可核销(Redeem 传组码) g 组券["2726518"] 200false0 ✗ 不可核销 h 组券["05375611","05375611"] 200false20000 ✗ 不可核销(重复组码)

图5 · 场景 a–h 详细说明卡

每个场景的输入、响应结构、UI 建议

场景 a · 成功

全部普通券有效

Body: ["0473990306","3629327113"]
HTTP 200 areAllVouchersValid: true faceValue: 100 + 500 totalFaceValue: 600 separate: true → 可进入 Redeem
场景 b · 部分失败

部分普通券无效

Body: ["0123456789","01234567"]
HTTP 200(注意仍是 200) areAllVouchersValid: false valid: ["0123456789"] faceValue 1000 invalid: ["01234567"] → 移除无效券后可重新验券
场景 c · 重复

普通券重复提交

Body: ["0123456789","0123456789"]
HTTP 200 第1条: isValid true, faceValue 1000 第2条: isValid false(重复) invalidVoucherCodes: ["0123456789"] → 前端应防重复录入
场景 d · 401

Header 非法

Auth/Merchant/POS/DateTime 任一无效或为空
HTTP 401 {"message":"Unauthorized"} → 检查配置,非券码问题
场景 e · 400

Body 非法

Body: [] / null / [null]
HTTP 400 {"message":"Bad Request"} → 未录入券码不应发起请求
场景 f · 组券成功

有效组券展开

Body: ["0001234567"](1 个组码)
HTTP 200 areAllVouchersValid: true 展开: 7439470471 + 3575594396 各 faceValue 10000, total 20000 validVoucherCodes = 子券码 → Redeem 仍传组码
场景 g · 无效组券

组券码本身无效

Body: ["2726518"]
HTTP 200 areAllVouchersValid: false isValid: false, totalFaceValue: 0 validVoucherCodes: [] → 提示券码无效
场景 h · 重复组券

同一组码提交两次

Body: ["05375611","05375611"]
HTTP 200 areAllVouchersValid: false 展开 2 组子券,部分 isValid true invalidVoucherCodes: ["58063524"] totalFaceValue: 20000 → 虽计算出面值,仍不可 Redeem

图6 · Validate 响应 → 业务动作映射

产品经理视角:每个场景收银端应该做什么

Validate 结果 判断条件 收银端动作 a / f 成功 areAllVouchersValid=true HTTP 200 + 全部有效 展示 totalFaceValue · 启用「确认抵扣」 separate=false 时可加提示 b 部分无效 areAllVouchersValid=false HTTP 200 但有 invalid 列表 高亮无效券 · 禁用核销按钮 引导移除后重新验券 c / h 重复 普通重复 / 组券重复 第2次出现判 invalid 提示「券码重复」· 自动去重 h 场景即使有 totalFaceValue 也不可核销 g 无效组券 totalFaceValue=0 组码 isValid=false 提示「组券无效」· 清空重录 d / e 请求错误 401 / 400 未进入券校验逻辑 d→检查门店/POS 配置 e→前端校验非空

图7 · 组券展开机制(场景 f vs g vs h)

理解输入组码与响应子券的对应关系

f 有效组券 组码 0001234567 7439470471 3575594396 areAllValid ✓ · total 20000 g 无效组券 组码 2726518 isValid ✗ totalFaceValue = 0 h 重复组券 05375611 05375611 ×2 1920529273 ✓ 1282499407 ✓ ... ✓ 58063524 ✗ areAllValid ✗ · 虽有 total 20000 仍不可核销 券码类型关系总结 • 录入层: 组码 / 普通码 / 子券码(Redeem 禁混用) • 响应层: 始终展开为具体券 code + faceValue • 类型层: separate 标识 product type 是否一致 • 业务层: 仅 areAllVouchersValid=true → 允许 Redeem
html2.link ·粘贴 HTML,一键生成链接