Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Jeepay
Commits
fa6e00c3
Commit
fa6e00c3
authored
Aug 26, 2021
by
terrfly
Browse files
完成订单的分账逻辑
parent
ad2afc15
Changes
45
Show whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayDivisionService.java
0 → 100644
View file @
fa6e00c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.channel.alipay
;
import
com.alibaba.fastjson.JSON
;
import
com.alipay.api.domain.*
;
import
com.alipay.api.request.AlipayTradeOrderSettleRequest
;
import
com.alipay.api.request.AlipayTradeRoyaltyRelationBindRequest
;
import
com.alipay.api.response.AlipayTradeOrderSettleResponse
;
import
com.alipay.api.response.AlipayTradeRoyaltyRelationBindResponse
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiver
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.core.utils.AmountUtil
;
import
com.jeequan.jeepay.core.utils.RegKit
;
import
com.jeequan.jeepay.core.utils.SeqKit
;
import
com.jeequan.jeepay.pay.channel.IDivisionService
;
import
com.jeequan.jeepay.pay.exception.ChannelException
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
/**
* 分账接口: 支付宝官方
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/8/22 09:05
*/
@Slf4j
@Service
public
class
AlipayDivisionService
implements
IDivisionService
{
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
ALIPAY
;
}
@Override
public
boolean
isSupport
()
{
return
false
;
}
@Override
public
ChannelRetMsg
bind
(
MchDivisionReceiver
mchDivisionReceiver
,
MchAppConfigContext
mchAppConfigContext
)
{
try
{
AlipayTradeRoyaltyRelationBindRequest
request
=
new
AlipayTradeRoyaltyRelationBindRequest
();
AlipayTradeRoyaltyRelationBindModel
model
=
new
AlipayTradeRoyaltyRelationBindModel
();
request
.
setBizModel
(
model
);
model
.
setOutRequestNo
(
SeqKit
.
genDivisionBatchId
());
RoyaltyEntity
royaltyEntity
=
new
RoyaltyEntity
();
royaltyEntity
.
setType
(
"loginName"
);
if
(
RegKit
.
isAlipayUserId
(
mchDivisionReceiver
.
getAccNo
())){
royaltyEntity
.
setType
(
"userId"
);
}
royaltyEntity
.
setAccount
(
mchDivisionReceiver
.
getAccNo
());
royaltyEntity
.
setName
(
mchDivisionReceiver
.
getAccName
());
royaltyEntity
.
setMemo
(
mchDivisionReceiver
.
getRelationTypeName
());
//分账关系描述
model
.
setReceiverList
(
Arrays
.
asList
(
royaltyEntity
));
AlipayTradeRoyaltyRelationBindResponse
alipayResp
=
mchAppConfigContext
.
getAlipayClientWrapper
().
execute
(
request
);
if
(
alipayResp
.
isSuccess
()){
return
ChannelRetMsg
.
confirmSuccess
(
null
);
}
//异常:
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrCode
(
AlipayKit
.
appendErrCode
(
alipayResp
.
getCode
(),
alipayResp
.
getSubCode
()));
channelRetMsg
.
setChannelErrMsg
(
AlipayKit
.
appendErrMsg
(
alipayResp
.
getMsg
(),
alipayResp
.
getSubMsg
()));
return
channelRetMsg
;
}
catch
(
ChannelException
e
)
{
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrCode
(
e
.
getChannelRetMsg
().
getChannelErrCode
());
channelRetMsg
.
setChannelErrMsg
(
e
.
getChannelRetMsg
().
getChannelErrMsg
());
return
channelRetMsg
;
}
catch
(
Exception
e
)
{
log
.
error
(
"绑定支付宝账号异常"
,
e
);
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrMsg
(
e
.
getMessage
());
return
channelRetMsg
;
}
}
@Override
public
ChannelRetMsg
singleDivision
(
PayOrder
payOrder
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
)
{
try
{
AlipayTradeOrderSettleRequest
request
=
new
AlipayTradeOrderSettleRequest
();
AlipayTradeOrderSettleModel
model
=
new
AlipayTradeOrderSettleModel
();
request
.
setBizModel
(
model
);
model
.
setOutRequestNo
(
recordList
.
get
(
0
).
getBatchOrderId
());
//结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model
.
setTradeNo
(
recordList
.
get
(
0
).
getPayOrderChannelOrderNo
());
//支付宝订单号
List
<
OpenApiRoyaltyDetailInfoPojo
>
reqReceiverList
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
recordList
.
size
();
i
++)
{
PayOrderDivisionRecord
record
=
recordList
.
get
(
i
);
if
(
record
.
getCalDivisionAmount
()
<=
0
){
//金额为 0 不参与分账处理
continue
;
}
OpenApiRoyaltyDetailInfoPojo
reqReceiver
=
new
OpenApiRoyaltyDetailInfoPojo
();
reqReceiver
.
setRoyaltyType
(
"transfer"
);
//分账类型: 普通分账
// 出款信息
// reqReceiver.setTransOutType("loginName"); reqReceiver.setTransOut("xqxemt4735@sandbox.com");
// 入款信息
reqReceiver
.
setTransIn
(
record
.
getAccNo
());
//收入方账号
reqReceiver
.
setTransInType
(
"loginName"
);
if
(
RegKit
.
isAlipayUserId
(
record
.
getAccNo
())){
reqReceiver
.
setTransInType
(
"userId"
);
}
// 分账金额
reqReceiver
.
setAmount
(
AmountUtil
.
convertCent2Dollar
(
record
.
getCalDivisionAmount
()));
reqReceiver
.
setDesc
(
"["
+
payOrder
.
getPayOrderId
()
+
"]订单分账"
);
reqReceiverList
.
add
(
reqReceiver
);
}
if
(
reqReceiverList
.
isEmpty
()){
// 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结解决,直接响应成功即可。
return
ChannelRetMsg
.
confirmSuccess
(
null
);
}
model
.
setRoyaltyParameters
(
reqReceiverList
);
// 分账明细信息
// 完结
SettleExtendParams
settleExtendParams
=
new
SettleExtendParams
();
settleExtendParams
.
setRoyaltyFinish
(
"true"
);
model
.
setExtendParams
(
settleExtendParams
);
//调起支付宝分账接口
if
(
log
.
isInfoEnabled
()){
log
.
info
(
"订单:[{}], 支付宝分账请求:{}"
,
payOrder
.
getPayOrderId
(),
JSON
.
toJSONString
(
model
));
}
AlipayTradeOrderSettleResponse
alipayResp
=
mchAppConfigContext
.
getAlipayClientWrapper
().
execute
(
request
);
log
.
info
(
"订单:[{}], 支付宝分账响应:{}"
,
payOrder
.
getPayOrderId
(),
alipayResp
.
getBody
());
if
(
alipayResp
.
isSuccess
()){
return
ChannelRetMsg
.
confirmSuccess
(
alipayResp
.
getTradeNo
());
}
//异常:
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrCode
(
AlipayKit
.
appendErrCode
(
alipayResp
.
getCode
(),
alipayResp
.
getSubCode
()));
channelRetMsg
.
setChannelErrMsg
(
AlipayKit
.
appendErrMsg
(
alipayResp
.
getMsg
(),
alipayResp
.
getSubMsg
()));
return
channelRetMsg
;
}
catch
(
ChannelException
e
)
{
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrCode
(
e
.
getChannelRetMsg
().
getChannelErrCode
());
channelRetMsg
.
setChannelErrMsg
(
e
.
getChannelRetMsg
().
getChannelErrMsg
());
return
channelRetMsg
;
}
catch
(
Exception
e
)
{
log
.
error
(
"绑定支付宝账号异常"
,
e
);
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrMsg
(
e
.
getMessage
());
return
channelRetMsg
;
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/ctrl/AlipayBizController.java
View file @
fa6e00c3
...
...
@@ -83,7 +83,7 @@ public class AlipayBizController extends AbstractCtrl {
}
String
redirectUrl
=
sysConfigService
.
getDBApplicationConfig
().
getPaySiteUrl
()
+
"/api/channelbiz/alipay/appToAppAuthCallback"
;
response
.
sendRedirect
(
String
.
format
(
oauthUrl
,
alipayIsvParams
.
getAppId
(),
URLUtil
.
encode
(
redirectUrl
),
isvAndMchAppId
));
response
.
sendRedirect
(
String
.
format
(
oauthUrl
,
alipayIsvParams
.
getAppId
(),
URLUtil
.
encode
All
(
redirectUrl
),
isvAndMchAppId
));
}
/** 支付宝授权回调地址 **/
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayDivisionService.java
View file @
fa6e00c3
...
...
@@ -17,19 +17,21 @@ package com.jeequan.jeepay.pay.channel.wxpay;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingReceiverRequest
;
import
com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingReceiverResult
;
import
com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingRequest
;
import
com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingResult
;
import
com.github.binarywang.wxpay.bean.profitsharing.*
;
import
com.github.binarywang.wxpay.exception.WxPayException
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiver
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.core.utils.SeqKit
;
import
com.jeequan.jeepay.pay.channel.IDivisionService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
java.math.BigDecimal
;
import
java.util.List
;
/**
...
...
@@ -54,12 +56,15 @@ public class WxpayDivisionService implements IDivisionService {
}
@Override
public
boolean
bind
(
MchDivisionReceiver
mchDivisionReceiver
,
MchAppConfigContext
mchAppConfigContext
)
{
public
ChannelRetMsg
bind
(
MchDivisionReceiver
mchDivisionReceiver
,
MchAppConfigContext
mchAppConfigContext
)
{
try
{
ProfitSharingReceiverRequest
request
=
new
ProfitSharingReceiverRequest
();
//放置isv信息
WxpayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
);
JSONObject
receiverJSON
=
new
JSONObject
();
// 0-个人, 1-商户 (目前仅支持服务商appI获取个人openId, 即: PERSONAL_OPENID, 不支持 PERSONAL_SUB_OPENID )
...
...
@@ -73,30 +78,49 @@ public class WxpayDivisionService implements IDivisionService {
ProfitSharingReceiverResult
profitSharingReceiverResult
=
mchAppConfigContext
.
getWxServiceWrapper
().
getWxPayService
().
getProfitSharingService
().
addReceiver
(
request
);
// 明确成功
return
ChannelRetMsg
.
confirmSuccess
(
null
);
}
catch
(
WxPayException
wxPayException
)
{
wxPayException
.
printStackTrace
();
}
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
WxpayKit
.
commonSetErrInfo
(
channelRetMsg
,
wxPayException
);
return
channelRetMsg
;
}
catch
(
Exception
e
)
{
return
false
;
log
.
error
(
"请求微信绑定分账接口异常!"
,
e
);
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrMsg
(
"系统异常:"
+
e
.
getMessage
());
return
channelRetMsg
;
}
}
@Override
public
boolean
singleDivision
(
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
)
{
public
ChannelRetMsg
singleDivision
(
PayOrder
payOrder
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
)
{
try
{
if
(
true
||
recordList
.
isEmpty
()){
return
true
;
}
ProfitSharingRequest
request
=
new
ProfitSharingRequest
();
request
.
setTransactionId
(
recordList
.
get
(
0
).
getPayOrderChannelOrderNo
());
request
.
setOutOrderNo
(
recordList
.
get
(
0
).
getBatchOrderId
());
request
.
setTransactionId
(
payOrder
.
getChannelOrderNo
());
//放置isv信息
WxpayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
);
if
(
recordList
.
isEmpty
()){
request
.
setOutOrderNo
(
SeqKit
.
genDivisionBatchId
());
// 随机生成一个订单号
}
else
{
request
.
setOutOrderNo
(
recordList
.
get
(
0
).
getBatchOrderId
());
//取到批次号
}
JSONArray
receiverJSONArray
=
new
JSONArray
();
for
(
PayOrderDivisionRecord
record
:
recordList
)
{
for
(
int
i
=
0
;
i
<
recordList
.
size
();
i
++)
{
PayOrderDivisionRecord
record
=
recordList
.
get
(
i
);
if
(
record
.
getCalDivisionAmount
()
<=
0
){
continue
;
}
JSONObject
receiverJSON
=
new
JSONObject
();
// 0-个人, 1-商户 (目前仅支持服务商appI获取个人openId, 即: PERSONAL_OPENID, 不支持 PERSONAL_SUB_OPENID )
receiverJSON
.
put
(
"type"
,
record
.
getAccType
()
==
0
?
"PERSONAL_OPENID"
:
"MERCHANT_ID"
);
...
...
@@ -106,15 +130,45 @@ public class WxpayDivisionService implements IDivisionService {
receiverJSONArray
.
add
(
receiverJSON
);
}
//不存在接收账号时,订单完结(解除冻结金额)
if
(
receiverJSONArray
.
isEmpty
()){
return
ChannelRetMsg
.
confirmSuccess
(
this
.
divisionFinish
(
payOrder
,
mchAppConfigContext
));
}
request
.
setReceivers
(
receiverJSONArray
.
toJSONString
());
ProfitSharingResult
profitSharingResult
=
mchAppConfigContext
.
getWxServiceWrapper
().
getWxPayService
().
getProfitSharingService
().
profitSharing
(
request
);
return
ChannelRetMsg
.
confirmSuccess
(
profitSharingResult
.
getOrderId
());
}
catch
(
WxPayException
wxPayException
)
{
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
WxpayKit
.
commonSetErrInfo
(
channelRetMsg
,
wxPayException
);
return
channelRetMsg
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
log
.
error
(
"微信分账失败"
,
e
);
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrMsg
(
e
.
getMessage
());
return
channelRetMsg
;
}
}
return
false
;
/** 调用订单的完结接口 (分账对象不存在时) */
private
String
divisionFinish
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
throws
WxPayException
{
ProfitSharingFinishRequest
request
=
new
ProfitSharingFinishRequest
();
//放置isv信息
WxpayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
);
request
.
setSubAppId
(
null
);
// 传入subAppId 将导致签名失败
request
.
setTransactionId
(
payOrder
.
getChannelOrderNo
());
request
.
setOutOrderNo
(
SeqKit
.
genDivisionBatchId
());
request
.
setDescription
(
"完结分账"
);
return
mchAppConfigContext
.
getWxServiceWrapper
().
getWxPayService
().
getProfitSharingService
().
profitSharingFinish
(
request
).
getOrderId
();
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayPaymentService.java
View file @
fa6e00c3
...
...
@@ -90,6 +90,11 @@ public class WxpayPaymentService extends AbstractPaymentService {
request
.
setNotifyUrl
(
getNotifyUrl
());
request
.
setProductId
(
System
.
currentTimeMillis
()+
""
);
//订单分账, 将冻结商户资金。
if
(
isDivisionOrder
(
payOrder
)){
request
.
setProfitSharing
(
"Y"
);
}
// 特约商户
if
(
mchAppConfigContext
.
isIsvsubMch
()){
WxpayIsvsubMchParams
isvsubMchParams
=
mchAppConfigContext
.
getIsvsubMchParamsByIfCode
(
getIfCode
(),
WxpayIsvsubMchParams
.
class
);
...
...
@@ -125,6 +130,13 @@ public class WxpayPaymentService extends AbstractPaymentService {
sceneInfo
.
put
(
"payer_client_ip"
,
payOrder
.
getClientIp
());
reqJSON
.
put
(
"scene_info"
,
sceneInfo
);
//订单分账, 将冻结商户资金。
if
(
isDivisionOrder
(
payOrder
)){
JSONObject
settleInfo
=
new
JSONObject
();
settleInfo
.
put
(
"profit_sharing"
,
true
);
reqJSON
.
put
(
"settle_info"
,
settleInfo
);
}
WxPayService
wxPayService
=
mchAppConfigContext
.
getWxServiceWrapper
().
getWxPayService
();
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
WxpayIsvsubMchParams
isvsubMchParams
=
mchAppConfigContext
.
getIsvsubMchParamsByIfCode
(
getIfCode
(),
WxpayIsvsubMchParams
.
class
);
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/payway/WxBar.java
View file @
fa6e00c3
...
...
@@ -70,6 +70,11 @@ public class WxBar extends WxpayPaymentService {
request
.
setSpbillCreateIp
(
payOrder
.
getClientIp
());
request
.
setAuthCode
(
bizRQ
.
getAuthCode
().
trim
());
//订单分账, 将冻结商户资金。
if
(
isDivisionOrder
(
payOrder
)){
request
.
setProfitSharing
(
"Y"
);
}
//放置isv信息
WxpayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
);
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/division/MchDivisionReceiverBindController.java
0 → 100644
View file @
fa6e00c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.ctrl.division
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiver
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup
;
import
com.jeequan.jeepay.core.entity.MchInfo
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.IDivisionService
;
import
com.jeequan.jeepay.pay.ctrl.ApiController
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.division.DivisionReceiverBindRQ
;
import
com.jeequan.jeepay.pay.rqrs.division.DivisionReceiverBindRS
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.transfer.TransferOrderRS
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.service.impl.MchDivisionReceiverGroupService
;
import
com.jeequan.jeepay.service.impl.MchDivisionReceiverService
;
import
com.jeequan.jeepay.service.impl.PayInterfaceConfigService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.math.BigDecimal
;
import
java.util.Date
;
/**
* 分账账号绑定
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/8/25 9:07
*/
@Slf4j
@RestController
public
class
MchDivisionReceiverBindController
extends
ApiController
{
@Autowired
private
ConfigContextService
configContextService
;
@Autowired
private
PayInterfaceConfigService
payInterfaceConfigService
;
@Autowired
private
MchDivisionReceiverService
mchDivisionReceiverService
;
@Autowired
private
MchDivisionReceiverGroupService
mchDivisionReceiverGroupService
;
/** 分账账号绑定 **/
@PostMapping
(
"/api/division/receiver/bind"
)
public
ApiRes
bind
(){
//获取参数 & 验签
DivisionReceiverBindRQ
bizRQ
=
getRQByWithMchSign
(
DivisionReceiverBindRQ
.
class
);
try
{
//检查商户应用是否存在该接口
String
ifCode
=
bizRQ
.
getIfCode
();
// 商户配置信息
MchAppConfigContext
mchAppConfigContext
=
configContextService
.
getMchAppConfigContext
(
bizRQ
.
getMchNo
(),
bizRQ
.
getAppId
());
if
(
mchAppConfigContext
==
null
){
throw
new
BizException
(
"获取商户应用信息失败"
);
}
MchInfo
mchInfo
=
mchAppConfigContext
.
getMchInfo
();
if
(!
payInterfaceConfigService
.
mchAppHasAvailableIfCode
(
bizRQ
.
getAppId
(),
ifCode
)){
throw
new
BizException
(
"商户应用的支付配置不存在或已关闭"
);
}
MchDivisionReceiverGroup
group
=
mchDivisionReceiverGroupService
.
findByIdAndMchNo
(
bizRQ
.
getReceiverGroupId
(),
bizRQ
.
getMchNo
());
if
(
group
==
null
){
throw
new
BizException
(
"商户分账账号组不存在,请检查或进入商户平台进行创建操作"
);
}
BigDecimal
divisionProfit
=
new
BigDecimal
(
bizRQ
.
getDivisionProfit
());
if
(
divisionProfit
.
compareTo
(
BigDecimal
.
ZERO
)
<=
0
||
divisionProfit
.
compareTo
(
BigDecimal
.
ONE
)
>
1
){
throw
new
BizException
(
"账号分账比例有误, 配置值为[0.0001~1.0000]"
);
}
//生成数据库对象信息 (数据不完成, 暂时不可入库操作)
MchDivisionReceiver
receiver
=
genRecord
(
bizRQ
,
group
,
mchInfo
,
divisionProfit
);
//调起上游接口
IDivisionService
divisionService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"DivisionService"
,
IDivisionService
.
class
);
if
(
divisionService
==
null
){
throw
new
BizException
(
"系统不支持该分账接口"
);
}
ChannelRetMsg
retMsg
=
divisionService
.
bind
(
receiver
,
mchAppConfigContext
);
if
(
retMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
){
receiver
.
setState
(
CS
.
YES
);
receiver
.
setBindSuccessTime
(
new
Date
());
mchDivisionReceiverService
.
save
(
receiver
);
}
else
{
receiver
.
setState
(
CS
.
NO
);
receiver
.
setChannelBindResult
(
retMsg
.
getChannelErrMsg
());
}
DivisionReceiverBindRS
bizRes
=
DivisionReceiverBindRS
.
buildByRecord
(
receiver
);
if
(
retMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
){
bizRes
.
setBindState
(
CS
.
YES
);
}
else
{
bizRes
.
setBindState
(
CS
.
NO
);
bizRes
.
setErrCode
(
retMsg
.
getChannelErrCode
());
bizRes
.
setErrMsg
(
retMsg
.
getChannelErrMsg
());
}
return
ApiRes
.
okWithSign
(
bizRes
,
mchAppConfigContext
.
getMchApp
().
getAppSecret
());
}
catch
(
BizException
e
)
{
return
ApiRes
.
customFail
(
e
.
getMessage
());
}
catch
(
Exception
e
)
{
log
.
error
(
"系统异常:{}"
,
e
);
return
ApiRes
.
customFail
(
"系统异常"
);
}
}
private
MchDivisionReceiver
genRecord
(
DivisionReceiverBindRQ
bizRQ
,
MchDivisionReceiverGroup
group
,
MchInfo
mchInfo
,
BigDecimal
divisionProfit
){
MchDivisionReceiver
receiver
=
new
MchDivisionReceiver
();
receiver
.
setReceiverAlias
(
StringUtils
.
defaultIfEmpty
(
bizRQ
.
getReceiverAlias
(),
bizRQ
.
getAccNo
()));
//别名
receiver
.
setReceiverGroupId
(
bizRQ
.
getReceiverGroupId
());
//分组ID
receiver
.
setReceiverGroupName
(
group
.
getReceiverGroupName
());
//组名称
receiver
.
setMchNo
(
bizRQ
.
getMchNo
());
//商户号
receiver
.
setIsvNo
(
mchInfo
.
getIsvNo
());
//isvNo
receiver
.
setAppId
(
bizRQ
.
getAppId
());
//appId
receiver
.
setIfCode
(
bizRQ
.
getIfCode
());
//接口代码
receiver
.
setAccType
(
bizRQ
.
getAccType
());
//账号类型
receiver
.
setAccNo
(
bizRQ
.
getAccNo
());
//账号
receiver
.
setAccName
(
bizRQ
.
getAccName
());
//账号名称
receiver
.
setRelationType
(
bizRQ
.
getRelationType
());
//关系
receiver
.
setRelationTypeName
(
getRelationTypeName
(
bizRQ
.
getRelationType
()));
//关系名称
if
(
receiver
.
getRelationTypeName
()
==
null
){
receiver
.
setRelationTypeName
(
bizRQ
.
getRelationTypeName
());
}
receiver
.
setDivisionProfit
(
divisionProfit
);
//分账比例
receiver
.
setChannelExtInfo
(
bizRQ
.
getChannelExtInfo
());
//渠道信息
return
receiver
;
}
public
String
getRelationTypeName
(
String
relationType
){
if
(
"PARTNER"
.
equals
(
relationType
)){
return
"合作伙伴"
;
}
else
if
(
"SERVICE_PROVIDER"
.
equals
(
relationType
)){
return
"服务商"
;
}
else
if
(
"STORE"
.
equals
(
relationType
)){
return
"门店"
;
}
else
if
(
"STAFF"
.
equals
(
relationType
)){
return
"员工"
;
}
else
if
(
"STORE_OWNER"
.
equals
(
relationType
)){
return
"店主"
;
}
else
if
(
"HEADQUARTER"
.
equals
(
relationType
)){
return
"总部"
;
}
else
if
(
"BRAND"
.
equals
(
relationType
)){
return
"品牌方"
;
}
else
if
(
"DISTRIBUTOR"
.
equals
(
relationType
)){
return
"分销商"
;
}
else
if
(
"USER"
.
equals
(
relationType
)){
return
"用户"
;
}
else
if
(
"SUPPLIER"
.
equals
(
relationType
)){
return
"供应商"
;
}
return
null
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/AbstractPayOrderController.java
View file @
fa6e00c3
...
...
@@ -234,7 +234,6 @@ public abstract class AbstractPayOrderController extends ApiController {
}
payOrder
.
setMchFeeAmount
(
AmountUtil
.
calPercentageFee
(
payOrder
.
getAmount
(),
payOrder
.
getMchFeeRate
()));
//商户手续费,单位分
payOrder
.
setMchIncomeAmount
(
payOrder
.
getAmount
()
-
payOrder
.
getMchFeeAmount
());
//商户入账金额(支付金额-手续费),单位分
payOrder
.
setCurrency
(
rq
.
getCurrency
());
//币种
payOrder
.
setState
(
PayOrder
.
STATE_INIT
);
//订单状态, 默认订单生成状态
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/qr/ChannelUserIdController.java
View file @
fa6e00c3
...
...
@@ -20,7 +20,6 @@ import com.alibaba.fastjson.JSONObject;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.utils.JeepayKit
;
import
com.jeequan.jeepay.core.utils.JsonKit
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.core.utils.StringKit
;
import
com.jeequan.jeepay.pay.channel.IChannelUserService
;
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/model/AlipayClientWrapper.java
View file @
fa6e00c3
...
...
@@ -58,8 +58,6 @@ public class AlipayClientWrapper {
alipayResp
=
alipayClient
.
execute
(
request
);
}
//判断返回的值: // TODO
return
alipayResp
;
}
catch
(
AlipayApiException
e
)
{
// 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/mq/PayOrderDivisionMQReceiver.java
View file @
fa6e00c3
...
...
@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import
com.jeequan.jeepay.components.mq.model.PayOrderDivisionMQ
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiver
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.core.exception.BizException
;
...
...
@@ -31,7 +32,9 @@ import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import
com.jeequan.jeepay.pay.channel.IDivisionService
;
import
com.jeequan.jeepay.pay.channel.ITransferService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.service.impl.MchDivisionReceiverGroupService
;
import
com.jeequan.jeepay.service.impl.MchDivisionReceiverService
;
import
com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
...
...
@@ -41,6 +44,7 @@ import org.springframework.stereotype.Component;
import
java.math.BigDecimal
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
/**
...
...
@@ -59,6 +63,8 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
@Autowired
private
MchDivisionReceiverService
mchDivisionReceiverService
;
@Autowired
private
MchDivisionReceiverGroupService
mchDivisionReceiverGroupService
;
@Autowired
private
PayOrderDivisionRecordService
payOrderDivisionRecordService
;
@Autowired
private
ConfigContextService
configContextService
;
...
...
@@ -95,8 +101,8 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
return
;
}
// 查询所有的分账接收对象
List
<
MchDivisionReceiver
>
allReceiver
=
queryReceiver
(
payOrder
,
payload
.
getReceiverList
());
// 查询
&过滤
所有的分账接收对象
List
<
MchDivisionReceiver
>
allReceiver
=
this
.
queryReceiver
(
payOrder
,
payload
.
getReceiverList
());
//得到全部分账比例 (所有待分账账号的分账比例总和)
BigDecimal
allDivisionProfit
=
BigDecimal
.
ZERO
;
...
...
@@ -104,8 +110,11 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
allDivisionProfit
=
allDivisionProfit
.
add
(
receiver
.
getDivisionProfit
());
}
//剩余待分账金额 (用作最后一个分账账号的 计算, 避免出现分账金额超出最大)
Long
subDivisionAmount
=
AmountUtil
.
calPercentageFee
(
payOrder
.
getMchIncomeAmount
(),
allDivisionProfit
);
//计算分账金额 = 商家实际入账金额
Long
payOrderDivisionAmount
=
payOrderService
.
calMchIncomeAmount
(
payOrder
);
//剩余待分账金额 (用作最后一个分账账号的 计算, 避免出现分账金额超出最大) [结果向下取整 , 避免出现金额溢出的情况。 ]
Long
subDivisionAmount
=
AmountUtil
.
calPercentageFee
(
payOrderDivisionAmount
,
allDivisionProfit
,
BigDecimal
.
ROUND_FLOOR
);
List
<
PayOrderDivisionRecord
>
recordList
=
new
ArrayList
<>();
...
...
@@ -115,7 +124,7 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
for
(
MchDivisionReceiver
receiver
:
allReceiver
)
{
PayOrderDivisionRecord
record
=
genRecord
(
batchOrderId
,
payOrder
,
receiver
,
subDivisionAmount
);
PayOrderDivisionRecord
record
=
genRecord
(
batchOrderId
,
payOrder
,
receiver
,
payOrderDivisionAmount
,
subDivisionAmount
);
//剩余金额
subDivisionAmount
=
subDivisionAmount
-
record
.
getCalDivisionAmount
();
...
...
@@ -134,14 +143,19 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
throw
new
BizException
(
"通道无此分账接口"
);
}
divisionService
.
singleDivision
(
recordList
,
configContextService
.
getMchAppConfigContext
(
payOrder
.
getMchNo
(),
payOrder
.
getAppId
()));
ChannelRetMsg
channelRetMsg
=
divisionService
.
singleDivision
(
payOrder
,
recordList
,
configContextService
.
getMchAppConfigContext
(
payOrder
.
getMchNo
(),
payOrder
.
getAppId
()));
if
(
true
)
{
// 确认分账成功
if
(
channelRetMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
)
{
//分账成功
payOrderDivisionRecordService
.
updateRecordSuccessOrFail
(
recordList
,
PayOrderDivisionRecord
.
STATE_SUCCESS
,
channelRetMsg
.
getChannelOrderId
(),
channelRetMsg
.
getChannelOriginResponse
());
}
else
{
//分账失败
payOrderDivisionRecordService
.
updateRecordSuccessOrFail
(
recordList
,
PayOrderDivisionRecord
.
STATE_FAIL
,
channelRetMsg
.
getChannelOrderId
(),
channelRetMsg
.
getChannelErrMsg
());
}
}
catch
(
BizException
e
)
{
...
...
@@ -149,14 +163,14 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
}
catch
(
Exception
e
)
{
log
.
error
(
"{}, 调用分账接口异常"
,
logPrefix
,
e
);
//分账失败
payOrderDivisionRecordService
.
updateRecordSuccessOrFail
(
recordList
,
PayOrderDivisionRecord
.
STATE_FAIL
,
null
,
"系统异常:"
+
e
.
getMessage
());
}
//更新 支付订单主表状态 分账任务已结束。
payOrderService
.
update
(
new
LambdaUpdateWrapper
<
PayOrder
>()
.
set
(
PayOrder:
:
getDivisionState
,
PayOrder
.
DIVISION_STATE_FINISH
)
.
set
(
PayOrder:
:
getDivisionLastTime
,
new
Date
())
.
eq
(
PayOrder:
:
getPayOrderId
,
payload
.
getPayOrderId
())
.
eq
(
PayOrder:
:
getDivisionState
,
PayOrder
.
DIVISION_STATE_ING
)
);
...
...
@@ -168,7 +182,8 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
/** 生成对象信息 **/
private
PayOrderDivisionRecord
genRecord
(
String
batchOrderId
,
PayOrder
payOrder
,
MchDivisionReceiver
receiver
,
Long
subDivisionAmount
){
private
PayOrderDivisionRecord
genRecord
(
String
batchOrderId
,
PayOrder
payOrder
,
MchDivisionReceiver
receiver
,
Long
payOrderDivisionAmount
,
Long
subDivisionAmount
){
PayOrderDivisionRecord
record
=
new
PayOrderDivisionRecord
();
record
.
setMchNo
(
payOrder
.
getMchNo
());
...
...
@@ -180,11 +195,12 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
record
.
setPayOrderId
(
payOrder
.
getPayOrderId
());
record
.
setPayOrderChannelOrderNo
(
payOrder
.
getChannelOrderNo
());
//支付订单渠道订单号
record
.
setPayOrderAmount
(
payOrder
.
getAmount
());
//订单金额
record
.
setPayOrderDivisionAmount
(
payOrder
.
getMchIncome
Amount
()
);
// 订单
实际分账金额, 单位:分(订单金额 - 商户手续费 - 已退款金额) //TODO 实际
计算金额
record
.
setPayOrderDivisionAmount
(
payOrder
Division
Amount
);
// 订单计算
分账
金额
record
.
setBatchOrderId
(
batchOrderId
);
//系统分账批次号
record
.
setState
(
Mch
DivisionRec
eiver
.
STATE_WAIT
);
//状态: 待分账
record
.
setState
(
PayOrder
DivisionRec
ord
.
STATE_WAIT
);
//状态: 待分账
record
.
setReceiverId
(
receiver
.
getReceiverId
());
record
.
setReceiverGroupId
(
receiver
.
getReceiverGroupId
());
record
.
setReceiverAlias
(
receiver
.
getReceiverAlias
());
record
.
setAccType
(
receiver
.
getAccType
());
record
.
setAccNo
(
receiver
.
getAccNo
());
record
.
setAccName
(
receiver
.
getAccName
());
...
...
@@ -195,7 +211,12 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
if
(
subDivisionAmount
<=
0
)
{
record
.
setCalDivisionAmount
(
0L
);
}
else
{
//计算的分账金额
record
.
setCalDivisionAmount
(
AmountUtil
.
calPercentageFee
(
record
.
getPayOrderDivisionAmount
(),
record
.
getDivisionProfit
()));
if
(
record
.
getCalDivisionAmount
()
>
subDivisionAmount
){
// 分账金额超过剩余总金额时: 将按照剩余金额进行分账。
record
.
setCalDivisionAmount
(
subDivisionAmount
);
}
}
return
record
;
...
...
@@ -212,6 +233,20 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
queryWrapper
.
eq
(
MchDivisionReceiver:
:
getIfCode
,
payOrder
.
getIfCode
());
//ifCode
queryWrapper
.
eq
(
MchDivisionReceiver:
:
getState
,
CS
.
PUB_USABLE
);
// 可用状态的账号
// 未设置接收者账号信息, 需要查询 自动分账组的账号
if
(
customerDivisionReceiverList
==
null
){
List
<
MchDivisionReceiverGroup
>
groups
=
mchDivisionReceiverGroupService
.
list
(
MchDivisionReceiverGroup
.
gw
().
eq
(
MchDivisionReceiverGroup:
:
getMchNo
,
payOrder
.
getMchNo
())
.
eq
(
MchDivisionReceiverGroup:
:
getAutoDivisionFlag
,
CS
.
YES
));
if
(
groups
.
isEmpty
()){
return
new
ArrayList
<>();
}
queryWrapper
.
eq
(
MchDivisionReceiver:
:
getReceiverGroupId
,
groups
.
get
(
0
).
getReceiverGroupId
());
}
//全部分账账号
List
<
MchDivisionReceiver
>
allMchReceiver
=
mchDivisionReceiverService
.
list
(
queryWrapper
);
if
(
allMchReceiver
.
isEmpty
()){
...
...
@@ -228,7 +263,6 @@ public class PayOrderDivisionMQReceiver implements PayOrderDivisionMQ.IMQReceive
return
new
ArrayList
<>();
}
// 过滤账号
List
<
MchDivisionReceiver
>
filterMchReceiver
=
new
ArrayList
<>();
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/division/DivisionReceiverBindRQ.java
0 → 100644
View file @
fa6e00c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.rqrs.division
;
import
com.jeequan.jeepay.pay.rqrs.AbstractMchAppRQ
;
import
lombok.Data
;
import
org.hibernate.validator.constraints.Range
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
/*
* 分账账号的绑定 请求参数
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/8/25 09:21
*/
@Data
public
class
DivisionReceiverBindRQ
extends
AbstractMchAppRQ
{
/** 支付接口代码 **/
@NotBlank
(
message
=
"支付接口代码不能为空"
)
private
String
ifCode
;
/** 接收者账号别名 **/
private
String
receiverAlias
;
/** 组ID **/
@NotNull
(
message
=
"组ID不能为空, 若不存在请先登录商户平台进行创建操作"
)
private
Long
receiverGroupId
;
/** 分账接收账号类型: 0-个人(对私) 1-商户(对公) **/
@NotNull
(
message
=
"分账接收账号类型不能为空"
)
@Range
(
min
=
0
,
max
=
1
,
message
=
"分账接收账号类型设置有误"
)
private
Byte
accType
;
/** 分账接收账号 **/
@NotBlank
(
message
=
"分账接收账号不能为空"
)
private
String
accNo
;
/** 分账接收账号名称 **/
private
String
accName
;
/** 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等 **/
@NotBlank
(
message
=
"分账关系类型不能为空"
)
private
String
relationType
;
/** 当选择自定义时,需要录入该字段。 否则为对应的名称 **/
private
String
relationTypeName
;
/** 渠道特殊信息 */
private
String
channelExtInfo
;
/** 分账比例 **/
@NotBlank
(
message
=
"分账比例不能为空"
)
private
String
divisionProfit
;
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/division/DivisionReceiverBindRS.java
0 → 100644
View file @
fa6e00c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.rqrs.division
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiver
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
lombok.Data
;
import
org.springframework.beans.BeanUtils
;
import
java.math.BigDecimal
;
/*
* 绑定账户 响应参数
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/6/8 17:34
*/
@Data
public
class
DivisionReceiverBindRS
extends
AbstractRS
{
/**
* 分账接收者ID
*/
private
Long
receiverId
;
/**
* 接收者账号别名
*/
private
String
receiverAlias
;
/**
* 组ID(便于商户接口使用)
*/
private
Long
receiverGroupId
;
/**
* 商户号
*/
private
String
mchNo
;
/**
* 应用ID
*/
private
String
appId
;
/**
* 支付接口代码
*/
private
String
ifCode
;
/**
* 分账接收账号类型: 0-个人(对私) 1-商户(对公)
*/
private
Byte
accType
;
/**
* 分账接收账号
*/
private
String
accNo
;
/**
* 分账接收账号名称
*/
private
String
accName
;
/**
* 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等
*/
private
String
relationType
;
/**
* 当选择自定义时,需要录入该字段。 否则为对应的名称
*/
private
String
relationTypeName
;
/**
* 渠道特殊信息
*/
private
String
channelExtInfo
;
/**
* 绑定成功时间
*/
private
Long
bindSuccessTime
;
/**
* 分账比例
*/
private
BigDecimal
divisionProfit
;
/**
* 分账状态 1-绑定成功, 0-绑定异常
*/
private
Byte
bindState
;
/**
* 支付渠道错误码
*/
private
String
errCode
;
/**
* 支付渠道错误信息
*/
private
String
errMsg
;
public
static
DivisionReceiverBindRS
buildByRecord
(
MchDivisionReceiver
record
){
if
(
record
==
null
){
return
null
;
}
DivisionReceiverBindRS
result
=
new
DivisionReceiverBindRS
();
BeanUtils
.
copyProperties
(
record
,
result
);
result
.
setBindSuccessTime
(
record
.
getBindSuccessTime
()
!=
null
?
record
.
getBindSuccessTime
().
getTime
()
:
null
);
return
result
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/service/ConfigContextService.java
View file @
fa6e00c3
...
...
@@ -50,6 +50,7 @@ import org.apache.commons.lang3.StringUtils;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
...
...
@@ -181,6 +182,12 @@ public class ConfigContextService {
return
;
}
// 商户应用mchNo 与参数不匹配
if
(!
dbMchApp
.
getMchNo
().
equals
(
mchNo
)){
return
;
}
//更新商户信息主体中的商户应用
mchInfoConfigContext
.
putMchApp
(
dbMchApp
);
...
...
@@ -256,19 +263,28 @@ public class ConfigContextService {
/** 初始化 [ISV支付参数配置信息] **/
public
synchronized
void
initIsvConfigContext
(
String
isvNo
){
//查询出所有商户的配置信息并更新
List
<
String
>
mchNoList
=
new
ArrayList
<>();
mchInfoService
.
list
(
MchInfo
.
gw
().
select
(
MchInfo:
:
getMchNo
).
eq
(
MchInfo:
:
getIsvNo
,
isvNo
)).
forEach
(
r
->
mchNoList
.
add
(
r
.
getMchNo
()));
// 查询出所有 所属当前服务商的所有应用集合
List
<
String
>
mchAppIdList
=
new
ArrayList
<>();
if
(!
mchNoList
.
isEmpty
()){
mchAppService
.
list
(
MchApp
.
gw
().
select
(
MchApp:
:
getAppId
).
in
(
MchApp:
:
getMchNo
,
mchNoList
)).
forEach
(
r
->
mchAppIdList
.
add
(
r
.
getAppId
()));
}
IsvConfigContext
isvConfigContext
=
new
IsvConfigContext
();
IsvInfo
isvInfo
=
isvInfoService
.
getById
(
isvNo
);
if
(
isvInfo
==
null
){
//查询出所有商户的配置信息并更新
mchInfoService
.
list
(
MchInfo
.
gw
().
select
(
MchInfo:
:
getMchNo
).
eq
(
MchInfo:
:
getIsvNo
,
isvNo
)).
forEach
(
mchInfoItem
->
{
for
(
String
appId
:
mchAppIdList
)
{
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchAppConfigContext
mchAppConfigContext
=
mchAppConfigContextMap
.
get
(
mchInfoItem
.
getMchNo
()
);
MchAppConfigContext
mchAppConfigContext
=
mchAppConfigContextMap
.
get
(
appId
);
if
(
mchAppConfigContext
!=
null
){
mchAppConfigContext
.
setIsvConfigContext
(
null
);
}
});
}
isvConfigContextMap
.
remove
(
isvNo
);
// 服务商有商户不可删除, 此处不再更新商户下的配置信息
return
;
}
...
...
@@ -314,16 +330,13 @@ public class ConfigContextService {
isvConfigContextMap
.
put
(
isvNo
,
isvConfigContext
);
//查询出所有商户的配置信息并更新
mchInfoService
.
list
(
MchInfo
.
gw
().
select
(
MchInfo:
:
getMchNo
).
eq
(
MchInfo:
:
getIsvNo
,
isvNo
)).
forEach
(
mchInfoItem
->
{
for
(
String
appId
:
mchAppIdList
)
{
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchAppConfigContext
mchAppConfigContext
=
mchAppConfigContextMap
.
get
(
mchInfoItem
.
getMchNo
()
);
MchAppConfigContext
mchAppConfigContext
=
mchAppConfigContextMap
.
get
(
appId
);
if
(
mchAppConfigContext
!=
null
){
mchAppConfigContext
.
setIsvConfigContext
(
isvConfigContext
);
}
});
}
}
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/service/PayOrderProcessService.java
View file @
fa6e00c3
...
...
@@ -75,7 +75,7 @@ public class PayOrderProcessService {
if
(
updDivisionState
){
//推送到分账MQ
mqSender
.
send
(
PayOrderDivisionMQ
.
build
(
payOrder
.
getPayOrderId
(),
null
),
1
);
//1分钟后执行
mqSender
.
send
(
PayOrderDivisionMQ
.
build
(
payOrder
.
getPayOrderId
(),
null
),
60
);
//1分钟后执行
}
}
catch
(
Exception
e
)
{
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/util/CodeImgUtil.java
View file @
fa6e00c3
...
...
@@ -69,7 +69,6 @@ public class CodeImgUtil {
}
//TODO
// 图片宽度的一般
private
static
final
int
IMAGE_WIDTH
=
25
;
private
static
final
int
IMAGE_HEIGHT
=
25
;
...
...
jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/MchDivisionReceiverGroupService.java
0 → 100644
View file @
fa6e00c3
package
com.jeequan.jeepay.service.impl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup
;
import
com.jeequan.jeepay.service.mapper.MchDivisionReceiverGroupMapper
;
import
org.springframework.stereotype.Service
;
/**
* <p>
* 分账账号组 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-23
*/
@Service
public
class
MchDivisionReceiverGroupService
extends
ServiceImpl
<
MchDivisionReceiverGroupMapper
,
MchDivisionReceiverGroup
>
{
/** 根据ID和商户号查询 **/
public
MchDivisionReceiverGroup
findByIdAndMchNo
(
Long
groupId
,
String
mchNo
){
return
getOne
(
MchDivisionReceiverGroup
.
gw
().
eq
(
MchDivisionReceiverGroup:
:
getReceiverGroupId
,
groupId
).
eq
(
MchDivisionReceiverGroup:
:
getMchNo
,
mchNo
));
}
}
jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/PayOrderDivisionRecordService.java
View file @
fa6e00c3
...
...
@@ -5,6 +5,9 @@ import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import
com.jeequan.jeepay.service.mapper.PayOrderDivisionRecordMapper
;
import
org.springframework.stereotype.Service
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* <p>
* 分账记录表 服务实现类
...
...
@@ -16,4 +19,27 @@ import org.springframework.stereotype.Service;
@Service
public
class
PayOrderDivisionRecordService
extends
ServiceImpl
<
PayOrderDivisionRecordMapper
,
PayOrderDivisionRecord
>
{
/** 更新分账记录为分账成功**/
public
void
updateRecordSuccessOrFail
(
List
<
PayOrderDivisionRecord
>
records
,
Byte
state
,
String
channelBatchOrderId
,
String
channelRespResult
){
if
(
records
==
null
||
records
.
isEmpty
()){
return
;
}
List
<
Long
>
recordIds
=
new
ArrayList
<>();
records
.
stream
().
forEach
(
r
->
recordIds
.
add
(
r
.
getRecordId
()));
PayOrderDivisionRecord
updateRecord
=
new
PayOrderDivisionRecord
();
updateRecord
.
setState
(
state
);
updateRecord
.
setChannelBatchOrderId
(
channelBatchOrderId
);
updateRecord
.
setChannelRespResult
(
channelRespResult
);
update
(
updateRecord
,
PayOrderDivisionRecord
.
gw
().
in
(
PayOrderDivisionRecord:
:
getRecordId
,
recordIds
).
eq
(
PayOrderDivisionRecord:
:
getState
,
PayOrderDivisionRecord
.
STATE_WAIT
));
}
}
jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/PayOrderService.java
View file @
fa6e00c3
...
...
@@ -27,10 +27,8 @@ import com.jeequan.jeepay.core.entity.IsvInfo;
import
com.jeequan.jeepay.core.entity.MchInfo
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.PayWay
;
import
com.jeequan.jeepay.service.mapper.IsvInfoMapper
;
import
com.jeequan.jeepay.service.mapper.MchInfoMapper
;
import
com.jeequan.jeepay.service.mapper.PayOrderMapper
;
import
com.jeequan.jeepay.service.mapper.PayWayMapper
;
import
com.jeequan.jeepay.core.utils.AmountUtil
;
import
com.jeequan.jeepay.service.mapper.*
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
...
...
@@ -53,6 +51,7 @@ public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
@Autowired
private
MchInfoMapper
mchInfoMapper
;
@Autowired
private
IsvInfoMapper
isvInfoMapper
;
@Autowired
private
PayWayMapper
payWayMapper
;
@Autowired
private
PayOrderDivisionRecordMapper
payOrderDivisionRecordMapper
;
/** 更新订单状态 【订单生成】 --》 【支付中】 **/
public
boolean
updateInit2Ing
(
String
payOrderId
,
PayOrder
payOrder
){
...
...
@@ -65,7 +64,6 @@ public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
updateRecord
.
setWayCode
(
payOrder
.
getWayCode
());
updateRecord
.
setMchFeeRate
(
payOrder
.
getMchFeeRate
());
updateRecord
.
setMchFeeAmount
(
payOrder
.
getMchFeeAmount
());
updateRecord
.
setMchIncomeAmount
(
payOrder
.
getMchIncomeAmount
());
return
update
(
updateRecord
,
new
LambdaUpdateWrapper
<
PayOrder
>()
.
eq
(
PayOrder:
:
getPayOrderId
,
payOrderId
).
eq
(
PayOrder:
:
getState
,
PayOrder
.
STATE_INIT
));
...
...
@@ -358,4 +356,26 @@ public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
payListMap
.
addAll
(
refundListMap
);
return
payListMap
;
}
/**
* 计算支付订单商家入账金额
* 商家订单入账金额 (支付金额 - 手续费 - 退款金额 - 总分账金额)
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/8/26 16:39
*/
public
Long
calMchIncomeAmount
(
PayOrder
dbPayOrder
){
//商家订单入账金额 (支付金额 - 手续费 - 退款金额 - 总分账金额)
Long
mchIncomeAmount
=
dbPayOrder
.
getAmount
()
-
dbPayOrder
.
getMchFeeAmount
()
-
dbPayOrder
.
getRefundAmount
();
//减去已分账金额
mchIncomeAmount
-=
payOrderDivisionRecordMapper
.
sumSuccessDivisionAmount
(
dbPayOrder
.
getPayOrderId
());
return
mchIncomeAmount
<=
0
?
0
:
mchIncomeAmount
;
}
}
jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/MchDivisionReceiverGroupMapper.java
0 → 100644
View file @
fa6e00c3
package
com.jeequan.jeepay.service.mapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup
;
/**
* <p>
* 分账账号组 Mapper 接口
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-23
*/
public
interface
MchDivisionReceiverGroupMapper
extends
BaseMapper
<
MchDivisionReceiverGroup
>
{
}
jeepay-service/src/main/java/com/jeequan/jeepay/service/mapper/MchDivisionReceiverGroupMapper.xml
0 → 100644
View file @
fa6e00c3
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.jeequan.jeepay.service.mapper.MchDivisionReceiverGroupMapper"
>
<!-- 通用查询映射结果 -->
<resultMap
id=
"BaseResultMap"
type=
"com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup"
>
<id
column=
"receiver_group_id"
property=
"receiverGroupId"
/>
<result
column=
"receiver_group_name"
property=
"receiverGroupName"
/>
<result
column=
"mch_no"
property=
"mchNo"
/>
<result
column=
"auto_division_flag"
property=
"autoDivisionFlag"
/>
<result
column=
"created_uid"
property=
"createdUid"
/>
<result
column=
"created_by"
property=
"createdBy"
/>
<result
column=
"created_at"
property=
"createdAt"
/>
<result
column=
"updated_at"
property=
"updatedAt"
/>
</resultMap>
</mapper>
Prev
1
2
3
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment