mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
1、优化第三方支付透传参数改为存在数据库中;2、新增超时支付单的轮训处理、增加关闭和待支付的判定和对应处理;3、新增更新前序购买记录的已支付属性;
This commit is contained in:
+8
-25
@@ -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】状态的订单返回,适合调用支付渠道失败时
|
||||
*/
|
||||
|
||||
-5
@@ -85,11 +85,6 @@ public class PayOrderUnifiedReqDTO {
|
||||
*/
|
||||
private Map<String, String> channelExtras;
|
||||
|
||||
/**
|
||||
* 发起支付给支付方后,异步回调原封不动回到调用方
|
||||
*/
|
||||
private Map<String, Object> passbackParams;
|
||||
|
||||
/**
|
||||
* 展示模式
|
||||
*
|
||||
|
||||
+25
@@ -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();
|
||||
}
|
||||
+73
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
@@ -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, "广告所选放置位置不存在");
|
||||
|
||||
+7
@@ -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;
|
||||
}
|
||||
|
||||
-5
@@ -90,11 +90,6 @@ public class PayOrderUnifiedReqDTO {
|
||||
*/
|
||||
private Map<String, String> channelExtras;
|
||||
|
||||
/**
|
||||
* 发起支付给支付方后,异步回调原封不动回到调用方
|
||||
*/
|
||||
private Map<String, Object> passbackParams;
|
||||
|
||||
/**
|
||||
* 展示模式
|
||||
*
|
||||
|
||||
+5
@@ -77,6 +77,11 @@ public class ProductDelayRecordDO extends BaseDO {
|
||||
*/
|
||||
private Long purchaseId;
|
||||
|
||||
/**
|
||||
* 是否支付
|
||||
*/
|
||||
private Boolean paid;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
||||
+5
-1
@@ -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;
|
||||
}
|
||||
|
||||
+2
-1
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -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;
|
||||
}
|
||||
-6
@@ -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
|
||||
}
|
||||
+8
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -47,4 +47,13 @@ public interface ProductDelayService {
|
||||
* @return
|
||||
*/
|
||||
PreviouProductDelayRespVO getActiveRecordsByProductId(Long productId, Long organId);
|
||||
|
||||
|
||||
/**
|
||||
* 更新购买记录下的延期记录为已支付
|
||||
*
|
||||
* @param purchaseId
|
||||
* @param organId
|
||||
*/
|
||||
void updatePurchaseDelayRecordsPaid(Long purchaseId, Long organId);
|
||||
}
|
||||
|
||||
+10
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-10
@@ -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);
|
||||
|
||||
/**
|
||||
* 作废历史组织产品购买记录
|
||||
*
|
||||
|
||||
+8
-15
@@ -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>()
|
||||
|
||||
+106
-78
@@ -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) {
|
||||
// 分页查询
|
||||
|
||||
+6
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -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;
|
||||
}
|
||||
|
||||
+24
-9
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+43
-7
@@ -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 的 bug:https://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 的 bug:https://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: # 多环境的配置项
|
||||
|
||||
Reference in New Issue
Block a user