## Feat - 京东支付
This commit is contained in:
parent
e308911271
commit
7105312311
|
@ -141,4 +141,12 @@ public interface ISaOrderServiceApi {
|
|||
*/
|
||||
R<BigDecimal> getRetailPayOrder(Long pkMember, String orderCode);
|
||||
|
||||
/**
|
||||
* 根据订单编号查询订单信息
|
||||
*
|
||||
* @param orderCode 订单编号
|
||||
* @param pkMember 会员主键
|
||||
* @return
|
||||
*/
|
||||
R<SaOrderExt> queryOrderByCode(String orderCode, Long pkMember);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.hzs.third.pay;
|
||||
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
|
||||
public interface ITOnlinePaymentServiceApi {
|
||||
R<TOnlinePayment> getOnlinePayment(String orderNo);
|
||||
R<String> refund(String orderNo, Long userId);
|
||||
}
|
|
@ -123,11 +123,11 @@ public class ApiCuMemberWithdrawController extends BaseController {
|
|||
return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_USER_NOT_EXIST));
|
||||
}
|
||||
//获取银行卡信息
|
||||
Long pkBank = cuMemberWithdrawParam.getPkBank();
|
||||
CuMemberBankVO memberBank = cuMemberBankService.selectCuMemberBankById(pkBank);
|
||||
if (null == memberBank) {
|
||||
return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.BIND_BANK_CARD));
|
||||
}
|
||||
// Long pkBank = cuMemberWithdrawParam.getPkBank();
|
||||
// CuMemberBankVO memberBank = cuMemberBankService.selectCuMemberBankById(pkBank);
|
||||
// if (null == memberBank) {
|
||||
// return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.BIND_BANK_CARD));
|
||||
// }
|
||||
//校验支付密码
|
||||
String payPwd = cuMemberLoginExt.getPayPwd();
|
||||
if (StringUtils.isEmpty(payPwd) || !SecurityUtils.matchesPassword(cuMemberWithdrawParam.getPayPwd(), payPwd)) {
|
||||
|
@ -232,7 +232,8 @@ public class ApiCuMemberWithdrawController extends BaseController {
|
|||
CurrencyDTO currencyDTO = baseService.getCurrency(pkCountry);
|
||||
|
||||
CuMemberWithdraw cuMemberWithdraw = CuMemberWithdraw.builder().pkMember(pkMember)
|
||||
.pkAccount(pkAccount).pkBank(pkBank).remarks(cuMemberWithdrawParam.getRemarks())
|
||||
// .pkAccount(pkAccount).pkBank(pkBank).remarks(cuMemberWithdrawParam.getRemarks())
|
||||
.pkAccount(pkAccount).pkBank(0L).remarks(cuMemberWithdrawParam.getRemarks())
|
||||
.pkRate(currencyDTO.getPkId()).cashAmount(cashAmount)
|
||||
.serviceCharge(serviceChargeAmount).incomeTax(payIncomeTax)
|
||||
.issuedAmount(issuedAmount).withdrawCode(code).build();
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.hzs.common.security.service.UserTokenService;
|
|||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.common.service.ITransactionCommonService;
|
||||
import com.hzs.common.util.TransactionUtils;
|
||||
import com.hzs.member.account.param.CuMemberWithdrawRejectParam;
|
||||
import com.hzs.member.account.service.ICuMemberBaseService;
|
||||
import com.hzs.member.account.service.ICuMemberWithdrawService;
|
||||
import com.hzs.member.account.vo.CuMemberPetitionVO;
|
||||
|
@ -209,4 +210,11 @@ public class CuMemberWithdrawController extends BaseController {
|
|||
return toAjax(cuMemberWithdrawService.withdrawPaymentPositiveByPkId(memberWithdrawVO));
|
||||
}
|
||||
|
||||
@Log(module = EOperationModule.WITHDRAWAL_DETAIL, business = EOperationBusiness.WITHDRAWAL_DETAIL, method = EOperationMethod.REJECT)
|
||||
@PostMapping("/reject")
|
||||
public AjaxResult reject(@RequestBody CuMemberWithdrawRejectParam param) {
|
||||
cuMemberWithdrawService.withdrawReject(param);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.hzs.member.account.param;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CuMemberWithdrawRejectParam implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private List<Long> idList;
|
||||
private String rejectRemark;
|
||||
}
|
|
@ -5,6 +5,7 @@ import com.hzs.common.domain.member.account.CuMemberAccount;
|
|||
import com.hzs.common.domain.member.account.CuMemberWithdraw;
|
||||
import com.hzs.common.domain.system.config.BdWithdrawal;
|
||||
import com.hzs.member.account.dto.MemberAccountAudit;
|
||||
import com.hzs.member.account.param.CuMemberWithdrawRejectParam;
|
||||
import com.hzs.member.account.vo.CuMemberPetitionVO;
|
||||
import com.hzs.member.account.vo.CuMemberWithdrawVO;
|
||||
|
||||
|
@ -192,4 +193,10 @@ public interface ICuMemberWithdrawService extends IService<CuMemberWithdraw> {
|
|||
*/
|
||||
List<Long> selectWithdrawMember(Integer pkCountry, Long pkMember);
|
||||
|
||||
/**
|
||||
* 提现驳回
|
||||
* @param param
|
||||
*/
|
||||
void withdrawReject(CuMemberWithdrawRejectParam param);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,12 +4,16 @@ import cn.hutool.core.bean.BeanUtil;
|
|||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hzs.common.core.constant.MemberFieldConstants;
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.hzs.common.core.enums.*;
|
||||
import com.hzs.common.core.exception.ServiceException;
|
||||
import com.hzs.common.core.utils.CommonUtil;
|
||||
import com.hzs.common.core.utils.reflect.ReflectUtils;
|
||||
import com.hzs.common.domain.member.account.CuMemberAccount;
|
||||
|
@ -20,9 +24,12 @@ import com.hzs.common.domain.member.base.CuMember;
|
|||
import com.hzs.common.domain.member.ext.CuMemberAccountExt;
|
||||
import com.hzs.common.domain.system.config.*;
|
||||
import com.hzs.common.domain.system.config.ext.BdWithdrawalTaxExt;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.member.account.dto.BusinessCommissionDTO;
|
||||
import com.hzs.member.account.dto.CuMemberAccountParam;
|
||||
import com.hzs.member.account.dto.MemberAccountAudit;
|
||||
import com.hzs.member.account.mapper.CuMemberWithdrawMapper;
|
||||
import com.hzs.member.account.param.CuMemberWithdrawRejectParam;
|
||||
import com.hzs.member.account.service.*;
|
||||
import com.hzs.member.account.vo.CuMemberBankVO;
|
||||
import com.hzs.member.account.vo.CuMemberPetitionVO;
|
||||
|
@ -47,10 +54,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import java.math.BigDecimal;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -727,4 +731,36 @@ public class CuMemberWithdrawServiceImpl extends ServiceImpl<CuMemberWithdrawMap
|
|||
public List<Long> selectWithdrawMember(Integer pkCountry, Long pkMember) {
|
||||
return baseMapper.selectWithdrawMember(pkCountry, pkMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withdrawReject(CuMemberWithdrawRejectParam param) {
|
||||
if(ObjectUtil.isEmpty(param)){
|
||||
throw new ServiceException("参数异常!");
|
||||
}
|
||||
if(CollUtil.isEmpty(param.getIdList())){
|
||||
throw new ServiceException("请选择需要驳回的数据!");
|
||||
}
|
||||
if(StrUtil.isEmpty(param.getRejectRemark())){
|
||||
throw new ServiceException("请录入驳回原因!");
|
||||
}
|
||||
LambdaQueryWrapper<CuMemberWithdraw> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(CuMemberWithdraw::getPkId, param.getIdList());
|
||||
CuMemberWithdraw withdraw = CuMemberWithdraw.builder().build();
|
||||
withdraw.setApproveRemarks(param.getRejectRemark());
|
||||
withdraw.setApproveState(EApproveStatus.REJECTED.getValue());
|
||||
withdraw.setApprover(SecurityUtils.getUserId());
|
||||
withdraw.setApproveTime(new Date());
|
||||
baseMapper.update(withdraw, wrapper);
|
||||
List<CuMemberWithdraw> cuMemberWithdrawList = baseMapper.selectList(wrapper);
|
||||
Integer pkCountry = SecurityUtils.getPkCountry();
|
||||
if(CollUtil.isNotEmpty(cuMemberWithdrawList)){
|
||||
for (CuMemberWithdraw cuMemberWithdraw : cuMemberWithdrawList) {
|
||||
BusinessCommissionDTO businessCommissionDTO = BusinessCommissionDTO.builder()
|
||||
.tradeCode(cuMemberWithdraw.getWithdrawCode()).pkCountry(pkCountry)
|
||||
.tradeType(EApprovalBusiness.WITHDRAWAL.getValue())
|
||||
.pkCreator(SecurityUtils.getUserId()).build();
|
||||
cuMemberTradeService.businessCommissionReject(businessCommissionDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.hzs.member.base.service.impl;
|
|||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
@ -33,6 +34,7 @@ import com.hzs.common.domain.sale.order.SaOrder;
|
|||
import com.hzs.common.domain.system.config.BdAccount;
|
||||
import com.hzs.common.domain.system.config.BdAwards;
|
||||
import com.hzs.common.domain.system.config.BdGrade;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.util.TransactionUtils;
|
||||
import com.hzs.member.account.dto.BusinessCommissionDTO;
|
||||
import com.hzs.member.account.service.ICuMemberAccountService;
|
||||
|
@ -56,6 +58,7 @@ import com.hzs.system.config.IAwardsServiceApi;
|
|||
import com.hzs.system.config.IGradeServiceApi;
|
||||
import com.hzs.system.config.dto.AreaCurrencyDTO;
|
||||
import com.hzs.system.config.dto.GradeDTO;
|
||||
import com.hzs.third.pay.ITOnlinePaymentServiceApi;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -86,6 +89,9 @@ public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {
|
|||
@DubboReference
|
||||
ISaOrderServiceApi iSaOrderServiceApi;
|
||||
|
||||
@DubboReference
|
||||
ITOnlinePaymentServiceApi itOnlinePaymentServiceApi;
|
||||
|
||||
@Autowired
|
||||
private MemberToolsHandler memberToolsHandler;
|
||||
@Autowired
|
||||
|
@ -583,7 +589,14 @@ public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {
|
|||
.set(CuMemberRetailRegion::getModifiedTime, currentDateTime)
|
||||
);
|
||||
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
|
||||
// 钱包支付,则需要回退金额
|
||||
// 默认回退给创建人
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
} else {
|
||||
// 在线支付,处理退款
|
||||
this.handleOnlineRefund(saOrder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -623,8 +636,13 @@ public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {
|
|||
.set(CuMemberRetailRegion::getDelFlag, EDelFlag.DELETE.getValue())
|
||||
.set(CuMemberRetailRegion::getModifiedTime, currentDateTime)
|
||||
);
|
||||
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
|
||||
// 钱包支付,则需要回退金额
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
} else {
|
||||
// 在线支付,处理退款
|
||||
this.handleOnlineRefund(saOrder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -845,8 +863,20 @@ public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {
|
|||
cuMemberRegister.setPkCountry(saOrder.getPkCountry());
|
||||
cuMemberRegister.setPkModified(saOrder.getPkCreator());
|
||||
iCuMemberRegisterService.updateCuMemberRegister(cuMemberRegister);
|
||||
CuMemberAccount payMemberAccount = cuMemberAccountMap.get(saOrder.getPkCreator());
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
|
||||
// 钱包支付,则需要回退金额
|
||||
CuMemberAccount payMemberAccount = cuMemberAccountMap.get(saOrder.getPkCreator());
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
}
|
||||
}
|
||||
for (int i = memberList.size() - 1; i >= 0; i--) {
|
||||
Long pkMember = memberList.get(i);
|
||||
SaOrderExt saOrder = saOrderMap.get(pkMember);
|
||||
|
||||
if (saOrder.getPayType().equals(EOrderPayType.ONLINE.getValue())) {
|
||||
// 在线支付,处理退款
|
||||
this.handleOnlineRefund(saOrder);
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
@ -889,12 +919,19 @@ public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {
|
|||
this.handleParentLevel(saOrder, currentDateTime);
|
||||
|
||||
// 部分撤单 todo 发货后邮费不退,未发货退邮费
|
||||
if (saOrder.getBackOrderAmount() != null && ComputeUtil.compareValue(saOrder.getBackOrderAmount())) {
|
||||
cancelPartOrderBackAmount(pkApprove, saOrder);
|
||||
if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
|
||||
// 钱包支付,则需要回退金额
|
||||
// 部分撤单
|
||||
if (saOrder.getBackOrderAmount() != null && ComputeUtil.compareValue(saOrder.getBackOrderAmount())) {
|
||||
cancelPartOrderBackAmount(pkApprove, saOrder);
|
||||
} else {
|
||||
CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
|
||||
// 回退账号余额
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
}
|
||||
} else {
|
||||
CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
|
||||
// 回退账号余额
|
||||
cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
|
||||
// 在线支付,处理退款
|
||||
this.handleOnlineRefund(saOrder);
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
@ -1647,4 +1684,23 @@ public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在线支付退款
|
||||
*
|
||||
* @param saOrder
|
||||
*/
|
||||
private void handleOnlineRefund(SaOrderExt saOrder) {
|
||||
R<TOnlinePayment> onlinePaymentR = itOnlinePaymentServiceApi.getOnlinePayment(saOrder.getOrderCode());
|
||||
if (ObjectUtil.isNotEmpty(onlinePaymentR)) {
|
||||
TOnlinePayment onlinePayment = onlinePaymentR.getData();
|
||||
if (ObjectUtil.isNotEmpty(onlinePayment)) {
|
||||
R<String> result = itOnlinePaymentServiceApi.refund(saOrder.getOrderCode(), saOrder.getPkCreator());
|
||||
if (!result.isSuccess()) {
|
||||
throw new ServiceException(result.getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.hzs.common.domain.sale.ext.SaOrderExt;
|
|||
import com.hzs.common.domain.sale.ext.SaOrderItemsExt;
|
||||
import com.hzs.common.domain.sale.order.SaOrder;
|
||||
import com.hzs.common.domain.sale.order.SaOrderItems;
|
||||
import com.hzs.common.domain.third.pay.ext.TOnlineRefundExt;
|
||||
import com.hzs.common.security.auth.AuthMemberUtil;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.common.util.TransactionUtils;
|
||||
|
@ -120,6 +121,16 @@ public class ApiOrderController extends BaseController {
|
|||
return tableDataInfo;
|
||||
}
|
||||
|
||||
@GetMapping("/refund-list")
|
||||
public TableDataInfo refundList() {
|
||||
// 返回结果
|
||||
startPage();
|
||||
List<TOnlineRefundExt> list = iSaOrderService.queryRefundList();
|
||||
TableDataInfo tableDataInfo = getDataTable(list);
|
||||
tableDataInfo.setRows(list);
|
||||
return tableDataInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
*
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.hzs.common.domain.sale.ext.SaDeliverItemsExt;
|
|||
import com.hzs.common.domain.sale.ext.SaOrderExt;
|
||||
import com.hzs.common.domain.sale.ext.SaOrderItemsExt;
|
||||
import com.hzs.common.domain.sale.order.SaOrder;
|
||||
import com.hzs.common.domain.third.pay.ext.TOnlineRefundExt;
|
||||
import com.hzs.sale.order.param.*;
|
||||
import com.hzs.sale.order.vo.*;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
@ -110,6 +111,8 @@ public interface SaOrderMapper extends BaseMapper<SaOrder> {
|
|||
@Param("memberId") Long memberId,
|
||||
@Param("pkCountry") Integer pkCountry);
|
||||
|
||||
List<TOnlineRefundExt> queryRefundList(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 自助撤单列表
|
||||
**/
|
||||
|
|
|
@ -161,4 +161,13 @@ public class SaOrderServiceProvider implements ISaOrderServiceApi {
|
|||
return R.ok(ComputeUtil.computeAdd(saOrder.getOrderAmount(), saOrder.getPostage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<SaOrderExt> queryOrderByCode(String orderCode, Long pkMember) {
|
||||
SaOrderExt saOrder = redisService.getCacheObject(CacheConstants.TEMP_ORDER + pkMember + orderCode);
|
||||
if (null == saOrder) {
|
||||
// 直销订单
|
||||
saOrder = iSaOrderService.queryOrderByCode(orderCode, null);
|
||||
}
|
||||
return R.ok(saOrder);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.hzs.common.domain.sale.ext.*;
|
|||
import com.hzs.common.domain.sale.order.SaOrder;
|
||||
import com.hzs.common.domain.sale.order.SaOrderItems;
|
||||
import com.hzs.common.domain.system.config.BdGrade;
|
||||
import com.hzs.common.domain.third.pay.ext.TOnlineRefundExt;
|
||||
import com.hzs.sale.order.param.*;
|
||||
import com.hzs.sale.order.vo.*;
|
||||
import com.hzs.system.config.dto.GradeDTO;
|
||||
|
@ -379,6 +380,8 @@ public interface ISaOrderService extends IService<SaOrder> {
|
|||
*/
|
||||
List<SaOrderExt> myOrderList(MyOrderParam param, Long memberId, Integer pkCountry);
|
||||
|
||||
List<TOnlineRefundExt> queryRefundList();
|
||||
|
||||
/**
|
||||
* 自助撤单列表
|
||||
**/
|
||||
|
|
|
@ -34,6 +34,7 @@ import com.hzs.common.domain.system.base.BdCountry;
|
|||
import com.hzs.common.domain.system.base.ext.BdProductStorehouseExt;
|
||||
import com.hzs.common.domain.system.config.BdAwards;
|
||||
import com.hzs.common.domain.system.config.BdGrade;
|
||||
import com.hzs.common.domain.third.pay.ext.TOnlineRefundExt;
|
||||
import com.hzs.common.security.service.UserTokenService;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.common.util.TransactionUtils;
|
||||
|
@ -1501,6 +1502,11 @@ public class SaOrderServiceImpl extends ServiceImpl<SaOrderMapper, SaOrder> impl
|
|||
return baseMapper.myOrderList(param, memberId, pkCountry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TOnlineRefundExt> queryRefundList() {
|
||||
return baseMapper.queryRefundList(SecurityUtils.getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SaOrderExt> selfRevokeOrderList(MyOrderParam param, Long memberId, Integer pkCountry) {
|
||||
return baseMapper.selfRevokeOrderList(param, memberId, pkCountry);
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.hzs.sale.shopping.service.impl;
|
|||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.hzs.common.core.constant.CacheConstants;
|
||||
import com.hzs.common.core.domain.R;
|
||||
|
@ -133,7 +134,7 @@ public class ShoppingCartServiceImpl implements IShoppingCartService {
|
|||
for (String innkey : innerShopMap.keySet()) {
|
||||
String mapValue = innerShopMap.get(innkey);
|
||||
ShoppingCartRedis scr = JSONUtil.toBean(mapValue, ShoppingCartRedis.class);
|
||||
if (scr.getSpecialArea() == value.getValue()) {
|
||||
if (ObjectUtil.isNotEmpty(scr.getSpecialArea()) && scr.getSpecialArea() == value.getValue()) {
|
||||
scv.setSpecialArea(value.getValue());
|
||||
scv.setSpecialAreaVal(value.getLabel());
|
||||
if (pkCountry.equals(scr.getPkCountry())) {
|
||||
|
|
|
@ -1414,4 +1414,29 @@
|
|||
group by cmrr.province, cmrr.city, cmrr.county) cmrr
|
||||
</select>
|
||||
|
||||
<select id="queryRefundList" resultType="com.hzs.common.domain.third.pay.ext.TOnlineRefundExt">
|
||||
select cm.member_code,
|
||||
cm.member_name,
|
||||
top.business_type pay_business_type,
|
||||
top.business_code pay_business_code,
|
||||
tor.business_code,
|
||||
tor.refund_status,
|
||||
tor.refund_money,
|
||||
tor.finish_money,
|
||||
tor.creation_time,
|
||||
tor.finish_time,
|
||||
tor.refund_channel,
|
||||
tor.refund_code,
|
||||
tor.error_msg
|
||||
from T_ONLINE_REFUND tor
|
||||
inner join T_ONLINE_PAYMENT top
|
||||
on top.pk_id = tor.pk_online_payment
|
||||
left join cu_member cm
|
||||
on cm.pk_id = top.pk_creator
|
||||
where tor.del_flag = 0
|
||||
<if test="userId != null">
|
||||
and tor.PK_CREATOR = #{userId}
|
||||
</if>
|
||||
order by creation_time desc
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
@ -321,6 +321,11 @@ public class CacheConstants {
|
|||
*/
|
||||
public static final String RETAIL_TEMP_OTHER_PARAM = CACHE_PREFIX + "retail:temp_other:param:";
|
||||
|
||||
/**
|
||||
* 在线支付回调上锁
|
||||
*/
|
||||
public final static String ONLINE_PAY_KEY = CACHE_PREFIX + "online:payment:";
|
||||
|
||||
/**
|
||||
* 手机每天获取短信缓存 -- Hash(sms:count: 年月日, 登录名)
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,12 @@ public class SysConstants {
|
|||
*/
|
||||
public static final String PAY_PASSWORD = "222222";
|
||||
|
||||
/**
|
||||
* 特殊处理编号(对外开放使用,主要用于支付接入审核)
|
||||
*/
|
||||
public static final String SPECIAL_CODE = "BD68880628";
|
||||
|
||||
|
||||
/**
|
||||
* 开放使用会员编号(用于支付登录查看数据)
|
||||
*/
|
||||
|
|
|
@ -121,6 +121,15 @@ public enum EOrderType {
|
|||
resultList.add(EOrderType.REPURCHASE_ORDER);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
|
||||
public static String getLabelByValue(Integer value) {
|
||||
if (null == value) {
|
||||
return "";
|
||||
}
|
||||
for (EOrderType enums : EOrderType.values()) {
|
||||
if (enums.getValue() == value) {
|
||||
return enums.getLabel();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@ import lombok.Getter;
|
|||
@Getter
|
||||
public enum EPayChannel {
|
||||
|
||||
/**
|
||||
* 通联
|
||||
*/
|
||||
ALLIN(3, "通联", 0, EnumsPrefixConstants.PAY_CHANNEL + "3"),
|
||||
|
||||
/**
|
||||
* 京东
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,12 @@ public enum EPayType {
|
|||
* 银行卡
|
||||
*/
|
||||
BANK_CARD(3, "银行卡", 0, EnumsPrefixConstants.PAY_TYPE + "3"),
|
||||
// , 5=(京东)小金库, 6=(京东)白条, 7=(京东)超级白条, 8=(京东)钱包余额), 9=(京东)云闪付
|
||||
MINI_TREASURY(5, "小金库", 0, EnumsPrefixConstants.PAY_TYPE + "5"),
|
||||
CREDIT_LINE(6, "白条", 0, EnumsPrefixConstants.PAY_TYPE + "6"),
|
||||
SUPER_CREDIT_LINE(7, "超级白条", 0, EnumsPrefixConstants.PAY_TYPE + "7"),
|
||||
WALLET_BALANCE(8, "钱包余额", 0, EnumsPrefixConstants.PAY_TYPE + "8"),
|
||||
CLOUD_PAY(9, "云闪付", 0, EnumsPrefixConstants.PAY_TYPE + "9"),
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -15,9 +15,6 @@ import org.apache.ibatis.type.JdbcType;
|
|||
|
||||
/**
|
||||
* 在线支付信息
|
||||
*
|
||||
* @author hzs
|
||||
* @since 2022-07-28
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
|
@ -59,7 +56,7 @@ public class TOnlinePayment extends BaseEntity {
|
|||
private BigDecimal businessMoney;
|
||||
|
||||
/**
|
||||
* 支付渠道(5=宝付,6=汇付,8=新汇付)
|
||||
* 支付渠道(0=杉德,1=支付宝,2=微信,3=通联,4=京东,5=宝付,6=汇付)
|
||||
*/
|
||||
@TableField("PAY_CHANNEL")
|
||||
private Integer payChannel;
|
||||
|
@ -125,4 +122,21 @@ public class TOnlinePayment extends BaseEntity {
|
|||
@TableField("PAY_SOURCE")
|
||||
private Integer paySource;
|
||||
|
||||
/**
|
||||
* 主账户金额
|
||||
*/
|
||||
@TableField("MAIN_ACCOUNT_MONEY")
|
||||
private BigDecimal mainAccountMoney;
|
||||
|
||||
/**
|
||||
* 子账户金额
|
||||
*/
|
||||
@TableField("SUB_ACCOUNT_MONEY")
|
||||
private BigDecimal subAccountMoney;
|
||||
|
||||
/**
|
||||
* 支付-前端回调页面的扩展参数
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String extParam;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package com.hzs.common.domain.third.pay;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.hzs.common.core.web.domain.BaseEntity;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求主表
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("T_ONLINE_PAYMENT_SEP_ACC")
|
||||
@KeySequence("T_ONLINE_PAYMENT_SEP_ACC_SEQ")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TOnlinePaymentSepAcc extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("PK_ID")
|
||||
private Long pkId;
|
||||
|
||||
/**
|
||||
* 在线支付信息ID
|
||||
*/
|
||||
@TableField("PK_PAYMENT")
|
||||
private Long pkPayment;
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
@TableField("VERSION")
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 支付请求信息
|
||||
*/
|
||||
@TableField("REQ_CONTENT")
|
||||
private String reqContent;
|
||||
|
||||
/**
|
||||
* 分账请求信息
|
||||
*/
|
||||
@TableField("REQ_CONTENT_SEP_ACC")
|
||||
private String reqContentSepAcc;
|
||||
|
||||
/**
|
||||
* 支付响应信息
|
||||
*/
|
||||
@TableField("RESP_CONTENT")
|
||||
private String respContent;
|
||||
|
||||
@TableField("TRADE_AMOUNT")
|
||||
private BigDecimal tradeAmount;
|
||||
|
||||
@TableField("OUT_TRADE_NO")
|
||||
private String outTradeNo;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<TOnlinePaymentSepAccD> sepAccDList;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.hzs.common.domain.third.pay;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.hzs.common.core.web.domain.BaseEntity;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求子表(分账)
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("T_ONLINE_PAYMENT_SEP_ACC_D")
|
||||
@KeySequence("T_ONLINE_PAYMENT_SEP_ACC_D_SEQ")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TOnlinePaymentSepAccD extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("PK_ID")
|
||||
private Long pkId;
|
||||
|
||||
/**
|
||||
* 支付请求主表ID
|
||||
*/
|
||||
@TableField("PK_SEP_ACC")
|
||||
private Long pkSepAcc;
|
||||
|
||||
/**
|
||||
* 分账账号
|
||||
*/
|
||||
@TableField("ACCOUNT")
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* 分账比例
|
||||
*/
|
||||
@TableField("PROPORTION")
|
||||
private BigDecimal proportion;
|
||||
|
||||
@TableField("TRADE_AMOUNT")
|
||||
private BigDecimal tradeAmount;
|
||||
|
||||
@TableField("OUT_TRADE_NO")
|
||||
private String outTradeNo;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package com.hzs.common.domain.third.pay.ext;
|
||||
|
||||
import com.hzs.common.core.annotation.Transaction;
|
||||
import com.hzs.common.core.constant.EnumsPrefixConstants;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
@ -32,4 +34,8 @@ public class TOnlinePaymentExt extends TOnlinePayment {
|
|||
*/
|
||||
private String phone;
|
||||
|
||||
|
||||
private Integer orderType;
|
||||
private String orderTypeVal;
|
||||
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ public class PayRefundListener {
|
|||
switch (EPayChannel.getEnumByValue(tOnlinePayment.getPayChannel())) {
|
||||
case HUIFU:
|
||||
// 新汇付
|
||||
str = iRefundService.huifuRefundHandle(tOnlinePayment);
|
||||
// str = iRefundService.huifuRefundHandle(tOnlinePayment);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
package com.hzs.third.mqcall.listener;
|
||||
|
||||
import com.hzs.common.core.constant.RabbitMqConstants;
|
||||
import com.hzs.common.core.enums.ECallbackStatus;
|
||||
import com.hzs.common.core.enums.EPayBusinessType;
|
||||
import com.hzs.common.core.enums.EPayChannel;
|
||||
import com.hzs.common.core.enums.EPayStatus;
|
||||
import com.hzs.common.domain.sale.ext.SaOrderExt;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.sale.order.ISaOrderServiceApi;
|
||||
import com.hzs.third.mq.dto.RefundOrderDTO;
|
||||
import com.hzs.third.pay.dto.RefundDTO;
|
||||
import com.hzs.third.pay.service.IPayService;
|
||||
import com.hzs.third.pay.service.IRefundService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentService;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.amqp.rabbit.annotation.*;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.support.AmqpHeaders;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 订单退款处理监听
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RefundOrderListener {
|
||||
|
||||
@Autowired
|
||||
private ITOnlinePaymentService itOnlinePaymentService;
|
||||
@Autowired
|
||||
private IRefundService iRefundService;
|
||||
@Autowired
|
||||
private IPayService iPayService;
|
||||
|
||||
@Autowired
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
@DubboReference
|
||||
ISaOrderServiceApi iSaOrderServiceApi;
|
||||
|
||||
/**
|
||||
* 此监听只处理在线支付,支付成功,但是订单未成功的处理
|
||||
*
|
||||
* @param message
|
||||
* @param channel
|
||||
* @throws Exception
|
||||
*/
|
||||
@RabbitListener(bindings = @QueueBinding(
|
||||
exchange = @Exchange(value = RabbitMqConstants.REFUND_ORDER_EXCHANGE, type = "topic"),
|
||||
value = @Queue(value = RabbitMqConstants.REFUND_ORDER_QUEUE, durable = "true", autoDelete = "false"),
|
||||
key = RabbitMqConstants.REFUND_ORDER_KEY))
|
||||
@RabbitHandler
|
||||
public void onMessage(Message<RefundOrderDTO> message, Channel channel) throws Exception {
|
||||
// 手动应答
|
||||
Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
|
||||
channel.basicAck(deliveryTag, false);
|
||||
|
||||
RefundOrderDTO refundOrderDTO = message.getPayload();
|
||||
log.info("订单退款MQ处理. 参数:{}", refundOrderDTO);
|
||||
|
||||
// 防止MQ推送比实际更新数据库快,此处停1.5秒再处理
|
||||
Thread.sleep(1500);
|
||||
|
||||
// 重试次数
|
||||
int retryNum = null != refundOrderDTO.getRetryNum() ? refundOrderDTO.getRetryNum() : 0;
|
||||
if (retryNum > 2) {
|
||||
log.error("订单退款MQ处理. 订单退款已重试3次,仍未成功,不进行再次重试");
|
||||
return;
|
||||
}
|
||||
// 支付会员ID
|
||||
Long pkMember = refundOrderDTO.getPkMember();
|
||||
// 支付订单编号
|
||||
String orderCode = refundOrderDTO.getOrderCode();
|
||||
// 支付业务类型
|
||||
Integer payBusinessType = refundOrderDTO.getPayBusinessType();
|
||||
|
||||
// 业务类型(默认为直销订单)
|
||||
EPayBusinessType eBusinessType = EPayBusinessType.MEMBER_ORDER;
|
||||
if (null != payBusinessType) {
|
||||
// 传入支付业务类型不为空,则进行转换
|
||||
EPayBusinessType ePayBusinessType = EPayBusinessType.getEnumByValue(payBusinessType);
|
||||
if (null != ePayBusinessType) {
|
||||
eBusinessType = ePayBusinessType;
|
||||
}
|
||||
}
|
||||
|
||||
// 校验在线支付信息是否可以进行退款
|
||||
TOnlinePayment tOnlinePayment = itOnlinePaymentService.queryByBusiness(eBusinessType.getValue(), orderCode, null);
|
||||
if (null == tOnlinePayment) {
|
||||
// 在线支付信息不存在
|
||||
log.error("订单退款MQ处理. 在线支付信息不存在");
|
||||
return;
|
||||
}
|
||||
if (EPayStatus.PAID.getValue() == tOnlinePayment.getPayStatus()
|
||||
&& ECallbackStatus.FAIL.getValue() == tOnlinePayment.getCallbackStatus()) {
|
||||
// 已支付 并且 回调业务失败,可以进行退款
|
||||
|
||||
// 业务重试次数
|
||||
int businessRetryNum = null != refundOrderDTO.getBusinessRetryNum() ? refundOrderDTO.getBusinessRetryNum() : 0;
|
||||
if (businessRetryNum > 2) {
|
||||
log.error("订单退款MQ处理. 直销订单业务已重试3次,仍未成功,不进行再次重试。开始进行退款");
|
||||
|
||||
if (EPayBusinessType.MEMBER_ORDER.equals(eBusinessType)) {
|
||||
// 直销订单
|
||||
// 业务处理重试三次都失败,则进行退款流程,进行退款处理
|
||||
SaOrderExt saOrderExt = iSaOrderServiceApi.queryOrderByCode(orderCode, pkMember).getData();
|
||||
if (null == saOrderExt) {
|
||||
log.error("订单退款MQ处理. 直销订单不存在");
|
||||
return;
|
||||
}
|
||||
log.info("订单退款MQ处理,订单数据:{}", saOrderExt);
|
||||
if (null != saOrderExt.getOrderStatus() && EPayStatus.PAID.getValue() == saOrderExt.getOrderStatus()) {
|
||||
log.error("订单退款MQ处理. 直销订单已支付成功,不能进行退款");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 退款处理
|
||||
String str = this.handleRefund(tOnlinePayment, eBusinessType, orderCode, pkMember);
|
||||
if (null == str) {
|
||||
log.info("订单退款MQ处理. 申请三方支付退款成功");
|
||||
return;
|
||||
} else {
|
||||
log.error("订单退款MQ处理. 申请三方支付退款失败:{}", str);
|
||||
}
|
||||
|
||||
// 退款失败,重试次数+1,推送MQ
|
||||
refundOrderDTO.setRetryNum(++retryNum);
|
||||
rabbitTemplate.convertAndSend(RabbitMqConstants.REFUND_ORDER_EXCHANGE, RabbitMqConstants.REFUND_ORDER_KEY, refundOrderDTO);
|
||||
return;
|
||||
}
|
||||
|
||||
// 直销订单,缓冲5秒后,进行重试
|
||||
Thread.sleep(5000);
|
||||
|
||||
tOnlinePayment.setPkModified(SecurityUtils.getUserId());
|
||||
tOnlinePayment.setModifiedTime(new Date());
|
||||
// 业务处理重试
|
||||
if (iPayService.retryHandle(tOnlinePayment, false)) {
|
||||
// 业务处理重试成功,直接结束
|
||||
return;
|
||||
}
|
||||
|
||||
// 业务处理重试失败,次数+1,继续推送MQ
|
||||
refundOrderDTO.setBusinessRetryNum(++businessRetryNum);
|
||||
rabbitTemplate.convertAndSend(RabbitMqConstants.REFUND_ORDER_EXCHANGE, RabbitMqConstants.REFUND_ORDER_KEY, refundOrderDTO);
|
||||
return;
|
||||
}
|
||||
log.info("订单退款MQ处理. 订单未支付或业务已经处理成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理退款
|
||||
*
|
||||
* @param tOnlinePayment 支付信息
|
||||
* @param eBusinessType 支付业务类型
|
||||
* @param orderCode 订单编号
|
||||
* @param pkMember 会员ID
|
||||
* @return
|
||||
*/
|
||||
private String handleRefund(TOnlinePayment tOnlinePayment, EPayBusinessType eBusinessType, String orderCode, Long pkMember) {
|
||||
String str = null;
|
||||
|
||||
RefundDTO refundDTO = RefundDTO.builder()
|
||||
.businessType(eBusinessType.getValue())
|
||||
.businessCode(orderCode)
|
||||
.refundAmount(tOnlinePayment.getPayMoney())
|
||||
.userId(pkMember)
|
||||
.pkCountry(tOnlinePayment.getPkCountry())
|
||||
.build();
|
||||
|
||||
// 订单存在并且没有支付成功,代表着钱收到了,但是单没有下成,所以需要进行退款
|
||||
switch (EPayChannel.getEnumByValue(tOnlinePayment.getPayChannel())) {
|
||||
case JD:
|
||||
// 京东
|
||||
str = iRefundService.jdRefundDivision(tOnlinePayment.getBusinessCode(), tOnlinePayment.getPkCreator());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.hzs.third.pay.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "jd.bank") // 绑定jd.pay前缀的配置
|
||||
public class JdPayBankProperties {
|
||||
|
||||
private String merchantNo;
|
||||
private String signKey;
|
||||
private String priCertPwd;
|
||||
private String priCert;
|
||||
private String pubCert;
|
||||
private String apiDomain;
|
||||
private String pageBackUrl;
|
||||
private String notifyUrl;
|
||||
private String refundNotifyUrl;
|
||||
|
||||
private List<JdPaySeparateAccountConfig> separateAccounts;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.hzs.third.pay.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 京东支付配置
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "jdpay")
|
||||
public class JdPayConfig {
|
||||
|
||||
/**
|
||||
* 商户编号
|
||||
*/
|
||||
private String customerNum;
|
||||
|
||||
/**
|
||||
* 店铺编号
|
||||
*/
|
||||
private String shopNum;
|
||||
|
||||
/**
|
||||
* 公钥
|
||||
*/
|
||||
private String accessKey;
|
||||
|
||||
/**
|
||||
* 私钥
|
||||
*/
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 回调地址
|
||||
*/
|
||||
private String callbackUrl;
|
||||
|
||||
/**
|
||||
* 代付回调地址
|
||||
*/
|
||||
private String agentCallbackUrl;
|
||||
|
||||
/**
|
||||
* 退款回调地址
|
||||
*/
|
||||
private String refundCallbackUrl;
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.hzs.third.pay.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class JdPaySeparateAccountConfig implements Serializable {
|
||||
private String account;
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
private BigDecimal proportion;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.hzs.third.pay.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "jd.wechat-alipay") // 绑定jd.pay前缀的配置
|
||||
public class JdPayWechatAlipayProperties {
|
||||
|
||||
private String merchantNo;
|
||||
private String signKey;
|
||||
private String priCertPwd;
|
||||
private String priCert;
|
||||
private String pubCert;
|
||||
private String apiDomain;
|
||||
private String pageBackUrl;
|
||||
private String notifyUrl;
|
||||
private String refundNotifyUrl;
|
||||
|
||||
private List<JdPaySeparateAccountConfig> separateAccounts;
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package com.hzs.third.pay.constants;
|
||||
|
||||
/**
|
||||
* 京东支付常量类
|
||||
*/
|
||||
public class JdPayConstants {
|
||||
|
||||
/**
|
||||
* 终端标记(暂用京东注册手机号)
|
||||
*/
|
||||
public static final String TERMINAL_ID = "18246334501";
|
||||
/**
|
||||
* 用户注册账号(暂用京东注册手机号)
|
||||
*/
|
||||
public static final String USER_ACCOUNT = "18246334501";
|
||||
/**
|
||||
* 应用名称
|
||||
*/
|
||||
public static final String APP_NAME = "盛美源";
|
||||
|
||||
// TODO 上面3项考试动态化配置
|
||||
|
||||
/**
|
||||
* 订单状态 - 交易处理中
|
||||
*/
|
||||
public static final String ORDER_INT = "INT";
|
||||
/**
|
||||
* 订单状态 - 成功
|
||||
*/
|
||||
public static final String ORDER_SUCCESS = "SUCCESS";
|
||||
|
||||
/**
|
||||
* 查询状态 - 交易处理中
|
||||
*/
|
||||
public static final String QUERY_INIT = "INIT";
|
||||
/**
|
||||
* 查询状态 - 成功
|
||||
*/
|
||||
public static final String QUERY_SUCCESS = "SUCCESS";
|
||||
/**
|
||||
* 查询状态 - 失败
|
||||
*/
|
||||
public static final String QUERY_FAIL = "FAIL";
|
||||
|
||||
/**
|
||||
* 处理成功
|
||||
*/
|
||||
public static final String RESULT_SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* 处理成功业务响应码
|
||||
*/
|
||||
public static final String RESULT_SUCCESS_CODE = "C000000";
|
||||
|
||||
/**
|
||||
* 银行卡交易不支持错误编码
|
||||
*/
|
||||
public static final String RESULT_FAIL_CODE_6 = "C000006";
|
||||
|
||||
/**
|
||||
* 请求成功
|
||||
*/
|
||||
public static final String SUCCESS = "true";
|
||||
|
||||
/**
|
||||
* 返回成功
|
||||
*/
|
||||
public static final String RETURN_SUCCESS = "200";
|
||||
/**
|
||||
* 返回失败
|
||||
*/
|
||||
public static final String RETURN_FAIL = "500";
|
||||
|
||||
/**
|
||||
* 支付接口版本
|
||||
*/
|
||||
public static final String PAY_VERSION = "V4.0";
|
||||
|
||||
/**
|
||||
* 绑卡类型: 身份证
|
||||
*/
|
||||
public static final String ID_CARD_TYPE = "IDCARD";
|
||||
|
||||
/**
|
||||
* 快捷支付标准业务场景
|
||||
*/
|
||||
public static final String FAST_TRADESCENE_QUICKPAY = "QUICKPAY";
|
||||
|
||||
/**
|
||||
* 代付业务类型
|
||||
*/
|
||||
public static final String AGENT_BUSINESS_TYPE = "DEFY";
|
||||
|
||||
/**
|
||||
* 代付支付方式
|
||||
*/
|
||||
public static final String AGENT_BANK_TYPE = "DEFY";
|
||||
|
||||
/**
|
||||
* 支付地址
|
||||
*/
|
||||
public static final String PAY_URL = "https://openapi.duolabao.com";
|
||||
|
||||
/**
|
||||
* 扫码支付调用方法
|
||||
*/
|
||||
public static final String METHOD_SCAN = "/v3/order/payurl/create";
|
||||
|
||||
/**
|
||||
* 快捷支付绑卡方法
|
||||
*/
|
||||
public static final String METHOD_BIND_CARD = "/api/applyBindCard";
|
||||
|
||||
/**
|
||||
* 快捷支付绑卡确认方法
|
||||
*/
|
||||
public static final String METHOD_CONFIRM_BIND = "/api/confirmBindCard";
|
||||
|
||||
/**
|
||||
* 快捷支付解绑方法
|
||||
*/
|
||||
public static final String METHOD_UNBIND = "/api/unBindCard";
|
||||
|
||||
/**
|
||||
* 快捷支付预下单
|
||||
*/
|
||||
public static final String METHOD_PRE_ORDER = "/api/applyQuickPayWithCheck";
|
||||
|
||||
/**
|
||||
* 快捷支付确认订单
|
||||
*/
|
||||
public static final String METHOD_CONFIRM_ORDER = "/api/confirmQuickPay";
|
||||
|
||||
/**
|
||||
* 京东代付余额查询方法
|
||||
*/
|
||||
public static final String METHOD_QUERY_BALANCE = "/api/queryBalance";
|
||||
|
||||
/**
|
||||
* 京东代付调用方法
|
||||
*/
|
||||
public static final String METHOD_AGENT = "/api/payWithCheck";
|
||||
|
||||
/**
|
||||
* 京东查询订单路径
|
||||
*/
|
||||
public static final String QUERY_ORDER = "/v3/order/query";
|
||||
|
||||
/**
|
||||
* 京东退款路径
|
||||
*/
|
||||
public static final String REFUND_ORDER = "/v3/order/refund/part";
|
||||
|
||||
}
|
|
@ -5,13 +5,19 @@ package com.hzs.third.pay.constants;
|
|||
*/
|
||||
public class PayConfigConstants {
|
||||
|
||||
// 新汇付PC微信扫码支付
|
||||
// 京东收银台(H5)
|
||||
public static final String PAY_CONFIG_5 = "PAY:CONFIG:%s:5";
|
||||
// 京东收银台(PC)
|
||||
public static final String PAY_CONFIG_6 = "PAY:CONFIG:%s:6";
|
||||
|
||||
// 通联微信
|
||||
public static final String PAY_CONFIG_32 = "PAY:CONFIG:%s:32";
|
||||
// 通联银行卡
|
||||
public static final String PAY_CONFIG_33 = "PAY:CONFIG:%s:33";
|
||||
|
||||
// 新汇付PC微信扫码
|
||||
public static final String PAY_CONFIG_81 = "PAY:CONFIG:%s:81";
|
||||
// 新汇付PC支付宝扫码支付
|
||||
// 新汇付PC支付宝扫码
|
||||
public static final String PAY_CONFIG_82 = "PAY:CONFIG:%s:82";
|
||||
// 新汇付H5微信支付
|
||||
public static final String PAY_CONFIG_83 = "PAY:CONFIG:%s:83";
|
||||
// 新汇付H5支付宝支付
|
||||
public static final String PAY_CONFIG_84 = "PAY:CONFIG:%s:84";
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package com.hzs.third.pay.controller.api;
|
||||
|
||||
import com.hzs.common.core.enums.EPayChannel;
|
||||
import com.hzs.common.core.enums.EPayStatus;
|
||||
import com.hzs.common.core.utils.StringUtils;
|
||||
import com.hzs.common.core.web.domain.AjaxResult;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.third.pay.controller.base.PayBaseController;
|
||||
import com.hzs.third.pay.dto.RefundDTO;
|
||||
import com.hzs.third.pay.param.PayParam;
|
||||
import com.hzs.third.pay.service.IRefundService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @Description: 京东退款控制器
|
||||
* @Author: jiang chao
|
||||
* @Time: 2023/8/17 15:11
|
||||
* @Classname: JdRefundController
|
||||
* @PackageName: com.hzs.third.pay.controller.api
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/jd-refund")
|
||||
public class JdRefundController extends PayBaseController {
|
||||
|
||||
@Autowired
|
||||
private IRefundService iRefundService;
|
||||
@Autowired
|
||||
private ITOnlinePaymentService itOnlinePaymentService;
|
||||
|
||||
@GetMapping("/test/{orderCode}")
|
||||
public AjaxResult test(@PathVariable String orderCode) {
|
||||
iRefundService.jdRefundDivision(orderCode, SecurityUtils.getUserId());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@GetMapping("/test2")
|
||||
public AjaxResult test2() {
|
||||
iRefundService.jdQueryEnterpriseWalletBalance();
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 京东退款接口
|
||||
*
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/refund")
|
||||
public AjaxResult refund(@RequestBody PayParam param) {
|
||||
if (null == param.getBusinessType() || StringUtils.isEmpty(param.getBusinessCode())) {
|
||||
// 缺少参数
|
||||
return AjaxResult.error("缺少参数");
|
||||
}
|
||||
// 查询在线支付明细
|
||||
TOnlinePayment tOnlinePayment = itOnlinePaymentService.queryByBusiness(param.getBusinessType(), param.getBusinessCode(), SecurityUtils.getPkCountry());
|
||||
if (null == tOnlinePayment || EPayStatus.UNPAID.getValue() == tOnlinePayment.getPayStatus()) {
|
||||
// 在线支付明细为空 或者 未支付成功,则不能进行退款
|
||||
return AjaxResult.error("订单不存在或未支付成功,不能进行退款");
|
||||
}
|
||||
// 获取支付渠道
|
||||
EPayChannel ePayChannel = EPayChannel.getEnumByValue(tOnlinePayment.getPayChannel());
|
||||
if (null == ePayChannel) {
|
||||
return AjaxResult.error("订单支付信息有误,不能进行退款");
|
||||
}
|
||||
|
||||
try {
|
||||
// 京东收银台退款处理
|
||||
String str = iRefundService.jdCashRefundHandle(RefundDTO.builder()
|
||||
.businessType(param.getBusinessType())
|
||||
.businessCode(param.getBusinessCode())
|
||||
.refundAmount(tOnlinePayment.getPayMoney())
|
||||
.userId(SecurityUtils.getUserId())
|
||||
.pkCountry(SecurityUtils.getPkCountry())
|
||||
.build(),
|
||||
tOnlinePayment);
|
||||
// 京东银行卡退款处理 -- 旧
|
||||
// String str = iRefundService.jdRefundHandle(RefundDTO.builder()
|
||||
// .businessType(param.getBusinessType())
|
||||
// .businessCode(param.getBusinessCode())
|
||||
// .refundAmount(tOnlinePayment.getPayMoney())
|
||||
// .userId(SecurityUtils.getUserId())
|
||||
// .pkCountry(SecurityUtils.getPkCountry())
|
||||
// .build(),
|
||||
// tOnlinePayment);
|
||||
if (null == str) {
|
||||
return AjaxResult.success();
|
||||
}
|
||||
return AjaxResult.error("退款失败:" + str);
|
||||
} catch (Exception e) {
|
||||
log.error("调用京东退款处理返回异常!", e);
|
||||
return AjaxResult.error("退款异常,请刷新后重试");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package com.hzs.third.pay.controller.api;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.hzs.activity.base.IActivityServiceApi;
|
||||
import com.hzs.common.core.annotation.RepeatSubmitSimple;
|
||||
import com.hzs.common.core.constant.SysConstants;
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.hzs.common.core.enums.*;
|
||||
import com.hzs.common.core.utils.CommonUtil;
|
||||
import com.hzs.common.core.utils.StringUtils;
|
||||
import com.hzs.common.core.web.domain.AjaxResult;
|
||||
import com.hzs.common.domain.member.account.CuMemberRecharge;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
|
@ -13,9 +16,11 @@ import com.hzs.member.account.IMemberTradeServiceApi;
|
|||
import com.hzs.sale.order.ISaOrderServiceApi;
|
||||
import com.hzs.sale.ticket.ITicketServiceApi;
|
||||
import com.hzs.third.pay.constants.PayConfigConstants;
|
||||
import com.hzs.third.pay.param.StatusParam;
|
||||
import com.hzs.third.pay.param.PayParam;
|
||||
import com.hzs.third.pay.param.UnifiedOrderParam;
|
||||
import com.hzs.third.pay.service.*;
|
||||
import com.hzs.third.pay.service.IHuiFuPayService;
|
||||
import com.hzs.third.pay.service.IJdPayService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentService;
|
||||
import com.hzs.third.pay.util.PayUtil;
|
||||
import com.hzs.third.pay.vo.OnlinePayConfigVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -24,7 +29,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
|
@ -39,9 +43,9 @@ public class PayController {
|
|||
@Autowired
|
||||
private ITOnlinePaymentService itOnlinePaymentService;
|
||||
@Autowired
|
||||
private IHuiFuPayService iHuiFuPayService;
|
||||
@Autowired
|
||||
private IJdPayService iJdPayService;
|
||||
@Autowired
|
||||
private IHuiFuPayService iHuiFuPayService;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
@ -52,18 +56,24 @@ public class PayController {
|
|||
IMemberTradeServiceApi iMemberTradeServiceApi;
|
||||
@DubboReference
|
||||
ITicketServiceApi iTicketServiceApi;
|
||||
@DubboReference
|
||||
IActivityServiceApi iActivityServiceApi;
|
||||
|
||||
/**
|
||||
* 统一下单
|
||||
*
|
||||
* @param source 请求来源(EDataSource)
|
||||
* @param source 请求来源(EDataSource)
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
@RepeatSubmitSimple
|
||||
@PostMapping("/unifiedorder")
|
||||
public AjaxResult unifiedOrder(@RequestHeader("Source") String source,
|
||||
@Valid @RequestBody UnifiedOrderParam param) {
|
||||
@RequestBody UnifiedOrderParam param) {
|
||||
if (null == param.getBusinessType() || StringUtils.isEmpty(param.getBusinessCode())
|
||||
|| null == param.getPayChannel() || null == param.getPayType()) {
|
||||
return AjaxResult.error("缺少参数");
|
||||
}
|
||||
EPayBusinessType payBusinessType = EPayBusinessType.getEnumByValue(param.getBusinessType());
|
||||
if (null == payBusinessType) {
|
||||
return AjaxResult.error("业务类型不存在");
|
||||
|
@ -85,6 +95,8 @@ public class PayController {
|
|||
Long userId = SecurityUtils.getUserId();
|
||||
// 登录用户国家
|
||||
Integer pkCountry = SecurityUtils.getPkCountry();
|
||||
// 微信 openId(用于微信小程序支付)
|
||||
String openId = null;
|
||||
|
||||
// 1. 根据业务类型、业务单号进行校验。如果已经支付成功,直接返回;其它情况则继续执行
|
||||
TOnlinePayment onlinePayment = itOnlinePaymentService.queryByBusiness(payBusinessType.getValue(), param.getBusinessCode(), pkCountry);
|
||||
|
@ -116,9 +128,12 @@ public class PayController {
|
|||
onlinePayment.setOriginalOrder(onlinePayment.getBusinessCode());
|
||||
onlinePayment.setPaySource(dataSource.getValue());
|
||||
}
|
||||
onlinePayment.setExtParam(param.getExtParam());
|
||||
|
||||
// 业务金额
|
||||
BigDecimal businessMoney = null;
|
||||
// 实际支付金额(随机立减之后)
|
||||
BigDecimal amount = null;
|
||||
|
||||
// 部分业务金额随机立减
|
||||
switch (payBusinessType) {
|
||||
|
@ -151,17 +166,11 @@ public class PayController {
|
|||
break;
|
||||
default:
|
||||
}
|
||||
if (null == businessMoney) {
|
||||
return AjaxResult.error("当前支付金额有误");
|
||||
}
|
||||
if (businessMoney.compareTo(new BigDecimal("10000")) >= 0) {
|
||||
return AjaxResult.error("当前支付方式单笔金额不能超过10000元");
|
||||
}
|
||||
|
||||
// 更新业务金额
|
||||
onlinePayment.setBusinessMoney(businessMoney);
|
||||
// 暂存于实际支付金额(业务进行随机立减后的)
|
||||
onlinePayment.setPayMoney(PayUtil.handleAmountRandom(businessMoney));
|
||||
amount = PayUtil.handleAmountRandom(businessMoney);
|
||||
// 暂存于实际支付金额(部分业务进行随机立减)
|
||||
onlinePayment.setPayMoney(amount);
|
||||
|
||||
// 结果实体
|
||||
R payResult = null;
|
||||
|
@ -171,53 +180,14 @@ public class PayController {
|
|||
// 京东
|
||||
switch (payType) {
|
||||
case WECHAT:
|
||||
// 微信
|
||||
break;
|
||||
case ALIPAY:
|
||||
// 支付宝
|
||||
// 微信、支付宝 扫码支付
|
||||
// payResult = iJdPayService.scanPay(onlinePayment);
|
||||
payResult = iJdPayService.cashRegister(onlinePayment, dataSource);
|
||||
break;
|
||||
default:
|
||||
// 默认京东收银台
|
||||
payResult = iJdPayService.cashDeskPay(onlinePayment);
|
||||
}
|
||||
break;
|
||||
case HUIFU:
|
||||
// 新汇付
|
||||
switch (payType) {
|
||||
case WECHAT:
|
||||
// 微信
|
||||
switch (dataSource) {
|
||||
case H5:
|
||||
// H5浏览器使用微信小程序支付
|
||||
if (null != param.getAppletFlag() && EYesNo.YES.getIntValue() == param.getAppletFlag()) {
|
||||
// 小程序支付
|
||||
payResult = iHuiFuPayService.wechatPrePayUrl(onlinePayment, false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// PC以及默认按扫码支付
|
||||
// 非小程序支付(微信内置浏览器)
|
||||
payResult = iHuiFuPayService.wechatPrePayUrl(onlinePayment, true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ALIPAY:
|
||||
// 支付宝
|
||||
switch (dataSource) {
|
||||
case H5:
|
||||
case APP:
|
||||
// H5浏览器 或者 APP
|
||||
payResult = iHuiFuPayService.aliPrePayUrl(onlinePayment);
|
||||
default:
|
||||
// PC以及默认按扫码支付
|
||||
|
||||
}
|
||||
break;
|
||||
case BANK_CARD:
|
||||
// 银行卡
|
||||
|
||||
default:
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
|
@ -225,8 +195,8 @@ public class PayController {
|
|||
if (null != payResult) {
|
||||
if (payResult.isSuccess()) {
|
||||
// 实际支付金额在支付之前不需要入库,实际以取支付回调为准
|
||||
onlinePayment.setPayMoney(null);
|
||||
itOnlinePaymentService.saveOrUpdate(onlinePayment);
|
||||
// onlinePayment.setPayMoney(null);
|
||||
// itOnlinePaymentService.saveOrUpdate(onlinePayment);
|
||||
|
||||
return AjaxResult.success(payResult.getData());
|
||||
}
|
||||
|
@ -242,16 +212,23 @@ public class PayController {
|
|||
* @return
|
||||
*/
|
||||
@GetMapping("/status")
|
||||
public AjaxResult status(@Valid StatusParam param) {
|
||||
// 业务类型(校验业务类型)
|
||||
EPayBusinessType ePayBusinessType = EPayBusinessType.getEnumByValue(param.getBusinessType());
|
||||
if (null == ePayBusinessType) {
|
||||
return AjaxResult.success("支付业务类型错误", 0);
|
||||
public AjaxResult status(PayParam param) {
|
||||
// if (null == param.getBusinessType() || StringUtils.isEmpty(param.getBusinessCode())) {
|
||||
// return AjaxResult.success("缺少参数");
|
||||
// }
|
||||
if (StringUtils.isEmpty(param.getBusinessCode())) {
|
||||
return AjaxResult.success("缺少参数");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<TOnlinePayment> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessType, param.getBusinessType());
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessCode, param.getBusinessCode());
|
||||
// 业务类型(校验业务类型)
|
||||
// EPayBusinessType ePayBusinessType = EPayBusinessType.getEnumByValue(param.getBusinessType());
|
||||
// if (null == ePayBusinessType) {
|
||||
// return AjaxResult.success("支付业务类型错误", 0);
|
||||
// }
|
||||
|
||||
QueryWrapper<TOnlinePayment> queryWrapper = new QueryWrapper<>();
|
||||
// queryWrapper.eq("BUSINESS_TYPE", param.getBusinessType());
|
||||
queryWrapper.eq("BUSINESS_CODE", param.getBusinessCode());
|
||||
TOnlinePayment onlinePayment = itOnlinePaymentService.getOne(queryWrapper);
|
||||
if (null == onlinePayment) {
|
||||
return AjaxResult.success("支付信息不存在", 0);
|
||||
|
@ -277,6 +254,28 @@ public class PayController {
|
|||
|
||||
// 各支付方式: true=显示,false=隐藏
|
||||
|
||||
// 京东收银台(H5)
|
||||
String pay5 = String.format(PayConfigConstants.PAY_CONFIG_5, pkCountry);
|
||||
if (redisTemplate.hasKey(pay5)) {
|
||||
payConfigVO.setPay5((Boolean) redisTemplate.opsForValue().get(pay5));
|
||||
}
|
||||
// 京东收银台(PC)
|
||||
String pay6 = String.format(PayConfigConstants.PAY_CONFIG_6, pkCountry);
|
||||
if (redisTemplate.hasKey(pay6)) {
|
||||
payConfigVO.setPay6((Boolean) redisTemplate.opsForValue().get(pay6));
|
||||
}
|
||||
|
||||
// 通联微信
|
||||
String pay32 = String.format(PayConfigConstants.PAY_CONFIG_32, pkCountry);
|
||||
if (redisTemplate.hasKey(pay32)) {
|
||||
payConfigVO.setPay32((Boolean) redisTemplate.opsForValue().get(pay32));
|
||||
}
|
||||
// 通联银行卡
|
||||
String pay33 = String.format(PayConfigConstants.PAY_CONFIG_33, pkCountry);
|
||||
if (redisTemplate.hasKey(pay33)) {
|
||||
payConfigVO.setPay33((Boolean) redisTemplate.opsForValue().get(pay33));
|
||||
}
|
||||
|
||||
// 新汇付PC微信扫码支付
|
||||
String pay81 = String.format(PayConfigConstants.PAY_CONFIG_81, pkCountry);
|
||||
if (redisTemplate.hasKey(pay81)) {
|
||||
|
@ -287,16 +286,12 @@ public class PayController {
|
|||
if (redisTemplate.hasKey(pay82)) {
|
||||
payConfigVO.setPay82((Boolean) redisTemplate.opsForValue().get(pay82));
|
||||
}
|
||||
// 新汇付H5微信支付
|
||||
String pay83 = String.format(PayConfigConstants.PAY_CONFIG_83, pkCountry);
|
||||
if (redisTemplate.hasKey(pay83)) {
|
||||
payConfigVO.setPay83((Boolean) redisTemplate.opsForValue().get(pay83));
|
||||
}
|
||||
// 新汇付H5支付宝支付
|
||||
String pay84 = String.format(PayConfigConstants.PAY_CONFIG_84, pkCountry);
|
||||
if (redisTemplate.hasKey(pay84)) {
|
||||
payConfigVO.setPay84((Boolean) redisTemplate.opsForValue().get(pay84));
|
||||
|
||||
if (SysConstants.SPECIAL_CODE.equals(SecurityUtils.getMemberCode())) {
|
||||
// 在线支付测试账号,强制显示支付方式
|
||||
payConfigVO.setPay5(true);
|
||||
}
|
||||
|
||||
return AjaxResult.success(payConfigVO);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package com.hzs.third.pay.controller.base;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* @Description: 京东基础控制器
|
||||
* @Author: jiang chao
|
||||
* @Time: 2022/12/27 17:47
|
||||
* @Classname: JdBaseController
|
||||
* @PackageName: com.hzs.third.pay.controller.base
|
||||
*/
|
||||
public class JdBaseController {
|
||||
|
||||
/**
|
||||
* 获取请求体
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected String getRequestBody(HttpServletRequest request) throws IOException {
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(request.getInputStream()));
|
||||
String line;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
return sb.toString();
|
||||
} finally {
|
||||
if (null != br) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
*
|
||||
* @param request
|
||||
* @param reqBody
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkToken(HttpServletRequest request, String reqBody, String secretKey) {
|
||||
// SHA1 加密串
|
||||
String shaStr = "secretKey=" + secretKey +
|
||||
"×tamp=" + request.getHeader("timestamp") +
|
||||
"&body=" + reqBody;
|
||||
String tokenCheck = SecureUtil.sha1(shaStr).toUpperCase();
|
||||
return tokenCheck.equals(request.getHeader("token"));
|
||||
}
|
||||
|
||||
}
|
|
@ -52,15 +52,15 @@ public class OnlinePayConfigController {
|
|||
payConfigVO.setPay82((Boolean) redisTemplate.opsForValue().get(pay82));
|
||||
}
|
||||
// 新汇付H5微信支付
|
||||
String pay83 = String.format(PayConfigConstants.PAY_CONFIG_83, pkCountry);
|
||||
if (redisTemplate.hasKey(pay83)) {
|
||||
payConfigVO.setPay83((Boolean) redisTemplate.opsForValue().get(pay83));
|
||||
}
|
||||
// 新汇付H5支付宝支付
|
||||
String pay84 = String.format(PayConfigConstants.PAY_CONFIG_84, pkCountry);
|
||||
if (redisTemplate.hasKey(pay84)) {
|
||||
payConfigVO.setPay84((Boolean) redisTemplate.opsForValue().get(pay84));
|
||||
}
|
||||
// String pay83 = String.format(PayConfigConstants.PAY_CONFIG_83, pkCountry);
|
||||
// if (redisTemplate.hasKey(pay83)) {
|
||||
// payConfigVO.setPay83((Boolean) redisTemplate.opsForValue().get(pay83));
|
||||
// }
|
||||
// // 新汇付H5支付宝支付
|
||||
// String pay84 = String.format(PayConfigConstants.PAY_CONFIG_84, pkCountry);
|
||||
// if (redisTemplate.hasKey(pay84)) {
|
||||
// payConfigVO.setPay84((Boolean) redisTemplate.opsForValue().get(pay84));
|
||||
// }
|
||||
|
||||
return AjaxResult.success(payConfigVO);
|
||||
}
|
||||
|
@ -76,10 +76,16 @@ public class OnlinePayConfigController {
|
|||
public AjaxResult saveConfig(@RequestBody OnlinePayConfigParam param) {
|
||||
Integer pkCountry = SecurityUtils.getPkCountry();
|
||||
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_5, pkCountry), param.getPay5());
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_6, pkCountry), param.getPay6());
|
||||
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_32, pkCountry), param.getPay32());
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_33, pkCountry), param.getPay33());
|
||||
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_81, pkCountry), param.getPay81());
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_82, pkCountry), param.getPay82());
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_83, pkCountry), param.getPay83());
|
||||
redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_84, pkCountry), param.getPay84());
|
||||
// redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_83, pkCountry), param.getPay83());
|
||||
// redisTemplate.opsForValue().set(String.format(PayConfigConstants.PAY_CONFIG_84, pkCountry), param.getPay84());
|
||||
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
|
|
@ -102,27 +102,27 @@ public class OnlineRefundController extends BaseController {
|
|||
* @param pkId 退款ID
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/query-status")
|
||||
public AjaxResult queryStatus(@RequestParam Long pkId) {
|
||||
TOnlineRefund tOnlineRefund = itOnlineRefundService.getById(pkId);
|
||||
if (ERefundStatus.REFUNDED.getValue() == tOnlineRefund.getRefundStatus()) {
|
||||
// 已经退款成功
|
||||
return AjaxResult.error("当前数据已退款");
|
||||
}
|
||||
|
||||
String str;
|
||||
|
||||
if (EPayChannel.HUIFU.getValue() == tOnlineRefund.getRefundChannel()) {
|
||||
// 新汇付退款
|
||||
str = iRefundService.queryHuifuRefundHandle(tOnlineRefund);
|
||||
} else {
|
||||
return AjaxResult.error("暂不支持该数据查询");
|
||||
}
|
||||
|
||||
if (null == str) {
|
||||
return AjaxResult.success();
|
||||
}
|
||||
return AjaxResult.error(str);
|
||||
}
|
||||
// @GetMapping("/query-status")
|
||||
// public AjaxResult queryStatus(@RequestParam Long pkId) {
|
||||
// TOnlineRefund tOnlineRefund = itOnlineRefundService.getById(pkId);
|
||||
// if (ERefundStatus.REFUNDED.getValue() == tOnlineRefund.getRefundStatus()) {
|
||||
// // 已经退款成功
|
||||
// return AjaxResult.error("当前数据已退款");
|
||||
// }
|
||||
//
|
||||
// String str;
|
||||
//
|
||||
// if (EPayChannel.HUIFU.getValue() == tOnlineRefund.getRefundChannel()) {
|
||||
// // 新汇付退款
|
||||
// str = iRefundService.queryHuifuRefundHandle(tOnlineRefund);
|
||||
// } else {
|
||||
// return AjaxResult.error("暂不支持该数据查询");
|
||||
// }
|
||||
//
|
||||
// if (null == str) {
|
||||
// return AjaxResult.success();
|
||||
// }
|
||||
// return AjaxResult.error(str);
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
package com.hzs.third.pay.controller.notify;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.hzs.common.core.enums.EPayChannel;
|
||||
import com.hzs.common.core.enums.EPayType;
|
||||
import com.hzs.common.core.utils.DateUtils;
|
||||
import com.hzs.third.pay.config.JdPayConfig;
|
||||
import com.hzs.third.pay.constants.JdPayConstants;
|
||||
import com.hzs.third.pay.controller.base.JdBaseController;
|
||||
import com.hzs.third.pay.dto.jd.JdPayNotifyBody;
|
||||
import com.hzs.third.pay.jdpay.dto.JdPayTradeSuccessNotify;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPay;
|
||||
import com.hzs.third.pay.jdpay.util.GsonUtil;
|
||||
import com.hzs.third.pay.service.IPayService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 京东支付回调控制器
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/jd")
|
||||
public class JdPayNotifyController extends JdBaseController {
|
||||
|
||||
@Autowired
|
||||
private JdPayConfig jdPayConfig;
|
||||
@Autowired
|
||||
private IPayService iPayService;
|
||||
|
||||
/**
|
||||
* 京东支付回调
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
@PostMapping("/notify")
|
||||
public String notify(HttpServletRequest request) {
|
||||
try {
|
||||
String reqBody = this.getRequestBody(request);
|
||||
log.info("京东支付回调! body: {}", reqBody);
|
||||
|
||||
if (this.checkToken(request, reqBody, jdPayConfig.getSecretKey())) {
|
||||
// 签名校验通过
|
||||
JdPayNotifyBody notifyBody = JSONUtil.toBean(reqBody, JdPayNotifyBody.class);
|
||||
|
||||
// 支付流水号
|
||||
String payNumber = notifyBody.getOrderNum();
|
||||
// 支付时间
|
||||
Date payTime = DateUtils.parseDate(notifyBody.getCompleteTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
|
||||
// 支付金额
|
||||
BigDecimal payMoney = new BigDecimal(notifyBody.getOrderAmount());
|
||||
|
||||
// 支付扩展类型
|
||||
String type = notifyBody.getExtraInfo();
|
||||
|
||||
// 回调订单编号
|
||||
String thirdOrderCode = notifyBody.getRequestNum();
|
||||
// 支付信息编号
|
||||
String orderCode = thirdOrderCode;
|
||||
// 处理订单号以及扩展类型
|
||||
if (orderCode.indexOf("-") > 0) {
|
||||
// 带有分隔,需要处理
|
||||
orderCode = orderCode.split("-")[0];
|
||||
}
|
||||
|
||||
// 支付后续业务处理
|
||||
if (iPayService.notifyHandle(type, orderCode, thirdOrderCode, payNumber, payTime, payMoney, EPayChannel.JD, "")) {
|
||||
return JdPayConstants.RETURN_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
log.error("京东支付回调签名校验失败!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("京东支付回调处理异常", e);
|
||||
}
|
||||
return JdPayConstants.RETURN_FAIL;
|
||||
}
|
||||
|
||||
|
||||
@Resource(name = "jdPayBank")
|
||||
private JdPay jdPay;
|
||||
|
||||
/**
|
||||
* 京东收银台处理成功返回
|
||||
*/
|
||||
private static final String SUCCESS = "SUCCESS";
|
||||
/**
|
||||
* 京东收银台处理失败返回
|
||||
*/
|
||||
private static final String ERROR = "ERROR";
|
||||
|
||||
/**
|
||||
* 京东收银台异步支付回调
|
||||
*
|
||||
* @param reqText
|
||||
* @return 成功返回"SUCCESS", 失败返回"ERROR",京东支付会再次发起通知,通知频次见接口文档。
|
||||
*/
|
||||
@PostMapping("/trade-notify")
|
||||
public String tradeNotify(@RequestBody String reqText) {
|
||||
log.info("京东收银台支付异步回调! reqText: {}", reqText);
|
||||
try {
|
||||
// 验证签名与解密
|
||||
String interData = jdPay.verifyResponse(reqText);
|
||||
JdPayTradeSuccessNotify successNotify = GsonUtil.fromJson(interData, JdPayTradeSuccessNotify.class);
|
||||
if (null != successNotify) {
|
||||
if ("FINI".equals(successNotify.getTradeStatus())) {
|
||||
// 支付成功处理
|
||||
|
||||
// 商户订单号
|
||||
String payNumber = successNotify.getTradeNo();
|
||||
// 渠道流水号
|
||||
String channelNumber = "";
|
||||
// 支付完成时间
|
||||
Date payTime = DateUtils.parseDateOne(successNotify.getFinishDate(), DateUtils.YAMMERERS);
|
||||
// 支付扩展类型
|
||||
String type = successNotify.getReturnParams();
|
||||
|
||||
// 回调订单编号
|
||||
String thirdOrderCode = successNotify.getOutTradeNo();
|
||||
// 订单编号
|
||||
String orderCode = thirdOrderCode;
|
||||
String acqOrderId = successNotify.getAcqOrderId();
|
||||
|
||||
// 订单金额
|
||||
int tradeAmount = Integer.parseInt(successNotify.getTradeAmount());
|
||||
BigDecimal payMoney = new BigDecimal(tradeAmount).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
|
||||
Integer payType = convertPayType(successNotify.getPayTool());
|
||||
// 支付后续业务处理
|
||||
if (iPayService.notifyHandle(type, orderCode, thirdOrderCode, payNumber, payTime, payMoney, EPayChannel.JD, channelNumber, payType, acqOrderId)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
} else {
|
||||
log.error("京东收银台支付异步回调失败,resultDesc: {}", successNotify.getResultDesc());
|
||||
}
|
||||
} else {
|
||||
log.error("京东收银台支付异步回调解密为空");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("京东收银台支付异步回调异常", e);
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
private Integer convertPayType(String payName){
|
||||
Integer result = EPayType.WECHAT.getValue();
|
||||
switch (payName){
|
||||
case "XJK":
|
||||
result = EPayType.MINI_TREASURY.getValue();
|
||||
break;
|
||||
case "JIOU":
|
||||
result = EPayType.CREDIT_LINE.getValue();
|
||||
break;
|
||||
case "SJIOU":
|
||||
result = EPayType.SUPER_CREDIT_LINE.getValue();
|
||||
break;
|
||||
case "ACCT":
|
||||
result = EPayType.WALLET_BALANCE.getValue();
|
||||
break;
|
||||
case "EXPR":
|
||||
result = EPayType.BANK_CARD.getValue();
|
||||
break;
|
||||
case "WX":
|
||||
result = EPayType.WECHAT.getValue();
|
||||
break;
|
||||
case "ALIPAY":
|
||||
result = EPayType.ALIPAY.getValue();
|
||||
break;
|
||||
case "YSF":
|
||||
result = EPayType.CLOUD_PAY.getValue();
|
||||
break;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 京东收银台页面回调
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/sync-notify")
|
||||
public String syncNotify(HttpServletRequest request) {
|
||||
// 签名验证逻辑,需要支持添加通知字段不影响结果
|
||||
Map<String, String> respMap = getAllRequestParam(request);
|
||||
log.info("京东收银台支付页面回调! request: {}", respMap);
|
||||
|
||||
try {
|
||||
if (jdPay.verifyPageCallBack(respMap)) {
|
||||
if ("FINI".equals(respMap.get("status"))) {
|
||||
// todo 支付成功
|
||||
|
||||
return SUCCESS;
|
||||
} else if ("WPAR".equals(respMap.get("status"))) {
|
||||
// todo 支付处理中
|
||||
log.error("京东支付页面回调,支付处理中");
|
||||
} else {
|
||||
// todo 支付失败
|
||||
log.error("京东支付页面回调,支付失败");
|
||||
}
|
||||
} else {
|
||||
// 签名异常,报错
|
||||
log.error("京东收银台支付页面回调!签名异常!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("京东支付页面回调参数", e);
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端请求参数中所有的信息
|
||||
*/
|
||||
private Map<String, String> getAllRequestParam(final HttpServletRequest request) {
|
||||
Map<String, String> respMap = new HashMap<>();
|
||||
Enumeration<?> temp = request.getParameterNames();
|
||||
if (null != temp) {
|
||||
while (temp.hasMoreElements()) {
|
||||
String en = (String) temp.nextElement();
|
||||
String value = request.getParameter(en);
|
||||
respMap.put(en, value);
|
||||
//如果字段的值为空,判断若值为空,则删除这个字段>
|
||||
if (null == respMap.get(en) || "".equals(respMap.get(en))) {
|
||||
respMap.remove(en);
|
||||
}
|
||||
}
|
||||
}
|
||||
return respMap;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package com.hzs.third.pay.controller.notify;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.hzs.common.core.enums.EPayChannel;
|
||||
import com.hzs.common.core.utils.DateUtils;
|
||||
import com.hzs.third.pay.config.JdPayConfig;
|
||||
import com.hzs.third.pay.constants.JdPayConstants;
|
||||
import com.hzs.third.pay.controller.base.JdBaseController;
|
||||
import com.hzs.third.pay.jdpay.dto.JdPayRefundSuccessNotify;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPay;
|
||||
import com.hzs.third.pay.jdpay.util.GsonUtil;
|
||||
import com.hzs.third.pay.service.IRefundService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description: 京东退填回调控制器
|
||||
* @Author: jiang chao
|
||||
* @Time: 2023/8/17 15:50
|
||||
* @Classname: JdRefundNotifyController
|
||||
* @PackageName: com.hzs.third.pay.controller.notify
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/jd-refund")
|
||||
public class JdRefundNotifyController extends JdBaseController {
|
||||
|
||||
@Autowired
|
||||
private JdPayConfig jdPayConfig;
|
||||
@Autowired
|
||||
private IRefundService iRefundService;
|
||||
|
||||
/**
|
||||
* 京东退款回调
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/notify")
|
||||
public String refundNotify(HttpServletRequest request) {
|
||||
try {
|
||||
String reqBody = this.getRequestBody(request);
|
||||
log.info("京东退款回调! body: {}", reqBody);
|
||||
|
||||
if (this.checkToken(request, reqBody, jdPayConfig.getSecretKey())) {
|
||||
// 签名校验通过
|
||||
Map<String, String> dataMap = JSONUtil.toBean(reqBody, HashMap.class);
|
||||
|
||||
// 退款编号
|
||||
String refundCode = dataMap.get("refundRequestNum");
|
||||
// 京东交易流水号
|
||||
String refundNumber = dataMap.get("orderNum");
|
||||
// 退款完成时间
|
||||
Date finishTime = DateUtils.parseDate(dataMap.get("refundSuccessTime"), DateUtils.YYYY_MM_DD_HH_MM_SS);
|
||||
// 退款金额
|
||||
BigDecimal finishMoney = new BigDecimal(dataMap.get("refundAmount"));
|
||||
|
||||
if (JdPayConstants.ORDER_SUCCESS.equals(dataMap.get("refundStatus"))) {
|
||||
// 退款成功
|
||||
// 退款后续业务处理
|
||||
if (iRefundService.notifyHandle(EPayChannel.JD, refundCode, refundNumber, finishTime, finishMoney)) {
|
||||
return JdPayConstants.RETURN_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
// 退款失败
|
||||
log.error("京东退款失败: {}", dataMap.get("failReason"));
|
||||
|
||||
if (iRefundService.notifyErrorHandle(EPayChannel.JD, refundCode, refundNumber, dataMap.get("failReason"))) {
|
||||
return JdPayConstants.RETURN_SUCCESS;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("京东支付回调签名校验失败!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("京东支付回调处理异常", e);
|
||||
}
|
||||
return JdPayConstants.RETURN_FAIL;
|
||||
}
|
||||
|
||||
|
||||
@Resource(name = "jdPayBank")
|
||||
private JdPay jdPay;
|
||||
|
||||
/**
|
||||
* 京东收银台处理成功返回
|
||||
*/
|
||||
private static final String SUCCESS = "SUCCESS";
|
||||
/**
|
||||
* 京东收银台处理失败返回
|
||||
*/
|
||||
private static final String ERROR = "ERROR";
|
||||
|
||||
/**
|
||||
* 京东收银台退款异步支付回调
|
||||
*
|
||||
* @param reqText
|
||||
* @return 成功返回"SUCCESS", 失败返回"ERROR",退款通知会再次发起通知,通知频次见接口文档。
|
||||
*/
|
||||
@PostMapping("/trade-notify")
|
||||
public String tradeNotify(@RequestBody String reqText) {
|
||||
log.info("京东收银台退款异步回调! reqText: {}", reqText);
|
||||
try {
|
||||
// 验证签名与解密
|
||||
String interData = jdPay.verifyResponse(reqText);
|
||||
JdPayRefundSuccessNotify successNotify = GsonUtil.fromJson(interData, JdPayRefundSuccessNotify.class);
|
||||
if (null != successNotify) {
|
||||
if ("FINI".equals(successNotify.getTradeStatus())) {
|
||||
|
||||
// 退款编号
|
||||
String refundCode = successNotify.getOutTradeNo();
|
||||
// 京东交易流水号
|
||||
String refundNumber = successNotify.getTradeNo();
|
||||
// 退款完成时间
|
||||
Date finishTime = DateUtils.parseDate(successNotify.getFinishDate(), DateUtils.YAMMERERS);
|
||||
// 退款金额
|
||||
int tradeAmount = Integer.parseInt(successNotify.getTradeAmount());
|
||||
BigDecimal finishMoney = new BigDecimal(tradeAmount).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
|
||||
|
||||
// 退款后续业务处理
|
||||
if (iRefundService.notifyHandle(EPayChannel.JD, refundCode, refundNumber, finishTime, finishMoney)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
} else {
|
||||
log.error("京东收银台退款异步回调失败,resultDesc: {}", successNotify.getResultDesc());
|
||||
}
|
||||
} else {
|
||||
log.error("京东收银台退款异步回调解密为空");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("京东收银台退款异步回调异常", e);
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.hzs.third.pay.dto.jd;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 京东支付回调body体
|
||||
*/
|
||||
@Data
|
||||
public class JdPayNotifyBody {
|
||||
|
||||
/**
|
||||
* 处理状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 商户订单编号
|
||||
*/
|
||||
private String requestNum;
|
||||
/**
|
||||
* 订单金额(元)
|
||||
*/
|
||||
private String orderAmount;
|
||||
/**
|
||||
* 订单完成时间
|
||||
*/
|
||||
private String completeTime;
|
||||
/**
|
||||
* 支付类型(支付宝、微信等)
|
||||
*/
|
||||
private String payWay;
|
||||
/**
|
||||
* 扩展内容
|
||||
*/
|
||||
private String extraInfo;
|
||||
|
||||
/**
|
||||
* 订单编号(京东系统订单号)
|
||||
*/
|
||||
private String orderNum;
|
||||
|
||||
/**
|
||||
* 银行订单号(银行流水号)
|
||||
*/
|
||||
private String bankOutTradeNum;
|
||||
/**
|
||||
* 银行流水号(渠道订单流水号)
|
||||
*/
|
||||
private String bankRequestNum;
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
*/
|
||||
private String orderType;
|
||||
/**
|
||||
* 订单子类型
|
||||
*/
|
||||
private String subOrderType;
|
||||
/**
|
||||
* 订单失败原因
|
||||
*/
|
||||
private String failReason;
|
||||
/**
|
||||
* 订单失败编码
|
||||
*/
|
||||
private String faiCode;
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.hzs.third.pay.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 京东应用类型
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum EJdAppType {
|
||||
|
||||
IOS("IOS", "IOS"),
|
||||
|
||||
AND("AND", "AND"),
|
||||
|
||||
H5("H5", "H5"),
|
||||
|
||||
WX("WX", "WX"),
|
||||
|
||||
OTHER("OTHER", "OTHER"),
|
||||
|
||||
;
|
||||
|
||||
private final String value;
|
||||
private final String label;
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.hzs.third.pay.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 京东快捷支付银行
|
||||
*/
|
||||
@Getter
|
||||
public enum EJdFastBankCode {
|
||||
|
||||
ICBC("ICBC", "工商银行"),
|
||||
BOC("BOC", "中国银行"),
|
||||
CCB("CCB", "建设银行"),
|
||||
CMBCHINA("CMBCHINA", "招商银行"),
|
||||
POST("POST", "邮政储蓄银行"),
|
||||
ECITIC("ECITIC", "中信银行"),
|
||||
CEB("CEB", "光大银行"),
|
||||
BOCO("BOCO", "交通银行"),
|
||||
CIB("CIB", "兴业银行"),
|
||||
CMBC("CMBC", "民生银行"),
|
||||
SZCB("SZCB", "平安银行"),
|
||||
CGB("CGB", "广发银行"),
|
||||
BCCB("BCCB", "北京银行"),
|
||||
HXB("HXB", "华夏银行"),
|
||||
SPDB("SPDB", "浦发银行"),
|
||||
SHB("SHB", "上海银行"),
|
||||
;
|
||||
|
||||
private final String value;
|
||||
private final String label;
|
||||
|
||||
EJdFastBankCode(String value, String label) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据value获取label
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static EJdFastBankCode getEnumByValue(String value) {
|
||||
for (EJdFastBankCode eJdFastBankCode : EJdFastBankCode.values()) {
|
||||
if (eJdFastBankCode.getValue().equals(value)) {
|
||||
return eJdFastBankCode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.hzs.third.pay.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 京东终端类型
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum EJdTerminalType {
|
||||
|
||||
IMEI("IMEI", "IMEI"),
|
||||
|
||||
MAC("MAC", "MAC"),
|
||||
|
||||
// 针对IOS系统
|
||||
UUID("UUID", "UUID"),
|
||||
|
||||
OTHER("OTHER", "OTHER"),
|
||||
|
||||
;
|
||||
|
||||
private final String value;
|
||||
private final String label;
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.hzs.third.pay.jdpay.config;
|
||||
|
||||
import com.hzs.third.pay.config.JdPayBankProperties;
|
||||
import com.hzs.third.pay.config.JdPayWechatAlipayProperties;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPay;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPayDefaultNewConfig;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPayNewConfig;
|
||||
import com.hzs.third.pay.jdpay.util.FileUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* 京东支付sdk初始化
|
||||
*
|
||||
*************************************************/
|
||||
@Configuration
|
||||
public class JdPayAutoConfiguration {
|
||||
@Autowired
|
||||
private JdPayBankProperties jdPayBankProperties;
|
||||
@Autowired
|
||||
private JdPayWechatAlipayProperties jdPayWechatAlipayProperties;
|
||||
|
||||
|
||||
|
||||
@Bean(name = "jdPayBank")
|
||||
public JdPay initJdBankPay() {
|
||||
// 加载商户私钥证书
|
||||
// byte[] privateCert = FileUtil.readFile(priCert);
|
||||
byte[] privateCert = FileUtil.readFile(jdPayBankProperties.getPriCert());
|
||||
// 加载商户公钥证书
|
||||
// byte[] publicCert = FileUtil.readFile(pubCert);
|
||||
byte[] publicCert = FileUtil.readFile(jdPayBankProperties.getPubCert());
|
||||
// 检查商户证书
|
||||
checkCert(privateCert, publicCert);
|
||||
// 初始化京东支付配置对象
|
||||
// JdPayNewConfig myConfig = new JdPayDefaultNewConfig(merchantNo, signKey, privateCert, priCertPwd, publicCert, apiDomain);
|
||||
JdPayNewConfig myConfig = new JdPayDefaultNewConfig(jdPayBankProperties.getMerchantNo()
|
||||
, jdPayBankProperties.getSignKey()
|
||||
, privateCert
|
||||
, jdPayBankProperties.getPriCertPwd()
|
||||
, publicCert
|
||||
, jdPayBankProperties.getApiDomain());
|
||||
return new JdPay(myConfig);
|
||||
}
|
||||
|
||||
private void checkCert(byte[] privateCert, byte[] publicCert) {
|
||||
if (privateCert == null) {
|
||||
throw new RuntimeException("读取京东支付商户私钥证书为空");
|
||||
}
|
||||
if (publicCert == null) {
|
||||
throw new RuntimeException("读取京东支付商户公钥证书为空");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 京东聚合下单请求
|
||||
*/
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayAggregateCreateOrderRequest implements Serializable {
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 订单总金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
/**
|
||||
* 订单创建时间
|
||||
*/
|
||||
private String createDate;
|
||||
/**
|
||||
* 订单时效时间 分钟
|
||||
*/
|
||||
private String tradeExpiryTime;
|
||||
/**
|
||||
* 交易名称
|
||||
*/
|
||||
private String tradeSubject;
|
||||
/**
|
||||
* 交易类型
|
||||
*/
|
||||
private String tradeType;
|
||||
/**
|
||||
* 交易描述
|
||||
*/
|
||||
private String tradeRemark;
|
||||
/**
|
||||
* 币种
|
||||
*/
|
||||
private String currency;
|
||||
/**
|
||||
* 用户ip
|
||||
*/
|
||||
private String userIp;
|
||||
/**
|
||||
* 回传字段
|
||||
*/
|
||||
private String returnParams;
|
||||
/**
|
||||
* 商品信息list-- json串
|
||||
*/
|
||||
private String goodsInfo;
|
||||
/**
|
||||
* 商户用户标识
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 交易异步通知url
|
||||
*/
|
||||
private String notifyUrl;
|
||||
/**
|
||||
* 同步通知页面url
|
||||
*/
|
||||
private String pageBackUrl;
|
||||
|
||||
/**
|
||||
* 点击完成按钮后跳转页面
|
||||
*/
|
||||
private String callbackUrl;
|
||||
/**
|
||||
* 风控信息map-- json串
|
||||
*/
|
||||
private String riskInfo;
|
||||
/**
|
||||
* 行业分类码
|
||||
*/
|
||||
private String categoryCode;
|
||||
/**
|
||||
* 业务类型
|
||||
*/
|
||||
private String bizTp;
|
||||
/**
|
||||
* 订单类型
|
||||
*/
|
||||
private String orderType;
|
||||
/**
|
||||
* 报文格式
|
||||
*/
|
||||
private String messageFormat;
|
||||
/**
|
||||
* 收货信息
|
||||
*/
|
||||
private String receiverInfo;
|
||||
/**
|
||||
* 交易场景
|
||||
*/
|
||||
private String sceneType;
|
||||
/**
|
||||
* 指定支付信息
|
||||
*/
|
||||
private String identity;
|
||||
/**
|
||||
* 接入方式
|
||||
*/
|
||||
private String accessType;
|
||||
/**
|
||||
* openId
|
||||
*/
|
||||
private String subOpenId;
|
||||
/**
|
||||
* appId
|
||||
*/
|
||||
private String subAppId;
|
||||
/**
|
||||
* 分帐信息
|
||||
*/
|
||||
private String divisionAccount;
|
||||
/**
|
||||
* 门店号
|
||||
*/
|
||||
private String storeNum;
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 京东聚合下单响应
|
||||
*/
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayAggregateCreateOrderResponse implements Serializable {
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String resultCode;
|
||||
/**
|
||||
* 响应描述
|
||||
*/
|
||||
private String resultDesc;
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String merchantNo;
|
||||
/**
|
||||
* 京东交易订单号
|
||||
*/
|
||||
private String tradeNo;
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 跳转收银台链接
|
||||
*/
|
||||
private String webUrl;
|
||||
/**
|
||||
* PC扫码支付
|
||||
*/
|
||||
private String qrCode;
|
||||
/**
|
||||
* 唤起通道参数
|
||||
*/
|
||||
private String payInfo;
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分账业务字段
|
||||
*/
|
||||
public class JdPayDivisionAccount implements Serializable {
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private String version = "v2";
|
||||
// private String version;
|
||||
/**
|
||||
* 分账交易信息
|
||||
*/
|
||||
private List<JdPayDivisionAccountTradeInfo> divisionAccountTradeInfoList;
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public List<JdPayDivisionAccountTradeInfo> getDivisionAccountTradeInfoList() {
|
||||
return divisionAccountTradeInfoList;
|
||||
}
|
||||
|
||||
public void setDivisionAccountTradeInfoList(List<JdPayDivisionAccountTradeInfo> divisionAccountTradeInfoList) {
|
||||
this.divisionAccountTradeInfoList = divisionAccountTradeInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{\"JdPayDivisionAccount\":{"
|
||||
+ "\"version\":\"" + version + "\""
|
||||
+ ", \"divisionAccountTradeInfoList\":" + divisionAccountTradeInfoList
|
||||
+ "}}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分账业务字段
|
||||
* @author liulian115
|
||||
*/
|
||||
public class JdPayDivisionAccountRefund implements Serializable {
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private String version="V2";
|
||||
/**
|
||||
* 分账交易信息
|
||||
* @see JdPayDivisionAccountRefundInfo
|
||||
*/
|
||||
private List<JdPayDivisionAccountRefundInfo> divisionAccountRefundInfoList;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{\"JdPayDivisionAccountRefund\":{"
|
||||
+ "\"version\":\"" + version + "\""
|
||||
+ ", \"divisionAccountRefundInfoList\":" + divisionAccountRefundInfoList
|
||||
+ "}}";
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public List<JdPayDivisionAccountRefundInfo> getDivisionAccountRefundInfoList() {
|
||||
return divisionAccountRefundInfoList;
|
||||
}
|
||||
|
||||
public void setDivisionAccountRefundInfoList(List<JdPayDivisionAccountRefundInfo> divisionAccountRefundInfoList) {
|
||||
this.divisionAccountRefundInfoList = divisionAccountRefundInfoList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 分账交易信息
|
||||
*/
|
||||
public class JdPayDivisionAccountRefundInfo implements Serializable {
|
||||
/**
|
||||
* 分账子商户号
|
||||
*/
|
||||
private String merchantNo;
|
||||
/**
|
||||
* 分账子商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 分账子商户业务单号
|
||||
*/
|
||||
private String bizTradeNo;
|
||||
/**
|
||||
* 分账子单金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
/**
|
||||
* 原商户订单号
|
||||
*/
|
||||
private String originalOutTradeNo;
|
||||
|
||||
public String getOriginalOutTradeNo() {
|
||||
return originalOutTradeNo;
|
||||
}
|
||||
|
||||
public void setOriginalOutTradeNo(String originalOutTradeNo) {
|
||||
this.originalOutTradeNo = originalOutTradeNo;
|
||||
}
|
||||
|
||||
public String getMerchantNo() {
|
||||
return merchantNo;
|
||||
}
|
||||
|
||||
public void setMerchantNo(String merchantNo) {
|
||||
this.merchantNo = merchantNo;
|
||||
}
|
||||
|
||||
public String getOutTradeNo() {
|
||||
return outTradeNo;
|
||||
}
|
||||
|
||||
public void setOutTradeNo(String outTradeNo) {
|
||||
this.outTradeNo = outTradeNo;
|
||||
}
|
||||
|
||||
public String getBizTradeNo() {
|
||||
return bizTradeNo;
|
||||
}
|
||||
|
||||
public void setBizTradeNo(String bizTradeNo) {
|
||||
this.bizTradeNo = bizTradeNo;
|
||||
}
|
||||
|
||||
public String getTradeAmount() {
|
||||
return tradeAmount;
|
||||
}
|
||||
|
||||
public void setTradeAmount(String tradeAmount) {
|
||||
this.tradeAmount = tradeAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{\"JdPayDivisionAccountRefundInfo\":{"
|
||||
+ "\"merchantNo\":\"" + merchantNo + "\""
|
||||
+ ", \"outTradeNo\":\"" + outTradeNo + "\""
|
||||
+ ", \"bizTradeNo\":\"" + bizTradeNo + "\""
|
||||
+ ", \"tradeAmount\":\"" + tradeAmount + "\""
|
||||
+ ", \"originalOutTradeNo\":\"" + originalOutTradeNo + "\""
|
||||
+ "}}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 分账交易信息
|
||||
*/
|
||||
public class JdPayDivisionAccountTradeInfo implements Serializable {
|
||||
/**
|
||||
* 分账子商户号
|
||||
*/
|
||||
private String merchantNo;
|
||||
/**
|
||||
* 分账子商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 分账子商户业务单号
|
||||
*/
|
||||
private String bizTradeNo;
|
||||
/**
|
||||
* 分账子单金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
|
||||
public String getMerchantNo() {
|
||||
return merchantNo;
|
||||
}
|
||||
|
||||
public void setMerchantNo(String merchantNo) {
|
||||
this.merchantNo = merchantNo;
|
||||
}
|
||||
|
||||
public String getOutTradeNo() {
|
||||
return outTradeNo;
|
||||
}
|
||||
|
||||
public void setOutTradeNo(String outTradeNo) {
|
||||
this.outTradeNo = outTradeNo;
|
||||
}
|
||||
|
||||
public String getBizTradeNo() {
|
||||
return bizTradeNo;
|
||||
}
|
||||
|
||||
public void setBizTradeNo(String bizTradeNo) {
|
||||
this.bizTradeNo = bizTradeNo;
|
||||
}
|
||||
|
||||
public String getTradeAmount() {
|
||||
return tradeAmount;
|
||||
}
|
||||
|
||||
public void setTradeAmount(String tradeAmount) {
|
||||
this.tradeAmount = tradeAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{\"JdPayDivisionAccountTradeInfo\":{"
|
||||
+ "\"merchantNo\":\"" + merchantNo + "\""
|
||||
+ ", \"outTradeNo\":\"" + outTradeNo + "\""
|
||||
+ ", \"bizTradeNo\":\"" + bizTradeNo + "\""
|
||||
+ ", \"tradeAmount\":\"" + tradeAmount + "\""
|
||||
+ "}}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayQueryEnterpriseWalletBalanceRequest implements Serializable {
|
||||
private String accountNo;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayQueryEnterpriseWalletBalanceResponse implements Serializable {
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String resultCode;
|
||||
/**
|
||||
* 响应描述
|
||||
*/
|
||||
private String resultDesc;
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 京东退款响应
|
||||
*/
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayRefundRequest implements Serializable {
|
||||
|
||||
/**
|
||||
* 商户原交易号
|
||||
*/
|
||||
private String originalOutTradeNo;
|
||||
/**
|
||||
* 商户退款单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
/**
|
||||
* 异步通知URL
|
||||
*/
|
||||
private String notifyUrl;
|
||||
/**
|
||||
* 回传字段
|
||||
*/
|
||||
private String returnParams;
|
||||
/**
|
||||
* 币种
|
||||
*/
|
||||
private String currency;
|
||||
/**
|
||||
* 交易时间
|
||||
*/
|
||||
private String tradeDate;
|
||||
/**
|
||||
* 退款分账信息
|
||||
*
|
||||
* @see
|
||||
*/
|
||||
private String divisionAccountRefund;
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 京东退款请求
|
||||
*/
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayRefundResponse implements Serializable {
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String resultCode;
|
||||
/**
|
||||
* 响应描述
|
||||
*/
|
||||
private String resultDesc;
|
||||
|
||||
/**
|
||||
* 京东退款订单号
|
||||
*/
|
||||
private String tradeNo;
|
||||
/**
|
||||
* 商户退款订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 商户原正单订单号
|
||||
*/
|
||||
private String originalOutTradeNo;
|
||||
/**
|
||||
* 订单总金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
private String tradeStatus;
|
||||
/**
|
||||
* 币种
|
||||
*/
|
||||
private String currency;
|
||||
/**
|
||||
* 退款完成时间
|
||||
*/
|
||||
private String finishDate;
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description: 退款成功通知
|
||||
* @Author: jiang chao
|
||||
* @Time: 2025/3/21 10:24
|
||||
* @Classname: JdPayRefundSuccessNotify
|
||||
* @PackageName: com.hzs.third.pay.jdpay.dto
|
||||
*/
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayRefundSuccessNotify implements Serializable {
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String resultCode;
|
||||
/**
|
||||
* 响应描述
|
||||
*/
|
||||
private String resultDesc;
|
||||
|
||||
/**
|
||||
* 京东退款订单号
|
||||
*/
|
||||
private String tradeNo;
|
||||
|
||||
/**
|
||||
* 商户退款订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 商户原正单订单号
|
||||
*/
|
||||
private String originalOutTradeNo;
|
||||
/**
|
||||
* 订单总金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
/**
|
||||
* 退款完成时间
|
||||
*/
|
||||
private String finishDate;
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
private String tradeStatus;
|
||||
/**
|
||||
* 回传字段
|
||||
*/
|
||||
private String returnParams;
|
||||
/**
|
||||
* 币种
|
||||
*/
|
||||
private String currency;
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package com.hzs.third.pay.jdpay.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description: 交易成功通知
|
||||
* @Author: jiang chao
|
||||
* @Time: 2025/3/21 10:24
|
||||
* @Classname: JdPayRefundSuccessNotify
|
||||
* @PackageName: com.hzs.third.pay.jdpay.dto
|
||||
*/
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JdPayTradeSuccessNotify implements Serializable {
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String resultCode;
|
||||
/**
|
||||
* 响应描述
|
||||
*/
|
||||
private String resultDesc;
|
||||
|
||||
/**
|
||||
* 京东交易订单号
|
||||
*/
|
||||
private String tradeNo;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 订单总金额
|
||||
*/
|
||||
private String tradeAmount;
|
||||
/**
|
||||
* 币种
|
||||
*/
|
||||
private String currency;
|
||||
/**
|
||||
* 支付完成时间
|
||||
*/
|
||||
private String finishDate;
|
||||
/**
|
||||
* 交易类型
|
||||
*/
|
||||
private String tradeType;
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
private String tradeStatus;
|
||||
/**
|
||||
* 回传字段
|
||||
*/
|
||||
private String returnParams;
|
||||
/**
|
||||
* 请求的端
|
||||
*/
|
||||
private String clientType;
|
||||
/**
|
||||
* 商户用户标识
|
||||
*/
|
||||
private String userId;
|
||||
/**
|
||||
* 优惠金额
|
||||
*/
|
||||
private String discountAmount;
|
||||
/**
|
||||
* 支付工具
|
||||
*/
|
||||
private String payTool;
|
||||
/**
|
||||
* 掩码卡号
|
||||
*/
|
||||
private String maskCardNo;
|
||||
/**
|
||||
* 卡类型
|
||||
*/
|
||||
private String cardType;
|
||||
/**
|
||||
* 银行编码
|
||||
*/
|
||||
private String bankCode;
|
||||
/**
|
||||
* 白条分期数
|
||||
*/
|
||||
private String installmentNum;
|
||||
|
||||
private String acqOrderId;
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import com.hzs.third.pay.jdpay.dto.*;
|
||||
import com.hzs.third.pay.jdpay.util.GsonUtil;
|
||||
import com.hzs.third.pay.jdpay.util.JdPayApiUtil;
|
||||
import com.hzs.third.pay.jdpay.util.SignUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* 京东支付api实现类
|
||||
*
|
||||
*************************************************/
|
||||
@Slf4j
|
||||
public class JdPay {
|
||||
|
||||
private JdPayNewConfig jdPayNewConfig;
|
||||
|
||||
private JdPayHttpClientProxy jdPayHttpClientProxy;
|
||||
|
||||
public JdPay(JdPayNewConfig jdPayNewConfig) {
|
||||
this.jdPayNewConfig = jdPayNewConfig;
|
||||
this.jdPayHttpClientProxy = new JdPayHttpClientProxy(jdPayNewConfig, new JdPayHttpClient());
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 作用:统一下单
|
||||
// * 场景:京东支付
|
||||
// *
|
||||
// * @param request 向jdPay post的请求数据
|
||||
// * @return JdPayCreateOrderResponse 返回数据
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayCreateOrderResponse createOrder(JdPayCreateOrderRequest request) throws Exception {
|
||||
// return this.baseExecute(JdPayConstant.CREATE_ORDER_URL, request, JdPayCreateOrderResponse.class);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 作用:三方聚合统一下单
|
||||
* 场景:三方聚合
|
||||
*
|
||||
* @param request 向jdPay post的请求数据
|
||||
* @return JdPayAggregateCreateOrderResponse 返回数据
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdPayAggregateCreateOrderResponse aggregateCreateOrder(JdPayAggregateCreateOrderRequest request) throws Exception {
|
||||
return this.baseExecute(JdPayConstant.AGGREGATE_CREATE_ORDER_URL, request, JdPayAggregateCreateOrderResponse.class);
|
||||
}
|
||||
// /**
|
||||
// * 作用:订单查询
|
||||
// * 场景:查询订单信息 - 包括首次支付订单与代扣订单
|
||||
// *
|
||||
// * @param request 向jdPay post的请求数据
|
||||
// * @return JdPayQueryOrderResponse 返回数据
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayQueryOrderResponse queryOrder(JdPayQueryOrderRequest request) throws Exception {
|
||||
// return this.baseExecute(JdPayConstant.TRADE_QUERY_URL, request, JdPayQueryOrderResponse.class);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 作用:代扣
|
||||
// * 场景:代扣交易场景
|
||||
// *
|
||||
// * @param request 向jdPay post的请求数据
|
||||
// * @return JdPayAgreementPayResponse 返回数据
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayAgreementPayResponse agreementPay(JdPayAgreementPayRequest request) throws Exception {
|
||||
// return this.baseExecute(JdPayConstant.AGREEMENT_PAY_URL, request, JdPayAgreementPayResponse.class);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 作用:申请退款
|
||||
* 场景:退款
|
||||
*
|
||||
* @param request 向jdPay post的请求数据
|
||||
* @return JdPayRefundResponse 返回数据
|
||||
* @throws Exception
|
||||
*/
|
||||
public JdPayRefundResponse refund(JdPayRefundRequest request) throws Exception {
|
||||
return this.baseExecute(JdPayConstant.REFUND_URL, request, JdPayRefundResponse.class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 作用:退款查询
|
||||
// * 场景:查询退款信息
|
||||
// *
|
||||
// * @param request 向jdPay post的请求数据
|
||||
// * @return JdPayQueryOrderResponse 返回数据
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayRefundQueryResponse refundQuery(JdPayRefundQueryRequest request) throws Exception {
|
||||
// return this.baseExecute(JdPayConstant.REFUND_QUERY_URL, request, JdPayRefundQueryResponse.class);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 作用:解约
|
||||
// * 场景:接触签约关系
|
||||
// *
|
||||
// * @param request 向jdPay post的请求数据
|
||||
// * @return JdPayAgreementCancelRequest 返回数据
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayAgreementCancelResponse agreementCancel(JdPayAgreementCancelRequest request) throws Exception {
|
||||
// return this.baseExecute(JdPayConstant.AGREEMENT_CANCEL_URL, request, JdPayAgreementCancelResponse.class);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 作用:解约查询
|
||||
// * 场景:查询签约关系
|
||||
// *
|
||||
// * @param request 向jdPay post的请求数据
|
||||
// * @return JdPayAgreementCancelRequest 返回数据
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayAgreementQueryResponse agreementQuery(JdPayAgreementQueryRequest request) throws Exception {
|
||||
// return this.baseExecute(JdPayConstant.AGREEMENT_QUERY_URL, request, JdPayAgreementQueryResponse.class);
|
||||
// }
|
||||
//
|
||||
// public JdPayAgreementSignResponse agreementNewSign(JdPayAgreementSignRequest request) throws Exception{
|
||||
// return this.baseExecute(JdPayConstant.AGREEMENT_NEW_SIGN_URL, request, JdPayAgreementSignResponse.class);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 验证接口参数签名
|
||||
* 场景:api接口返回参数,异步回调请求参数
|
||||
*/
|
||||
public String verifyResponse(String respText) throws Exception {
|
||||
String interData = JdPayApiUtil.decryptAndVerifySign(jdPayNewConfig, respText);
|
||||
log.info("京东支付异步通知-解析数据:{}", interData);
|
||||
return interData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证页面回调参数
|
||||
*
|
||||
* @param respMap 页面回调参数
|
||||
* @return 验证结果
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public boolean verifyPageCallBack(Map<String, String> respMap) throws Exception {
|
||||
return SignUtil.verifyPageCallBackSign(respMap, jdPayNewConfig.getSignKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行接口调用
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param clazz 返回对象类型
|
||||
* @return 返回对象
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public <REQ, RES> RES baseExecute(String urlSuffix, REQ request, Class<RES> clazz) throws Exception {
|
||||
String reqJson = GsonUtil.toJson(request);
|
||||
String respJson = jdPayHttpClientProxy.execute(urlSuffix, reqJson);
|
||||
return GsonUtil.fromJson(respJson, clazz);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 账户签约
|
||||
// * @param request
|
||||
// * @return
|
||||
// * @throws Exception
|
||||
// */
|
||||
// public JdPayAgreementSignApplyResponse agreementSignApply(JdPayAgreementSignApplyRequest request) throws Exception{
|
||||
// return this.baseExecute(JdPayConstant.AGREEMENT_SIGN_APPLY_URL, request, JdPayAgreementSignApplyResponse.class);
|
||||
// }
|
||||
|
||||
|
||||
public JdPayQueryEnterpriseWalletBalanceResponse queryEnterpriseWalletBalance(JdPayQueryEnterpriseWalletBalanceRequest request) throws Exception{
|
||||
return this.baseExecute(JdPayConstant.QUERY_ENTERPRISE_WALLET_BALANCE_URL, request, JdPayQueryEnterpriseWalletBalanceResponse.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
|
||||
public class JdPayConstant {
|
||||
|
||||
/**
|
||||
* 京东支付统一收单 url
|
||||
**/
|
||||
public static final String CREATE_ORDER_URL = "/api/createOrder";
|
||||
/**
|
||||
* 三方聚合统一收单 url
|
||||
**/
|
||||
// public static final String AGGREGATE_CREATE_ORDER_URL = "/api/createAggregateOrder";
|
||||
public static final String AGGREGATE_CREATE_ORDER_URL = "/api/createIndustryOrder";
|
||||
/**
|
||||
* 交易查询 url
|
||||
**/
|
||||
public static final String TRADE_QUERY_URL = "/api/queryOrder";
|
||||
/**
|
||||
* 退款申请 url
|
||||
**/
|
||||
public static final String REFUND_URL = "/api/refund";
|
||||
/**
|
||||
* 退款查询 url
|
||||
**/
|
||||
public static final String REFUND_QUERY_URL = "/api/refundQuery";
|
||||
/**
|
||||
* 代扣 url
|
||||
**/
|
||||
public static final String AGREEMENT_PAY_URL = "/api/agreementPay";
|
||||
/**
|
||||
* 签约关系查询 url
|
||||
**/
|
||||
public static final String AGREEMENT_QUERY_URL = "/api/agreementQuery";
|
||||
/**
|
||||
* 解约申请 url
|
||||
**/
|
||||
public static final String AGREEMENT_CANCEL_URL = "/api/agreementCancel";
|
||||
|
||||
/**
|
||||
* 无卡号签约
|
||||
*/
|
||||
public static final String AGREEMENT_NEW_SIGN_URL = "/api/agreementNewSign";
|
||||
|
||||
/**
|
||||
* 账户签约
|
||||
*/
|
||||
public static final String AGREEMENT_SIGN_APPLY_URL = "/api/agreementSignApply";
|
||||
public static final String QUERY_ENTERPRISE_WALLET_BALANCE_URL = "/api/queryEnterpriseWalletBalance";
|
||||
|
||||
/**
|
||||
* 随机字符常量
|
||||
*/
|
||||
public static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
/**
|
||||
* 公共字段常量 start
|
||||
**/
|
||||
public static final String CCM = "CCM";
|
||||
public static final String MERCHANT_NO = "merchantNo";
|
||||
public static final String REQ_NO = "reqNo";
|
||||
public static final String CHARSET = "charset";
|
||||
public static final String FORMAT_TYPE = "formatType";
|
||||
public static final String SIGN_TYPE = "signType";
|
||||
public static final String ENC_TYPE = "encType";
|
||||
public static final String UTF8 = "UTF-8";
|
||||
public static final String JSON = "JSON";
|
||||
public static final String SHA256 = "SHA-256";
|
||||
public static final String AP7 = "AP7";
|
||||
public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
|
||||
public static final String SIGN_DATA = "signData";
|
||||
public static final String ENC_DATA = "encData";
|
||||
public static final String RESP_DATA = "respData";
|
||||
public static final String CODE = "code";
|
||||
public static final String DESC = "desc";
|
||||
public static final String SUCCESS_CODE = "00000";
|
||||
/* 公共字段常量 end */
|
||||
|
||||
|
||||
/**
|
||||
* http请求常量 start
|
||||
**/
|
||||
public static final String HTTP = "http";
|
||||
public static final String HTTPS = "https";
|
||||
public static final String CONTENT_TYPE = "Content-Type";
|
||||
public static final String UA = "User-Agent";
|
||||
public static final String PKCS12 = "PKCS12";
|
||||
public static final String TLS = "TLS";
|
||||
public static final String APPLICATION_JSON = "application/json";
|
||||
public static final String USER_AGENT = "jdPay" +
|
||||
" (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") +
|
||||
") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion();
|
||||
/* http请求常量 end */
|
||||
|
||||
public static final String URL_PATH = "/api/";
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import com.hzs.third.pay.jdpay.util.FileUtil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* 商户默认配置类
|
||||
* 商户也可以自行实现JdPayConfig,调整配置属性
|
||||
*
|
||||
*************************************************/
|
||||
public class JdPayDefaultNewConfig extends JdPayNewConfig {
|
||||
|
||||
private String merchantNo;
|
||||
private String signKey;
|
||||
private byte[] priCert;
|
||||
private String priCertPwd;
|
||||
private byte[] pubCert;
|
||||
private String apiDomain;
|
||||
|
||||
public JdPayDefaultNewConfig(String merchantNo, String signKey, byte[] priCert, String priCertPwd, byte[] pubCert, String apiDomain) {
|
||||
this.merchantNo = merchantNo;
|
||||
this.signKey = signKey;
|
||||
this.priCert = priCert;
|
||||
this.priCertPwd = priCertPwd;
|
||||
this.pubCert = pubCert;
|
||||
this.apiDomain = apiDomain;
|
||||
}
|
||||
|
||||
public JdPayDefaultNewConfig(String merchantNo, String signKey, String priCertPwd, String apiDomain, String priCertPath, String pubCertPath) {
|
||||
this.merchantNo = merchantNo;
|
||||
this.signKey = signKey;
|
||||
this.priCertPwd = priCertPwd;
|
||||
this.apiDomain = apiDomain;
|
||||
|
||||
//加载商户私钥证书
|
||||
this.priCert = FileUtil.readFile(priCertPath);
|
||||
//加载商户公钥证书
|
||||
this.pubCert = FileUtil.readFile(pubCertPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMerchantNo() {
|
||||
return this.merchantNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignKey() {
|
||||
return this.signKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getPriCert() {
|
||||
return new ByteArrayInputStream(this.priCert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPriCertPwd() {
|
||||
return this.priCertPwd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getPubCert() {
|
||||
return new ByteArrayInputStream(this.pubCert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApiDomain() {
|
||||
return this.apiDomain;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import com.hzs.common.core.exception.ServiceException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.*;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||
import org.apache.http.conn.HttpClientConnectionManager;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeaderElementIterator;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public class JdPayHttpClient {
|
||||
|
||||
private CloseableHttpClient httpClient = null;
|
||||
|
||||
public JdPayHttpClient() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程调用
|
||||
*
|
||||
* @param jdPayNewConfig 京东支付配置
|
||||
* @param urlSuffix 接口url后缀
|
||||
* @param request 请求参数
|
||||
* @return 返回参数看
|
||||
* @throws Exception 远程调用异常信息
|
||||
*/
|
||||
public String execute(JdPayNewConfig jdPayNewConfig, String urlSuffix, String request) {
|
||||
HttpClient httpClient = buildHttpClient(jdPayNewConfig);
|
||||
String url = jdPayNewConfig.getApiDomain() + urlSuffix;
|
||||
int connectTimeoutMs = jdPayNewConfig.getHttpConnectTimeoutMs();
|
||||
int readTimeoutMs = jdPayNewConfig.getHttpReadTimeoutMs(urlSuffix);
|
||||
try {
|
||||
return this.sendRequest(httpClient, url, request, connectTimeoutMs, readTimeoutMs);
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("HTTP read timeout");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取httpClient
|
||||
*
|
||||
* @param jdPayNewConfig 京东支付配置
|
||||
* @return httpClient
|
||||
*/
|
||||
private HttpClient buildHttpClient(JdPayNewConfig jdPayNewConfig) {
|
||||
if (jdPayNewConfig.useHttpConnectPool()) {
|
||||
return getHttpClientByPoolingConnectionManager(jdPayNewConfig);
|
||||
} else {
|
||||
return getHttpClientByBasicConnectionManager();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
*
|
||||
* @param httpClient httpClient
|
||||
* @param url 请求地址
|
||||
* @param data 请求数据
|
||||
* @param connectTimeoutMs 连接超时时间,单位是毫秒
|
||||
* @param readTimeoutMs 读超时时间,单位是毫秒
|
||||
* @return api接口返回参数
|
||||
*/
|
||||
private String sendRequest(HttpClient httpClient, String url, String data, int connectTimeoutMs, int readTimeoutMs) throws IOException {
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
|
||||
httpPost.setConfig(requestConfig);
|
||||
|
||||
StringEntity postEntity = new StringEntity(data, JdPayConstant.UTF8);
|
||||
httpPost.addHeader(JdPayConstant.CONTENT_TYPE, JdPayConstant.APPLICATION_JSON);
|
||||
httpPost.addHeader(JdPayConstant.UA, JdPayConstant.USER_AGENT);
|
||||
httpPost.setEntity(postEntity);
|
||||
HttpResponse httpResponse = httpClient.execute(httpPost);
|
||||
int statusCode = httpResponse.getStatusLine().getStatusCode();
|
||||
if (HttpStatus.SC_OK != statusCode) {
|
||||
throw new ServiceException(String.format("httpStatusCode: %s", statusCode));
|
||||
}
|
||||
HttpEntity httpEntity = httpResponse.getEntity();
|
||||
return EntityUtils.toString(httpEntity, JdPayConstant.UTF8);
|
||||
}
|
||||
|
||||
private HttpClient getHttpClientByBasicConnectionManager() {
|
||||
HttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(
|
||||
RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register(JdPayConstant.HTTP, PlainConnectionSocketFactory.getSocketFactory())
|
||||
.register(JdPayConstant.HTTPS, SSLConnectionSocketFactory.getSocketFactory())
|
||||
.build(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
return HttpClientBuilder.create()
|
||||
// 连接池
|
||||
.setConnectionManager(connManager)
|
||||
// 重试策略
|
||||
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)).build();
|
||||
}
|
||||
|
||||
private HttpClient getHttpClientByPoolingConnectionManager(JdPayNewConfig jdPayNewConfig) {
|
||||
if (httpClient != null) {
|
||||
return httpClient;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (httpClient == null) {
|
||||
long start = System.currentTimeMillis();
|
||||
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager(
|
||||
RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register(JdPayConstant.HTTP, PlainConnectionSocketFactory.getSocketFactory())
|
||||
.register(JdPayConstant.HTTPS, SSLConnectionSocketFactory.getSocketFactory())
|
||||
.build()
|
||||
);
|
||||
// 设置最大连接数
|
||||
httpClientConnectionManager.setMaxTotal(jdPayNewConfig.getHttpConnectMaxTotal());
|
||||
// 将每个路由默认最大连接数
|
||||
httpClientConnectionManager.setDefaultMaxPerRoute(jdPayNewConfig.getHttpConnectDefaultTotal());
|
||||
httpClient = HttpClients.custom()
|
||||
// 设置连接池
|
||||
.setConnectionManager(httpClientConnectionManager)
|
||||
// 连接存活策略
|
||||
.setKeepAliveStrategy(getConnectionKeepAliveStrategy())
|
||||
// 重试策略
|
||||
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)).build();
|
||||
// 连接回收策略
|
||||
JdPayHttpConnectionMonitor idleConnectionMonitor = new JdPayHttpConnectionMonitor(httpClientConnectionManager, jdPayNewConfig.getHttpConnectIdleAliveMs());
|
||||
idleConnectionMonitor.start();
|
||||
log.info("初始化http连接池耗时:{}", System.currentTimeMillis() - start);
|
||||
}
|
||||
}
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
private ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
|
||||
return new ConnectionKeepAliveStrategy() {
|
||||
@Override
|
||||
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
|
||||
// Honor 'keep-alive' header
|
||||
HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
|
||||
while (it.hasNext()) {
|
||||
HeaderElement he = it.nextElement();
|
||||
String param = he.getName();
|
||||
String value = he.getValue();
|
||||
if (value != null && "timeout".equalsIgnoreCase(param)) {
|
||||
try {
|
||||
log.info("Keep-Alive指定时长:{}", value);
|
||||
return Long.parseLong(value) * 1000;
|
||||
} catch (NumberFormatException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Keep alive for 300 seconds only
|
||||
return 300 * 1000;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import com.hzs.third.pay.jdpay.util.JdPayApiUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
@Slf4j
|
||||
public class JdPayHttpClientProxy {
|
||||
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
|
||||
private final JdPayNewConfig jdPayNewConfig;
|
||||
|
||||
private final JdPayHttpClient jdPayHttpClient;
|
||||
|
||||
public JdPayHttpClientProxy(JdPayNewConfig jdPayNewConfig, JdPayHttpClient jdPayHttpClient) {
|
||||
this.jdPayNewConfig = jdPayNewConfig;
|
||||
this.jdPayHttpClient = jdPayHttpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机字符串,含数字和大小写英文字母
|
||||
*/
|
||||
private static String genNonceStr() {
|
||||
char[] nonceChars = new char[32];
|
||||
for (int index = 0; index < nonceChars.length; ++index) {
|
||||
nonceChars[index] = JdPayConstant.SYMBOLS.charAt(RANDOM.nextInt(JdPayConstant.SYMBOLS.length()));
|
||||
}
|
||||
return new String(nonceChars);
|
||||
}
|
||||
|
||||
public String execute(String urlSuffix, String request) throws Exception {
|
||||
long startTimestampMs = System.currentTimeMillis();
|
||||
String response;
|
||||
// 接口名称
|
||||
String apiName = urlSuffix.replaceFirst(JdPayConstant.URL_PATH, "");
|
||||
// 唯一请求号
|
||||
String reqNo = genNonceStr();
|
||||
try {
|
||||
log.info("1.{}接口请求参数:{}", apiName, request);
|
||||
// 请求参数加密和签名
|
||||
String httpRequest = JdPayApiUtil.encryptAndSignature(jdPayNewConfig, reqNo, request);
|
||||
log.info("2.{}远程调用请求参数:{}", apiName, httpRequest);
|
||||
String httpResponse = jdPayHttpClient.execute(jdPayNewConfig, urlSuffix, httpRequest);
|
||||
log.info("3.{}远程调用返回参数:{}", apiName, httpResponse);
|
||||
// 验证和解析返回参数
|
||||
response = JdPayApiUtil.decryptAndVerifySign(jdPayNewConfig, httpResponse);
|
||||
log.info("4.{}耗时:{},接口返回参数:{}", apiName, (System.currentTimeMillis() - startTimestampMs), response);
|
||||
} catch (Exception e) {
|
||||
log.error("{}远程调用异常,接口参数:{}", apiName, request, e);
|
||||
throw e;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.conn.HttpClientConnectionManager;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 用于监控空闲的连接池连接
|
||||
*/
|
||||
@Slf4j
|
||||
public class JdPayHttpConnectionMonitor extends Thread {
|
||||
|
||||
// 轮询检查时间间隔,单位毫秒
|
||||
private static final int MONITOR_INTERVAL_MS = 5000;
|
||||
// 连接最大空闲时间,单位毫秒
|
||||
private static int IDLE_ALIVE_MS = 20000;
|
||||
|
||||
private final HttpClientConnectionManager httpClientConnectionManager;
|
||||
|
||||
private volatile boolean shutdown;
|
||||
|
||||
JdPayHttpConnectionMonitor(HttpClientConnectionManager httpClientConnectionManager, int idleAliveMs) {
|
||||
super();
|
||||
this.httpClientConnectionManager = httpClientConnectionManager;
|
||||
IDLE_ALIVE_MS = idleAliveMs;
|
||||
this.shutdown = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (!shutdown) {
|
||||
synchronized (this) {
|
||||
wait(MONITOR_INTERVAL_MS);
|
||||
// 关闭无效的连接
|
||||
httpClientConnectionManager.closeExpiredConnections();
|
||||
// 关闭空闲时间超过IDLE_ALIVE_MS的连接
|
||||
httpClientConnectionManager.closeIdleConnections(IDLE_ALIVE_MS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("连接池管理任务异常:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭后台连接
|
||||
public void shutdown() {
|
||||
shutdown = true;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 京东支付配置类
|
||||
*/
|
||||
public abstract class JdPayNewConfig {
|
||||
|
||||
/**
|
||||
* 接口超时时间全局配置
|
||||
*/
|
||||
private static final HashMap<String, Integer> HTTP_READ_TIMEOUT_CONFIG = new HashMap<String, Integer>() {{
|
||||
put(JdPayConstant.CREATE_ORDER_URL, 15000);
|
||||
put(JdPayConstant.TRADE_QUERY_URL, 5000);
|
||||
put(JdPayConstant.REFUND_URL, 5000);
|
||||
put(JdPayConstant.REFUND_QUERY_URL, 5000);
|
||||
put(JdPayConstant.AGREEMENT_PAY_URL, 10000);
|
||||
put(JdPayConstant.AGREEMENT_QUERY_URL, 5000);
|
||||
put(JdPayConstant.AGREEMENT_CANCEL_URL, 5000);
|
||||
}};
|
||||
|
||||
/**
|
||||
* 获取merchantNo
|
||||
*
|
||||
* @return merchantNo
|
||||
*/
|
||||
public abstract String getMerchantNo();
|
||||
|
||||
/**
|
||||
* 获取signKey
|
||||
*
|
||||
* @return signKey
|
||||
*/
|
||||
public abstract String getSignKey();
|
||||
|
||||
/**
|
||||
* 获取 私钥证书
|
||||
*
|
||||
* @return 私钥证书
|
||||
*/
|
||||
public abstract InputStream getPriCert();
|
||||
|
||||
/**
|
||||
* 获取 私钥证书密钥
|
||||
*
|
||||
* @return 私钥证书密钥
|
||||
*/
|
||||
public abstract String getPriCertPwd();
|
||||
|
||||
/**
|
||||
* 获取 公钥证书
|
||||
*
|
||||
* @return 公钥证书
|
||||
*/
|
||||
public abstract InputStream getPubCert();
|
||||
|
||||
/**
|
||||
* 获取域名-新api接口
|
||||
*
|
||||
* @return 域名-新api接口
|
||||
*/
|
||||
public abstract String getApiDomain();
|
||||
|
||||
/**
|
||||
* HTTP(S) 连接超时时间,单位毫秒
|
||||
*
|
||||
* @return 连接时间
|
||||
*/
|
||||
public int getHttpConnectTimeoutMs() {
|
||||
return 6 * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置HTTP(S) 读数据超时时间,单位毫秒
|
||||
*
|
||||
* @param urlSuffix api地址除去域名后的路径
|
||||
* @param httpReadTimeoutMs 读超时时间,单位毫秒
|
||||
*/
|
||||
public void setHttpReadTimeoutMs(String urlSuffix, int httpReadTimeoutMs) {
|
||||
HTTP_READ_TIMEOUT_CONFIG.put(urlSuffix, httpReadTimeoutMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询HTTP(S) 读数据超时时间,单位毫秒
|
||||
*
|
||||
* @return 读超时时间,单位毫秒
|
||||
*/
|
||||
public int getHttpReadTimeoutMs(String requestPath) {
|
||||
if (!HTTP_READ_TIMEOUT_CONFIG.containsKey(requestPath)) {
|
||||
return 15000;
|
||||
}
|
||||
return HTTP_READ_TIMEOUT_CONFIG.get(requestPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否自动上报异常请求。默认为 true
|
||||
* 若要关闭,子类中实现该函数返回 false 即可。
|
||||
*/
|
||||
public boolean shouldAutoReport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行异常上报的线程的数量
|
||||
*/
|
||||
public int getReportWorkerNum() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量上报,一次报多条异常数据
|
||||
*/
|
||||
public int getReportBatchSize() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常上报缓存消息队列最大数量。
|
||||
* 队列满后,不会上报新增的异常信息
|
||||
*/
|
||||
public int getReportQueueMaxSize() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用http连接池
|
||||
*/
|
||||
public boolean useHttpConnectPool() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* http连接池最大连接数量
|
||||
*/
|
||||
public int getHttpConnectMaxTotal() {
|
||||
return 800;
|
||||
}
|
||||
|
||||
/**
|
||||
* http连接池默认连接数量
|
||||
*/
|
||||
public int getHttpConnectDefaultTotal() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* http连接最大闲置时长,单位毫秒
|
||||
*/
|
||||
public int getHttpConnectIdleAliveMs() {
|
||||
return 20000;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class JdPaySecurity {
|
||||
|
||||
public String signEnvelop(InputStream signCert, String password, InputStream envelopCert, byte[] orgData) {
|
||||
byte[] signData = JdPaySign.getInstance().attachSign(signCert, password, orgData);
|
||||
byte[] envelop = JdPaySign.getInstance().encryptEnvelop(envelopCert, signData);
|
||||
return new String(Base64.encode(envelop));
|
||||
}
|
||||
|
||||
public byte[] verifyEnvelop(InputStream envelopCert, String password, byte[] envelopData) {
|
||||
byte[] signData = JdPaySign.getInstance().decryptEnvelop(envelopCert, password, envelopData);
|
||||
return JdPaySign.getInstance().verifyAttachSign(signData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
package com.hzs.third.pay.jdpay.sdk;
|
||||
|
||||
import com.hzs.common.core.exception.ServiceException;
|
||||
import com.hzs.third.pay.jdpay.util.CertUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.asn1.DEROutputStream;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||
import org.bouncycastle.cms.*;
|
||||
import org.bouncycastle.cms.jcajce.*;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||
import org.bouncycastle.util.Store;
|
||||
|
||||
import javax.security.auth.x500.X500PrivateCredential;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class JdPaySign {
|
||||
|
||||
private static final String SIGN_ALGORITHMS = "SHA1WITHRSA";
|
||||
private static final String BC = "BC";
|
||||
|
||||
private static JdPaySign INSTANCE = null;
|
||||
|
||||
static {
|
||||
BouncyCastleProvider provider = new BouncyCastleProvider();
|
||||
Security.addProvider(provider);
|
||||
}
|
||||
|
||||
private JdPaySign() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例,双重校验
|
||||
*/
|
||||
public static JdPaySign getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (JdPaySign.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new JdPaySign();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
public byte[] attachSign(InputStream priCert, String password, byte[] data) {
|
||||
return this.sign(priCert, password, data, true);
|
||||
}
|
||||
|
||||
public byte[] detachSign(InputStream priCert, String password, byte[] data) {
|
||||
return this.sign(priCert, password, data, false);
|
||||
}
|
||||
|
||||
private byte[] sign(InputStream priCert, String password, byte[] data, boolean isDetach) {
|
||||
try {
|
||||
X500PrivateCredential privateCert = CertUtil.getPrivateCert(priCert, password.toCharArray());
|
||||
X509Certificate x509Certificate = privateCert.getCertificate();
|
||||
PrivateKey privateKey = privateCert.getPrivateKey();
|
||||
|
||||
List<X509Certificate> certList = new ArrayList<>();
|
||||
certList.add(x509Certificate);
|
||||
Store certs = new JcaCertStore(certList);
|
||||
|
||||
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
|
||||
ContentSigner sha1Signer = new JcaContentSignerBuilder(SIGN_ALGORITHMS).setProvider(BC).build(privateKey);
|
||||
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, x509Certificate));
|
||||
generator.addCertificates(certs);
|
||||
|
||||
CMSTypedData msg = new CMSProcessableByteArray(data);
|
||||
return generator.generate(msg, isDetach).getEncoded();
|
||||
} catch (CertificateException e) {
|
||||
log.error("=====", e);
|
||||
log.error(e.getMessage());
|
||||
throw new ServiceException(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("-----", e);
|
||||
log.error(e.getMessage());
|
||||
throw new ServiceException("签名异常");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public int verifyDetachSign(byte[] data, byte[] signData) {
|
||||
try {
|
||||
CMSProcessable content = new CMSProcessableByteArray(data);
|
||||
CMSSignedData s = new CMSSignedData(content, signData);
|
||||
Store certStore = s.getCertificates();
|
||||
SignerInformationStore signers = s.getSignerInfos();
|
||||
Collection c = signers.getSigners();
|
||||
Iterator it = c.iterator();
|
||||
int verified = 0, size = 0;
|
||||
while (it.hasNext()) {
|
||||
size++;
|
||||
SignerInformation signer = (SignerInformation) it.next();
|
||||
Collection certCollection = certStore.getMatches(signer.getSID());
|
||||
Iterator certIt = certCollection.iterator();
|
||||
X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
|
||||
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
|
||||
verified++;
|
||||
}
|
||||
}
|
||||
if (size == verified) {
|
||||
return 1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes"})
|
||||
public byte[] verifyAttachSign(byte[] signData) {
|
||||
try {
|
||||
byte[] data = null;
|
||||
CMSSignedData s = new CMSSignedData(signData);
|
||||
Store certStore = s.getCertificates();
|
||||
SignerInformationStore signers = s.getSignerInfos();
|
||||
Collection c = signers.getSigners();
|
||||
Iterator it = c.iterator();
|
||||
int verified = 0, size = 0;
|
||||
|
||||
while (it.hasNext()) {
|
||||
size++;
|
||||
SignerInformation signer = (SignerInformation) it.next();
|
||||
Collection certCollection = certStore.getMatches(signer.getSID());
|
||||
Iterator certIt = certCollection.iterator();
|
||||
X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
|
||||
|
||||
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
|
||||
verified++;
|
||||
CMSTypedData cmsData = s.getSignedContent();
|
||||
data = (byte[]) cmsData.getContent();
|
||||
}
|
||||
}
|
||||
if (size == verified) {
|
||||
return data;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encryptEnvelop(InputStream pubCert, byte[] bOrgData) {
|
||||
try {
|
||||
X509Certificate publicCert = CertUtil.getPublicCert(pubCert);
|
||||
CMSEnvelopedDataGenerator generator = new CMSEnvelopedDataGenerator();
|
||||
generator.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(publicCert).setProvider(BC));
|
||||
CMSEnvelopedData enveloped = generator.generate(new CMSProcessableByteArray(bOrgData), new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
new DEROutputStream(out).writeObject(enveloped.toASN1Structure());
|
||||
byte[] result = out.toByteArray();
|
||||
out.close();
|
||||
return result;
|
||||
} catch (CertificateException | CMSException | IOException e) {
|
||||
log.error("加密异常:{}", e.getMessage());
|
||||
throw new ServiceException("加密异常");
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] decryptEnvelop(InputStream priCert, String privateKeyPassword, byte[] bEnvelop) {
|
||||
try {
|
||||
CMSEnvelopedData enveloped = new CMSEnvelopedData(bEnvelop);
|
||||
RecipientInformationStore ris = enveloped.getRecipientInfos();
|
||||
if (ris == null) {
|
||||
log.error("数字信封格式不对:{}", new String(bEnvelop));
|
||||
throw new ServiceException("验签异常");
|
||||
}
|
||||
|
||||
X500PrivateCredential privateCert = CertUtil.getPrivateCert(priCert, privateKeyPassword.toCharArray());
|
||||
PrivateKey privateKey = privateCert.getPrivateKey();
|
||||
|
||||
byte[] sign = null;
|
||||
Collection recipients = ris.getRecipients();
|
||||
for (Object object : recipients) {
|
||||
RecipientInformation recipient = (RecipientInformation) object;
|
||||
sign = recipient.getContent(new JceKeyTransEnvelopedRecipient(privateKey).setProvider(BC));
|
||||
}
|
||||
return sign;
|
||||
} catch (CMSException | CertificateException e) {
|
||||
log.error("验签异常:{}", e.getMessage());
|
||||
throw new ServiceException("验签异常");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package com.hzs.third.pay.jdpay.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.security.auth.x500.X500PrivateCredential;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
|
||||
@Slf4j
|
||||
public class CertUtil {
|
||||
|
||||
private static final String PKCS12 = "PKCS12";
|
||||
|
||||
public static X500PrivateCredential getPrivateCert(InputStream pfxCert, char[] privateKeyPassword) throws CertificateException {
|
||||
KeyStore keyStore;
|
||||
String keyStoreAlias = null;
|
||||
|
||||
/* Load KeyStore contents from file */
|
||||
try {
|
||||
keyStore = KeyStore.getInstance(CertUtil.PKCS12);
|
||||
keyStore.load(pfxCert, privateKeyPassword);
|
||||
|
||||
/* Get aliases */
|
||||
Enumeration aliases = keyStore.aliases();
|
||||
if (aliases != null) {
|
||||
while (aliases.hasMoreElements()) {
|
||||
keyStoreAlias = (String) aliases.nextElement();
|
||||
Certificate[] certs = keyStore.getCertificateChain(keyStoreAlias);
|
||||
if (certs == null || certs.length == 0) {
|
||||
continue;
|
||||
}
|
||||
X509Certificate cert = (X509Certificate) certs[0];
|
||||
if (matchUsage(cert.getKeyUsage(), 1)) {
|
||||
try {
|
||||
cert.checkValidity();
|
||||
} catch (CertificateException e) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (GeneralSecurityException | IOException e) {
|
||||
log.error("===============", e);
|
||||
throw new CertificateException("Error initializing keystore");
|
||||
}
|
||||
|
||||
if (keyStoreAlias == null) {
|
||||
throw new CertificateException("None certificate for sign in this keystore");
|
||||
}
|
||||
|
||||
/* Get certificate chain and create a certificate path */
|
||||
Certificate[] fromKeyStore;
|
||||
try {
|
||||
fromKeyStore = keyStore.getCertificateChain(keyStoreAlias);
|
||||
if (fromKeyStore == null
|
||||
|| fromKeyStore.length == 0
|
||||
|| !(fromKeyStore[0] instanceof X509Certificate)) {
|
||||
throw new CertificateException("Unable to find X.509 certificate chain in keystore");
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new CertificateException("Error using keystore");
|
||||
}
|
||||
|
||||
/* Get PrivateKey */
|
||||
Key privateKey;
|
||||
try {
|
||||
privateKey = keyStore.getKey(keyStoreAlias, privateKeyPassword);
|
||||
if (!(privateKey instanceof PrivateKey)) {
|
||||
throw new CertificateException("Unable to recover key from keystore");
|
||||
}
|
||||
} catch (KeyStoreException | NoSuchAlgorithmException e) {
|
||||
throw new CertificateException("Error using keystore");
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
throw new CertificateException("Unable to recover key from keystore");
|
||||
}
|
||||
|
||||
X509Certificate certificate = (X509Certificate) fromKeyStore[0];
|
||||
return new X500PrivateCredential(certificate, (PrivateKey) privateKey, keyStoreAlias);
|
||||
}
|
||||
|
||||
public static X509Certificate getPublicCert(InputStream publicCert) throws CertificateException {
|
||||
try {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X509");
|
||||
Certificate certificate = cf.generateCertificate(publicCert);
|
||||
return (X509Certificate) certificate;
|
||||
} catch (CertificateException e) {
|
||||
throw new CertificateException("Error loading public key certificate");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean matchUsage(boolean[] keyUsage, int usage) {
|
||||
if (usage == 0 || keyUsage == null) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < Math.min(keyUsage.length, 32); i++) {
|
||||
if ((usage & (1 << i)) != 0 && !keyUsage[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.hzs.third.pay.jdpay.util;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FileUtil {
|
||||
|
||||
public FileUtil() {
|
||||
}
|
||||
|
||||
public static byte[] readFile(String filename) {
|
||||
ClassPathResource classPathResource = new ClassPathResource(filename);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
BufferedInputStream in = null;
|
||||
try {
|
||||
in = new BufferedInputStream(classPathResource.getInputStream());
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while (-1 != (len = in.read(buffer, 0, 1024))) {
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
return bos.toByteArray();
|
||||
} catch (IOException var21) {
|
||||
var21.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (null != in) {
|
||||
in.close();
|
||||
}
|
||||
} catch (IOException var20) {
|
||||
var20.printStackTrace();
|
||||
}
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException var19) {
|
||||
var19.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package com.hzs.third.pay.jdpay.util;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.internal.Primitives;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* Gson工具类,对Google的gson工具进行封装
|
||||
* (1)日期格式yyyyMMddHHmmss
|
||||
* (2)toJson时支持掩码
|
||||
* (3)toJson时支持跳过指定属性
|
||||
*************************************************/
|
||||
public class GsonUtil {
|
||||
private static final String EMPTY_JSON = "{}";
|
||||
private static final String EMPTY_JSON_ARRAY = "[]";
|
||||
private static final String DEFAULT_DATE_PATTERN = "yyyyMMddHHmmss";
|
||||
private static final Gson DEFAULT_GSON;
|
||||
|
||||
static {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.setDateFormat(DEFAULT_DATE_PATTERN);
|
||||
DEFAULT_GSON = builder.create();
|
||||
DEFAULT_GSON.toJson(null);
|
||||
}
|
||||
|
||||
public static String toJson(Object target) {
|
||||
return toJson(target, null, null, null);
|
||||
}
|
||||
|
||||
public static String toJson(Object target, Type targetType) {
|
||||
return toJson(target, targetType, null, null);
|
||||
}
|
||||
|
||||
public static String toMaskJson(Object target) {
|
||||
return toJson(target, null, null, null);
|
||||
}
|
||||
|
||||
public static String toMaskJson(Object target, List<String> excludeFields) {
|
||||
return toJson(target, null, null, excludeFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印目标对象的json串
|
||||
*
|
||||
* @param target 目标对象
|
||||
* @param targetType 对象类型,可为null
|
||||
* @param datePattern 日期格式,可为null,若为null则按 DEFAULT_DATE_PATTERN格式输出
|
||||
* @param excludeFields 不打印的字段,可为null
|
||||
* @return 目标对象的标准json串
|
||||
*/
|
||||
public static String toJson(Object target, Type targetType, String datePattern, final List<String> excludeFields) {
|
||||
if (target == null) {
|
||||
return EMPTY_JSON;
|
||||
}
|
||||
|
||||
Gson gson = DEFAULT_GSON;
|
||||
if (null != datePattern && !"".equals(datePattern)) {
|
||||
gson = getGson(datePattern);
|
||||
}
|
||||
if (isNotEmpty(excludeFields)) {
|
||||
gson = getStrategyGson(excludeFields);
|
||||
}
|
||||
|
||||
String result = emptyResult(target);
|
||||
try {
|
||||
if (targetType == null) {
|
||||
targetType = target.getClass();
|
||||
}
|
||||
result = gson.toJson(target, targetType);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, TypeToken<T> token) {
|
||||
return fromJson(json, token, null);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, TypeToken<T> token, String datePattern) {
|
||||
return fromJson(json, token.getType(), datePattern);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> classOfT) {
|
||||
Object object = fromJson(json, (Type) classOfT, null);
|
||||
return Primitives.wrap(classOfT).cast(object);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> classOfT, String datePattern) {
|
||||
Object object = fromJson(json, (Type) classOfT, datePattern);
|
||||
return Primitives.wrap(classOfT).cast(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json串转化为目标对象
|
||||
*
|
||||
* @param json json串
|
||||
* @param type 目标对象类型
|
||||
* @param datePattern json串中日期格式,若为null,则按两个标准日期尝试解析:DEFAULT_DATE_PATTERN和DEFAULT_DATE_PATTERN_1
|
||||
* @param <T>
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static <T> T fromJson(String json, Type type, String datePattern) {
|
||||
if (null == json || "".equals(json)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null == datePattern || "".equals(datePattern)) {
|
||||
try {
|
||||
return DEFAULT_GSON.fromJson(json, type);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Gson gson = getGson(datePattern);
|
||||
return gson.fromJson(json, type);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Gson getGson(String datePattern) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.setDateFormat(datePattern);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private static Gson getStrategyGson(final List<String> excludeFields) {
|
||||
ExclusionStrategy myExclusionStrategy = new ExclusionStrategy() {
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes fa) {
|
||||
return excludeFields != null && excludeFields.contains(fa.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
return new GsonBuilder().setExclusionStrategies(myExclusionStrategy).create();
|
||||
}
|
||||
|
||||
private static boolean isNotEmpty(final List<String> fieldNames) {
|
||||
return fieldNames != null && !fieldNames.isEmpty();
|
||||
}
|
||||
|
||||
private static String emptyResult(Object target) {
|
||||
if (target == null) {
|
||||
return EMPTY_JSON;
|
||||
}
|
||||
if (target instanceof Collection
|
||||
|| target instanceof Iterator
|
||||
|| target instanceof Enumeration
|
||||
|| target.getClass().isArray()) {
|
||||
return EMPTY_JSON_ARRAY;
|
||||
}
|
||||
return EMPTY_JSON;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.hzs.third.pay.jdpay.util;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPayConstant;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPayNewConfig;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPaySecurity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* 京东支付接口工具类
|
||||
*
|
||||
*************************************************/
|
||||
public class JdPayApiUtil {
|
||||
|
||||
/**
|
||||
* 加密和签名
|
||||
*/
|
||||
public static String encryptAndSignature(JdPayNewConfig jdPayNewConfig, String reqNo, String jsonParam) throws IOException {
|
||||
// 组装公共请求参数
|
||||
Map<String, String> commonParam = fillCommonParam(jdPayNewConfig.getMerchantNo(), reqNo);
|
||||
// 加密
|
||||
byte[] dataBytes = jsonParam.getBytes(StandardCharsets.UTF_8);
|
||||
JdPaySecurity se = new JdPaySecurity();
|
||||
String encData = se.signEnvelop(jdPayNewConfig.getPriCert(), jdPayNewConfig.getPriCertPwd(), jdPayNewConfig.getPubCert(), dataBytes);
|
||||
commonParam.put(JdPayConstant.ENC_DATA, encData);
|
||||
// 签名
|
||||
String sign = SignUtil.sign(commonParam, JdPayConstant.SHA256, jdPayNewConfig.getSignKey(), JdPayConstant.UTF8);
|
||||
commonParam.put(JdPayConstant.SIGN_DATA, sign);
|
||||
return GsonUtil.toJson(commonParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密和验签
|
||||
*/
|
||||
public static String decryptAndVerifySign(JdPayNewConfig jdPayNewConfig, String respText) throws Exception {
|
||||
Map<String, String> respMap = GsonUtil.fromJson(respText, new TypeToken<Map<String, String>>() {
|
||||
});
|
||||
String code = respMap.get(JdPayConstant.CODE);
|
||||
if (!JdPayConstant.SUCCESS_CODE.equals(code)) {
|
||||
return respText;
|
||||
}
|
||||
if (!respMap.containsKey(JdPayConstant.SIGN_DATA)) {
|
||||
throw new Exception(String.format("No sign field in response: %s", respText));
|
||||
}
|
||||
String sign = respMap.remove(JdPayConstant.SIGN_DATA);
|
||||
String signType = respMap.get(JdPayConstant.SIGN_TYPE);
|
||||
String charset = respMap.get(JdPayConstant.CHARSET);
|
||||
boolean isRespSignValid = SignUtil.verify(sign, respMap, signType, jdPayNewConfig.getSignKey(), charset);
|
||||
if (!isRespSignValid) {
|
||||
throw new Exception(String.format("Invalid sign value in response: %s", respText));
|
||||
}
|
||||
return SignUtil.decodeBase64(respMap.get(JdPayConstant.RESP_DATA), respMap.get(JdPayConstant.CHARSET), false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装api公共参数赋值
|
||||
*/
|
||||
private static Map<String, String> fillCommonParam(String merchantNo, String reqNo) {
|
||||
|
||||
Map<String, String> reqMap = new HashMap<>();
|
||||
// 二级商户号
|
||||
reqMap.put(JdPayConstant.MERCHANT_NO, merchantNo);
|
||||
//商户生成的唯一标识,可以与outTradeNo一致
|
||||
reqMap.put(JdPayConstant.REQ_NO, reqNo);
|
||||
//字符集
|
||||
reqMap.put(JdPayConstant.CHARSET, JdPayConstant.UTF8);
|
||||
//固定值
|
||||
reqMap.put(JdPayConstant.FORMAT_TYPE, JdPayConstant.JSON);
|
||||
//签名类型
|
||||
reqMap.put(JdPayConstant.SIGN_TYPE, JdPayConstant.SHA256);
|
||||
//固定值,证书加密
|
||||
reqMap.put(JdPayConstant.ENC_TYPE, JdPayConstant.AP7);
|
||||
return reqMap;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package com.hzs.third.pay.jdpay.util;
|
||||
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPayConstant;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.BaseNCodec;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class SignUtil {
|
||||
|
||||
private static final String[] HEX_STRINGS;
|
||||
|
||||
static {
|
||||
HEX_STRINGS = new String[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
StringBuilder d = new StringBuilder(2);
|
||||
char ch = Character.forDigit(((byte) i >> 4) & 0x0F, 16);
|
||||
d.append(Character.toUpperCase(ch));
|
||||
ch = Character.forDigit((byte) i & 0x0F, 16);
|
||||
d.append(Character.toUpperCase(ch));
|
||||
HEX_STRINGS[i] = d.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算签名
|
||||
*
|
||||
* @param map 有key和value的map,使用=和&拼接所有参数,
|
||||
* "sign_type", "sign_data", "encrypt_type", "encrypt_data"不参加计算
|
||||
* @param algorithm 签名算法 MD5, SHA-1, SHA-256
|
||||
* @param salt 签名密钥
|
||||
* @param charset 字符串编码
|
||||
* @return 签名
|
||||
*/
|
||||
public static String sign(Map<String, String> map, String algorithm, String salt, String charset) throws UnsupportedEncodingException {
|
||||
String linkString = map2LinkString(map);
|
||||
String data = linkString + salt;
|
||||
return digestHex(algorithm, data, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名正确性。
|
||||
*
|
||||
* @param sign 签名数据
|
||||
* @param map 数据
|
||||
* @param algorithm 签名算法 MD5, SHA-1, SHA-256
|
||||
* @param salt 签名密钥
|
||||
* @param charset 字符串
|
||||
* @return 验证结果
|
||||
*/
|
||||
public static boolean verify(String sign,
|
||||
Map<String, String> map,
|
||||
String algorithm,
|
||||
String salt,
|
||||
String charset) throws UnsupportedEncodingException {
|
||||
if (sign == null || "".equals(sign.trim()) || map.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
String newSign = sign(map, algorithm, salt, charset);
|
||||
return newSign.equals(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证页面回调
|
||||
*
|
||||
* @param respMap 页面回调参数
|
||||
* @param signKey signKey
|
||||
* @return 验证结果
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static boolean verifyPageCallBackSign(Map<String, String> respMap, String signKey) throws UnsupportedEncodingException {
|
||||
String sign = respMap.remove("sign");
|
||||
String newSign = sign(respMap, JdPayConstant.SHA256, signKey, JdPayConstant.UTF8);
|
||||
return newSign.equals(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将MAP数据用=和&拼接成String
|
||||
*
|
||||
* @param map 数据
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String map2LinkString(Map<String, String> map) {
|
||||
ArrayList<String> mapKeys = new ArrayList<String>(map.keySet());
|
||||
Collections.sort(mapKeys);
|
||||
StringBuilder link = new StringBuilder(2048);
|
||||
for (String key : mapKeys) {
|
||||
String value = map.get(key);
|
||||
// 属性为空不参与签名
|
||||
if (value == null || "".equals(value.trim())) {
|
||||
continue;
|
||||
}
|
||||
link.append(key).append("=").append(value).append("&");
|
||||
}
|
||||
// 删除末尾的&
|
||||
link.deleteCharAt(link.length() - 1);
|
||||
return link.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对数据进行指定算法的数据摘要
|
||||
*
|
||||
* @param algorithm 算法名,如MD2, MD5, SHA-1, SHA-256, SHA-512
|
||||
* @param data 待计算的数据
|
||||
* @param charset 字符串的编码
|
||||
* @return 摘要结果
|
||||
*/
|
||||
public static String digestHex(String algorithm, String data, String charset) throws UnsupportedEncodingException {
|
||||
byte[] digest = DigestUtils.getDigest(algorithm).digest(data.getBytes(charset));
|
||||
return hexString(digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换成HEX String
|
||||
*
|
||||
* @param b
|
||||
* @return HEX String
|
||||
*/
|
||||
public static String hexString(byte[] b) {
|
||||
StringBuilder d = new StringBuilder(b.length * 2);
|
||||
for (byte aB : b) {
|
||||
d.append(HEX_STRINGS[(int) aB & 0xFF]);
|
||||
}
|
||||
return d.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对数据进行BASE64解码
|
||||
*
|
||||
* @param base64Data Base64数据
|
||||
* @param charset 解码的编码格式
|
||||
* @param urlSafe 是否是URL安全的,如果为true,则将会被URL编码的'+', '/'转成'-', '_'
|
||||
* @param oneLine 是否是一行
|
||||
* @return 解码后数据
|
||||
*/
|
||||
public static String decodeBase64(String base64Data, String charset, boolean urlSafe, boolean oneLine) throws UnsupportedEncodingException {
|
||||
Base64 base64 = oneLine ? new Base64(BaseNCodec.MIME_CHUNK_SIZE, null, urlSafe) : new Base64(urlSafe);
|
||||
byte[] binaryData = base64.decode(base64Data);
|
||||
return new String(binaryData, charset);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.hzs.third.pay.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求子表(分账) Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
public interface TOnlinePaymentSepAccDMapper extends BaseMapper<TOnlinePaymentSepAccD> {
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.hzs.third.pay.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求主表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
public interface TOnlinePaymentSepAccMapper extends BaseMapper<TOnlinePaymentSepAcc> {
|
||||
TOnlinePaymentSepAcc getSepAccByOrderCode(@Param("orderCode") String orderCode);
|
||||
}
|
|
@ -12,23 +12,34 @@ import lombok.Data;
|
|||
@Data
|
||||
public class OnlinePayConfigParam {
|
||||
|
||||
/**
|
||||
* 宝付微信
|
||||
*/
|
||||
private Boolean pay11 = Boolean.FALSE;
|
||||
/**
|
||||
* 宝付微信扫码
|
||||
*/
|
||||
private Boolean pay12 = Boolean.FALSE;
|
||||
// /**
|
||||
// * 京东银行卡
|
||||
// */
|
||||
// private Boolean pay4 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 汇付微信
|
||||
* 京东收银台(H5)
|
||||
*/
|
||||
private Boolean pay13 = Boolean.FALSE;
|
||||
private Boolean pay5 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 汇付银行卡
|
||||
* 京东收银台(PC)
|
||||
*/
|
||||
private Boolean pay15 = Boolean.FALSE;
|
||||
private Boolean pay6 = Boolean.FALSE;
|
||||
|
||||
// /**
|
||||
// * 微信APP
|
||||
// */
|
||||
// private Boolean pay20 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 通联微信
|
||||
*/
|
||||
private Boolean pay32 = Boolean.FALSE;
|
||||
/**
|
||||
* 通联银行卡
|
||||
*/
|
||||
private Boolean pay33 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 新汇付PC微信扫码支付
|
||||
|
@ -38,13 +49,5 @@ public class OnlinePayConfigParam {
|
|||
* 新汇付PC支付宝扫码支付
|
||||
*/
|
||||
private Boolean pay82 = Boolean.FALSE;
|
||||
/**
|
||||
* 新汇付H5微信支付
|
||||
*/
|
||||
private Boolean pay83 = Boolean.FALSE;
|
||||
/**
|
||||
* 新汇付H5支付宝支付
|
||||
*/
|
||||
private Boolean pay84 = Boolean.FALSE;
|
||||
|
||||
}
|
||||
|
|
|
@ -75,4 +75,10 @@ public class OnlinePaymentParam {
|
|||
private Integer systemType;
|
||||
|
||||
|
||||
/**
|
||||
* 订单类型 EOrderType
|
||||
* -1为充值
|
||||
*/
|
||||
private Integer orderType;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package com.hzs.third.pay.param;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 支付入参
|
||||
*/
|
||||
@Data
|
||||
public class PayParam {
|
||||
|
||||
/**
|
||||
* 业务类型(EPayBusinessType)
|
||||
*/
|
||||
private Integer businessType;
|
||||
/**
|
||||
* 业务单号
|
||||
*/
|
||||
private String businessCode;
|
||||
|
||||
/**
|
||||
* 支付渠道(EPayChannel)
|
||||
*/
|
||||
private Integer payChannel;
|
||||
/**
|
||||
* 支付类型(EPayType)
|
||||
*/
|
||||
private Integer payType;
|
||||
|
||||
/**
|
||||
* 绑卡编号(银行卡支付使用)
|
||||
*/
|
||||
private String bindCode;
|
||||
|
||||
/**
|
||||
* 小程序支付标记(为0则小程序支付)
|
||||
*/
|
||||
private Integer appletFlag;
|
||||
|
||||
/**
|
||||
* 支付-前端回调页面的扩展参数
|
||||
*/
|
||||
private String extParam;
|
||||
}
|
|
@ -47,4 +47,9 @@ public class UnifiedOrderParam implements Serializable {
|
|||
*/
|
||||
private Integer appletFlag;
|
||||
|
||||
/**
|
||||
* 支付-前端回调页面的扩展参数
|
||||
*/
|
||||
private String extParam;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.hzs.third.pay.provider;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.hzs.common.core.enums.EPayChannel;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.third.pay.ITOnlinePaymentServiceApi;
|
||||
import com.hzs.third.pay.service.IRefundService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentService;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@DubboService
|
||||
public class ITOnlinePaymentServiceProvider implements ITOnlinePaymentServiceApi {
|
||||
@Autowired
|
||||
private ITOnlinePaymentService itOnlinePaymentService;
|
||||
@Autowired
|
||||
private IRefundService iRefundService;
|
||||
@Override
|
||||
public R<TOnlinePayment> getOnlinePayment(String orderNo) {
|
||||
LambdaQueryWrapper<TOnlinePayment> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessCode, orderNo);
|
||||
return R.ok(itOnlinePaymentService.getOne(queryWrapper, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<String> refund(String orderNo, Long userId) {
|
||||
LambdaQueryWrapper<TOnlinePayment> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessCode, orderNo);
|
||||
TOnlinePayment tOnlinePayment = itOnlinePaymentService.getOne(queryWrapper, false);
|
||||
if(ObjectUtil.isNotEmpty(tOnlinePayment)){
|
||||
if (Objects.requireNonNull(EPayChannel.getEnumByValue(tOnlinePayment.getPayChannel())) == EPayChannel.JD) {
|
||||
return R.ok(iRefundService.jdRefundDivision(orderNo, userId));
|
||||
}
|
||||
}
|
||||
return R.fail();
|
||||
}
|
||||
}
|
|
@ -1,23 +1,21 @@
|
|||
package com.hzs.third.pay.service;
|
||||
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.hzs.common.core.enums.EDataSource;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
|
||||
/**
|
||||
* @Description: 京东支付服务
|
||||
* @Author: jiang chao
|
||||
* @Time: 2025/2/6 9:57
|
||||
* @Classname: IJdPayService
|
||||
* @PackageName: com.hzs.third.pay.service
|
||||
* 京东支付服务
|
||||
*/
|
||||
public interface IJdPayService {
|
||||
|
||||
/**
|
||||
* 京东收银台支付
|
||||
* 收银台支付
|
||||
*
|
||||
* @param tOnlinePayment 在线支付信息
|
||||
* @param onlinePayment
|
||||
* @param dataSource
|
||||
* @return
|
||||
*/
|
||||
R<String> cashDeskPay(TOnlinePayment tOnlinePayment);
|
||||
R<String> cashRegister(TOnlinePayment onlinePayment, EDataSource dataSource);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ public interface IPayService {
|
|||
boolean notifyHandle(String businessType, String businessCode, String originalOrder,
|
||||
String payNumber, Date payTime, BigDecimal payMoney,
|
||||
EPayChannel ePayChannel, String channelNumber);
|
||||
boolean notifyHandle(String businessType, String businessCode, String originalOrder,
|
||||
String payNumber, Date payTime, BigDecimal payMoney,
|
||||
EPayChannel ePayChannel, String channelNumber, Integer payType, String acqOrderId);
|
||||
|
||||
|
||||
/**
|
||||
* 业务处理重试
|
||||
|
|
|
@ -2,36 +2,24 @@ package com.hzs.third.pay.service;
|
|||
|
||||
import com.hzs.common.core.enums.EPayChannel;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.domain.third.pay.TOnlineRefund;
|
||||
import com.hzs.third.pay.dto.RefundDTO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @Description: 基础退款服务
|
||||
* @Author: jiang chao
|
||||
* @Time: 2023/8/16 17:00
|
||||
* @Classname: IRefundService
|
||||
* @PackageName: com.hzs.third.pay.service
|
||||
* 基础退款服务
|
||||
*/
|
||||
public interface IRefundService {
|
||||
|
||||
/**
|
||||
* 新汇付退款处理
|
||||
* 通联退款处理
|
||||
*
|
||||
* @param tOnlinePayment 在线支付信息
|
||||
* @param refundDTO 业务类型
|
||||
* @param tOnlinePayment 退款对应支付信息
|
||||
* @return
|
||||
*/
|
||||
String huifuRefundHandle(TOnlinePayment tOnlinePayment);
|
||||
|
||||
/**
|
||||
* 新汇付退款查询
|
||||
*
|
||||
* @param tOnlineRefund 退款信息
|
||||
* @return
|
||||
*/
|
||||
String queryHuifuRefundHandle(TOnlineRefund tOnlineRefund);
|
||||
|
||||
String allInRefundHandle(RefundDTO refundDTO, TOnlinePayment tOnlinePayment);
|
||||
|
||||
/**
|
||||
* 退款回调成功处理
|
||||
|
@ -56,4 +44,25 @@ public interface IRefundService {
|
|||
*/
|
||||
boolean notifyErrorHandle(EPayChannel ePayChannel, String refundCode, String refundNumber, String errorMsg);
|
||||
|
||||
|
||||
/**
|
||||
* 京东退款处理
|
||||
*
|
||||
* @param refundDTO 业务类型
|
||||
* @param tOnlinePayment 退款对应支付信息
|
||||
* @return
|
||||
*/
|
||||
String jdRefundHandle(RefundDTO refundDTO, TOnlinePayment tOnlinePayment);
|
||||
|
||||
/**
|
||||
* 京东收银台退款处理
|
||||
*
|
||||
* @param refundDTO 业务类型
|
||||
* @param tOnlinePayment 退款对应支付信息
|
||||
* @return
|
||||
*/
|
||||
String jdCashRefundHandle(RefundDTO refundDTO, TOnlinePayment tOnlinePayment);
|
||||
|
||||
String jdRefundDivision(String orderCode, Long userId);
|
||||
String jdQueryEnterpriseWalletBalance();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package com.hzs.third.pay.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求子表(分账) 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
public interface ITOnlinePaymentSepAccDService extends IService<TOnlinePaymentSepAccD> {
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.hzs.third.pay.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求主表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
public interface ITOnlinePaymentSepAccService extends IService<TOnlinePaymentSepAcc> {
|
||||
void saveOrUpdateReq(TOnlinePaymentSepAcc tOnlinePaymentSepAcc);
|
||||
|
||||
TOnlinePaymentSepAcc getSepAccByOrderCode(String code);
|
||||
}
|
|
@ -9,9 +9,6 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* 在线支付信息 服务类
|
||||
*
|
||||
* @author hzs
|
||||
* @since 2022-07-28
|
||||
*/
|
||||
public interface ITOnlinePaymentService extends IService<TOnlinePayment> {
|
||||
|
||||
|
|
|
@ -9,9 +9,6 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* 在线退款信息 服务类
|
||||
*
|
||||
* @author hzs
|
||||
* @since 2023-08-16
|
||||
*/
|
||||
public interface ITOnlineRefundService extends IService<TOnlineRefund> {
|
||||
|
||||
|
|
|
@ -1,23 +1,199 @@
|
|||
package com.hzs.third.pay.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.hzs.common.core.config.BdConfig;
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.hzs.common.core.enums.EDataSource;
|
||||
import com.hzs.common.core.enums.EEnv;
|
||||
import com.hzs.common.core.utils.DateUtils;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.third.pay.config.JdPayBankProperties;
|
||||
import com.hzs.third.pay.config.JdPayConfig;
|
||||
import com.hzs.third.pay.config.JdPaySeparateAccountConfig;
|
||||
import com.hzs.third.pay.config.JdPayWechatAlipayProperties;
|
||||
import com.hzs.third.pay.jdpay.dto.JdPayAggregateCreateOrderRequest;
|
||||
import com.hzs.third.pay.jdpay.dto.JdPayAggregateCreateOrderResponse;
|
||||
import com.hzs.third.pay.jdpay.dto.JdPayDivisionAccount;
|
||||
import com.hzs.third.pay.jdpay.dto.JdPayDivisionAccountTradeInfo;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPay;
|
||||
import com.hzs.third.pay.jdpay.util.GsonUtil;
|
||||
import com.hzs.third.pay.service.IJdPayService;
|
||||
import com.hzs.third.pay.service.ITOnlineCardService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentSepAccService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description: 京东支付服务
|
||||
* @Author: jiang chao
|
||||
* @Time: 2025/2/6 9:57
|
||||
* @Classname: JdPayServiceImpl
|
||||
* @PackageName: com.hzs.third.pay.service.impl
|
||||
* 京东支付服务
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class JdPayServiceImpl implements IJdPayService {
|
||||
|
||||
@Autowired
|
||||
private JdPayConfig jdPayConfig;
|
||||
@Autowired
|
||||
private ITOnlineCardService itOnlineCardService;
|
||||
@Resource(name = "jdPayBank")
|
||||
private JdPay jdPay;
|
||||
@Autowired
|
||||
private JdPayBankProperties jdPayBankProperties;
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
@Autowired
|
||||
private ITOnlinePaymentSepAccService itOnlinePaymentSepAccService;
|
||||
|
||||
@Autowired
|
||||
private ITOnlinePaymentService itOnlinePaymentService;
|
||||
|
||||
@Resource
|
||||
private JdPayWechatAlipayProperties jdPayWechatAlipayProperties;
|
||||
|
||||
@Override
|
||||
public R<String> cashDeskPay(TOnlinePayment tOnlinePayment) {
|
||||
return null;
|
||||
public R<String> cashRegister(TOnlinePayment onlinePayment, EDataSource dataSource) {
|
||||
try {
|
||||
// 交易场景(ONLINE_APP:线上移动端 ONLINE_PC:线上PC)
|
||||
String sceneType = "ONLINE_APP";
|
||||
// 交易类型(AGGRE:聚合收银台 AGGRE_QR:PC扫码)
|
||||
String tradeType = "AGGRE";
|
||||
if (null != dataSource && EDataSource.PC.getValue().equals(dataSource.getValue())) {
|
||||
sceneType = "ONLINE_PC";
|
||||
tradeType = "AGGRE_QR";
|
||||
}
|
||||
|
||||
// String userId = onlinePayment.getPkCreator().toString();
|
||||
String userId = SecurityUtils.getMemberCode();
|
||||
if (EEnv.TEST.getValue().equals(BdConfig.getEnv())) {
|
||||
userId = "T_" + userId;
|
||||
}
|
||||
|
||||
JdPayAggregateCreateOrderRequest request = JdPayAggregateCreateOrderRequest.builder()
|
||||
// 商户订单号(最大32位)
|
||||
.outTradeNo(onlinePayment.getBusinessCode())
|
||||
// 订单总金额(单位:分)
|
||||
.tradeAmount(onlinePayment.getPayMoney().multiply(new BigDecimal("100")).intValue() + "")
|
||||
// 订单创建时间(最大14位:yyyyMMddHHmmss)
|
||||
.createDate(DateUtils.parseDateToFormat(DateUtils.YAMMERERS, onlinePayment.getCreationTime()))
|
||||
// 订单有效时长(分钟)
|
||||
.tradeExpiryTime("1440")
|
||||
// 交易名称
|
||||
.tradeSubject("支付:" + onlinePayment.getBusinessCode())
|
||||
// 交易描述
|
||||
.tradeRemark("支付:" + onlinePayment.getBusinessCode())
|
||||
// 币种
|
||||
.currency("CNY")
|
||||
// 用户IP
|
||||
.userIp(InetAddress.getLocalHost().getHostAddress())
|
||||
// 通道业务类型
|
||||
.bizTp("100001")
|
||||
// 回传字段
|
||||
.returnParams(onlinePayment.getBusinessType().toString())
|
||||
// 用户标识(收银台必传)
|
||||
.userId(userId)
|
||||
// 同步通知URL(收银台必传,页面回调地址)
|
||||
.pageBackUrl(jdPayBankProperties.getPageBackUrl() + "?extParam=" + onlinePayment.getExtParam())
|
||||
.callbackUrl(jdPayBankProperties.getPageBackUrl() + "?extParam=" + onlinePayment.getExtParam())
|
||||
// 支付回调地址
|
||||
.notifyUrl(jdPayBankProperties.getNotifyUrl())
|
||||
// 交易类型
|
||||
.tradeType(tradeType)
|
||||
// 交易场景(ONLINE_APP:线上移动端 ONLINE_PC:线上PC)
|
||||
.sceneType(sceneType)
|
||||
.accessType("MINIAPP")
|
||||
.build();
|
||||
|
||||
|
||||
JdPayDivisionAccount divisionAccount = new JdPayDivisionAccount();
|
||||
List<JdPayDivisionAccountTradeInfo> divisionAccountTradeInfoList = new ArrayList<JdPayDivisionAccountTradeInfo>();
|
||||
List<TOnlinePaymentSepAccD> sepAccDList = new ArrayList<>();
|
||||
if(ObjectUtil.isNotEmpty(jdPayBankProperties)){
|
||||
List<JdPaySeparateAccountConfig> separateAccounts = jdPayBankProperties.getSeparateAccounts();
|
||||
separateAccounts.sort(Comparator.comparing(JdPaySeparateAccountConfig::getProportion).reversed());
|
||||
if(ObjectUtil.isNotEmpty(separateAccounts)){
|
||||
BigDecimal tradeAmount = onlinePayment.getPayMoney();
|
||||
BigDecimal remaining = onlinePayment.getPayMoney();
|
||||
for (int i = 0; i < separateAccounts.size(); i++) {
|
||||
JdPaySeparateAccountConfig separateAccount = separateAccounts.get(i);
|
||||
BigDecimal subTradeAmount;
|
||||
if(i == separateAccounts.size() - 1){
|
||||
subTradeAmount = remaining;
|
||||
log.info("分账 最后一个账户( 总 - 已分账 ) : {}, {}", subTradeAmount, remaining);
|
||||
onlinePayment.setSubAccountMoney(subTradeAmount);
|
||||
}else{
|
||||
subTradeAmount = tradeAmount.subtract(tradeAmount.multiply(separateAccount.getProportion().setScale(2, BigDecimal.ROUND_DOWN)).setScale(2, BigDecimal.ROUND_DOWN));
|
||||
remaining = remaining.subtract(subTradeAmount).setScale(2, BigDecimal.ROUND_DOWN);
|
||||
onlinePayment.setMainAccountMoney(subTradeAmount);
|
||||
log.info("分账 过程 : {}, {}, {}", subTradeAmount, remaining, separateAccount.getProportion().setScale(2, BigDecimal.ROUND_DOWN));
|
||||
}
|
||||
JdPayDivisionAccountTradeInfo divisionAccountTradeInfo = new JdPayDivisionAccountTradeInfo();
|
||||
divisionAccountTradeInfo.setMerchantNo(separateAccount.getAccount());
|
||||
divisionAccountTradeInfo.setOutTradeNo(onlinePayment.getBusinessCode() + "_" + (i + 1));
|
||||
divisionAccountTradeInfo.setTradeAmount(subTradeAmount.multiply(new BigDecimal(100)).intValue() + "");
|
||||
divisionAccountTradeInfoList.add(divisionAccountTradeInfo);
|
||||
sepAccDList.add(
|
||||
TOnlinePaymentSepAccD.builder()
|
||||
.account(separateAccount.getAccount())
|
||||
.proportion(separateAccount.getProportion())
|
||||
.tradeAmount(subTradeAmount)
|
||||
.outTradeNo(divisionAccountTradeInfo.getOutTradeNo())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
divisionAccount.setVersion( "V2" );
|
||||
divisionAccount.setDivisionAccountTradeInfoList(divisionAccountTradeInfoList);
|
||||
request.setDivisionAccount(GsonUtil.toJson(divisionAccount));
|
||||
|
||||
// 请求京东支付接口
|
||||
JdPayAggregateCreateOrderResponse response = jdPay.aggregateCreateOrder(request);
|
||||
TOnlinePaymentSepAcc sepAcc = TOnlinePaymentSepAcc.builder()
|
||||
.sepAccDList(sepAccDList)
|
||||
.reqContent(request.getDivisionAccount())
|
||||
.reqContentSepAcc(JSONUtil.toJsonStr(divisionAccountTradeInfoList))
|
||||
.version(divisionAccount.getVersion())
|
||||
.respContent(JSONUtil.toJsonStr(response))
|
||||
.tradeAmount(onlinePayment.getPayMoney())
|
||||
.outTradeNo(request.getOutTradeNo())
|
||||
.build();
|
||||
if ("00000".equals(response.getResultCode())) {
|
||||
// 请求响应成功
|
||||
// 京东唯一订单号
|
||||
onlinePayment.setPayNumber(response.getTradeNo());
|
||||
// 将controller内入库逻辑移至此为止
|
||||
onlinePayment.setPayMoney(null);
|
||||
itOnlinePaymentService.saveOrUpdate(onlinePayment);
|
||||
// 2025年7月1日 保存分账主表&子表
|
||||
sepAcc.setPkPayment(onlinePayment.getPkId());
|
||||
itOnlinePaymentSepAccService.saveOrUpdateReq(sepAcc);
|
||||
if ("AGGRE_QR".equals(tradeType)) {
|
||||
return R.ok(response.getQrCode());
|
||||
}
|
||||
return R.ok(response.getWebUrl());
|
||||
} else {
|
||||
log.error("京东收银台返回失败,resultDesc: {}", response.getResultDesc());
|
||||
return R.fail("调用京东收银台返回失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("京东收银台处理异常!", e);
|
||||
return R.fail("京东收银台处理异常");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.hzs.third.pay.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.hzs.common.core.constant.MagicNumberConstants;
|
||||
import com.hzs.common.core.constant.RabbitMqConstants;
|
||||
|
@ -10,7 +11,8 @@ import com.hzs.member.account.IMemberTradeServiceApi;
|
|||
import com.hzs.retail.sale.IRetailOrderServiceApi;
|
||||
import com.hzs.sale.ticket.ITicketServiceApi;
|
||||
import com.hzs.third.mq.dto.RefundOrderDTO;
|
||||
import com.hzs.third.pay.service.*;
|
||||
import com.hzs.third.pay.service.IPayService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentService;
|
||||
import com.hzs.third.pay.util.PayUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
|
@ -58,7 +60,9 @@ public class PayServiceImpl implements IPayService {
|
|||
String payNumber, Date payTime, BigDecimal payMoney,
|
||||
EPayChannel ePayChannel, String channelNumber) {
|
||||
// 校验支付信息状态、业务与支付金额是否一致等
|
||||
TOnlinePayment onlinePayment = itOnlinePaymentService.queryByBusiness(Integer.valueOf(businessType), businessCode, null);
|
||||
TOnlinePayment onlinePayment = itOnlinePaymentService.queryByBusiness(
|
||||
ObjectUtil.isNotEmpty(businessType) ? Integer.valueOf(businessType) : null
|
||||
, businessCode, null);
|
||||
if (null == onlinePayment || EPayStatus.PAID.getValue() == onlinePayment.getPayStatus()) {
|
||||
log.error("支付信息不存在或已支付");
|
||||
return false;
|
||||
|
@ -103,6 +107,60 @@ public class PayServiceImpl implements IPayService {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyHandle(String businessType, String businessCode, String originalOrder, String payNumber,
|
||||
Date payTime, BigDecimal payMoney, EPayChannel ePayChannel, String channelNumber,
|
||||
Integer payType, String acqOrderId) {
|
||||
// 校验支付信息状态、业务与支付金额是否一致等
|
||||
TOnlinePayment onlinePayment = itOnlinePaymentService.queryByBusiness(
|
||||
ObjectUtil.isNotEmpty(businessType) ? Integer.valueOf(businessType) : null
|
||||
, businessCode, null);
|
||||
if (null == onlinePayment || EPayStatus.PAID.getValue() == onlinePayment.getPayStatus()) {
|
||||
log.error("支付信息不存在或已支付");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!PayUtil.checkAmount(onlinePayment.getBusinessMoney(), payMoney)) {
|
||||
// 业务金额 大于 实际支付金额
|
||||
log.error("业务金额大于实际支付金额,支付编号:{}, 支付金额:{}", onlinePayment.getPaymentCode(), payMoney);
|
||||
}
|
||||
|
||||
onlinePayment.setPayStatus(EPayStatus.PAID.getValue());
|
||||
onlinePayment.setPayNumber(payNumber);
|
||||
onlinePayment.setPayTime(payTime);
|
||||
onlinePayment.setPayMoney(payMoney);
|
||||
onlinePayment.setOriginalOrder(originalOrder);
|
||||
onlinePayment.setChannelNumber(channelNumber);
|
||||
onlinePayment.setPkModified(MagicNumberConstants.PK_ADMIN);
|
||||
onlinePayment.setModifiedTime(new Date());
|
||||
onlinePayment.setPayType(payType);
|
||||
onlinePayment.setChannelNumber(acqOrderId);
|
||||
if (null != ePayChannel) {
|
||||
onlinePayment.setPayChannel(ePayChannel.getValue());
|
||||
}
|
||||
// 更新支付相关信息
|
||||
if (itOnlinePaymentService.updateById(onlinePayment)) {
|
||||
// 进行支付业务处理
|
||||
this.handleBusiness(onlinePayment, true);
|
||||
// 更新业务处理信息
|
||||
itOnlinePaymentService.updateById(onlinePayment);
|
||||
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("在线支付信息回调处理异常", e);
|
||||
|
||||
// 更新业务处理信息
|
||||
itOnlinePaymentService.update(Wrappers.<TOnlinePayment>lambdaUpdate()
|
||||
.eq(TOnlinePayment::getPkId, onlinePayment.getPkId())
|
||||
.set(TOnlinePayment::getCallbackStatus, ECallbackStatus.FAIL.getValue())
|
||||
.set(TOnlinePayment::getCallbackInfo, e.getMessage())
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retryHandle(TOnlinePayment tOnlinePayment, boolean mqPush) {
|
||||
// 支付业务处理
|
||||
|
|
|
@ -1,165 +1,66 @@
|
|||
package com.hzs.third.pay.service.impl;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.huifu.bspay.sdk.opps.client.BasePayClient;
|
||||
import com.huifu.bspay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
|
||||
import com.huifu.bspay.sdk.opps.core.request.V2TradePaymentScanpayRefundqueryRequest;
|
||||
import com.huifu.bspay.sdk.opps.core.utils.DateTools;
|
||||
import com.hzs.common.core.constant.MagicNumberConstants;
|
||||
import com.hzs.common.core.domain.R;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.hzs.common.core.enums.*;
|
||||
import com.hzs.common.core.utils.*;
|
||||
import com.hzs.common.core.utils.CommonUtil;
|
||||
import com.hzs.common.core.utils.DateUtils;
|
||||
import com.hzs.common.core.utils.StringUtils;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD;
|
||||
import com.hzs.common.domain.third.pay.TOnlineRefund;
|
||||
import com.hzs.common.domain.third.pay.ext.TOnlineRefundExt;
|
||||
import com.hzs.sale.refund.ISaRefundServiceApi;
|
||||
import com.hzs.third.pay.config.HuiFuConfig;
|
||||
import com.hzs.third.pay.constants.HuiFuPayConstants;
|
||||
import com.hzs.third.pay.service.IRefundService;
|
||||
import com.hzs.third.pay.service.ITOnlineRefundService;
|
||||
import com.hzs.third.pay.config.JdPayBankProperties;
|
||||
import com.hzs.third.pay.config.JdPayConfig;
|
||||
import com.hzs.third.pay.dto.RefundDTO;
|
||||
import com.hzs.third.pay.jdpay.dto.*;
|
||||
import com.hzs.third.pay.jdpay.sdk.JdPay;
|
||||
import com.hzs.third.pay.jdpay.util.GsonUtil;
|
||||
import com.hzs.third.pay.service.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description: 基础退款服务
|
||||
* @Author: jiang chao
|
||||
* @Time: 2023/8/16 17:00
|
||||
* @Classname: RefundServiceImpl
|
||||
* @PackageName: com.hzs.third.pay.service.impl
|
||||
* 基础退款服务
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class RefundServiceImpl implements IRefundService {
|
||||
|
||||
@Autowired
|
||||
private HuiFuConfig huiFuConfig;
|
||||
@Autowired
|
||||
private ITOnlineRefundService itOnlineRefundService;
|
||||
@Autowired
|
||||
private JdPayConfig jdPayConfig;
|
||||
|
||||
@DubboReference
|
||||
ISaRefundServiceApi iSaRefundServiceApi;
|
||||
|
||||
@Override
|
||||
public String huifuRefundHandle(TOnlinePayment tOnlinePayment) {
|
||||
// 返回信息
|
||||
String returnStr = null;
|
||||
try {
|
||||
// 退款单号
|
||||
String refundCode = CommonUtil.createSerialNumber(EOrderPrefix.REFUND_CODE);
|
||||
// 保存退款信息
|
||||
TOnlineRefund tOnlineRefund = TOnlineRefund.builder()
|
||||
.refundCode(refundCode)
|
||||
.businessCode(tOnlinePayment.getBusinessCode())
|
||||
.refundStatus(ERefundStatus.REFUND_REQUEST.getValue())
|
||||
.refundMoney(tOnlinePayment.getPayMoney())
|
||||
.refundChannel(tOnlinePayment.getPayChannel())
|
||||
.pkOnlinePayment(tOnlinePayment.getPkId())
|
||||
.build();
|
||||
tOnlineRefund.setPkCreator(MagicNumberConstants.PK_ADMIN);
|
||||
tOnlineRefund.setPkCountry(tOnlinePayment.getPkCountry());
|
||||
itOnlineRefundService.save(tOnlineRefund);
|
||||
@Resource(name = "jdPayBank")
|
||||
private JdPay jdPay;
|
||||
@Resource
|
||||
private JdPayBankProperties jdPayBankProperties;
|
||||
|
||||
// 组装交易参数
|
||||
V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
|
||||
// 请求日期
|
||||
request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
|
||||
// 请求流水号(保证唯一)
|
||||
request.setReqSeqId(refundCode);
|
||||
// 商户号
|
||||
request.setHuifuId(huiFuConfig.getSysId());
|
||||
// 申请退款金额
|
||||
request.setOrdAmt(new DecimalFormat("#0.00").format(tOnlinePayment.getPayMoney()));
|
||||
// 原交易请求日期
|
||||
request.setOrgReqDate(DateTools.dateToDateString(tOnlinePayment.getCreationTime(), DateTools.DATE_YYYYMMDD));
|
||||
// 设置非必填字段
|
||||
Map<String, Object> extendInfoMap = new HashMap<>();
|
||||
// 原交易流水号
|
||||
extendInfoMap.put("org_hf_seq_id", tOnlinePayment.getPayNumber());
|
||||
// 追加参数
|
||||
request.setExtendInfo(extendInfoMap);
|
||||
@Autowired
|
||||
private ITOnlinePaymentService itOnlinePaymentService;
|
||||
@Autowired
|
||||
private ITOnlinePaymentSepAccService sepAccService;
|
||||
@Autowired
|
||||
private ITOnlinePaymentSepAccDService sepAccDService;
|
||||
|
||||
log.info("新汇付退款调用参数:{}", JSONUtil.toJsonStr(request));
|
||||
|
||||
Map<String, Object> response = BasePayClient.request(request);
|
||||
|
||||
log.info("新汇付退款调用返回:{}", JSONUtil.toJsonStr(response));
|
||||
|
||||
tOnlineRefund.setRefundNumber(response.get("hf_seq_id").toString());
|
||||
if (HuiFuPayConstants.TRANS_SUCCESS.equals(response.get("trans_stat").toString())) {
|
||||
// 处理成功
|
||||
tOnlineRefund.setRefundStatus(ERefundStatus.REFUNDED.getValue());
|
||||
tOnlineRefund.setFinishTime(DateUtils.parseDateOne(response.get("trans_finish_time"), DateUtils.YAMMERERS));
|
||||
if (null != response.get("actual_ref_amt")) {
|
||||
tOnlineRefund.setFinishMoney(new BigDecimal(response.get("actual_ref_amt").toString()));
|
||||
}
|
||||
} else if (HuiFuPayConstants.TRANS_PROCESSING.equals(response.get("trans_stat").toString())) {
|
||||
// 处理中
|
||||
tOnlineRefund.setRefundStatus(ERefundStatus.REFUNDING.getValue());
|
||||
} else {
|
||||
// 退款失败
|
||||
tOnlineRefund.setRefundStatus(ERefundStatus.REFUND_FAILED.getValue());
|
||||
tOnlineRefund.setErrorMsg(response.get("resp_desc").toString());
|
||||
|
||||
log.error("新汇付退款交易失败! resp_desc: {}, bank_message: {}, hf_seq_id: {}", response.get("resp_desc"), response.get("bank_message"), response.get("hf_seq_id"));
|
||||
returnStr = "新汇付退款交易失败";
|
||||
}
|
||||
|
||||
// 更新接口返回状态
|
||||
itOnlineRefundService.updateById(tOnlineRefund);
|
||||
} catch (Exception e) {
|
||||
log.error("新汇付退款处理异常", e);
|
||||
returnStr = "新汇付退款处理异常:" + e.getMessage();
|
||||
}
|
||||
return returnStr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryHuifuRefundHandle(TOnlineRefund tOnlineRefund) {
|
||||
try {
|
||||
V2TradePaymentScanpayRefundqueryRequest request = new V2TradePaymentScanpayRefundqueryRequest();
|
||||
|
||||
// 商户号
|
||||
request.setHuifuId(huiFuConfig.getSysId());
|
||||
// 退款请求日期
|
||||
request.setOrgReqDate(DateTools.dateToDateString(tOnlineRefund.getCreationTime(), DateTools.DATE_YYYYMMDD));
|
||||
// 退款全局流水号退款请求流水号,退款全局流水号,终端订单号三选一不能都为空
|
||||
request.setOrgHfSeqId(tOnlineRefund.getRefundNumber());
|
||||
|
||||
log.info("新汇付退款查询调用参数:{}", JSONUtil.toJsonStr(request));
|
||||
|
||||
Map<String, Object> response = BasePayClient.request(request);
|
||||
|
||||
log.info("新汇付退款查询调用返回:{}", JSONUtil.toJsonStr(response));
|
||||
|
||||
if (HuiFuPayConstants.TRANS_SUCCESS.equals(response.get("trans_stat").toString())) {
|
||||
// 处理成功
|
||||
tOnlineRefund.setRefundStatus(ERefundStatus.REFUNDED.getValue());
|
||||
tOnlineRefund.setFinishTime(DateUtils.parseDateOne(response.get("trans_finish_time"), DateUtils.YAMMERERS));
|
||||
if (null != response.get("actual_ref_amt")) {
|
||||
tOnlineRefund.setFinishMoney(new BigDecimal(response.get("actual_ref_amt").toString()));
|
||||
}
|
||||
} else if (HuiFuPayConstants.TRANS_PROCESSING.equals(response.get("trans_stat").toString())) {
|
||||
// 处理中
|
||||
tOnlineRefund.setRefundStatus(ERefundStatus.REFUNDING.getValue());
|
||||
} else if (HuiFuPayConstants.TRANS_FAIL.equals(response.get("trans_stat").toString())) {
|
||||
// 退款失败
|
||||
tOnlineRefund.setRefundStatus(ERefundStatus.REFUND_FAILED.getValue());
|
||||
tOnlineRefund.setErrorMsg(response.get("resp_desc").toString());
|
||||
} else {
|
||||
return "新汇付退款查询状态:初始化,需要联系汇付技术人员处理";
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("新汇付退款查询处理异常", e);
|
||||
return "新汇付退款查询处理异常:" + e.getMessage();
|
||||
}
|
||||
public String allInRefundHandle(RefundDTO refundDTO, TOnlinePayment tOnlinePayment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -189,7 +90,6 @@ public class RefundServiceImpl implements IRefundService {
|
|||
// 退款业务处理
|
||||
if (StringUtils.isNotEmpty(onlineRefund.getPayBusinessCode())) {
|
||||
// 如果退款业务单号存在则进行业务回调处理,如果不存在则表示直接根据支付信息进行退款,不需要进行业务回调
|
||||
|
||||
if (this.handleBusiness(onlineRefund)) {
|
||||
// 更新业务处理信息
|
||||
if (itOnlineRefundService.updateById(onlineRefund)) {
|
||||
|
@ -270,19 +170,19 @@ public class RefundServiceImpl implements IRefundService {
|
|||
// 服务调用返回信息
|
||||
String resultMsg = "";
|
||||
// 根据业务类型调用具体业务处理 dubbo 服务
|
||||
switch (businessType) {
|
||||
case MEMBER_ORDER:
|
||||
// 会员订单
|
||||
R<String> saRefundR = iSaRefundServiceApi.onlinePayRefundCallback(onlineRefund.getPayBusinessCode(), onlineRefund.getBusinessCode(), onlineRefund.getRefundStatus(), onlineRefund.getErrorMsg());
|
||||
if (saRefundR.isSuccess()) {
|
||||
resultBool = true;
|
||||
} else {
|
||||
resultBool = false;
|
||||
resultMsg = saRefundR.getMsg();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
// switch (businessType) {
|
||||
// case DIRECT_SELLING:
|
||||
// // 直销订单
|
||||
// R<String> saRefundR = iSaRefundServiceApi.onlinePayRefundCallback(onlineRefund.getPayBusinessCode(), onlineRefund.getRefundCode(), onlineRefund.getRefundStatus(), onlineRefund.getErrorMsg());
|
||||
// if (saRefundR.isSuccess()) {
|
||||
// resultBool = true;
|
||||
// } else {
|
||||
// resultBool = false;
|
||||
// resultMsg = saRefundR.getMsg();
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// }
|
||||
|
||||
if (null != resultBool) {
|
||||
if (resultBool) {
|
||||
|
@ -304,4 +204,152 @@ public class RefundServiceImpl implements IRefundService {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String jdRefundHandle(RefundDTO refundDTO, TOnlinePayment tOnlinePayment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jdCashRefundHandle(RefundDTO refundDTO, TOnlinePayment tOnlinePayment) {
|
||||
try {
|
||||
// 退款金额(默认按全款退)
|
||||
BigDecimal amount = tOnlinePayment.getPayMoney();
|
||||
if (null != refundDTO.getRefundAmount()) {
|
||||
// 如果传入实际退款金额,则按实际退款金额处理
|
||||
amount = refundDTO.getRefundAmount();
|
||||
}
|
||||
|
||||
// 退款编号
|
||||
String refundCode = CommonUtil.createSerialNumber(EOrderPrefix.REFUND_CODE);
|
||||
// 当前时间
|
||||
Date nowDate = new Date();
|
||||
|
||||
JdPayRefundRequest request = JdPayRefundRequest.builder()
|
||||
// 退款订单号
|
||||
.outTradeNo(refundCode)
|
||||
// 原订单号(需要退款的订单号)
|
||||
.originalOutTradeNo(tOnlinePayment.getBusinessCode())
|
||||
// 退款时间
|
||||
.tradeDate(DateUtils.parseDateToFormat(DateUtils.YAMMERERS, nowDate))
|
||||
// 退款金额
|
||||
.tradeAmount(amount.multiply(new BigDecimal("100")).intValue() + "")
|
||||
// 货币种类
|
||||
.currency("CNY")
|
||||
// 退款回调地址
|
||||
.notifyUrl(jdPayBankProperties.getRefundNotifyUrl())
|
||||
// 回传信息
|
||||
// .returnParams("")
|
||||
.build();
|
||||
|
||||
// 请求京东退款接口
|
||||
JdPayRefundResponse response = jdPay.refund(request);
|
||||
|
||||
if ("0000".equals(response.getResultCode())) {
|
||||
// 请求响应成功
|
||||
// 申请退款成功,保存退款
|
||||
TOnlineRefund tOnlineRefund = new TOnlineRefund();
|
||||
tOnlineRefund.setRefundCode(refundCode);
|
||||
tOnlineRefund.setPkOnlinePayment(tOnlinePayment.getPkId());
|
||||
tOnlineRefund.setBusinessCode(refundDTO.getRefundBusinessCode());
|
||||
tOnlineRefund.setRefundMoney(amount);
|
||||
tOnlineRefund.setRefundChannel(tOnlinePayment.getPayChannel());
|
||||
tOnlineRefund.setRefundNumber(response.getTradeNo());
|
||||
tOnlineRefund.setPkCountry(refundDTO.getPkCountry());
|
||||
tOnlineRefund.setPkCreator(refundDTO.getUserId());
|
||||
if (itOnlineRefundService.save(tOnlineRefund)) {
|
||||
return null;
|
||||
} else {
|
||||
log.error("调用京东收银台退款入库处理失败,desc: {}", response.getResultDesc());
|
||||
return "退款失败,请联系系统管理员处理";
|
||||
}
|
||||
}
|
||||
log.error("调用京东收银台退款处理失败,desc: {}", response.getResultDesc());
|
||||
return "退款失败,请重试";
|
||||
} catch (Exception e) {
|
||||
log.error("调用京东收银台退款处理返回异常!", e);
|
||||
return "退款异常,请重试";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jdRefundDivision(String orderCode, Long userId) {
|
||||
TOnlinePaymentSepAcc sepAcc = sepAccService.getSepAccByOrderCode(orderCode);
|
||||
LambdaQueryWrapper<TOnlinePaymentSepAccD> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(TOnlinePaymentSepAccD::getPkSepAcc, sepAcc.getPkId());
|
||||
queryWrapper.eq(TOnlinePaymentSepAccD::getDelFlag, EDelFlag.UN_DELETE.getValue());
|
||||
queryWrapper.orderByAsc(TOnlinePaymentSepAccD::getPkId);
|
||||
LambdaQueryWrapper<TOnlinePayment> paymentQueryWrapper = new LambdaQueryWrapper<>();
|
||||
paymentQueryWrapper.eq(TOnlinePayment::getBusinessCode, orderCode);
|
||||
TOnlinePayment tOnlinePayment = itOnlinePaymentService.getOne(paymentQueryWrapper, false);
|
||||
List<TOnlinePaymentSepAccD> sepAccDList = sepAccDService.list(queryWrapper);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String now = sdf.format(new Date());
|
||||
String refundCode = "R_" + orderCode;
|
||||
JdPayRefundRequest request = JdPayRefundRequest.builder()
|
||||
.outTradeNo("R_" + orderCode)
|
||||
.originalOutTradeNo(orderCode)
|
||||
.tradeAmount(sepAcc.getTradeAmount().multiply(new BigDecimal("100")).intValue() + "")
|
||||
.currency("CNY")
|
||||
.tradeDate(now)
|
||||
.returnParams("")
|
||||
.notifyUrl(jdPayBankProperties.getRefundNotifyUrl())
|
||||
.build();
|
||||
|
||||
JdPayDivisionAccountRefund divisionAccountRefund = new JdPayDivisionAccountRefund();
|
||||
List<JdPayDivisionAccountRefundInfo> divisionAccountTradeInfoList = new ArrayList<>();
|
||||
for (int i = 0; i < sepAccDList.size(); i++) {
|
||||
TOnlinePaymentSepAccD sepAccD = sepAccDList.get(i);
|
||||
JdPayDivisionAccountRefundInfo divisionAccountTradeInfo = new JdPayDivisionAccountRefundInfo();
|
||||
divisionAccountTradeInfo.setMerchantNo(sepAccD.getAccount());
|
||||
divisionAccountTradeInfo.setOutTradeNo("R_" + orderCode + "_" + ( i + 1 ));
|
||||
divisionAccountTradeInfo.setOriginalOutTradeNo(sepAccD.getOutTradeNo());
|
||||
divisionAccountTradeInfo.setTradeAmount(sepAccD.getTradeAmount().multiply(new BigDecimal("100")).intValue() + "");
|
||||
divisionAccountTradeInfoList.add(divisionAccountTradeInfo);
|
||||
}
|
||||
divisionAccountRefund.setDivisionAccountRefundInfoList(divisionAccountTradeInfoList);
|
||||
request.setDivisionAccountRefund(GsonUtil.toJson(divisionAccountRefund));
|
||||
try {
|
||||
JdPayRefundResponse response = jdPay.refund(request);
|
||||
log.info("JdPayRefundResponse -> {}", JSONUtil.toJsonStr(response));
|
||||
if ("0000".equals(response.getResultCode())) {
|
||||
log.info("提交退款成功");
|
||||
TOnlineRefund tOnlineRefund = new TOnlineRefund();
|
||||
tOnlineRefund.setRefundCode(refundCode);
|
||||
tOnlineRefund.setPkOnlinePayment(tOnlinePayment.getPkId());
|
||||
tOnlineRefund.setBusinessCode(tOnlinePayment.getBusinessCode());
|
||||
tOnlineRefund.setRefundMoney(tOnlinePayment.getPayMoney());
|
||||
tOnlineRefund.setRefundChannel(tOnlinePayment.getPayChannel());
|
||||
tOnlineRefund.setRefundNumber(response.getTradeNo());
|
||||
tOnlineRefund.setPkCountry(1);
|
||||
tOnlineRefund.setPkCreator(userId);
|
||||
itOnlineRefundService.save(tOnlineRefund);
|
||||
return "提交退款成功";
|
||||
} else {
|
||||
log.info("提交退款失败");
|
||||
return "提交退款失败!["+response.getResultDesc()+"]";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return "提交退款异常! ["+e.getMessage()+"]";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jdQueryEnterpriseWalletBalance() {
|
||||
JdPayQueryEnterpriseWalletBalanceRequest request1 = JdPayQueryEnterpriseWalletBalanceRequest.builder()
|
||||
.accountNo("153428607005")
|
||||
.build();
|
||||
JdPayQueryEnterpriseWalletBalanceRequest request2 = JdPayQueryEnterpriseWalletBalanceRequest.builder()
|
||||
.accountNo("153428607007")
|
||||
.build();
|
||||
try {
|
||||
JdPayQueryEnterpriseWalletBalanceResponse response1 = jdPay.queryEnterpriseWalletBalance(request1);
|
||||
log.info("response1 -> {}", JSONUtil.toJsonStr(response1));
|
||||
JdPayQueryEnterpriseWalletBalanceResponse response2 = jdPay.queryEnterpriseWalletBalance(request2);
|
||||
log.info("response2 -> {}", JSONUtil.toJsonStr(response2));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.hzs.third.pay.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD;
|
||||
import com.hzs.third.pay.mapper.TOnlinePaymentSepAccDMapper;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentSepAccDService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求子表(分账) 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
@Service
|
||||
public class TOnlinePaymentSepAccDServiceImpl extends ServiceImpl<TOnlinePaymentSepAccDMapper, TOnlinePaymentSepAccD> implements ITOnlinePaymentSepAccDService {
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.hzs.third.pay.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hzs.common.core.enums.EDelFlag;
|
||||
import com.hzs.common.core.utils.DateUtils;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD;
|
||||
import com.hzs.common.security.utils.SecurityUtils;
|
||||
import com.hzs.third.pay.mapper.TOnlinePaymentSepAccMapper;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentSepAccDService;
|
||||
import com.hzs.third.pay.service.ITOnlinePaymentSepAccService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付请求主表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author bd
|
||||
* @since 2025-07-01
|
||||
*/
|
||||
@Service
|
||||
public class TOnlinePaymentSepAccServiceImpl extends ServiceImpl<TOnlinePaymentSepAccMapper, TOnlinePaymentSepAcc> implements ITOnlinePaymentSepAccService {
|
||||
|
||||
@Autowired
|
||||
private ITOnlinePaymentSepAccDService itOnlinePaymentSepAccDService;
|
||||
@Override
|
||||
public void saveOrUpdateReq(TOnlinePaymentSepAcc tOnlinePaymentSepAcc) {
|
||||
LambdaQueryWrapper<TOnlinePaymentSepAcc> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(TOnlinePaymentSepAcc::getPkPayment, tOnlinePaymentSepAcc.getPkPayment());
|
||||
TOnlinePaymentSepAcc source = this.getOne(wrapper, false);
|
||||
if(ObjectUtil.isNotEmpty(source)){
|
||||
tOnlinePaymentSepAcc.setPkId(source.getPkId());
|
||||
}else{
|
||||
tOnlinePaymentSepAcc.setCreationTime(DateUtils.currentDateTime());
|
||||
tOnlinePaymentSepAcc.setPkCreator(SecurityUtils.getUserId());
|
||||
}
|
||||
tOnlinePaymentSepAcc.setDelFlag(EDelFlag.UN_DELETE.getValue());
|
||||
tOnlinePaymentSepAcc.setModifiedTime(DateUtils.currentDateTime());
|
||||
tOnlinePaymentSepAcc.setPkModified(SecurityUtils.getUserId());
|
||||
this.saveOrUpdate(tOnlinePaymentSepAcc);
|
||||
LambdaQueryWrapper<TOnlinePaymentSepAccD> wrapperD = new LambdaQueryWrapper<>();
|
||||
wrapperD.eq(TOnlinePaymentSepAccD::getPkSepAcc, tOnlinePaymentSepAcc.getPkId());
|
||||
itOnlinePaymentSepAccDService.remove(wrapperD);
|
||||
if(CollUtil.isNotEmpty(tOnlinePaymentSepAcc.getSepAccDList())){
|
||||
for (TOnlinePaymentSepAccD tOnlinePaymentSepAccD : tOnlinePaymentSepAcc.getSepAccDList()) {
|
||||
tOnlinePaymentSepAccD.setPkSepAcc(tOnlinePaymentSepAcc.getPkId());
|
||||
tOnlinePaymentSepAccD.setCreationTime(DateUtils.currentDateTime());
|
||||
tOnlinePaymentSepAccD.setPkCreator(SecurityUtils.getUserId());
|
||||
tOnlinePaymentSepAccD.setModifiedTime(DateUtils.currentDateTime());
|
||||
tOnlinePaymentSepAccD.setPkModified(SecurityUtils.getUserId());
|
||||
tOnlinePaymentSepAccD.setDelFlag(EDelFlag.UN_DELETE.getValue());
|
||||
}
|
||||
itOnlinePaymentSepAccDService.saveBatch(tOnlinePaymentSepAcc.getSepAccDList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TOnlinePaymentSepAcc getSepAccByOrderCode(String code) {
|
||||
return baseMapper.getSepAccByOrderCode(code);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
package com.hzs.third.pay.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hzs.common.core.enums.EOrderType;
|
||||
import com.hzs.common.domain.third.pay.TOnlinePayment;
|
||||
import com.hzs.common.domain.third.pay.ext.TOnlinePaymentExt;
|
||||
import com.hzs.third.pay.mapper.TOnlinePaymentMapper;
|
||||
|
@ -36,7 +38,9 @@ public class TOnlinePaymentServiceImpl extends ServiceImpl<TOnlinePaymentMapper,
|
|||
if (null != pkCountry) {
|
||||
queryWrapper.eq(TOnlinePayment::getPkCountry, pkCountry);
|
||||
}
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessType, businessType);
|
||||
if(ObjectUtil.isNotEmpty(businessType)){
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessType, businessType);
|
||||
}
|
||||
queryWrapper.eq(TOnlinePayment::getBusinessCode, businessCode);
|
||||
return baseMapper.selectOne(queryWrapper);
|
||||
}
|
||||
|
@ -51,7 +55,15 @@ public class TOnlinePaymentServiceImpl extends ServiceImpl<TOnlinePaymentMapper,
|
|||
|
||||
@Override
|
||||
public List<TOnlinePaymentExt> queryList(OnlinePaymentParam param, Integer pkCountry) {
|
||||
return baseMapper.queryList(param, pkCountry);
|
||||
List<TOnlinePaymentExt> result = baseMapper.queryList(param, pkCountry);
|
||||
for (TOnlinePaymentExt tOnlinePaymentExt : result) {
|
||||
if(ObjectUtil.isNotEmpty(tOnlinePaymentExt.getOrderType())){
|
||||
tOnlinePaymentExt.setOrderTypeVal(EOrderType.getLabelByValue(tOnlinePaymentExt.getOrderType()));
|
||||
}else{
|
||||
tOnlinePaymentExt.setOrderTypeVal("充值订单");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,52 @@ import lombok.Data;
|
|||
@Data
|
||||
public class OnlinePayConfigVO {
|
||||
|
||||
/**
|
||||
* 京东银行卡
|
||||
*/
|
||||
private Boolean pay4 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 京东收银台(H5)
|
||||
*/
|
||||
private Boolean pay5 = Boolean.FALSE;
|
||||
/**
|
||||
* 京东收银台(PC)
|
||||
*/
|
||||
private Boolean pay6 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 宝付微信
|
||||
*/
|
||||
private Boolean pay11 = Boolean.FALSE;
|
||||
/**
|
||||
* 宝付微信扫码
|
||||
*/
|
||||
private Boolean pay12 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 汇付微信
|
||||
*/
|
||||
private Boolean pay13 = Boolean.FALSE;
|
||||
/**
|
||||
* 汇付银行卡
|
||||
*/
|
||||
private Boolean pay15 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 微信APP
|
||||
*/
|
||||
private Boolean pay20 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 通联微信
|
||||
*/
|
||||
private Boolean pay32 = Boolean.FALSE;
|
||||
/**
|
||||
* 通联银行卡
|
||||
*/
|
||||
private Boolean pay33 = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 新汇付PC微信扫码支付
|
||||
*/
|
||||
|
@ -20,13 +66,5 @@ public class OnlinePayConfigVO {
|
|||
* 新汇付PC支付宝扫码支付
|
||||
*/
|
||||
private Boolean pay82 = Boolean.FALSE;
|
||||
/**
|
||||
* 新汇付H5微信支付
|
||||
*/
|
||||
private Boolean pay83 = Boolean.FALSE;
|
||||
/**
|
||||
* 新汇付H5支付宝支付
|
||||
*/
|
||||
private Boolean pay84 = Boolean.FALSE;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.hzs.third.pay.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.hzs.common.core.annotation.BigDecimalFormat;
|
||||
import com.hzs.common.core.annotation.Excel;
|
||||
import com.hzs.common.core.annotation.Transaction;
|
||||
import com.hzs.common.core.constant.EnumsPrefixConstants;
|
||||
|
@ -144,4 +146,22 @@ public class OnlinePaymentVO {
|
|||
*/
|
||||
private String callbackInfo;
|
||||
|
||||
/**
|
||||
* 主账户金额
|
||||
*/
|
||||
@Excel(name = "主账户金额")
|
||||
@BigDecimalFormat
|
||||
private BigDecimal mainAccountMoney;
|
||||
|
||||
/**
|
||||
* 子账户金额
|
||||
*/
|
||||
@Excel(name = "子账户金额")
|
||||
@BigDecimalFormat
|
||||
private BigDecimal subAccountMoney;
|
||||
|
||||
private Integer orderType;
|
||||
|
||||
@Excel(name = "订单类型")
|
||||
private String orderTypeVal;
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -30,13 +30,14 @@
|
|||
|
||||
<!-- 查询列表 -->
|
||||
<select id="queryList" resultType="com.hzs.common.domain.third.pay.ext.TOnlinePaymentExt">
|
||||
select top.*, cm.member_code, cm.member_name, cm.phone
|
||||
select top.*, cm.member_code, cm.member_name,
|
||||
so.order_type orderType
|
||||
from T_ONLINE_PAYMENT top
|
||||
left join cu_member cm
|
||||
on cm.pk_id = top.pk_creator
|
||||
left join sa_order so on so.ORDER_CODE = top.business_code
|
||||
where top.del_flag = 0
|
||||
and top.pk_country = #{pkCountry}
|
||||
and cm.system_type = #{param.systemType}
|
||||
<if test="param.memberCode != null and param.memberCode != ''">
|
||||
and cm.member_code like #{param.memberCode} || '%'
|
||||
</if>
|
||||
|
@ -72,6 +73,12 @@
|
|||
<if test="param.payNumber != null">
|
||||
and top.pay_number like #{param.payNumber} || '%'
|
||||
</if>
|
||||
<if test="param.orderType != null and param.orderType > 0">
|
||||
and so.order_type = #{param.orderType}
|
||||
</if>
|
||||
<if test="param.orderType != null and param.orderType == -1">
|
||||
and so.order_type is null
|
||||
</if>
|
||||
order by top.creation_time desc
|
||||
</select>
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?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.hzs.third.pay.mapper.TOnlinePaymentSepAccDMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="com.hzs.common.domain.third.pay.TOnlinePaymentSepAccD">
|
||||
<id column="PK_ID" property="pkId" />
|
||||
<result column="DEL_FLAG" property="delFlag" />
|
||||
<result column="CREATION_TIME" property="creationTime" />
|
||||
<result column="MODIFIED_TIME" property="modifiedTime" />
|
||||
<result column="PK_CREATOR" property="pkCreator" />
|
||||
<result column="PK_MODIFIED" property="pkModified" />
|
||||
<result column="PK_SEP_ACC" property="pkSepAcc" />
|
||||
<result column="ACCOUNT" property="account" />
|
||||
<result column="PROPORTION" property="proportion" />
|
||||
<result column="TRADE_AMOUNT" property="tradeAmount" />
|
||||
<result column="OUT_TRADE_NO" property="outTradeNo" />
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
DEL_FLAG,
|
||||
CREATION_TIME,
|
||||
MODIFIED_TIME,
|
||||
PK_CREATOR,
|
||||
PK_MODIFIED,
|
||||
PK_ID, PK_SEP_ACC, ACCOUNT, PROPORTION
|
||||
</sql>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,35 @@
|
|||
<?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.hzs.third.pay.mapper.TOnlinePaymentSepAccMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc">
|
||||
<id column="PK_ID" property="pkId" />
|
||||
<result column="DEL_FLAG" property="delFlag" />
|
||||
<result column="CREATION_TIME" property="creationTime" />
|
||||
<result column="MODIFIED_TIME" property="modifiedTime" />
|
||||
<result column="PK_CREATOR" property="pkCreator" />
|
||||
<result column="PK_MODIFIED" property="pkModified" />
|
||||
<result column="PK_PAYMENT" property="pkPayment" />
|
||||
<result column="VERSION" property="version" />
|
||||
<result column="REQ_CONTENT" property="reqContent" />
|
||||
<result column="REQ_CONTENT_SEP_ACC" property="reqContentSepAcc" />
|
||||
<result column="RESP_CONTENT" property="respContent" />
|
||||
<result column="TRADE_AMOUNT" property="tradeAmount" />
|
||||
<result column="OUT_TRADE_NO" property="outTradeNo" />
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
DEL_FLAG,
|
||||
CREATION_TIME,
|
||||
MODIFIED_TIME,
|
||||
PK_CREATOR,
|
||||
PK_MODIFIED,
|
||||
PK_ID, PK_PAYMENT, VERSION, REQ_CONTENT, REQ_CONTENT_SEP_ACC, RESP_CONTENT
|
||||
</sql>
|
||||
<select id="getSepAccByOrderCode" resultType="com.hzs.common.domain.third.pay.TOnlinePaymentSepAcc">
|
||||
select * from T_ONLINE_PAYMENT_SEP_ACC where pk_payment in (select pk_id from T_ONLINE_PAYMENT where BUSINESS_CODE = #{orderCode})
|
||||
</select>
|
||||
|
||||
</mapper>
|
Loading…
Reference in New Issue