Commit fa6e00c3 authored by terrfly's avatar terrfly
Browse files

完成订单的分账逻辑

parent ad2afc15
/*
* 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;
}
}
}
......@@ -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.encodeAll(redirectUrl), isvAndMchAppId));
}
/** 支付宝授权回调地址 **/
......
......@@ -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();
}
}
......@@ -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);
......
......@@ -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);
......
/*
* 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;
}
}
......@@ -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); //订单状态, 默认订单生成状态
......
......@@ -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;
......
......@@ -58,8 +58,6 @@ public class AlipayClientWrapper {
alipayResp = alipayClient.execute(request);
}
//判断返回的值: // TODO
return alipayResp;
} catch (AlipayApiException e) { // 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。
......
......@@ -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.getMchIncomeAmount()); // 订单实际分账金额, 单位:分(订单金额 - 商户手续费 - 已退款金额) //TODO 实际计算金额
record.setPayOrderDivisionAmount(payOrderDivisionAmount); // 订单计算分账金额
record.setBatchOrderId(batchOrderId); //系统分账批次号
record.setState(MchDivisionReceiver.STATE_WAIT); //状态: 待分账
record.setState(PayOrderDivisionRecord.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<>();
......
/*
* 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;
}
/*
* 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;
}
}
......@@ -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);
}
});
}
}
......
......@@ -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) {
......
......@@ -69,7 +69,6 @@ public class CodeImgUtil {
}
//TODO
// 图片宽度的一般
private static final int IMAGE_WIDTH = 25;
private static final int IMAGE_HEIGHT = 25;
......
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));
}
}
......@@ -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));
}
}
......@@ -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;
}
}
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> {
}
<?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>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment