mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-09 13:59:05 +00:00
feat 对账和退款同步接口
This commit is contained in:
@@ -91,4 +91,10 @@ public interface WeChatPayCode {
|
||||
/** 退款总金额(各退款单的退款金额累加) */
|
||||
String REFUND_FEE = "refund_fee";
|
||||
|
||||
/** 当前返回退款笔数 */
|
||||
String REFUND_COUNT = "refund_count";
|
||||
|
||||
/** 订单总退款次数 */
|
||||
String TOTAL_REFUND_COUNT = "total_refund_count";
|
||||
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ import lombok.experimental.Accessors;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@DbTable(comment = "支付宝支付记录")
|
||||
@TableName("pay_ali_pay_order")
|
||||
@TableName("pay_alipay_order")
|
||||
public class AliPayOrder extends BasePayOrder implements EntityBaseFunction<AliPaymentDto> {
|
||||
|
||||
/** 支付宝交易号 */
|
||||
|
@@ -48,10 +48,9 @@ public class AliPaySyncService {
|
||||
// 查询参数
|
||||
AlipayTradeQueryResponse response = AliPayApi.tradeQueryToResponse(queryModel);
|
||||
String tradeStatus = response.getTradeStatus();
|
||||
syncResult.setSyncInfo(JSONUtil.toJsonStr(response));
|
||||
syncResult.setSyncPayInfo(JSONUtil.toJsonStr(response));
|
||||
// 支付完成 TODO 部分退款也在这个地方, 但无法进行区分, 需要借助对账进行处理
|
||||
if (Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_SUCCESS) || Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_FINISHED)) {
|
||||
this.syncRefundStatus(payOrder);
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setTradeNo(response.getTradeNo());
|
||||
// 支付完成时间
|
||||
LocalDateTime payTime = LocalDateTimeUtil.of(response.getSendPayDate());
|
||||
|
@@ -0,0 +1,62 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.AlipayDataDataserviceBillDownloadurlQueryModel;
|
||||
import com.ijpay.alipay.AliPayApi;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付宝对账服务
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AlipayReconcileService {
|
||||
|
||||
/**
|
||||
* 下载对账单, 并进行解析进行保存
|
||||
*/
|
||||
@SneakyThrows
|
||||
public String downAndSave(String date){
|
||||
try {
|
||||
AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
|
||||
model.setBillDate(date);
|
||||
model.setBillType("trade");
|
||||
// 获取对账单下载地址并下载
|
||||
String url = AliPayApi.billDownloadUrlQuery(model);
|
||||
byte[] bytes = HttpUtil.downloadBytes(url);
|
||||
// 使用 Apache commons-compress 包装流,
|
||||
ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(new ByteArrayInputStream(bytes),"GBK");
|
||||
|
||||
ZipArchiveEntry entry;
|
||||
while ((entry= zipArchiveInputStream.getNextZipEntry()) != null){
|
||||
String name = entry.getName();
|
||||
System.out.println(name);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(zipArchiveInputStream,"GBK"));
|
||||
List<String> strings = IoUtil.readLines(bufferedReader, new ArrayList<>());
|
||||
strings.forEach(System.out::println);
|
||||
|
||||
}
|
||||
|
||||
return url;
|
||||
} catch (AlipayApiException e) {
|
||||
log.error("下载对账单失败",e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.wechat.dao;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.common.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.wechat.WeChatPayConfigParam;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@@ -22,13 +15,4 @@ import org.springframework.stereotype.Repository;
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayConfigManager extends BaseManager<WeChatPayConfigMapper, WeChatPayConfig> {
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public Page<WeChatPayConfig> page(PageParam pageParam, WeChatPayConfigParam param) {
|
||||
Page<WeChatPayConfig> mpPage = MpUtil.getMpPage(pageParam, WeChatPayConfig.class);
|
||||
QueryWrapper<WeChatPayConfig> wrapper = QueryGenerator.generator(param);
|
||||
wrapper.orderByDesc(MpIdEntity.Id.id);
|
||||
return this.page(mpPage,wrapper);
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,22 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderChannelManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderChannel;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.sync.result.GatewaySyncResult;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.model.OrderQueryModel;
|
||||
import com.ijpay.wxpay.model.UnifiedOrderModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -31,13 +36,14 @@ import java.util.Objects;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPaySyncService {
|
||||
private final PayOrderChannelManager payOrderChannelManager;
|
||||
|
||||
/**
|
||||
* 同步查询
|
||||
*/
|
||||
public GatewaySyncResult syncPayStatus(PayOrder order, WeChatPayConfig weChatPayConfig) {
|
||||
GatewaySyncResult syncResult = new GatewaySyncResult().setSyncStatus(PaySyncStatusEnum.FAIL);
|
||||
Map<String, String> params = UnifiedOrderModel.builder()
|
||||
Map<String, String> params = OrderQueryModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
@@ -47,7 +53,7 @@ public class WeChatPaySyncService {
|
||||
try {
|
||||
String xmlResult = WxPayApi.orderQuery(params);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
syncResult.setSyncInfo(JSONUtil.toJsonStr(result));
|
||||
syncResult.setSyncPayInfo(JSONUtil.toJsonStr(result));
|
||||
// 查询失败
|
||||
if (!WxPayKit.codeIsOk(result.get(WeChatPayCode.RETURN_CODE))) {
|
||||
log.warn("查询微信订单失败:{}", result);
|
||||
@@ -76,7 +82,7 @@ public class WeChatPaySyncService {
|
||||
|
||||
// 已退款/退款中 触发一下退款记录的查询
|
||||
if (Objects.equals(tradeStatus, WeChatPayCode.TRADE_REFUND)) {
|
||||
this.syncRefundStatus(order.getId(), weChatPayConfig);
|
||||
this.syncRefundStatus(order, weChatPayConfig);
|
||||
}
|
||||
// 已关闭
|
||||
if (Objects.equals(tradeStatus, WeChatPayCode.TRADE_CLOSED)
|
||||
@@ -95,16 +101,28 @@ public class WeChatPaySyncService {
|
||||
/**
|
||||
* 退款查询
|
||||
*/
|
||||
private GatewaySyncResult syncRefundStatus(Long paymentId, WeChatPayConfig weChatPayConfig){
|
||||
private GatewaySyncResult syncRefundStatus(PayOrder order, WeChatPayConfig weChatPayConfig){
|
||||
PayOrderChannel orderChannel = payOrderChannelManager.findByPaymentIdAndChannel(order.getId(), PayChannelEnum.WECHAT.getCode())
|
||||
.orElseThrow(() -> new PayFailureException("支付订单通道信息不存在"));
|
||||
|
||||
Map<String, String> params = UnifiedOrderModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.out_trade_no(String.valueOf(paymentId))
|
||||
.out_trade_no(String.valueOf(order.getId()))
|
||||
.build()
|
||||
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
|
||||
String xmlResult = WxPayApi.orderRefundQuery(false, params);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
return new GatewaySyncResult().setSyncInfo(JSONUtil.toJsonStr(result));
|
||||
// 获取
|
||||
|
||||
|
||||
|
||||
// 判断是否全部退款
|
||||
Integer refundFee = Integer.valueOf(result.get(WeChatPayCode.REFUND_FEE));
|
||||
if (Objects.equals(refundFee, orderChannel.getAmount())){
|
||||
return new GatewaySyncResult().setSyncStatus(PaySyncStatusEnum.REFUND);
|
||||
}
|
||||
return new GatewaySyncResult().setSyncPayInfo(JSONUtil.toJsonStr(result));
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,79 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.model.DownloadBillModel;
|
||||
import com.ijpay.wxpay.model.DownloadFundFlowModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信支付对账
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WechatPayReconcileService {
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
/**
|
||||
* 下载对账单并保存
|
||||
* @param date 下载日期
|
||||
*/
|
||||
public void downAndSave(String date, WeChatPayConfig config) {
|
||||
config = weChatPayConfigService.getConfig();
|
||||
this.downBill(date, config);
|
||||
this.downFundFlow(date, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载交易账单
|
||||
*/
|
||||
public void downBill(String date, WeChatPayConfig config){
|
||||
// 下载交易账单
|
||||
Map<String, String> bill = DownloadBillModel.builder()
|
||||
.mch_id(config.getWxMchId())
|
||||
.appid(config.getWxAppId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.bill_date(date)
|
||||
.bill_type("ALL")
|
||||
.build()
|
||||
.createSign(config.getApiKeyV2(), SignType.HMACSHA256);
|
||||
String s = WxPayApi.downloadBill(config.isSandbox(), bill);
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载资金账单, 需要双向证书
|
||||
*/
|
||||
public void downFundFlow(String date, WeChatPayConfig config){
|
||||
if (StrUtil.isBlank(config.getP12())){
|
||||
return;
|
||||
}
|
||||
Map<String, String> fundFlow = DownloadFundFlowModel.builder()
|
||||
.mch_id(config.getWxMchId())
|
||||
.appid(config.getWxAppId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.bill_date(date)
|
||||
.account_type("Basic")
|
||||
.build()
|
||||
.createSign(config.getApiKeyV2(), SignType.HMACSHA256);
|
||||
byte[] fileBytes = Base64.decode(config.getP12());
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
|
||||
// 证书密码为 微信商户号
|
||||
String s = WxPayApi.downloadFundFlow(fundFlow, inputStream, config.getWxMchId());
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
@@ -2,18 +2,17 @@ package cn.bootx.platform.daxpay.service.core.order.pay.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.timeout.service.PayExpiredTimeService;
|
||||
import cn.bootx.platform.daxpay.util.PayUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付订单服务
|
||||
@@ -60,10 +59,7 @@ public class PayOrderService {
|
||||
public void updateRefundSuccess(PayOrder payment, int amount, PayChannelEnum payChannelEnum) {
|
||||
// 删除旧有的退款记录, 替换退款完的新的
|
||||
List<RefundableInfo> refundableInfos = payment.getRefundableInfos();
|
||||
RefundableInfo refundableInfo = refundableInfos.stream()
|
||||
.filter(o -> Objects.equals(o.getChannel(), payChannelEnum.getCode()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new PayFailureException("退款数据不存在"));
|
||||
RefundableInfo refundableInfo = PayUtil.refundableInfoFilter(refundableInfos, payChannelEnum);
|
||||
refundableInfos.remove(refundableInfo);
|
||||
refundableInfo.setAmount(refundableInfo.getAmount() - amount);
|
||||
refundableInfos.add(refundableInfo);
|
||||
|
@@ -11,12 +11,13 @@ import org.mapstruct.factory.Mappers;
|
||||
* @since 2022/3/2
|
||||
*/
|
||||
@Mapper
|
||||
public interface PayRefundConvert {
|
||||
public interface PayRefundOrderConvert {
|
||||
|
||||
PayRefundConvert CONVERT = Mappers.getMapper(PayRefundConvert.class);
|
||||
PayRefundOrderConvert CONVERT = Mappers.getMapper(PayRefundOrderConvert.class);
|
||||
|
||||
PayRefundOrderDto convert(PayRefundOrder in);
|
||||
|
||||
RefundOrderResult convertResult(PayRefundOrder in);
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.refund.convert;
|
||||
|
||||
import cn.bootx.platform.daxpay.result.order.RefundOrderChannelResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrderChannel;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderChannelDto;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Mapper
|
||||
public interface RefundOrderChannelConvert {
|
||||
RefundOrderChannelConvert CONVERT = Mappers.getMapper(RefundOrderChannelConvert.class);
|
||||
|
||||
|
||||
RefundOrderChannelDto convert(PayRefundOrderChannel in);
|
||||
|
||||
RefundOrderChannelResult convertResult(PayRefundOrderChannel in);
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.refund.dao;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrderChannel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class PayRefundOrderChannelManager extends BaseManager<PayRefundOrderChannelMapper, PayRefundOrderChannel> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据退款单ID查找
|
||||
*/
|
||||
public List<PayRefundOrderChannel> findAllByRefundId(Long paymentId){
|
||||
return findAllByField(PayRefundOrderChannel::getRefundId,paymentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据退款单ID和退款通道查询
|
||||
*/
|
||||
public Optional<PayRefundOrderChannel> findByPaymentIdAndChannel(Long paymentId, String channel) {
|
||||
return lambdaQuery()
|
||||
.eq(PayRefundOrderChannel::getRefundId,paymentId)
|
||||
.eq(PayRefundOrderChannel::getChannel,channel)
|
||||
.oneOpt();
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.refund.dao;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrderChannel;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Mapper
|
||||
public interface PayRefundOrderChannelMapper extends BaseMapper<PayRefundOrderChannel> {
|
||||
}
|
@@ -5,7 +5,7 @@ import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import cn.bootx.platform.daxpay.service.common.typehandler.RefundableInfoTypeHandler;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.PayRefundConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.PayRefundOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
@@ -104,7 +104,7 @@ public class PayRefundOrder extends MpBaseEntity implements EntityBaseFunction<P
|
||||
|
||||
@Override
|
||||
public PayRefundOrderDto toDto() {
|
||||
return PayRefundConvert.CONVERT.convert(this);
|
||||
return PayRefundOrderConvert.CONVERT.convert(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.refund.entity;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付退款订单关联通道信息
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@DbTable(comment = "支付退款通道订单")
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_refund_order_channel")
|
||||
public class PayRefundOrderChannel extends MpBaseEntity {
|
||||
|
||||
@DbColumn(comment = "关联退款id")
|
||||
private Long refundId;
|
||||
|
||||
@DbColumn(comment = "通道")
|
||||
private String channel;
|
||||
|
||||
/** 关联支付网关退款请求号 */
|
||||
@DbColumn(comment = "异步方式关联退款请求号(部分退款情况)")
|
||||
private String refundRequestNo;
|
||||
|
||||
@DbColumn(comment = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
@DbColumn(comment = "退款金额")
|
||||
private Integer amount;
|
||||
|
||||
}
|
@@ -6,10 +6,14 @@ import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.param.pay.QueryRefundParam;
|
||||
import cn.bootx.platform.daxpay.result.order.RefundOrderChannelResult;
|
||||
import cn.bootx.platform.daxpay.result.order.RefundOrderResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.PayRefundConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.PayRefundOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderChannelConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.PayRefundOrderChannelManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.PayRefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrderChannel;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
|
||||
import cn.bootx.platform.daxpay.service.param.order.PayRefundOrderQuery;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -18,7 +22,9 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 退款
|
||||
@@ -32,6 +38,7 @@ import java.util.Objects;
|
||||
public class PayRefundOrderService {
|
||||
|
||||
private final PayRefundOrderManager refundOrderManager;
|
||||
private final PayRefundOrderChannelManager refundOrderChannelManager;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
@@ -57,7 +64,7 @@ public class PayRefundOrderService {
|
||||
throw new ValidationFailedException("退款号或退款ID不能都为空");
|
||||
}
|
||||
|
||||
// 查询支付单
|
||||
// 查询退款单
|
||||
PayRefundOrder refundOrder = null;
|
||||
if (Objects.nonNull(param.getRefundId())){
|
||||
refundOrder = refundOrderManager.findById(param.getRefundId())
|
||||
@@ -67,6 +74,14 @@ public class PayRefundOrderService {
|
||||
refundOrder = refundOrderManager.findByRefundNo(param.getRefundNo())
|
||||
.orElseThrow(() -> new DataNotExistException("未查询到支付订单"));
|
||||
}
|
||||
return PayRefundConvert.CONVERT.convertResult(refundOrder);
|
||||
// 查询退款明细
|
||||
List<PayRefundOrderChannel> refundOrderChannels = refundOrderChannelManager.findAllByRefundId(refundOrder.getId());
|
||||
List<RefundOrderChannelResult> channels = refundOrderChannels.stream()
|
||||
.map(RefundOrderChannelConvert.CONVERT::convertResult)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
RefundOrderResult refundOrderResult = PayRefundOrderConvert.CONVERT.convertResult(refundOrder);
|
||||
refundOrderResult.setChannels(channels);
|
||||
return refundOrderResult;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 支付对账单下载服务
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayReconcileService {
|
||||
|
||||
/**
|
||||
* 下载对账单
|
||||
*/
|
||||
public void downReconcileBill(){
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 支付宝对账策略
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Slf4j
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AlipayReconcileStrategy {
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 微信支付对账策略
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Slf4j
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WechatPayReconcileStrategy {
|
||||
}
|
@@ -22,8 +22,16 @@ public class GatewaySyncResult {
|
||||
*/
|
||||
private PaySyncStatusEnum syncStatus = FAIL;
|
||||
|
||||
/** 网关返回的对象, 序列化为json字符串 */
|
||||
private String syncInfo;
|
||||
/** 同步支付时网关返回的对象, 序列化为json字符串 */
|
||||
private String syncPayInfo;
|
||||
|
||||
/** 同步退款时网关返回的对象, 序列化为json字符串 */
|
||||
private String syncRefundInfo;
|
||||
|
||||
/** 退款信息是否需要修复 */
|
||||
private boolean repairRefund;
|
||||
|
||||
/** 网关返回退款信息列表 */
|
||||
|
||||
/** 错误提示 */
|
||||
private String errorMsg;
|
||||
|
@@ -227,7 +227,7 @@ public class PaySyncService {
|
||||
|
||||
|
||||
/**
|
||||
* 保存同步记录
|
||||
* 保存同步记录 TODO 目前出现一次请求多次与网关同步, 未全部记录
|
||||
* @param payOrder 支付单
|
||||
* @param syncResult 同步结果
|
||||
* @param repair 是否修复
|
||||
@@ -238,7 +238,7 @@ public class PaySyncService {
|
||||
.setPaymentId(payOrder.getId())
|
||||
.setBusinessNo(payOrder.getBusinessNo())
|
||||
.setAsyncChannel(payOrder.getAsyncChannel())
|
||||
.setSyncInfo(syncResult.getSyncInfo())
|
||||
.setSyncInfo(syncResult.getSyncPayInfo())
|
||||
.setGatewayStatus(syncResult.getSyncStatus().getCode())
|
||||
.setRepairOrder(repair)
|
||||
.setRepairOrderId(repairOrderId)
|
||||
|
@@ -39,6 +39,6 @@ public class PayApiConfigManager extends BaseManager<PayApiConfigMapper, PayApiC
|
||||
*/
|
||||
@Override
|
||||
public List<PayApiConfig> findAll() {
|
||||
return lambdaQuery().orderByDesc(MpIdEntity::getId).list();
|
||||
return lambdaQuery().orderByAsc(MpIdEntity::getId).list();
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,6 @@ public class PayChannelInfoManager extends BaseManager<PayChannelInfoMapper, Pay
|
||||
*/
|
||||
@Override
|
||||
public List<PayChannelInfo> findAll() {
|
||||
return lambdaQuery().orderByDesc(MpIdEntity::getId).list();
|
||||
return lambdaQuery().orderByAsc(MpIdEntity::getId).list();
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ public class PayChannelInfo extends MpBaseEntity implements EntityBaseFunction<P
|
||||
|
||||
/** 是否启用 */
|
||||
@DbColumn(comment = "是否启用")
|
||||
private boolean enabled;
|
||||
private Boolean enabled;
|
||||
|
||||
/** 备注 */
|
||||
@DbColumn(comment = "备注")
|
||||
|
@@ -1,33 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.channel.config;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付通道配置
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2023-05-24
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Schema(title = "支付通道配置")
|
||||
@Accessors(chain = true)
|
||||
public class PayChannelConfigDto extends BaseDto {
|
||||
|
||||
@Schema(description = "渠道编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "渠道名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "图片")
|
||||
private Long image;
|
||||
|
||||
@Schema(description = "排序")
|
||||
private Double sortNo;
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.refund;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付退款通道订单
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "支付退款通道订单")
|
||||
public class RefundOrderChannelDto extends BaseDto {
|
||||
}
|
@@ -28,7 +28,7 @@ public class PayChannelInfoDto extends BaseDto {
|
||||
|
||||
/** 是否启用 */
|
||||
@DbColumn(comment = "是否启用")
|
||||
private boolean enabled;
|
||||
private Boolean enabled;
|
||||
|
||||
/** logo图片 */
|
||||
@Schema(description = "logo图片")
|
||||
|
Reference in New Issue
Block a user