1、优化第三方支付透传参数改为存在数据库中;2、新增超时支付单的轮训处理、增加关闭和待支付的判定和对应处理;3、新增更新前序购买记录的已支付属性;

This commit is contained in:
gaoqr
2025-09-25 17:04:40 +08:00
parent 01535623ba
commit b328878d14
25 changed files with 388 additions and 170 deletions
@@ -26,9 +26,13 @@ public class PayOrderRespDTO {
private Integer status;
/**
* 外部订单
* 第三方交易
*/
private String tradeNo;
/**
* 系统内订单号
*
* 对应 PayOrderExtensionDO 的 no 字段
*/
private String outTradeNo;
@@ -76,11 +80,6 @@ public class PayOrderRespDTO {
*/
private String channelErrorMsg;
/**
* 发起支付给支付方后,异步回调原封不动回到调用方
*/
private Map<String,Object> passbackParams;
/**
* 支付渠道:0-支付宝、1-微信
*/
@@ -105,13 +104,14 @@ public class PayOrderRespDTO {
* 创建【WAITING】状态的订单返回
*/
public static PayOrderRespDTO waitingOf(String displayMode, String displayContent,
String outTradeNo, Object rawData, Integer channelCode) {
String outTradeNo, String tradeNo, Object rawData, Integer channelCode) {
PayOrderRespDTO respDTO = new PayOrderRespDTO();
respDTO.status = PayOrderStatusRespEnum.WAITING.getStatus();
respDTO.displayMode = displayMode;
respDTO.displayContent = displayContent;
// 相对通用的字段
respDTO.outTradeNo = outTradeNo;
respDTO.tradeNo = tradeNo;
respDTO.rawData = rawData;
respDTO.channelCode = channelCode;
return respDTO;
@@ -149,23 +149,6 @@ public class PayOrderRespDTO {
return respDTO;
}
/**
* 创建指定状态的订单返回,适合支付渠道回调时
*/
public static PayOrderRespDTO of(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime,
String outTradeNo, Object rawData, Map<String, Object> passbackParams) {
PayOrderRespDTO respDTO = new PayOrderRespDTO();
respDTO.status = status;
respDTO.channelOrderNo = channelOrderNo;
respDTO.channelUserId = channelUserId;
respDTO.successTime = successTime;
// 相对通用的字段
respDTO.outTradeNo = outTradeNo;
respDTO.rawData = rawData;
respDTO.passbackParams = passbackParams;
return respDTO;
}
/**
* 创建【CLOSED】状态的订单返回,适合调用支付渠道失败时
*/
@@ -85,11 +85,6 @@ public class PayOrderUnifiedReqDTO {
*/
private Map<String, String> channelExtras;
/**
* 发起支付给支付方后,异步回调原封不动回到调用方
*/
private Map<String, Object> passbackParams;
/**
* 展示模式
*
@@ -0,0 +1,25 @@
package com.cf.imes.framework.excel.core.convert;
/**
* 基础枚举接口,code为布尔类型
* <p>
* 用于easyexcel convert
*
* @author Gqr
* @since 2025/8/27 11:51
*/
public interface BaseBoolValEnum {
/**
* 魔值
*
* @return
*/
Boolean getCode();
/**
* 描述
*
* @return
*/
String getDesc();
}
@@ -0,0 +1,73 @@
package com.cf.imes.framework.excel.core.convert;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.cf.imes.framework.excel.core.annotations.EnumFormat;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
/**
* Excel 枚举转换器
*
* @author Gqr
* @since 2025/8/27 11:02
*/
@Slf4j
public class EnumBoolValConvert implements Converter<Boolean> {
@Override
public Class<?> supportJavaTypeKey() {
return Boolean.class; // 泛型接口
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.BOOLEAN; // Excel 存字符串
}
// 写出:Integer -> 枚举描述
@Override
public WriteCellData<String> convertToExcelData(WriteConverterContext<Boolean> context) {
Boolean code = context.getValue();
if (code == null) {
return new WriteCellData<>("");
}
Class<? extends Enum> enumClass = getEnumClass(context.getContentProperty().getField());
if (enumClass != null) {
for (Object e : enumClass.getEnumConstants()) {
BaseBoolValEnum baseEnum = (BaseBoolValEnum) e;
if (baseEnum.getCode().equals(code)) {
return new WriteCellData<>(baseEnum.getDesc());
}
}
}
return new WriteCellData<>("");
}
// 读入:枚举描述 -> Integer code
@Override
public Boolean convertToJavaData(ReadConverterContext<?> context) {
String desc = context.getReadCellData().getStringValue();
if (desc == null) {
return Boolean.FALSE;
}
Class<? extends Enum> enumClass = getEnumClass(context.getContentProperty().getField());
if (enumClass != null) {
for (Object e : enumClass.getEnumConstants()) {
BaseBoolValEnum baseEnum = (BaseBoolValEnum) e;
if (baseEnum.getDesc().equals(desc)) {
return baseEnum.getCode();
}
}
}
return Boolean.FALSE;
}
private Class<? extends Enum> getEnumClass(Field field) {
EnumFormat annotation = field.getAnnotation(EnumFormat.class);
return annotation != null ? annotation.value() : null;
}
}
@@ -473,6 +473,7 @@ public class ErrorCodeConstants {
public static final ErrorCode PRODUCTS_OUTPUT_NOT_SUPPORT = new ErrorCode(1_002_045_009, "暂不支持创建购买方式为【产量】的定价规则");
public static final ErrorCode RECHARGE_ACTIVE_NO_EXIST = new ErrorCode(1_002_045_010, "当前赠送金活动不存在");
public static final ErrorCode PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT = new ErrorCode(1_002_045_011, "不支持的时长单位,请检查该定价规则的时长单位");
public static final ErrorCode ORG_PRODUCT_PURCHASE_WAIT_PAY_ERROR = new ErrorCode(1_002_045_012, "组织下存在当前产品的待支付记录,请确认或取消支付后再次发起软件购买");
//=========== 广告相关 1-002-046-000 ============
public static final ErrorCode ADVERTISEMENT_POSITION_NO_EXIST = new ErrorCode(1_002_046_001, "广告所选放置位置不存在");
@@ -3,7 +3,9 @@ package com.cf.imes.module.system.controller.admin.funds.delay.vo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.cf.imes.framework.excel.core.annotations.EnumFormat;
import com.cf.imes.framework.excel.core.convert.EnumBoolValConvert;
import com.cf.imes.framework.excel.core.convert.EnumConvert;
import com.cf.imes.module.system.enums.common.WhetherEnum;
import com.cf.imes.module.system.enums.pay.DurationUnitEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -60,4 +62,9 @@ public class ProductDelayRespVO {
@Schema(description = "操作人")
@ExcelProperty("操作人")
private String creator;
@Schema(description = "是否支付")
@ExcelProperty(value = "是否支付", converter = EnumBoolValConvert.class)
@EnumFormat(value = WhetherEnum.class)
private Boolean paid;
}
@@ -90,11 +90,6 @@ public class PayOrderUnifiedReqDTO {
*/
private Map<String, String> channelExtras;
/**
* 发起支付给支付方后,异步回调原封不动回到调用方
*/
private Map<String, Object> passbackParams;
/**
* 展示模式
*
@@ -77,6 +77,11 @@ public class ProductDelayRecordDO extends BaseDO {
*/
private Long purchaseId;
/**
* 是否支付
*/
private Boolean paid;
/**
* 备注
*/
@@ -68,6 +68,11 @@ public class PayOrderDO extends BaseDO {
*/
private String payNo;
/**
* 交易类型
*/
private Integer tradeType;
/**
* 支付状态
*/
@@ -99,7 +104,6 @@ public class PayOrderDO extends BaseDO {
/**
* 支付渠道的同步/异步通知的内容
*
*/
private String channelNotifyData;
}
@@ -26,6 +26,7 @@ public interface ProductDelayRecordMapper extends BaseMapperX<ProductDelayRecord
.eqIfPresent(ProductDelayRecordDO::getProductName, pageReqVO.getProductName())
.eqIfPresent(ProductDelayRecordDO::getDelayDuration, pageReqVO.getDelayDuration())
.betweenIfPresent(ProductDelayRecordDO::getCreateTime, pageReqVO.getCreateTime())
.eqIfPresent(ProductDelayRecordDO::getCreator, pageReqVO.getOperator()));
.eqIfPresent(ProductDelayRecordDO::getCreator, pageReqVO.getOperator())
.orderByDesc(ProductDelayRecordDO::getId));
}
}
@@ -0,0 +1,22 @@
package com.cf.imes.module.system.enums.common;
import com.cf.imes.framework.excel.core.convert.BaseBoolValEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 是否枚举
*
* @author Gqr
* @since 2025/9/25 15:54
*/
@Getter
@AllArgsConstructor
public enum WhetherEnum implements BaseBoolValEnum {
TRUE(true, ""),
FALSE(false, "");
private final Boolean code;
private final String desc;
}
@@ -7,13 +7,7 @@ package com.cf.imes.module.system.enums.pay;
* @since 2025/8/12 17:49
*/
public class PayConstants {
public static final String PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY = "tradeType"; //支付passback 交易类型key
public static final String PAY_PASSBACK_PARAMS_KEY = "passback_params";// 回调参数passback key
public static final String PAY_ORDER_PREFIX_FORMAT = "P%dO%s"; // 第三方支付流水号格式
public static final String PAY_PRODUCT_DETAIL_BUSINESSNO_PREFIX_FORMAT = "P%dD%s"; // 产品购买流水号格式
public static final String PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY = "purchaseRecordId"; //支付passback 购买记录key
}
@@ -27,9 +27,14 @@ public enum PayOrderStatusEnum {
SUCCESS(10),
/**
* 支付失败
* 已退款
*/
FAIL(20);
REFUND(20),
/**
* 支付关闭
*/
CLOSED(30);
@EnumValue
private final Integer status;
@@ -61,6 +66,6 @@ public enum PayOrderStatusEnum {
* @return 是否支付关闭
*/
public static boolean isClosed(Integer status) {
return Objects.equals(status, FAIL.getStatus());
return Objects.equals(status, CLOSED.getStatus());
}
}
@@ -4,6 +4,7 @@ import cn.hutool.core.text.CharSequenceUtil;
import com.cf.imes.module.system.service.pay.PayOrderService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
@@ -20,11 +21,13 @@ public class PayOrderExpireJob {
@Resource
private PayOrderService payOrderService;
// @Scheduled(cron = "0 0/1 * * * ?")
@Scheduled(cron = "0 0/1 * * * ?")
public String execute() {
int count = payOrderService.expirePayOrder();
log.info("[execute][支付过期 ({}) 个]", count);
return CharSequenceUtil.format("支付过期 ({}) 个",count);
if (count > 0) {
log.info("[execute][支付过期 ({}) 个]", count);
}
return CharSequenceUtil.format("支付过期 ({}) 个", count);
}
}
@@ -47,4 +47,13 @@ public interface ProductDelayService {
* @return
*/
PreviouProductDelayRespVO getActiveRecordsByProductId(Long productId, Long organId);
/**
* 更新购买记录下的延期记录为已支付
*
* @param purchaseId
* @param organId
*/
void updatePurchaseDelayRecordsPaid(Long purchaseId, Long organId);
}
@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
@@ -100,6 +101,7 @@ public class ProductDelayServiceImpl implements ProductDelayService {
.endTime(endTime)
.delayTime(delayTime)
.purchaseId(purchaseId)
.paid(false)
.build();
productDelayRecordMapper.insert(productDelayRecordDO);
return productDelayRecordDO.getId();
@@ -183,4 +185,12 @@ public class ProductDelayServiceImpl implements ProductDelayService {
}
return previouProductDelayRespVO;
}
@Override
public void updatePurchaseDelayRecordsPaid(Long purchaseId, Long organId) {
productDelayRecordMapper.update(new LambdaUpdateWrapper<ProductDelayRecordDO>()
.eq(ProductDelayRecordDO::getPurchaseId, purchaseId)
.eq(ProductDelayRecordDO::getOrganId, organId)
.set(ProductDelayRecordDO::getPaid, true));
}
}
@@ -117,13 +117,13 @@ public interface PurchaseService {
PurchaseRecordDO getOrgInitialPurchaseRecord(Long organId, Long productId);
/**
* 获取组织产品购买记录
* 获取组织产品待支付的购买记录
*
* @param organId
* @param productId
* @return
*/
List<PurchaseRecordDO> getOrgProductPurchaseList(Long organId, Long productId);
List<PurchaseRecordDO> getOrgProductPendingPurchaseList(Long organId, Long productId);
/**
* 获取组织续费定价规则列表
@@ -133,14 +133,6 @@ public interface PurchaseService {
*/
List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId);
/**
* 更新历史组织产品购买记录为待支付
*
* @param organId
* @param purchaseRecordId
*/
void pendingHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId);
/**
* 作废历史组织产品购买记录
*
@@ -42,7 +42,6 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -83,7 +82,11 @@ public class PurchaseServiceImpl implements PurchaseService {
@Override
public void deleteRecord(Long id) {
purchaseRecordMapper.deleteById(id);
// 删除且作废
purchaseRecordMapper.update(new LambdaUpdateWrapper<PurchaseRecordDO>()
.eq(PurchaseRecordDO::getId, id)
.set(PurchaseRecordDO::getDeleted, true)
.set(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.INACTIVE.getStatus()));
}
@Override
@@ -253,12 +256,12 @@ public class PurchaseServiceImpl implements PurchaseService {
}
@Override
public List<PurchaseRecordDO> getOrgProductPurchaseList(Long organId, Long productId) {
public List<PurchaseRecordDO> getOrgProductPendingPurchaseList(Long organId, Long productId) {
return purchaseRecordMapper.selectList(new LambdaQueryWrapper<PurchaseRecordDO>()
.eq(PurchaseRecordDO::getOrganId, organId)
.eq(PurchaseRecordDO::getProductId, productId)
.eq(PurchaseRecordDO::getDeleted, false)
.ne(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.PENDING.getStatus()));
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.PENDING.getStatus())
.eq(PurchaseRecordDO::getDeleted, false));
}
@Override
@@ -335,16 +338,6 @@ public class PurchaseServiceImpl implements PurchaseService {
return resultList;
}
@Override
public void pendingHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId) {
purchaseRecordMapper.update(new LambdaUpdateWrapper<PurchaseRecordDO>()
.eq(PurchaseRecordDO::getOrganId, organId)
.eq(PurchaseRecordDO::getId, purchaseRecordId)
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.ACTIVE.getStatus())
.eq(PurchaseRecordDO::getDeleted, false)
.set(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.PENDING.getStatus()));
}
@Override
public void invalidHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId) {
purchaseRecordMapper.update(new LambdaUpdateWrapper<PurchaseRecordDO>()
@@ -1,7 +1,7 @@
package com.cf.imes.module.system.service.pay;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -67,6 +67,7 @@ import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
@@ -76,7 +77,6 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@@ -84,7 +84,7 @@ import java.util.regex.Pattern;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORG_PRODUCT_PURCHASE_LOCK_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORG_PRODUCT_PURCHASE_WAIT_PAY_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_CHANNEL_QUERY_NOT_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_NOTIFY_DATA_PARSE_ERROR;
@@ -154,6 +154,9 @@ public class PayOrderServiceImpl implements PayOrderService {
@Resource
private ChenfengCacheProperties chenfengCacheProperties;
@Resource
private TransactionTemplate transactionTemplate;
@Override
@Transactional(rollbackFor = Exception.class)
public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
@@ -179,6 +182,12 @@ public class PayOrderServiceImpl implements PayOrderService {
// 获取渠道方处理器
Integer channelCode = PayProductChannelCodeEnum.isAliPay(payProductOrderUnifiedReqVO.getProductChannelCode()) ? PayChannelCodeEnum.ALIPAY_PC.getCode() : PayChannelCodeEnum.WECHAT_NATIVE.getCode();
try {
// 检查机构产品是否有待支付的购买记录
List<PurchaseRecordDO> pendingPurchaseList = purchaseService.getOrgProductPendingPurchaseList(organId, productId);
if (CollUtil.isNotEmpty(pendingPurchaseList)) {
throw new ServiceException(ORG_PRODUCT_PURCHASE_WAIT_PAY_ERROR);
}
// 查询组织余额信息
OrganAmountDO organAmount = organAmountService.validOrganAmount(organId);
@@ -215,15 +224,10 @@ public class PayOrderServiceImpl implements PayOrderService {
if (ObjectUtil.isNotNull(payOrder)) {
payOrderMapper.insert(payOrder);
// 拼接充值个性化参数
Map<String, Object> passbackParams = new HashMap<>();
passbackParams.put(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY, TradeTypeEnum.PRODUCT.getCode());// 交易类型
passbackParams.put(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY, productProcessorRespVO.getPurchaseRecordDO().getId());// 购买记录id,用于更新开票状态
// 发起渠道方支付
AbstractPayHandler payHandler = payHandlerFactory.getPayHandler(channelCode);
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder, passbackParams);
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder);
return payHandler.unifiedOrder(payOrderUnifiedReqDTO);
}
// 软件购买锁解锁
@@ -246,7 +250,7 @@ public class PayOrderServiceImpl implements PayOrderService {
/**
* 处理前序购买记录:
* 1、需要第三方支付,更新为等待支付,第三方支付回调后作废
* 1、需要第三方支付,当前购买记录状态为待支付,第三方回调/超期轮训处理到的时候标记为成功还是失败
* 2、不需要第三方支付,直接作废
*
* @param previouProductDelayRespVO
@@ -258,12 +262,11 @@ public class PayOrderServiceImpl implements PayOrderService {
if (ObjectUtil.isNotNull(previouPurchaseRecord)) {
Long previousId = previouPurchaseRecord.getId();
Long organId = previouPurchaseRecord.getOrganId();
if (ObjectUtil.isNotNull(payOrder)) {
// 历史的购买记录更新为等待支付,需要第三方支付回调后作废前序
purchaseService.pendingHistoryOrganProductPurchaseRecord(organId, previousId);
} else {
if (ObjectUtil.isNull(payOrder)) {
// 作废历史的购买记录
purchaseService.invalidHistoryOrganProductPurchaseRecord(organId, previousId);
// 更新前置购买记录下的延期记录为已支付
productDelayService.updatePurchaseDelayRecordsPaid(previousId, organId);
}
}
}
@@ -286,7 +289,7 @@ public class PayOrderServiceImpl implements PayOrderService {
AbstractPayHandler payHandler = payHandlerFactory.getPayHandler(channelCode);
// 创建支付订单
PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode);
PayOrderDO payOrder = createRechargePayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode);
// 设置赠送活动编号
Long rechargeActivityId = payRechargeOrderReqVO.getRechargeActivityId();
if (ObjectUtil.isNotNull(rechargeActivityId)) {
@@ -296,14 +299,10 @@ public class PayOrderServiceImpl implements PayOrderService {
}
payOrderMapper.insert(payOrder);
// 拼接充值个性化参数
Map<String, Object> passbackParams = new HashMap<>();
passbackParams.put(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY, TradeTypeEnum.RECHARGE.getCode());
// 发起渠道方支付
PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = null;
try {
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder, passbackParams);
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder);
return payHandler.unifiedOrder(payOrderUnifiedReqDTO);
} catch (Throwable e) {
// 系统异常,则包装成 PayException 异常抛出
@@ -380,12 +379,12 @@ public class PayOrderServiceImpl implements PayOrderService {
}
/**
* 创建支付订单
* 创建充值支付订单
*
* @param
* @return
*/
private PayOrderDO createPayOrder(BigDecimal price, String subject, Integer channelCode) {
private PayOrderDO createRechargePayOrder(BigDecimal price, String subject, Integer channelCode) {
PayOrderDO payOrderDO = new PayOrderDO();
Long payOrderId = IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId();
@@ -399,6 +398,7 @@ public class PayOrderServiceImpl implements PayOrderService {
payOrderDO.setSubject(subject);
payOrderDO.setChannelCode(PayChannelCodeEnum.fromType(channelCode));
payOrderDO.setOrganId(organId);
payOrderDO.setTradeType(TradeTypeEnum.RECHARGE.getCode());
return payOrderDO;
}
@@ -408,7 +408,7 @@ public class PayOrderServiceImpl implements PayOrderService {
* @param payOrderDO
* @return
*/
private PayOrderUnifiedReqDTO createPayOrderUnifiedReqDTO(PayOrderDO payOrderDO, Map<String, Object> passbackParams) {
private PayOrderUnifiedReqDTO createPayOrderUnifiedReqDTO(PayOrderDO payOrderDO) {
PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = new PayOrderUnifiedReqDTO();
String subject = payOrderDO.getSubject();
@@ -418,7 +418,6 @@ public class PayOrderServiceImpl implements PayOrderService {
payOrderUnifiedReqDTO.setPrice(payOrderDO.getPrice());
payOrderUnifiedReqDTO.setExpireTime(payOrderDO.getExpireTime());
payOrderUnifiedReqDTO.setNotifyUrl(String.format(alipayConfig.getNotifyUrl(), payOrderDO.getChannelCode().getCode()));
payOrderUnifiedReqDTO.setPassbackParams(passbackParams);
return payOrderUnifiedReqDTO;
}
@@ -525,7 +524,7 @@ public class PayOrderServiceImpl implements PayOrderService {
}
// 如果已经是成功,直接返回,不用重复更新
if (PayOrderStatusEnum.isSuccess(order.getStatus().getStatus())) {
log.debug("[updateOrderExtensionSuccess][order({}) 已经是已支付,无需更新]", order.getId());
log.debug("[notifyOrderSuccess][order({}) 已经是已支付,无需更新]", order.getId());
return;
}
if (!PayOrderStatusEnum.WAITING.equals(order.getStatus())) { // 校验状态,必须是待支付
@@ -545,21 +544,18 @@ public class PayOrderServiceImpl implements PayOrderService {
if (updateCounts == 0) { // 校验状态,必须是待支付
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
}
log.debug("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
log.debug("[notifyOrderSuccess][order({}) 更新为已支付]", order.getId());
// 3. 根据交易类型做对应回调处理
Map<String, Object> passbackParams = notify.getPassbackParams();
Object passbackObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY);
AssertUtils.notEmpty(passbackObj, PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR);
switch (TradeTypeEnum.fromCode(NumberUtil.parseInt(passbackObj.toString()))) {
switch (TradeTypeEnum.fromCode(order.getTradeType())) {
case RECHARGE:
notifyRechargeOrderSuccess(order, organId);
break;
case PRODUCT:
notifyProductPayOrderSuccess(organId, passbackParams);
notifyProductPayOrderSuccess(order);
break;
default:
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, passbackObj.toString());
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, order.getTradeType());
}
}
@@ -603,21 +599,26 @@ public class PayOrderServiceImpl implements PayOrderService {
/**
* 产品购买成功回调
*
* @param organId
* @param passbackParams
* @param payOrderDO
*/
private void notifyProductPayOrderSuccess(Long organId, Map<String, Object> passbackParams) {
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
private void notifyProductPayOrderSuccess(PayOrderDO payOrderDO) {
if (ObjectUtil.isNotNull(payOrderDO) && ObjectUtil.isNotNull(payOrderDO.getPurchaseId())) {
Long organId = payOrderDO.getOrganId();
// 1、更新购买记录的开票状态
long purchaseId = NumberUtil.parseLong(purchaseRecordIdObj.toString());
long purchaseId = payOrderDO.getPurchaseId();
purchaseService.updateRecordInvoicable(purchaseId, organId);
// 2、作废前置购买记录
// 2、激活本次的购买记录
purchaseService.activateHistoryOrganProductPurchaseRecord(organId, purchaseId);
// 3、作废前置购买记录
PurchaseRecordDO record = purchaseService.getRecord(purchaseId);
Long previousId = record.getPreviousId();
if (ObjectUtil.isNotNull(previousId)) {
purchaseService.invalidHistoryOrganProductPurchaseRecord(organId, previousId);
// 4、更新前置购买记录下的延期记录为已支付
productDelayService.updatePurchaseDelayRecordsPaid(previousId, organId);
}
}
@@ -657,7 +658,7 @@ public class PayOrderServiceImpl implements PayOrderService {
.eq(PayOrderDO::getId, order.getId())
.eq(PayOrderDO::getStatus, PayOrderStatusEnum.WAITING)
.eq(PayOrderDO::getOrganId, organId)
.set(PayOrderDO::getStatus, PayOrderStatusEnum.FAIL.getStatus())
.set(PayOrderDO::getStatus, PayOrderStatusEnum.CLOSED.getStatus())
.set(PayOrderDO::getNotifyTime, LocalDateTime.now())
.set(PayOrderDO::getChannelErrorCode, notify.getChannelErrorCode())
.set(PayOrderDO::getChannelErrorMsg, notify.getChannelErrorMsg())
@@ -669,18 +670,15 @@ public class PayOrderServiceImpl implements PayOrderService {
log.debug("[notifyOrderClosed][order({}) 更新为支付关闭]", order.getId());
// 3. 根据交易类型做对应回调处理
Map<String, Object> passbackParams = notify.getPassbackParams();
Object passbackObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY);
AssertUtils.notEmpty(passbackObj, PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR);
switch (TradeTypeEnum.fromCode(NumberUtil.parseInt(passbackObj.toString()))) {
switch (TradeTypeEnum.fromCode(order.getTradeType())) {
case RECHARGE:
notifyRechargeOrderFail(order, organId);
break;
case PRODUCT:
notifyProductPayOrderFail(organId, passbackParams);
notifyProductPayOrderFail(order);
break;
default:
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, passbackObj.toString());
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, order.getTradeType());
}
}
@@ -697,41 +695,41 @@ public class PayOrderServiceImpl implements PayOrderService {
/**
* 产品购买失败回调
*
* @param organId
* @param passbackParams
* @param orderDO
*/
private void notifyProductPayOrderFail(Long organId, Map<String, Object> passbackParams) {
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
long purchaseId = NumberUtil.parseLong(purchaseRecordIdObj.toString());
private void notifyProductPayOrderFail(PayOrderDO orderDO) {
if (ObjectUtil.isNotNull(orderDO) && ObjectUtil.isNotNull(orderDO.getPurchaseId())) {
Long organId = orderDO.getOrganId();
Long purchaseId = orderDO.getPurchaseId();
PurchaseRecordDO record = purchaseService.getRecord(purchaseId);
// 1、产品购买第三方支付失败 删除购买记录
purchaseService.deleteRecord(purchaseId);
// 2、混合支付失败,退回扣除的现金和赠送金
BigDecimal zero = BigDecimal.ZERO;
BigDecimal accountBalanceSpent = record.getAccountBalanceSpent();
BigDecimal giftMoneySpent = record.getGiftMoneySpent();
OrganRechargeAmountRespVO organRefundProductRespVO = organAmountService.refundProductOrganAmountBalanceAndGift(organId, accountBalanceSpent, giftMoneySpent);
// 如果现金花费和赠送金花费任一不为0,则代表有要退回的操作
if (accountBalanceSpent.compareTo(zero) > 0 || giftMoneySpent.compareTo(zero) > 0) {
// 2、混合支付失败,退回扣除的现金和赠送金
OrganRechargeAmountRespVO organRefundProductRespVO = organAmountService.refundProductOrganAmountBalanceAndGift(organId, accountBalanceSpent, giftMoneySpent);
// 3、新增退回的收支记录
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
.organId(organId)
.orderNo(String.valueOf(record.getId()))
.businessNo(LocalDateTimeUtils.formatNow())
.tradeType(TradeTypeEnum.PRODUCT.getCode())
.incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getCode())
.cashAmountChange(accountBalanceSpent)
.giftAmountChange(giftMoneySpent)
.availableAmount(organRefundProductRespVO.getAvailableAmount())
.amount(organRefundProductRespVO.getAmount())
.giftAmount(organRefundProductRespVO.getGiftAmount())
.build();
incomeExpenseDetailsDO.setCreator(record.getCreator());
incomeExpenseDetailsDO.setUpdater(record.getUpdater());
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
// 4、回退前序购买记录的状态
purchaseService.activateHistoryOrganProductPurchaseRecord(organId, purchaseId);
// 3、新增退回的收支记录
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
.organId(organId)
.orderNo(String.valueOf(record.getId()))
.businessNo(LocalDateTimeUtils.formatNow())
.tradeType(TradeTypeEnum.PRODUCT.getCode())
.incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getCode())
.cashAmountChange(accountBalanceSpent)
.giftAmountChange(giftMoneySpent)
.availableAmount(organRefundProductRespVO.getAvailableAmount())
.amount(organRefundProductRespVO.getAmount())
.giftAmount(organRefundProductRespVO.getGiftAmount())
.build();
incomeExpenseDetailsDO.setCreator(record.getCreator());
incomeExpenseDetailsDO.setUpdater(record.getUpdater());
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
}
}
}
@@ -778,18 +776,48 @@ public class PayOrderServiceImpl implements PayOrderService {
// 2、调用三方接口,查询支付单状态,是不是已支付
PayOrderRespDTO payOrderRespDTO = payHandler.queryPayOrder(order.getPayNo());
if (PayOrderStatusEnum.isSuccess(payOrderRespDTO.getStatus())) {
notifyOrder(payOrderRespDTO);
return false;
if (PayOrderStatusEnum.isSuccess(payOrderRespDTO.getStatus()) || PayOrderStatusEnum.isClosed(payOrderRespDTO.getStatus())) {
notifyOrderWithTx(payOrderRespDTO);
log.info("[expireOrder][order({}) 更新为支付关闭成功]", order.getId());
return true;
}
log.info("[expireOrder][order({}) 更新为支付关闭失败]", order.getId());
return true;
// 3、系统内超期未支付状态是NOTPAY,主动关单后再次查询状态
if (PayOrderStatusEnum.WAITING.getStatus().equals(payOrderRespDTO.getStatus())) {
boolean closeOrderResult = payHandler.closeOrder(order.getPayNo());
if (closeOrderResult) {
payOrderRespDTO = payHandler.queryPayOrder(order.getPayNo());
if (PayOrderStatusEnum.isSuccess(payOrderRespDTO.getStatus()) || PayOrderStatusEnum.isClosed(payOrderRespDTO.getStatus())) {
notifyOrderWithTx(payOrderRespDTO);
log.info("[expireOrder][order({}) 更新为支付关闭成功]", order.getId());
return true;
}
}
}
return false;
} catch (Throwable e) {
log.error("[expireOrder][order({}) 过期订单异常]", order.getId(), e);
return false;
}
}
/**
* 手动控制支付回调中更新数据库操作的事务
*
* @param notify
*/
private void notifyOrderWithTx(PayOrderRespDTO notify) {
transactionTemplate.executeWithoutResult(status -> {
try {
notifyOrder(notify);
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
}
@Override
public PageResult<RechargeDetailRespVO> getRechargeDetailsPage(RechargeDetailsPageReqVO reqVO) {
// 分页查询
@@ -299,7 +299,7 @@ public class PayProductProcessor {
.monthAverageAmount(monthAverageAmount)
.alipaySpent(price)
.initial(initialized)
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
.status(PurchaseRecordStatusEnum.PENDING.getStatus())
.build();
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
@@ -340,7 +340,7 @@ public class PayProductProcessor {
.monthAverageAmount(monthAverageAmount)
.wechatSpent(price)
.initial(initialized)
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
.status(PurchaseRecordStatusEnum.PENDING.getStatus())
.build();
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
@@ -507,6 +507,7 @@ public class PayProductProcessor {
} else {
purchaseRecordDO.setWechatSpent(remaining);
}
purchaseRecordDO.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
}
// 更新余额
@@ -587,6 +588,7 @@ public class PayProductProcessor {
} else {
purchaseRecordDO.setWechatSpent(remaining);
}
purchaseRecordDO.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
}
// 更新余额
@@ -677,6 +679,7 @@ public class PayProductProcessor {
} else {
purchaseRecordDO.setWechatSpent(remaining);
}
purchaseRecordDO.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
}
// 更新余额
@@ -708,6 +711,7 @@ public class PayProductProcessor {
payOrderDO.setChannelCode(payChannelCodeEnum);
payOrderDO.setOrganId(organId);
payOrderDO.setPurchaseId(purchaseId);
payOrderDO.setTradeType(TradeTypeEnum.PRODUCT.getCode());
return payOrderDO;
}
@@ -37,4 +37,12 @@ public abstract class AbstractPayHandler {
* @return
*/
public abstract PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable;
/**
* 关闭订单
*
* @param outTradeNo 系统内部交易号
* @return 订单是否关闭成功
*/
public abstract boolean closeOrder(String outTradeNo) throws Throwable;
}
@@ -8,11 +8,14 @@ import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeCloseModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.cf.imes.framework.common.util.object.ObjectUtils;
@@ -21,7 +24,6 @@ import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
import com.cf.imes.module.system.controller.admin.pay.vo.PayOrderUnifiedReqDTO;
import com.cf.imes.framework.pay.core.enums.order.PayOrderStatusRespEnum;
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.PayConstants;
import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -30,7 +32,6 @@ import jakarta.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
@@ -63,7 +64,6 @@ public class AlipayPcPayHandler extends AbstractPayHandler {
model.setTimeExpire(LocalDateTimeUtil.format(reqDTO.getExpireTime(), NORM_DATETIME_FORMATTER));
model.setProductCode(alipayConfig.getProductCode());
model.setQrPayMode(alipayConfig.getQrPayMode());
model.setPassbackParams(JSON.toJSONString(reqDTO.getPassbackParams()));
// 1.2 构建 AlipayTradePagePayRequest 请求
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
@@ -81,7 +81,7 @@ public class AlipayPcPayHandler extends AbstractPayHandler {
outTradeNo, response);
}
return PayOrderRespDTO.waitingOf(null, response.getBody(),
outTradeNo, response, PayChannelCodeEnum.ALIPAY_PC.getCode());
outTradeNo, response.getTradeNo(), response, PayChannelCodeEnum.ALIPAY_PC.getCode());
}
@Override
@@ -118,15 +118,30 @@ public class AlipayPcPayHandler extends AbstractPayHandler {
Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
Integer status = parseStatus(bodyObj.get("trade_status"));
// 3.解析创建支付时候的个性化参数
String passbackParamsStr = bodyObj.get(PayConstants.PAY_PASSBACK_PARAMS_KEY);
Map<String, Object> passbackParams = JSON.parseObject(passbackParamsStr, Map.class);
Assert.notNull(status, (Supplier<Throwable>) () -> {
throw new IllegalArgumentException(CharSequenceUtil.format("body({}) 的 trade_status 不正确", body));
});
return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")),
bodyObj.get("out_trade_no"), body, passbackParams);
bodyObj.get("out_trade_no"), body);
}
@Override
public boolean closeOrder(String outTradeNo) throws AlipayApiException {
// 构造请求参数以调用接口
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
model.setOutTradeNo(outTradeNo);
request.setBizModel(model);
// 请求关单
DefaultAlipayClient client = new DefaultAlipayClient(alipayConfig);
AlipayTradeCloseResponse response = client.execute(request);
if (response.isSuccess()) {
return true;
} else {
return false;
}
}
/**
@@ -3,7 +3,6 @@ package com.cf.imes.module.system.service.pay.factory.impl.wechat;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson.JSON;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.pay.config.ChenfengWechatPayConfig;
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
@@ -14,7 +13,9 @@ import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
@@ -54,7 +55,6 @@ public class WechatNativePayHandler extends AbstractPayHandler {
request.setTimeExpire(formatDateV3(reqDTO.getExpireTime()));
request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(getClientIP()));
request.setNotifyUrl(reqDTO.getNotifyUrl());
request.setAttach(JSON.toJSONString(reqDTO.getPassbackParams()));
// 加载配置,创建client
WxPayService client = new WxPayServiceImpl();
@@ -65,12 +65,28 @@ public class WechatNativePayHandler extends AbstractPayHandler {
// 转换结果
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), JsonUtils.toJsonString(response),
reqDTO.getOutTradeNo(), response, PayChannelCodeEnum.WECHAT_NATIVE.getCode());
reqDTO.getOutTradeNo(), null, response, PayChannelCodeEnum.WECHAT_NATIVE.getCode());
}
@Override
public PayOrderRespDTO queryPayOrder(String outTradeNo) {
return null;
public PayOrderRespDTO queryPayOrder(String outTradeNo) throws WxPayException {
// 加载配置,创建client
WxPayService client = new WxPayServiceImpl();
client.setConfig(chenfengWechatPayConfig);
//todo 可能是 wxjava 的 bughttps://github.com/binarywang/WxJava/issues/1557
client.getConfig().setApiV3HttpClient(null);
// 构建 WxPayUnifiedOrderRequest 对象
WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request()
.setOutTradeNo(outTradeNo);
// 执行请求
WxPayOrderQueryV3Result response = client.queryOrderV3(request);
// 转换结果
Integer status = parseStatus(response.getTradeState());
String openid = response.getPayer() != null ? response.getPayer().getOpenid() : null;
return PayOrderRespDTO.of(status, response.getTransactionId(), openid, parseDateV3(response.getSuccessTime()),
outTradeNo, response);
}
@Override
@@ -87,13 +103,33 @@ public class WechatNativePayHandler extends AbstractPayHandler {
Integer status = parseStatus(result.getTradeState());
String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null;
return PayOrderRespDTO.of(status, result.getTransactionId(), openid, parseDateV3(result.getSuccessTime()),
result.getOutTradeNo(), body, JSON.parseObject(result.getAttach(), Map.class));
result.getOutTradeNo(), body);
}
@Override
public boolean closeOrder(String outTradeNo) {
// 加载配置,创建client
WxPayService client = new WxPayServiceImpl();
client.setConfig(chenfengWechatPayConfig);
//todo 可能是 wxjava 的 bughttps://github.com/binarywang/WxJava/issues/1557
client.getConfig().setApiV3HttpClient(null);
// 执行请求
try {
client.closeOrderV3(outTradeNo);
} catch (WxPayException wxPayException) {
log.error("微信关闭订单失败:{}", wxPayException);
return false;
}
return true;
}
static String formatDateV3(LocalDateTime time) {
return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN);
}
/**
* 组装请求头重的签名信息
*
@@ -120,7 +156,7 @@ public class WechatNativePayHandler extends AbstractPayHandler {
case "CLOSED":
case "REVOKED": // 已撤销(刷卡支付独有)
case "PAYERROR": // 支付失败(其它原因,如银行返回失败)
return PayOrderStatusEnum.FAIL.getStatus();
return PayOrderStatusEnum.CLOSED.getStatus();
default:
throw new IllegalArgumentException(CharSequenceUtil.format("未知的支付状态({})", tradeState));
}
@@ -236,6 +236,11 @@ chenfeng:
- advertisement
- system_advertisement_task
- gift_money_details
- pay_order
- purchase_record
- income_expense_details
- system_organization_amount
- product_delay_record
use-data-code: imes_prod #动态数据源标识,后期添加的数据源需要修改此值
xss:
@@ -252,6 +252,11 @@ chenfeng:
- advertisement
- system_advertisement_task
- gift_money_details
- pay_order
- purchase_record
- income_expense_details
- system_organization_amount
- product_delay_record
use-data-code: imes_prod #动态数据源标识,后期添加的数据源需要修改此值
env: # 多环境的配置项