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
25667a05
Commit
25667a05
authored
Mar 30, 2023
by
xiaoyu
Browse files
分账结果查询,定时任务逻辑
parent
56bc6dc8
Changes
4
Hide whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IDivisionService.java
View file @
25667a05
...
...
@@ -18,11 +18,10 @@ package com.jeequan.jeepay.pay.channel;
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.entity.TransferOrder
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.transfer.TransferOrderRQ
;
import
java.util.HashMap
;
import
java.util.List
;
/**
...
...
@@ -46,4 +45,7 @@ public interface IDivisionService {
/** 单次分账 (无需调用完结接口,或自动解冻商户资金) **/
ChannelRetMsg
singleDivision
(
PayOrder
payOrder
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
);
/** 查询分账结果 **/
HashMap
<
Long
,
ChannelRetMsg
>
queryDivision
(
PayOrder
payOrder
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
);
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayDivisionService.java
View file @
25667a05
...
...
@@ -15,16 +15,20 @@
*/
package
com.jeequan.jeepay.pay.channel.alipay
;
import
cn.hutool.core.collection.CollectionUtil
;
import
com.alibaba.fastjson.JSON
;
import
com.alipay.api.domain.*
;
import
com.alipay.api.request.AlipayTradeOrderSettleQueryRequest
;
import
com.alipay.api.request.AlipayTradeOrderSettleRequest
;
import
com.alipay.api.request.AlipayTradeRoyaltyRelationBindRequest
;
import
com.alipay.api.response.AlipayTradeOrderSettleQueryResponse
;
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.exception.BizException
;
import
com.jeequan.jeepay.core.utils.AmountUtil
;
import
com.jeequan.jeepay.core.utils.RegKit
;
import
com.jeequan.jeepay.core.utils.SeqKit
;
...
...
@@ -39,6 +43,7 @@ import org.springframework.stereotype.Service;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.List
;
/**
...
...
@@ -205,4 +210,86 @@ public class AlipayDivisionService implements IDivisionService {
}
}
@Override
public
HashMap
<
Long
,
ChannelRetMsg
>
queryDivision
(
PayOrder
payOrder
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
)
{
// 创建返回结果
HashMap
<
Long
,
ChannelRetMsg
>
resultMap
=
new
HashMap
<>();
// 同批次分账记录结果集
HashMap
<
String
,
RoyaltyDetail
>
aliAcMap
=
new
HashMap
<>();
try
{
// 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。
if
(
recordList
.
isEmpty
()){
throw
new
BizException
(
"payOrderId:"
+
payOrder
.
getPayOrderId
()
+
"分账记录为空。recordList:"
+
recordList
);
}
AlipayTradeOrderSettleQueryRequest
request
=
new
AlipayTradeOrderSettleQueryRequest
();
AlipayTradeOrderSettleQueryModel
model
=
new
AlipayTradeOrderSettleQueryModel
();
request
.
setBizModel
(
model
);
//统一放置 isv接口必传信息
AlipayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
,
model
);
// 支付宝分账请求单号
model
.
setSettleNo
(
recordList
.
get
(
0
).
getBatchOrderId
());
//结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model
.
setOutRequestNo
(
payOrder
.
getPayOrderId
());
//支付宝订单号
model
.
setTradeNo
(
payOrder
.
getChannelOrderNo
());
//调起支付宝分账接口
if
(
log
.
isInfoEnabled
()){
log
.
info
(
"订单:[{}], 支付宝查询分账请求:{}"
,
recordList
.
get
(
0
).
getBatchOrderId
(),
JSON
.
toJSONString
(
model
));
}
AlipayTradeOrderSettleQueryResponse
alipayResp
=
configContextQueryService
.
getAlipayClientWrapper
(
mchAppConfigContext
).
execute
(
request
);
log
.
info
(
"订单:[{}], 支付宝查询分账响应:{}"
,
payOrder
.
getPayOrderId
(),
alipayResp
.
getBody
());
if
(
alipayResp
.
isSuccess
()){
List
<
RoyaltyDetail
>
detailList
=
alipayResp
.
getRoyaltyDetailList
();
if
(
CollectionUtil
.
isNotEmpty
(
detailList
))
{
// 遍历匹配与当前账户相同的分账单
detailList
.
stream
().
forEach
(
item
->
{
// 分账操作类型为转账类型
if
(
"transfer"
.
equals
(
item
.
getOperationType
()))
{
aliAcMap
.
put
(
item
.
getTransIn
(),
item
);
}
});
}
}
else
{
log
.
error
(
"支付宝分账查询响应异常, alipayResp:{}"
,
JSON
.
toJSONString
(
alipayResp
));
throw
new
BizException
(
"支付宝分账查询响应异常:"
+
alipayResp
.
getSubMsg
());
}
// 返回结果
recordList
.
stream
().
forEach
(
record
->
{
// 对应入账账号匹配
if
(
aliAcMap
.
get
(
record
.
getAccNo
())
!=
null
)
{
RoyaltyDetail
detail
=
aliAcMap
.
get
(
record
.
getAccNo
());
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
// 错误码
channelRetMsg
.
setChannelErrCode
(
detail
.
getErrorCode
());
// 错误信息
channelRetMsg
.
setChannelErrMsg
(
detail
.
getErrorDesc
());
// 仅返回分账记录为最终态的结果 处理中的分账单不做返回处理
if
(
"SUCCESS"
.
equals
(
detail
.
getState
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
resultMap
.
put
(
record
.
getRecordId
(),
channelRetMsg
);
}
else
if
(
"FAIL"
.
equals
(
detail
.
getState
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
resultMap
.
put
(
record
.
getRecordId
(),
channelRetMsg
);
}
}
});
}
catch
(
Exception
e
)
{
log
.
error
(
"查询分账信息异常"
,
e
);
throw
new
BizException
(
e
.
getMessage
());
}
return
resultMap
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayDivisionService.java
View file @
25667a05
...
...
@@ -15,6 +15,7 @@
*/
package
com.jeequan.jeepay.pay.channel.wxpay
;
import
cn.hutool.core.collection.CollectionUtil
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.profitsharing.*
;
...
...
@@ -26,6 +27,7 @@ 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.exception.BizException
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams
;
import
com.jeequan.jeepay.core.utils.SeqKit
;
import
com.jeequan.jeepay.pay.channel.IDivisionService
;
...
...
@@ -38,8 +40,8 @@ import lombok.extern.slf4j.Slf4j;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
java.math.BigDecimal
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
/**
...
...
@@ -246,6 +248,106 @@ public class WxpayDivisionService implements IDivisionService {
}
}
@Override
public
HashMap
<
Long
,
ChannelRetMsg
>
queryDivision
(
PayOrder
payOrder
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
)
{
// 创建返回结果
HashMap
<
Long
,
ChannelRetMsg
>
resultMap
=
new
HashMap
<>();
try
{
// 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。
if
(
recordList
.
isEmpty
()){
throw
new
BizException
(
"payOrderId:"
+
payOrder
.
getPayOrderId
()
+
"分账记录为空。recordList:"
+
recordList
);
}
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
if
(
CS
.
PAY_IF_VERSION
.
WX_V2
.
equals
(
wxServiceWrapper
.
getApiVersion
()))
{
//V2
// 同批次分账记录结果集
HashMap
<
String
,
ProfitSharingQueryResult
.
Receiver
>
wxAcMap
=
new
HashMap
<>();
ProfitSharingQueryRequest
request
=
new
ProfitSharingQueryRequest
();
request
.
setTransactionId
(
payOrder
.
getChannelOrderNo
());
//放置isv信息
WxpayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
);
request
.
setOutOrderNo
(
recordList
.
get
(
0
).
getBatchOrderId
());
//取到批次号
ProfitSharingQueryResult
profitSharingQueryResult
=
wxServiceWrapper
.
getWxPayService
().
getProfitSharingService
().
profitSharingQuery
(
request
);
List
<
ProfitSharingQueryResult
.
Receiver
>
receivers
=
profitSharingQueryResult
.
getReceivers
();
if
(
CollectionUtil
.
isNotEmpty
(
receivers
))
{
// 遍历匹配与当前账户相同的分账单
receivers
.
stream
().
forEach
(
item
->
{
wxAcMap
.
put
(
item
.
getAccount
(),
item
);
});
}
recordList
.
stream
().
forEach
(
record
->
{
ProfitSharingQueryResult
.
Receiver
receiver
=
wxAcMap
.
get
(
record
.
getAccNo
());
if
(
receiver
!=
null
)
{
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
// 错误信息
channelRetMsg
.
setChannelErrMsg
(
receiver
.
getFailReason
());
if
(
"SUCCESS"
.
equals
(
receiver
.
getResult
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
resultMap
.
put
(
record
.
getRecordId
(),
channelRetMsg
);
}
else
if
(
"CLOSED"
.
equals
(
receiver
.
getResult
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
resultMap
.
put
(
record
.
getRecordId
(),
channelRetMsg
);
}
}
});
}
else
if
(
CS
.
PAY_IF_VERSION
.
WX_V3
.
equals
(
wxServiceWrapper
.
getApiVersion
()))
{
// 同批次分账记录结果集
HashMap
<
String
,
com
.
github
.
binarywang
.
wxpay
.
bean
.
profitsharingV3
.
ProfitSharingResult
.
Receiver
>
wxAcMap
=
new
HashMap
<>();
// 发起请求
com
.
github
.
binarywang
.
wxpay
.
bean
.
profitsharingV3
.
ProfitSharingResult
profitSharingResult
=
wxServiceWrapper
.
getWxPayService
().
getProfitSharingV3Service
().
getProfitSharingResult
(
recordList
.
get
(
0
).
getBatchOrderId
(),
payOrder
.
getChannelOrderNo
());
List
<
com
.
github
.
binarywang
.
wxpay
.
bean
.
profitsharingV3
.
ProfitSharingResult
.
Receiver
>
receivers
=
profitSharingResult
.
getReceivers
();
if
(
CollectionUtil
.
isNotEmpty
(
receivers
))
{
// 遍历匹配与当前账户相同的分账单
receivers
.
stream
().
forEach
(
item
->
{
wxAcMap
.
put
(
item
.
getAccount
(),
item
);
});
}
recordList
.
stream
().
forEach
(
record
->
{
com
.
github
.
binarywang
.
wxpay
.
bean
.
profitsharingV3
.
ProfitSharingResult
.
Receiver
receiver
=
wxAcMap
.
get
(
record
.
getAccNo
());
if
(
receiver
!=
null
)
{
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
// 错误信息
channelRetMsg
.
setChannelErrMsg
(
receiver
.
getFailReason
());
if
(
"SUCCESS"
.
equals
(
receiver
.
getResult
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
resultMap
.
put
(
record
.
getRecordId
(),
channelRetMsg
);
}
else
if
(
"CLOSED"
.
equals
(
receiver
.
getResult
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
resultMap
.
put
(
record
.
getRecordId
(),
channelRetMsg
);
}
}
});
}
}
catch
(
WxPayException
wxPayException
)
{
log
.
error
(
"微信查询分账结果失败{}"
,
wxPayException
.
getCustomErrorMsg
());
throw
new
BizException
(
wxPayException
.
getCustomErrorMsg
());
}
catch
(
Exception
e
)
{
log
.
error
(
"微信分账失败"
,
e
);
throw
new
BizException
(
e
.
getMessage
());
}
return
resultMap
;
}
/** 调用订单的完结接口 (分账对象不存在时) */
private
String
divisionFinish
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
throws
WxPayException
{
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/task/PayOrderDivisionRecordReissueTask.java
View file @
25667a05
...
...
@@ -19,14 +19,22 @@ import cn.hutool.core.date.DateUtil;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.IDivisionService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Component
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.List
;
/*
...
...
@@ -43,6 +51,8 @@ public class PayOrderDivisionRecordReissueTask {
private
static
final
int
QUERY_PAGE_SIZE
=
100
;
//每次查询数量
@Autowired
private
PayOrderDivisionRecordService
payOrderDivisionRecordService
;
@Autowired
private
ConfigContextQueryService
configContextQueryService
;
@Autowired
private
PayOrderService
payOrderService
;
@Scheduled
(
cron
=
"0 0/1 * * * ?"
)
// 每分钟执行一次
public
void
start
()
{
...
...
@@ -61,7 +71,6 @@ public class PayOrderDivisionRecordReissueTask {
while
(
true
){
try
{
IPage
<
PayOrderDivisionRecord
>
pageRecordList
=
payOrderDivisionRecordService
.
getBaseMapper
().
distinctBatchOrderIdList
(
new
Page
(
currentPageIndex
,
QUERY_PAGE_SIZE
),
lambdaQueryWrapper
);
log
.
info
(
"处理分账补单任务, 共计{}条"
,
pageRecordList
.
getTotal
());
...
...
@@ -87,13 +96,44 @@ public class PayOrderDivisionRecordReissueTask {
continue
;
}
// 查询支付订单信息
PayOrder
payOrder
=
payOrderService
.
getById
(
batchRecord
.
getPayOrderId
());
if
(
payOrder
==
null
)
{
log
.
error
(
"支付订单记录不存在:{}"
,
batchRecord
.
getPayOrderId
());
continue
;
}
// 查询转账接口是否存在
IDivisionService
divisionService
=
SpringBeansUtil
.
getBean
(
batchRecord
.
getIfCode
()
+
"DivisionService"
,
IDivisionService
.
class
);
if
(
divisionService
==
null
)
{
log
.
error
(
"查询转账接口不存在:{}"
,
batchRecord
.
getIfCode
());
continue
;
}
MchAppConfigContext
mchAppConfigContext
=
configContextQueryService
.
queryMchInfoAndAppInfo
(
payOrder
.
getMchNo
(),
payOrder
.
getAppId
());
// 调用渠道侧的查单接口: 注意: 渠道内需保证:
// 1. 返回的条目 必须全部来自recordList, 可以少于recordList但是不得高于 recordList 数量;
// 2. recordList 的记录可能与接口返回的数量不一致, 接口实现不要求对条目数量做验证;
// 3. 接口查询的记录若recordList 不存在, 忽略即可。 ( 例如两条相同的accNo, 则可能仅匹配一条。 那么另外一条将在下一次循环中处理。 )
// 4. 仅明确状态的再返回,若不明确则不需返回;
HashMap
<
Long
,
ChannelRetMsg
>
queryDivision
=
divisionService
.
queryDivision
(
payOrder
,
recordList
,
mchAppConfigContext
);
// 处理查询结果
recordList
.
stream
().
forEach
(
record
->
{
ChannelRetMsg
channelRetMsg
=
queryDivision
.
get
(
record
.
getRecordId
());
// 响应状态为分账成功或失败时,更新该记录状态
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
==
channelRetMsg
.
getChannelState
()
||
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
==
channelRetMsg
.
getChannelState
())
{
PayOrderDivisionRecord
upDivisionRecord
=
new
PayOrderDivisionRecord
();
upDivisionRecord
.
setRecordId
(
record
.
getRecordId
());
upDivisionRecord
.
setChannelRespResult
(
channelRetMsg
.
getChannelErrMsg
());
upDivisionRecord
.
setState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
==
channelRetMsg
.
getChannelState
()
?
PayOrderDivisionRecord
.
STATE_SUCCESS
:
PayOrderDivisionRecord
.
STATE_FAIL
);
// channelOrderReissueService.processPayOrder(payOrder);
// payOrderDivisionRecordService.updateRecordSuccessOrFail(upDivisionRecord);
}
});
}
catch
(
Exception
e1
)
{
log
.
error
(
"处理补单任务单条[{}]异常"
,
batchRecord
.
getBatchOrderId
(),
e1
);
...
...
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