ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Jeepay 分账接口实战指南:绑定分账用户与发起订单分账(基于 jeepay-payment 源码解析)

Jeepay 分账接口实战指南:绑定分账用户与发起订单分账(基于 jeepay-payment 源码解析) Jeepay 分账接口实战指南绑定分账用户与发起订单分账基于 jeepay-payment 源码解析【免费下载链接】jeepayJeepay是一套适合互联网企业使用的开源支付系统支持多渠道服务商和普通商户模式。已对接微信支付支付宝云闪付官方接口支持聚合码支付。项目地址: https://gitcode.com/GitHub_Trending/je/jeepay本文以 Jeepay 支付系统分账接口文档jeepay-payment/src/main/resources/markdown/doc/api5.md为核心系统讲解商户分账业务的两个核心 API——绑定分账用户/api/division/receiver/bind与发起订单分账/api/division/exec的完整参数、请求/返回示例与调用前提并结合jeepay-payment模块的控制器、请求体与渠道适配源码深入剖析分账从请求校验、接收者匹配、金额计算到渠道侧调用的完整链路。读完本文你将能够独立对接 Jeepay 分账接口理解按账号分账按组自动分账商户手动分账三种模式的区别并掌握分账失败时的补单与排查思路。一、分账业务概述分账Profit Sharing / Royalty是支付系统中面向多角色资金分配的核心能力。商户将交易成功的资金按照一定的周期或比例分账给其他方——可以是合作伙伴、员工、用户或者其他分润方。在 Jeepay 中分账能力由支付网关模块jeepay-payment统一对外提供其接口目录位于 jeepay-payment/src/main/resources/markdown/doc/api5.md包含两个公开接口接口请求 URL作用绑定分账用户POST /api/division/receiver/bind将分账接收者账号绑定到某个分账账号组绑定成功后才能参与订单分账发起订单分账POST /api/division/exec对一笔已支付成功且处于商户手动分账模式的订单执行分账两个接口的适用对象均为普通商户与特约商户即既支持普通商户直连模式也支持服务商模式下的特约商户ISV 子商户调用。说明微信、支付宝官方对分账能力均有独立的产品定义与开通要求微信分账、支付宝分账。Jeepay 侧只是将这些渠道能力统一封装为上述两个接口实际能否分账还取决于商户在渠道侧是否已开通对应分账权限下文源码中NOAUTH 无分账权限的返回即与此相关。二、接口通用约定两个接口具备相同的通用规范调用前需先了解请求方式POST请求类型application/json或application/x-www-form-urlencoded公共必传参数由 AbstractMchAppRQ.java 定义并强制校验参数说明mchNo商户号30 位以内字符串appId商户应用 ID24 位字符串reqTime请求接口时间13 位毫秒时间戳version接口版本号固定1.0signType签名类型目前仅支持MD5sign签名值32 位字符串详见签名算法返回结构统一返回体由 ApiRes.java 定义字段类型说明codeint返回状态0表示处理成功其他表示处理有误详见错误码msgString具体错误原因如签名失败参数格式校验错误signString对data内数据签名data为空时不返回dataString返回业务数据JSON 格式三、接口一绑定分账用户/api/division/receiver/bind分账接收者必须先绑定后分账。该接口用于把某个分账接收账号个人或商户绑定到指定分账账号组绑定结果由上游渠道确认Jeepay 侧保存绑定记录。请求 URLhttps://pay.jeepay.vip/api/division/receiver/bind按实际部署域名替换3.1 请求参数字段名变量名必填类型示例值描述商户号mchNo是String(30)M1621873433953商户号应用IDappId是String(24)60cc09bce4b0f1c0b83761c9应用ID接口代码ifCode是String(10)wxpaywxpay-微信官方接口 ; alipay-支付宝官方接口接收者账号别名receiverAlias是String(64)张三接收者账号别名组IDreceiverGroupId是long10001需先登录商户系统查找待加入的组ID分账接收账号类型accType是int1分账接收账号类型: 0-个人(对私) 1-商户(对公)分账接收账号accNo是String(10)1231312qq.com分账接收账号微信个人是openid支付宝可以是userId或登录名分账接收账号名称accName否String(30)张三微信选填当填入则验证支付宝账号必填分账关系类型relationType是String(30)PARTNER分账关系类型见下方枚举说明分账关系类型名称relationTypeName否String(30)我的员工当 relationTypeCUSTOM 时必填渠道特殊信息channelExtInfo否String(256)-渠道特殊信息默认分账比例divisionProfit是String(10)0.3若分账30%则填入 0.3请求时间reqTime是long1622016572190请求接口时间13位时间戳接口版本version是String(3)1.0接口版本号固定1.0签名sign是String(32)C380BEC2BFD727A4B6845133519F3AD6签名值详见签名算法签名类型signType是String(32)MD5签名类型目前只支持MD5方式分账关系类型relationType枚举对齐微信分账关系定义SERVICE_PROVIDER服务商 STORE门店 STAFF员工 STORE_OWNER店主 PARTNER合作伙伴 HEADQUARTER总部 BRAND品牌方 DISTRIBUTOR分销商 USER用户 SUPPLIER供应商 CUSTOM自定义当relationTypeCUSTOM自定义时relationTypeName必填。其余情况下MchDivisionReceiverBindController.java 中的getRelationTypeName方法会将枚举自动映射为中文名称如PARTNER→ 合作伙伴仅在映射不到时才取请求中的relationTypeName。3.2 请求示例数据{ version: 1.0, reqTime: 1622016572190, signType: MD5, sign: MD5MD5MD5MD5MD5MD5MD5MD5MD5MD5MD5MD5, mchNo: M1623997000, appId: 60cc3ba74ee0e6685f57e000, ifCode: wxpay, receiverAlias: 我的第一个账号, receiverGroupId: 100001, accType: 0, accNo: sfsfsdqq.com, accName: 张三, relationType: OTHERS, relationTypeName: 我的员工, divisionProfit: 0.3 }3.3 返回参数字段名变量名必填类型示例值描述返回状态code是int00-处理成功其他-处理有误详见错误码返回信息msg否String(128)签名失败具体错误原因签名信息sign否String(32)CCD9083A6DAD9A2DA9F668C3D4517A84对data内数据签名返回数据data否String(512){}返回绑定数据json格式data 数据格式字段名变量名必填类型示例值描述绑定账号IDreceiverId是long10001绑定账号ID订单分账将使用该ID接收者账号别名receiverAlias是String(64)张三接收者账号别名组IDreceiverGroupId是long10001组ID分账接收账号类型accType是int1分账接收账号类型: 0-个人(对私) 1-商户(对公)分账接收账号accNo是String(10)1231312qq.com分账接收账号分账接收账号名称accName否String(30)张三分账接收账号名称分账关系类型relationType是String(30)PARTNER分账关系类型渠道特殊信息channelExtInfo否String(256)-渠道特殊信息默认分账比例divisionProfit是String(10)0.3默认分账比例绑定成功时间bindSuccessTime是Long1622016572190绑定成功时间毫秒时间戳绑定状态bindState是int1绑定状态 1-绑定成功0-绑定异常渠道错误码errCode否StringACQ.PAYMENT_AUTH_CODE_INVALID上游渠道返回的错误码渠道错误描述errMsg否StringBusiness Failed 失败上游渠道返回的错误描述返回示例数据{ code: 0, data: { accName: 张三, accNo: sfsfsdqq.com, accType: 0, appId: 60cc3ba74ee0e6685f57eb1e, bindState: 0, divisionProfit: 0.3, errCode: NOAUTH, errMsg: 无分账权限, ifCode: wxpay, mchNo: M1623997351, receiverAlias: 我的第一个账号, receiverGroupId: 100001, relationType: OTHERS, relationTypeName: 我的员工 }, msg: SUCCESS, sign: 552CB91FA1E1DB378A534B377E4E9403 }注意上例中code0仅表示 Jeepay 侧请求处理成功但data.bindState0、errCodeNOAUTH、errMsg无分账权限说明渠道侧绑定失败——即商户尚未在微信侧开通分账权限。这是绑定接口最典型的业务失败形态调用方务必同时校验code与bindState。3.4 源码解析绑定流程绑定接口由 MchDivisionReceiverBindController.java 实现核心流程如下验签与参数解析调用getRQByWithMchSign(DivisionReceiverBindRQ.class)完成签名校验与参数绑定请求体定义见 DivisionReceiverBindRQ.java。其中accType通过Range(min0, max1)限制ifCode、receiverGroupId、accNo、relationType、divisionProfit均强制非空。商户应用校验通过configContextQueryService.queryMchInfoAndAppInfo(mchNo, appId)校验商户与应用存在性通过payInterfaceConfigService.mchAppHasAvailableIfCode(appId, ifCode)校验该应用已配置并启用对应支付接口否则抛出商户应用的支付配置不存在或已关闭。分账组校验调用mchDivisionReceiverGroupService.findByIdAndMchNo(receiverGroupId, mchNo)校验组归属必须属于该商户否则提示请进入商户平台进行创建操作。分账比例校验divisionProfit解析为BigDecimal后必须满足0 比例 ≤ 1即取值范围为[0.0001, 1.0000]。调起渠道绑定通过SpringBeansUtil.getBean(ifCode DivisionService, IDivisionService.class)按接口代码动态获取渠道实现如wxpayDivisionService、alipayDivisionService调用divisionService.bind(receiver, mchAppConfigContext)。结果落库与返回渠道返回CONFIRM_SUCCESS时绑定状态置为成功bindState1并落库否则记录渠道错误码与错误信息返回调用方。渠道适配层通过统一的 IDivisionService.java 接口抽象其bind方法在不同渠道中映射到不同上游接口微信WxpayDivisionService.javaV2 使用ProfitSharingReceiverRequest添加分账接收方V3 使用ProfitSharingReceiverV3Request账号类型0-个人映射为PERSONAL_OPENID1-商户映射为MERCHANT_ID。支付宝AlipayDivisionService.java调用AlipayTradeRoyaltyRelationBindRequest分账关系绑定通过正则RegKit.isAlipayUserId判断accNo是userId还是loginName以决定RoyaltyEntity.type。四、接口二发起订单分账/api/division/exec当订单下单时传入的分账模式divisionMode 2商户手动分账即解冻商户金额支付成功后支持商户手动发起订单分账。重要前提需要在订单支付完成后建议 1 分钟后再调用分账接口避免渠道侧订单状态尚未最终确认导致分账失败。请求 URLhttps://pay.jeepay.vip/api/division/exec4.1 请求参数字段名变量名必填类型示例值描述商户号mchNo是String(30)M1621873433953商户号应用IDappId是String(24)60cc09bce4b0f1c0b83761c9应用ID支付订单号payOrderId否String(30)P20160427210604000490支付中心生成的支付订单号与mchOrderNo二者传一即可商户单号mchOrderNo否String(30)20160427210604000490商户生成的支付单号与payOrderId二者传一即可是否使用系统配置的自动分账组useSysAutoDivisionReceivers是int1是否使用系统配置的自动分账组 0-否 1-是分账接收者账号列表receivers否String(512)[]接收者账号列表JSONArray 转换为字符串类型仅当 useSysAutoDivisionReceivers0 时该字段值有效请求时间reqTime是long1622016572190请求接口时间13位时间戳接口版本version是String(3)1.0接口版本号固定1.0签名sign是String(32)C380BEC2BFD727A4B6845133519F3AD6签名值详见签名算法签名类型signType是String(32)MD5签名类型目前只支持MD5方式receivers 字段说明JSONArray 序列化后的字符串方式1按账号维度[{receiverId: 800001, divisionProfit: 0.1}]——divisionProfit不填则使用系统默认配置值。方式2按组维度[{receiverGroupId: 100001, divisionProfit: 0.1}]—— 该组所有当前订单渠道账号且可用状态的接收者全部参与分账divisionProfit表示每个账号的分账比例不填则使用系统默认配置值建议不填写。4.2 请求示例数据{ version: 1.0, reqTime: 1622016572190, signType: MD5, sign: 1, mchNo: M1623997351, appId: 60cc3ba74ee0e6685f57eb1e, payOrderId: P202108271011463510002, useSysAutoDivisionReceivers: 0, receivers: [{receiverGroupId:,receiverId:800029,divisionProfit:0.0001},{receiverGroupId:,receiverId:800028,divisionProfit:0.0002}] }4.3 返回参数字段名变量名必填类型示例值描述返回状态code是int00-处理成功其他-处理有误详见错误码返回信息msg否String(128)签名失败具体错误原因签名信息sign否String(32)CCD9083A6DAD9A2DA9F668C3D4517A84对data内数据签名返回数据data否String(512){}返回分账数据json格式data 数据格式字段名变量名必填类型示例值描述分账状态state是int2分账状态 1-分账成功2-分账失败上游分账批次号channelBatchOrderId否String(30)T20160427210604000490上游分账批次号渠道错误码errCode否String1002渠道返回错误码渠道错误描述errMsg否StringERROR渠道返回错误描述返回示例数据{ code: 0, data: { errCode: unknown-sub-code, errMsg: Business Failed【未知的错误码ACQ.ROYALTY_ACCOUNT_NOT_EXIST】, state: 2 }, msg: SUCCESS, sign: 56836E18015DD7E4FAFE45380C0AD098 }该示例展示了一次典型的分账失败code0表示请求与校验通过但渠道侧返回ACQ.ROYALTY_ACCOUNT_NOT_EXIST支付宝分账接收方账号不存在即所传receivers中的账号尚未在支付宝侧完成分账关系绑定因此data.state2。排查方向先调用绑定接口确认每个 receiver 绑定成功再发起分账。4.4 源码解析分账执行流程分账执行接口由 PayOrderDivisionExecController.java 实现核心流程如下验签与参数解析请求体见 PayOrderDivisionExecRQ.java其中useSysAutoDivisionReceivers强制非空。订单定位与状态校验payOrderId与mchOrderNo至少传一项同时为空直接报错通过payOrderService.queryMchOrder查询订单后必须同时满足三个条件才允许分账payOrder.state STATE_SUCCESS支付成功payOrder.divisionState DIVISION_STATE_UNHAPPEN未发生过自动分账/待分账payOrder.divisionMode DIVISION_MODE_MANUAL商户手动分账模式。 否则抛出当前订单状态不支持分账。接收者列表解析与校验当useSysAutoDivisionReceivers0且receivers非空时将 JSON 字符串反序列化为PayOrderDivisionMQ.CustomerDivisionReceiver列表checkReceiverList逐项校验receiverId与receiverGroupId必填一项divisionProfit必须介于 0%100% 之间按账号维度时校验 receiverId 集合均属于该商户、该应用、该渠道且状态可用stateYES按组维度时校验 receiverGroupId 集合均属于该商户。执行分账调用 PayOrderDivisionProcessService.processPayOrderDivision 完成分账处理详见下节。结果映射根据渠道返回状态映射data.state——CONFIRM_SUCCESS→1分账成功、CONFIRM_FAIL→2分账失败、其余WAITING等→ 受理中并回填上游分账批次号channelBatchOrderId与渠道错误信息。4.5 分账处理核心逻辑PayOrderDivisionProcessService.java 是分账执行的服务层核心其关键设计状态机流转订单divisionState依次经历WAIT_TASK/UNHAPPEN待分账→ING分账处理中→FINISH分账任务结束。通过带divisionState等值条件的乐观更新防止重复发起。接收者查询queryReceiveruseSysAutoDivisionReceivers1时查询商户下autoDivisionFlagYES的自动分账组取第一个自动分账组内的全部可用接收者useSysAutoDivisionReceivers0时按mchNo appId ifCode state可用查询全部接收者再与请求中的receivers列表按receiverId或receiverGroupId匹配过滤若请求中某接收者携带divisionProfit将覆盖其系统默认分账比例。金额计算以商户实际入账金额calMchIncomeAmount即扣除渠道手续费的净额作为分账基数先按全部分账比例总和算出剩余待分账金额向下取整避免金额溢出再逐条按分账金额 分账基数 × 分账比例计算并保证最后一个账号分账金额不超过剩余金额。记录落库每条分账明细生成PayOrderDivisionRecord状态STATE_WAIT待分账同一批次共享batchOrderIdSeqKit.genDivisionBatchId()生成并记录订单号、渠道订单号、接收者信息、计算分账金额等快照。渠道调用通过SpringBeansUtil.getBean(payOrder.getIfCode() DivisionService, IDivisionService.class)动态获取渠道实现并调用singleDivision。以支付宝为例AlipayDivisionService.java调用AlipayTradeOrderSettleRequest交易结算并设置royaltyModesync同步分账、royaltyFinishtrue分账完结支付宝无完结接口因此直接完结接收者列表为空时直接返回成功。结果回写渠道明确成功则明细更新为STATE_SUCCESS明确失败则更新为STATE_FAIL并记录渠道错误WAITING已受理则更新为STATE_ACCEPT等待补单任务轮询。4.6 分账补单机制对于渠道返回已受理STATE_ACCEPT的分账明细PayOrderDivisionRecordReissueTask.java 提供兜底补偿定时任务每分钟执行一次cron 0 0/1 * * * ?查询受理中且创建时间早于当前时间 5 分钟的分账记录按batchOrderId分组后调用渠道queryDivision查询最终结果并将明确的成功/失败状态回写明细记录。这也是分账接口建议支付完成后 1 分钟再调用的原因之一——给渠道留出状态收敛时间。五、两种分账模式的使用场景建议场景推荐模式说明固定合作伙伴、固定比例定期分润自动分账组下单时divisionMode1配合系统自动分账支付完成后系统按自动分账组自动触发无需手动调用/api/division/exec每次分账对象与比例灵活变化商户手动分账下单时divisionMode2支付成功后调用/api/division/exec通过receivers按账号或按组指定本次分账明细同一批接收者长期复用分账账号组组 ID 模式先在商户平台创建账号组绑定接口按receiverGroupId加入分账时按组纬度引用六、对接要点与常见问题排查绑定是分账的前置条件微信、支付宝均要求分账接收者先在渠道侧完成关系绑定否则分账时返回ACQ.ROYALTY_ACCOUNT_NOT_EXIST支付宝或NOAUTH无分账权限微信。绑定结果以data.bindState为准而非外层code。订单状态必须匹配发起分账前确认订单divisionMode2手动分账、支付成功且尚未分账否则返回当前订单状态不支持分账。分账比例校验单个接收者比例范围为0.0001 ~ 1.0000绑定接口或0% ~ 100%分账执行接口建议控制全部分账比例总和不超过 100%系统会在计算时对最后一个账号按剩余金额向下取整兜底。渠道权限分账属于微信/支付宝的高权限能力需在渠道侧单独申请开通微信分账、支付宝分账Jeepay 侧无法替代渠道审核。幂等与补单receivers列表重复提交时系统通过订单分账状态乐观锁防重渠道已受理的分账会由 PayOrderDivisionRecordReissueTask.java 每分钟自动补单查询无需业务方重复发起。返回码判定所有接口先看code0判断请求链路是否正常再看data内业务状态bindState/state判断渠道侧结果两者不可混淆。七、相关参考接口文档原文jeepay-payment/src/main/resources/markdown/doc/api5.md绑定接口实现MchDivisionReceiverBindController.java分账执行实现PayOrderDivisionExecController.java分账处理服务PayOrderDivisionProcessService.java渠道分账接口抽象IDivisionService.java渠道实现示例AlipayDivisionService.java、WxpayDivisionService.java分账补单任务PayOrderDivisionRecordReissueTask.java相关数据实体MchDivisionReceiver.java、MchDivisionReceiverGroup.java、PayOrderDivisionRecord.java【免费下载链接】jeepayJeepay是一套适合互联网企业使用的开源支付系统支持多渠道服务商和普通商户模式。已对接微信支付支付宝云闪付官方接口支持聚合码支付。项目地址: https://gitcode.com/GitHub_Trending/je/jeepay创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表