mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-14 13:42:07 +08:00
完善软件购买时扣除延期时间区间、作废/待支付旧订购记录、第三方支付回调支持作废/激活旧支付记录流程
This commit is contained in:
+3
-2
@@ -3,6 +3,7 @@ package com.cf.imes.framework.redis.config;
|
|||||||
import cn.hutool.core.text.StrPool;
|
import cn.hutool.core.text.StrPool;
|
||||||
import com.cf.imes.framework.redis.core.TimeoutRedisCacheManager;
|
import com.cf.imes.framework.redis.core.TimeoutRedisCacheManager;
|
||||||
import com.cf.imes.framework.redis.util.RedisLockUtil;
|
import com.cf.imes.framework.redis.util.RedisLockUtil;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.cache.CacheProperties;
|
import org.springframework.boot.autoconfigure.cache.CacheProperties;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
@@ -81,7 +82,7 @@ public class ChenfengCacheAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RedisLockUtil lockUtil(RedisTemplate<String, Object> redisTemplate) {
|
public RedisLockUtil lockUtil(RedisTemplate<String, Object> redisTemplate, RedissonClient client) {
|
||||||
return new RedisLockUtil(redisTemplate);
|
return new RedisLockUtil(redisTemplate, client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -19,7 +19,7 @@ public class RedisKeyConstants {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 软件购买
|
||||||
*/
|
*/
|
||||||
public static final String PAY_NOTIFY_ORDER_LOCK_KEY = "pay_recharge_order:%s%s";
|
public static final String PRODUCT_PURCHASE_LOCK_KEY = "product_purchase:%s%s";
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -3,6 +3,8 @@ package com.cf.imes.framework.redis.util;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -19,6 +21,42 @@ public class RedisLockUtil {
|
|||||||
|
|
||||||
private RedisTemplate redisTemplate;
|
private RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加锁
|
||||||
|
*
|
||||||
|
* @param key rediskey
|
||||||
|
* @param timeout 锁的超时时间,传空则按照默认配置
|
||||||
|
* @param waitTime 等待获取锁的时间,传空则按照默认配置
|
||||||
|
* @return true拿到锁,反之没有做对应的业务提醒
|
||||||
|
*/
|
||||||
|
public boolean redissonLock(String key, Integer waitTime, Integer timeout) {
|
||||||
|
boolean getLock = false;
|
||||||
|
try {
|
||||||
|
RLock rLock = redissonClient.getLock(key);
|
||||||
|
return rLock.tryLock(waitTime, timeout, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[RedisLockUtil][lock]加锁失败", e);
|
||||||
|
return getLock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解锁
|
||||||
|
* 使用注意:配合以上redisson的lock只能在当前线程中unlock,否则失败!!!
|
||||||
|
*
|
||||||
|
* @param key rediskey
|
||||||
|
*/
|
||||||
|
public void redissonReleaseLock(String key) {
|
||||||
|
try {
|
||||||
|
RLock rLock = redissonClient.getLock(key);
|
||||||
|
rLock.unlock();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[RedisLockUtil][unlock]解锁失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动set nx ex加锁
|
* 手动set nx ex加锁
|
||||||
* 使用注意:可用于跨服务
|
* 使用注意:可用于跨服务
|
||||||
|
|||||||
+3
@@ -444,6 +444,7 @@ public class ErrorCodeConstants {
|
|||||||
public static final ErrorCode INVOICE_TITLE_ORG_EXISTS_ERROR = new ErrorCode(1_002_043_031, "组织下已存在发票抬头,请刷新后编辑抬头内容");
|
public static final ErrorCode INVOICE_TITLE_ORG_EXISTS_ERROR = new ErrorCode(1_002_043_031, "组织下已存在发票抬头,请刷新后编辑抬头内容");
|
||||||
public static final ErrorCode INVOICE_TITLE_TAXPAYERID_EXISTS_ERROR = new ErrorCode(1_002_043_032, "纳税人识别号已存在,请检查");
|
public static final ErrorCode INVOICE_TITLE_TAXPAYERID_EXISTS_ERROR = new ErrorCode(1_002_043_032, "纳税人识别号已存在,请检查");
|
||||||
public static final ErrorCode PRODUCTS_NOT_NOLIST = new ErrorCode(1_002_043_033, "当前产品未上架");
|
public static final ErrorCode PRODUCTS_NOT_NOLIST = new ErrorCode(1_002_043_033, "当前产品未上架");
|
||||||
|
public static final ErrorCode ORG_PRODUCT_PURCHASE_LOCK_ERROR = new ErrorCode(1_002_043_034, "组织下存在购买中的产品操作,请稍后再试");
|
||||||
|
|
||||||
//=========== 支付相关 1-002-048-000 ============
|
//=========== 支付相关 1-002-048-000 ============
|
||||||
public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道");
|
public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道");
|
||||||
@@ -489,6 +490,8 @@ public class ErrorCodeConstants {
|
|||||||
|
|
||||||
//=========== 产品延期管理 1-002-049-000 ============
|
//=========== 产品延期管理 1-002-049-000 ============
|
||||||
public static final ErrorCode PRODUCT_PURCHASE_NO_EXIST = new ErrorCode(1_002_049_001, "当前购买记录不存在,请检查");
|
public static final ErrorCode PRODUCT_PURCHASE_NO_EXIST = new ErrorCode(1_002_049_001, "当前购买记录不存在,请检查");
|
||||||
|
public static final ErrorCode PRODUCT_PURCHASE_ENDTIME_BEFORE_DELAYTIME_ERROR = new ErrorCode(1_002_049_002, "当前订购的产品延期时间{}超过续费时间{},请调整续费时长");
|
||||||
|
public static final ErrorCode PRODUCT_PURCHASE_ENDTIME_NOT_ENOUGH_ERROR = new ErrorCode(1_002_049_003, "本次订购的产品结束时间{}早于当前有效产品结束时间{},请勿重复订购");
|
||||||
|
|
||||||
//=========== 手工调账管理 1-002-050-000 ============
|
//=========== 手工调账管理 1-002-050-000 ============
|
||||||
public static final ErrorCode RECHARGE_GIFT_MEANWHILE_EMPTY_ERROR = new ErrorCode(1_002_050_001, "充值金额、赠送金额不能同时为空");
|
public static final ErrorCode RECHARGE_GIFT_MEANWHILE_EMPTY_ERROR = new ErrorCode(1_002_050_001, "充值金额、赠送金额不能同时为空");
|
||||||
|
|||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.cf.imes.module.system.controller.admin.funds.delay.vo;
|
||||||
|
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前序购买记留和延期记录Resp VO
|
||||||
|
*
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/9/19 15:29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PreviouProductDelayRespVO {
|
||||||
|
/**
|
||||||
|
* 前序购买记录
|
||||||
|
*/
|
||||||
|
private PurchaseRecordDO previouPurchaseRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前序购买记录下的延期记录
|
||||||
|
*/
|
||||||
|
private List<ProductDelayRespVO> delayRespVOList;
|
||||||
|
}
|
||||||
+6
@@ -1,5 +1,6 @@
|
|||||||
package com.cf.imes.module.system.controller.admin.funds.delay.vo;
|
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.alibaba.excel.annotation.ExcelProperty;
|
||||||
import com.cf.imes.framework.excel.core.annotations.EnumFormat;
|
import com.cf.imes.framework.excel.core.annotations.EnumFormat;
|
||||||
import com.cf.imes.framework.excel.core.convert.EnumConvert;
|
import com.cf.imes.framework.excel.core.convert.EnumConvert;
|
||||||
@@ -38,6 +39,11 @@ public class ProductDelayRespVO {
|
|||||||
@EnumFormat(value = DurationUnitEnum.class)
|
@EnumFormat(value = DurationUnitEnum.class)
|
||||||
private Integer delayDurationUnit;
|
private Integer delayDurationUnit;
|
||||||
|
|
||||||
|
@Schema(description = "产品结束时间")
|
||||||
|
@ExcelIgnore
|
||||||
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT)
|
||||||
|
private LocalDate endTime;
|
||||||
|
|
||||||
@Schema(description = "产品有效时间")
|
@Schema(description = "产品有效时间")
|
||||||
@ExcelProperty("产品有效时间")
|
@ExcelProperty("产品有效时间")
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT)
|
||||||
|
|||||||
+5
@@ -42,6 +42,11 @@ public class ProductDelayRecordDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private String organName;
|
private String organName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品id
|
||||||
|
*/
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品名称
|
* 产品名称
|
||||||
*/
|
*/
|
||||||
|
|||||||
+10
@@ -43,6 +43,11 @@ public class PurchaseRecordDO extends BaseDO {
|
|||||||
private Long organId;
|
private Long organId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上次订购记录ID
|
||||||
|
*/
|
||||||
|
private Long previousId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品ID
|
* 产品ID
|
||||||
*/
|
*/
|
||||||
@@ -163,4 +168,9 @@ public class PurchaseRecordDO extends BaseDO {
|
|||||||
* 是否首次订购
|
* 是否首次订购
|
||||||
*/
|
*/
|
||||||
private Boolean initial;
|
private Boolean initial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.cf.imes.module.system.enums.pay;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品购买记录状态枚举
|
||||||
|
*
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/9/18 15:50
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum PurchaseRecordStatusEnum {
|
||||||
|
/**
|
||||||
|
* 有效
|
||||||
|
*/
|
||||||
|
ACTIVE(1),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待支付
|
||||||
|
*/
|
||||||
|
PENDING(2),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作废
|
||||||
|
*/
|
||||||
|
INACTIVE(3);
|
||||||
|
|
||||||
|
private final Integer status;
|
||||||
|
}
|
||||||
+10
@@ -1,6 +1,7 @@
|
|||||||
package com.cf.imes.module.system.service.funds.delay;
|
package com.cf.imes.module.system.service.funds.delay;
|
||||||
|
|
||||||
import com.cf.imes.framework.common.pojo.PageResult;
|
import com.cf.imes.framework.common.pojo.PageResult;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.PreviouProductDelayRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayPageReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayPageReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelaySaveReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelaySaveReqVO;
|
||||||
@@ -37,4 +38,13 @@ public interface ProductDelayService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<ProductDelayRespVO> getRecordsByPurchaseId(Long purchaseId, Long organId);
|
List<ProductDelayRespVO> getRecordsByPurchaseId(Long purchaseId, Long organId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询组织产品下有效的延期记录
|
||||||
|
*
|
||||||
|
* @param productId
|
||||||
|
* @param organId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
PreviouProductDelayRespVO getActiveRecordsByProductId(Long productId, Long organId);
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -1,11 +1,14 @@
|
|||||||
package com.cf.imes.module.system.service.funds.delay;
|
package com.cf.imes.module.system.service.funds.delay;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.cf.imes.framework.common.pojo.PageResult;
|
import com.cf.imes.framework.common.pojo.PageResult;
|
||||||
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
||||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||||
|
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.PreviouProductDelayRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayPageReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayPageReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelaySaveReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelaySaveReqVO;
|
||||||
@@ -13,7 +16,9 @@ import com.cf.imes.module.system.dal.dataobject.funds.delay.ProductDelayRecordDO
|
|||||||
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
||||||
import com.cf.imes.module.system.dal.mysql.funds.delay.ProductDelayRecordMapper;
|
import com.cf.imes.module.system.dal.mysql.funds.delay.ProductDelayRecordMapper;
|
||||||
|
import com.cf.imes.module.system.dal.mysql.funds.purchase.PurchaseRecordMapper;
|
||||||
import com.cf.imes.module.system.enums.pay.DurationUnitEnum;
|
import com.cf.imes.module.system.enums.pay.DurationUnitEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PurchaseRecordStatusEnum;
|
||||||
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
|
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
|
||||||
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
|
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
|
||||||
import com.cf.imes.module.system.service.organ.OrganService;
|
import com.cf.imes.module.system.service.organ.OrganService;
|
||||||
@@ -45,6 +50,9 @@ public class ProductDelayServiceImpl implements ProductDelayService {
|
|||||||
@Resource
|
@Resource
|
||||||
private ProductDelayRecordMapper productDelayRecordMapper;
|
private ProductDelayRecordMapper productDelayRecordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PurchaseRecordMapper purchaseRecordMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createProductDelay(ProductDelaySaveReqVO productDelaySaveReqVO) {
|
public Long createProductDelay(ProductDelaySaveReqVO productDelaySaveReqVO) {
|
||||||
Long organId = productDelaySaveReqVO.getOrganId();
|
Long organId = productDelaySaveReqVO.getOrganId();
|
||||||
@@ -85,6 +93,7 @@ public class ProductDelayServiceImpl implements ProductDelayService {
|
|||||||
ProductDelayRecordDO productDelayRecordDO = ProductDelayRecordDO.builder()
|
ProductDelayRecordDO productDelayRecordDO = ProductDelayRecordDO.builder()
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.organName(organizationDO.getName())
|
.organName(organizationDO.getName())
|
||||||
|
.productId(purchaseRecordDO.getProductId())
|
||||||
.productName(purchaseRecordDO.getProductName())
|
.productName(purchaseRecordDO.getProductName())
|
||||||
.delayDuration(delayDuration)
|
.delayDuration(delayDuration)
|
||||||
.delayDurationUnit(delayDurationUnit)
|
.delayDurationUnit(delayDurationUnit)
|
||||||
@@ -147,4 +156,30 @@ public class ProductDelayServiceImpl implements ProductDelayService {
|
|||||||
.orderByDesc(ProductDelayRecordDO::getId)
|
.orderByDesc(ProductDelayRecordDO::getId)
|
||||||
.select(ProductDelayRecordDO::getDelayDuration, ProductDelayRecordDO::getDelayDurationUnit, ProductDelayRecordDO::getDelayTime)), ProductDelayRespVO.class);
|
.select(ProductDelayRecordDO::getDelayDuration, ProductDelayRecordDO::getDelayDurationUnit, ProductDelayRecordDO::getDelayTime)), ProductDelayRespVO.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreviouProductDelayRespVO getActiveRecordsByProductId(Long productId, Long organId) {
|
||||||
|
PreviouProductDelayRespVO previouProductDelayRespVO = new PreviouProductDelayRespVO();
|
||||||
|
PurchaseRecordDO purchaseRecordDO = purchaseRecordMapper.selectOne(new LambdaQueryWrapperX<PurchaseRecordDO>()
|
||||||
|
.eq(PurchaseRecordDO::getOrganId, organId)
|
||||||
|
.eq(PurchaseRecordDO::getProductId, productId)
|
||||||
|
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
|
);
|
||||||
|
List<ProductDelayRespVO> resultList;
|
||||||
|
if(ObjectUtil.isNotNull(purchaseRecordDO)) {
|
||||||
|
previouProductDelayRespVO.setPreviouPurchaseRecord(purchaseRecordDO);
|
||||||
|
List<ProductDelayRecordDO> recordDOS = productDelayRecordMapper.selectList(new LambdaQueryWrapper<ProductDelayRecordDO>()
|
||||||
|
.eq(ProductDelayRecordDO::getProductId, productId)
|
||||||
|
.eq(ProductDelayRecordDO::getOrganId, organId)
|
||||||
|
.eq(ProductDelayRecordDO::getPurchaseId, purchaseRecordDO.getId())
|
||||||
|
.eq(ProductDelayRecordDO::getDeleted, false)
|
||||||
|
.select(ProductDelayRecordDO::getDelayDuration, ProductDelayRecordDO::getDelayDurationUnit, ProductDelayRecordDO::getDelayTime, ProductDelayRecordDO::getEndTime)
|
||||||
|
);
|
||||||
|
if(CollUtil.isNotEmpty(recordDOS)) {
|
||||||
|
resultList = BeanUtil.copyToList(recordDOS, ProductDelayRespVO.class);
|
||||||
|
previouProductDelayRespVO.setDelayRespVOList(resultList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return previouProductDelayRespVO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -27,6 +27,13 @@ public interface PurchaseService {
|
|||||||
*/
|
*/
|
||||||
PurchaseRecordDO getRecord(Long id);
|
PurchaseRecordDO getRecord(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除购买记录
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void deleteRecord(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询购买记录分页
|
* 查询购买记录分页
|
||||||
*
|
*
|
||||||
@@ -116,4 +123,28 @@ public interface PurchaseService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId);
|
List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作废历史组织产品购买记录
|
||||||
|
*
|
||||||
|
* @param organId
|
||||||
|
* @param purchaseRecordId
|
||||||
|
*/
|
||||||
|
void pendingHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作废历史组织产品购买记录
|
||||||
|
*
|
||||||
|
* @param organId
|
||||||
|
* @param purchaseRecordId
|
||||||
|
*/
|
||||||
|
void invalidHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 激活历史组织产品购买记录
|
||||||
|
*
|
||||||
|
* @param organId
|
||||||
|
* @param purchaseRecordId
|
||||||
|
*/
|
||||||
|
void activateHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId);
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-2
@@ -8,7 +8,6 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|||||||
import com.cf.imes.framework.common.exception.ServiceException;
|
import com.cf.imes.framework.common.exception.ServiceException;
|
||||||
import com.cf.imes.framework.common.pojo.PageParam;
|
import com.cf.imes.framework.common.pojo.PageParam;
|
||||||
import com.cf.imes.framework.common.pojo.PageResult;
|
import com.cf.imes.framework.common.pojo.PageResult;
|
||||||
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
|
||||||
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
|
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalSalesAmountRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalSalesAmountRespVO;
|
||||||
@@ -28,6 +27,7 @@ import com.cf.imes.module.system.dal.mysql.funds.purchase.PurchaseRecordMapper;
|
|||||||
import com.cf.imes.module.system.enums.pay.InvoiceStatusEnum;
|
import com.cf.imes.module.system.enums.pay.InvoiceStatusEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
|
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
|
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PurchaseRecordStatusEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
||||||
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
|
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
|
||||||
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
|
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
|
||||||
@@ -75,6 +75,11 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|||||||
return purchaseRecordMapper.selectById(id);
|
return purchaseRecordMapper.selectById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteRecord(Long id) {
|
||||||
|
purchaseRecordMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<PurchaseRecordRespVO> getPurchaseRecord(PurchaseRecordPageReqVO pageReqVO) {
|
public PageResult<PurchaseRecordRespVO> getPurchaseRecord(PurchaseRecordPageReqVO pageReqVO) {
|
||||||
// 生成起时间0点和止时间12点的区间
|
// 生成起时间0点和止时间12点的区间
|
||||||
@@ -199,6 +204,7 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|||||||
.originalAmount(price)
|
.originalAmount(price)
|
||||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||||
.initial(true)
|
.initial(true)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
createRecord(purchaseRecordDO);
|
createRecord(purchaseRecordDO);
|
||||||
}
|
}
|
||||||
@@ -206,7 +212,10 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PurchaseRecordDO> getOrgPurchaseList(Set<Long> organIds) {
|
public List<PurchaseRecordDO> getOrgPurchaseList(Set<Long> organIds) {
|
||||||
return purchaseRecordMapper.selectList(new LambdaQueryWrapper<PurchaseRecordDO>().in(PurchaseRecordDO::getOrganId, organIds));
|
return purchaseRecordMapper.selectList(new LambdaQueryWrapper<PurchaseRecordDO>()
|
||||||
|
.in(PurchaseRecordDO::getOrganId, organIds)
|
||||||
|
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
|
.eq(PurchaseRecordDO::getDeleted, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -323,4 +332,34 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|||||||
|
|
||||||
return resultList;
|
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>()
|
||||||
|
.eq(PurchaseRecordDO::getOrganId, organId)
|
||||||
|
.eq(PurchaseRecordDO::getId, purchaseRecordId)
|
||||||
|
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
|
.eq(PurchaseRecordDO::getDeleted, false)
|
||||||
|
.set(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.INACTIVE.getStatus()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void activateHistoryOrganProductPurchaseRecord(Long organId, Long purchaseRecordId) {
|
||||||
|
purchaseRecordMapper.update(new LambdaUpdateWrapper<PurchaseRecordDO>()
|
||||||
|
.eq(PurchaseRecordDO::getOrganId, organId)
|
||||||
|
.eq(PurchaseRecordDO::getId, purchaseRecordId)
|
||||||
|
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.PENDING.getStatus())
|
||||||
|
.eq(PurchaseRecordDO::getDeleted, false)
|
||||||
|
.set(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.ACTIVE.getStatus()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+124
-47
@@ -22,6 +22,10 @@ import com.cf.imes.framework.organ.core.context.OrganContextHolder;
|
|||||||
import com.cf.imes.framework.pay.config.ChenfengAlipayConfig;
|
import com.cf.imes.framework.pay.config.ChenfengAlipayConfig;
|
||||||
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
||||||
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
|
import com.cf.imes.framework.redis.config.ChenfengCacheProperties;
|
||||||
|
import com.cf.imes.framework.redis.constants.RedisKeyConstants;
|
||||||
|
import com.cf.imes.framework.redis.util.RedisLockUtil;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.PreviouProductDelayRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeDetailRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeDetailRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeDetailsPageReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeDetailsPageReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.pay.vo.PayOrderUnifiedReqDTO;
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayOrderUnifiedReqDTO;
|
||||||
@@ -32,6 +36,7 @@ import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRech
|
|||||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductProcessorRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductProcessorRespVO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.pay.PayOrderRechargeDetailDO;
|
import com.cf.imes.module.system.dal.dataobject.pay.PayOrderRechargeDetailDO;
|
||||||
|
import com.cf.imes.module.system.service.funds.delay.ProductDelayService;
|
||||||
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
|
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
|
||||||
import com.cf.imes.module.system.controller.admin.pay.vo.PayProductOrderUnifiedReqVO;
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayProductOrderUnifiedReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO;
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO;
|
||||||
@@ -78,6 +83,7 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
|
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.PAY_NOTIFY_PASSBACK_NOT_EXISTS_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_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_CHANNEL_QUERY_NOT_EXIST;
|
||||||
@@ -139,6 +145,15 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
@Resource
|
@Resource
|
||||||
private OrganService organService;
|
private OrganService organService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProductDelayService productDelayService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisLockUtil redisLockUtil;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ChenfengCacheProperties chenfengCacheProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
|
public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
|
||||||
@@ -150,61 +165,107 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
|
|
||||||
// 校验产品和产品明细
|
// 校验产品和产品明细
|
||||||
ProductsDetailDO productsDetailDO = productsDetailService.validateProductDetailsExists(payProductOrderUnifiedReqVO.getProductDetailsId());
|
ProductsDetailDO productsDetailDO = productsDetailService.validateProductDetailsExists(payProductOrderUnifiedReqVO.getProductDetailsId());
|
||||||
ProductsDO productsDO = productsDetailService.validateProductExist(productsDetailDO.getProductId());
|
Long productId = productsDetailDO.getProductId();
|
||||||
|
ProductsDO productsDO = productsDetailService.validateProductExist(productId);
|
||||||
|
|
||||||
// 查询组织余额信息
|
// 检查机构产品购买锁
|
||||||
OrganAmountDO organAmount = organAmountService.validOrganAmount(organId);
|
String purchaseLockKey = String.format(RedisKeyConstants.PRODUCT_PURCHASE_LOCK_KEY, organId, productId);
|
||||||
|
boolean lockResult = redisLockUtil.redissonLock(purchaseLockKey, chenfengCacheProperties.getLockWaitTime(), chenfengCacheProperties.getLockTimeout());
|
||||||
// 查询组织产品的首次购买记录
|
if (!lockResult) {
|
||||||
PurchaseRecordDO orgInitialPurchaseRecord = purchaseService.getOrgInitialPurchaseRecord(organId, productsDO.getId());
|
throw new ServiceException(ORG_PRODUCT_PURCHASE_LOCK_ERROR);
|
||||||
|
|
||||||
// 根据购买类型做价格处理
|
|
||||||
PayProductProcessor payProductProcessor = new PayProductProcessor(productsDO, productsDetailDO, orgInitialPurchaseRecord, organAmount, organId, payConfig, mybatisIdProperties);
|
|
||||||
ProductProcessorRespVO productProcessorRespVO = payProductProcessor.processPayment(PayProductChannelCodeEnum.fromType(payProductOrderUnifiedReqVO.getProductChannelCode()));
|
|
||||||
|
|
||||||
// 记录入库,如果有外部支付发起请求二维码
|
|
||||||
// 购买记录入库
|
|
||||||
purchaseService.createRecord(productProcessorRespVO.getPurchaseRecordDO());
|
|
||||||
// 收支明细入库
|
|
||||||
IncomeExpenseDetailsDO incomeExpenseDetailsDO = productProcessorRespVO.getIncomeExpenseDetailsDO();
|
|
||||||
if (ObjectUtil.isNotNull(incomeExpenseDetailsDO)) {
|
|
||||||
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新组织资金,纯第三方支付不需要更新余额
|
PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = null;
|
||||||
OrganAmountDO finalOrganAmountDO = productProcessorRespVO.getOrganAmountDO();
|
// 获取渠道方处理器
|
||||||
if (ObjectUtil.isNotNull(finalOrganAmountDO)) {
|
Integer channelCode = PayProductChannelCodeEnum.isAliPay(payProductOrderUnifiedReqVO.getProductChannelCode()) ? PayChannelCodeEnum.ALIPAY_PC.getCode() : PayChannelCodeEnum.WECHAT_NATIVE.getCode();
|
||||||
organAmountService.productPay(finalOrganAmountDO);
|
try {
|
||||||
}
|
// 查询组织余额信息
|
||||||
|
OrganAmountDO organAmount = organAmountService.validOrganAmount(organId);
|
||||||
|
|
||||||
// 如果有外部支付,发起请求
|
// 查询组织产品的首次购买记录
|
||||||
PayOrderDO payOrder = productProcessorRespVO.getPayOrderDO();
|
PurchaseRecordDO orgInitialPurchaseRecord = purchaseService.getOrgInitialPurchaseRecord(organId, productsDO.getId());
|
||||||
if(ObjectUtil.isNotNull(payOrder)) {
|
|
||||||
payOrderMapper.insert(payOrder);
|
|
||||||
|
|
||||||
// 拼接充值个性化参数
|
// 查询组织有效产品购买记录下的延期记录
|
||||||
Map<String, Object> passbackParams = new HashMap<>();
|
PreviouProductDelayRespVO previouProductDelayRespVO = productDelayService.getActiveRecordsByProductId(productId, organId);
|
||||||
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,用于更新开票状态
|
|
||||||
|
|
||||||
// 发起渠道方支付
|
// 根据购买类型做价格处理
|
||||||
PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = null;
|
PayProductProcessor payProductProcessor = new PayProductProcessor(productsDO, productsDetailDO, orgInitialPurchaseRecord, previouProductDelayRespVO, organAmount, organId, payConfig, mybatisIdProperties);
|
||||||
Integer channelCode = PayProductChannelCodeEnum.isAliPay(payProductOrderUnifiedReqVO.getProductChannelCode()) ? PayChannelCodeEnum.ALIPAY_PC.getCode() : PayChannelCodeEnum.WECHAT_NATIVE.getCode();
|
ProductProcessorRespVO productProcessorRespVO = payProductProcessor.processPayment(PayProductChannelCodeEnum.fromType(payProductOrderUnifiedReqVO.getProductChannelCode()));
|
||||||
try {
|
PayOrderDO payOrder = productProcessorRespVO.getPayOrderDO();
|
||||||
// 获取渠道方处理器
|
|
||||||
|
// 处理前置的购买记录
|
||||||
|
processPreviosPurchaseRecord(previouProductDelayRespVO, payOrder);
|
||||||
|
|
||||||
|
// 记录入库,如果有外部支付发起请求二维码
|
||||||
|
// 购买记录入库
|
||||||
|
purchaseService.createRecord(productProcessorRespVO.getPurchaseRecordDO());
|
||||||
|
// 收支明细入库
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = productProcessorRespVO.getIncomeExpenseDetailsDO();
|
||||||
|
if (ObjectUtil.isNotNull(incomeExpenseDetailsDO)) {
|
||||||
|
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新组织资金,纯第三方支付不需要更新余额
|
||||||
|
OrganAmountDO finalOrganAmountDO = productProcessorRespVO.getOrganAmountDO();
|
||||||
|
if (ObjectUtil.isNotNull(finalOrganAmountDO)) {
|
||||||
|
organAmountService.productPay(finalOrganAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有外部支付,发起请求
|
||||||
|
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);
|
AbstractPayHandler payHandler = payHandlerFactory.getPayHandler(channelCode);
|
||||||
|
|
||||||
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder, passbackParams);
|
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder, passbackParams);
|
||||||
return payHandler.unifiedOrder(payOrderUnifiedReqDTO);
|
return payHandler.unifiedOrder(payOrderUnifiedReqDTO);
|
||||||
} catch (Throwable e) {
|
}
|
||||||
// 系统异常,则包装成 PayException 异常抛出
|
// 软件购买锁解锁
|
||||||
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
|
redisLockUtil.redissonReleaseLock(purchaseLockKey);
|
||||||
channelCode, JSON.toJSONString(payOrderUnifiedReqDTO), e);
|
return null;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 系统异常,则包装成 PayException 异常抛出
|
||||||
|
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
|
||||||
|
channelCode, JSON.toJSONString(payOrderUnifiedReqDTO), e);
|
||||||
|
if(e instanceof ServiceException) {
|
||||||
|
throw (ServiceException) e;
|
||||||
|
} else {
|
||||||
throw new PayException(PAY_ORDER_SUBMIT_CHANNEL_ERROR);
|
throw new PayException(PAY_ORDER_SUBMIT_CHANNEL_ERROR);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
// 软件购买锁解锁
|
||||||
|
redisLockUtil.redissonReleaseLock(purchaseLockKey);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
/**
|
||||||
|
* 处理前序购买记录:
|
||||||
|
* 1、需要第三方支付,更新为等待支付,第三方支付回调后作废
|
||||||
|
* 2、不需要第三方支付,直接作废
|
||||||
|
*
|
||||||
|
* @param previouProductDelayRespVO
|
||||||
|
* @param payOrder
|
||||||
|
*/
|
||||||
|
private void processPreviosPurchaseRecord(PreviouProductDelayRespVO previouProductDelayRespVO, PayOrderDO payOrder) {
|
||||||
|
// 前序购买记录
|
||||||
|
PurchaseRecordDO previouPurchaseRecord = previouProductDelayRespVO.getPreviouPurchaseRecord();
|
||||||
|
if (ObjectUtil.isNotNull(previouPurchaseRecord)) {
|
||||||
|
Long previousId = previouPurchaseRecord.getId();
|
||||||
|
Long organId = previouPurchaseRecord.getOrganId();
|
||||||
|
if (ObjectUtil.isNotNull(payOrder)) {
|
||||||
|
// 历史的购买记录更新为等待支付,需要第三方支付回调后作废前序
|
||||||
|
purchaseService.pendingHistoryOrganProductPurchaseRecord(organId, previousId);
|
||||||
|
} else {
|
||||||
|
// 作废历史的购买记录更新为等待支付
|
||||||
|
purchaseService.pendingHistoryOrganProductPurchaseRecord(organId, previousId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -228,7 +289,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode);
|
PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode);
|
||||||
// 设置赠送活动编号
|
// 设置赠送活动编号
|
||||||
Long rechargeActivityId = payRechargeOrderReqVO.getRechargeActivityId();
|
Long rechargeActivityId = payRechargeOrderReqVO.getRechargeActivityId();
|
||||||
if(ObjectUtil.isNotNull(rechargeActivityId)) {
|
if (ObjectUtil.isNotNull(rechargeActivityId)) {
|
||||||
// 校验活动类型和渠道是否匹配
|
// 校验活动类型和渠道是否匹配
|
||||||
validRechargeActivity(rechargeActivityId, channelCode);
|
validRechargeActivity(rechargeActivityId, channelCode);
|
||||||
payOrder.setRechargeActivityId(rechargeActivityId);
|
payOrder.setRechargeActivityId(rechargeActivityId);
|
||||||
@@ -541,15 +602,25 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品购买成功回调
|
* 产品购买成功回调
|
||||||
|
*
|
||||||
* @param organId
|
* @param organId
|
||||||
* @param passbackParams
|
* @param passbackParams
|
||||||
*/
|
*/
|
||||||
private void notifyProductPayOrderSuccess(Long organId, Map<String, Object> passbackParams) {
|
private void notifyProductPayOrderSuccess(Long organId, Map<String, Object> passbackParams) {
|
||||||
// 1、更新购买记录的开票状态
|
|
||||||
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
|
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
|
||||||
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
|
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
|
||||||
purchaseService.updateRecordInvoicable(NumberUtil.parseLong(purchaseRecordIdObj.toString()), organId);
|
// 1、更新购买记录的开票状态
|
||||||
|
long purchaseId = NumberUtil.parseLong(purchaseRecordIdObj.toString());
|
||||||
|
purchaseService.updateRecordInvoicable(purchaseId, organId);
|
||||||
|
|
||||||
|
// 2、作废前置购买记录
|
||||||
|
PurchaseRecordDO record = purchaseService.getRecord(purchaseId);
|
||||||
|
Long previousId = record.getPreviousId();
|
||||||
|
if (ObjectUtil.isNotNull(previousId)) {
|
||||||
|
purchaseService.invalidHistoryOrganProductPurchaseRecord(organId, previousId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -632,14 +703,17 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
private void notifyProductPayOrderFail(Long organId, Map<String, Object> passbackParams) {
|
private void notifyProductPayOrderFail(Long organId, Map<String, Object> passbackParams) {
|
||||||
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
|
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
|
||||||
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
|
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
|
||||||
PurchaseRecordDO record = purchaseService.getRecord(NumberUtil.parseLong(purchaseRecordIdObj.toString()));
|
long purchaseId = NumberUtil.parseLong(purchaseRecordIdObj.toString());
|
||||||
|
PurchaseRecordDO record = purchaseService.getRecord(purchaseId);
|
||||||
|
// 1、产品购买第三方支付失败 删除购买记录
|
||||||
|
purchaseService.deleteRecord(purchaseId);
|
||||||
|
|
||||||
// 1、混合支付失败,退回扣除的现金和赠送金
|
// 2、混合支付失败,退回扣除的现金和赠送金
|
||||||
BigDecimal accountBalanceSpent = record.getAccountBalanceSpent();
|
BigDecimal accountBalanceSpent = record.getAccountBalanceSpent();
|
||||||
BigDecimal giftMoneySpent = record.getGiftMoneySpent();
|
BigDecimal giftMoneySpent = record.getGiftMoneySpent();
|
||||||
OrganRechargeAmountRespVO organRefundProductRespVO = organAmountService.refundProductOrganAmountBalanceAndGift(organId, accountBalanceSpent, giftMoneySpent);
|
OrganRechargeAmountRespVO organRefundProductRespVO = organAmountService.refundProductOrganAmountBalanceAndGift(organId, accountBalanceSpent, giftMoneySpent);
|
||||||
|
|
||||||
// 2、新增退回的收支记录
|
// 3、新增退回的收支记录
|
||||||
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.orderNo(String.valueOf(record.getId()))
|
.orderNo(String.valueOf(record.getId()))
|
||||||
@@ -655,6 +729,9 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
incomeExpenseDetailsDO.setCreator(record.getCreator());
|
incomeExpenseDetailsDO.setCreator(record.getCreator());
|
||||||
incomeExpenseDetailsDO.setUpdater(record.getUpdater());
|
incomeExpenseDetailsDO.setUpdater(record.getUpdater());
|
||||||
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
||||||
|
|
||||||
|
// 4、回退前序购买记录的状态
|
||||||
|
purchaseService.activateHistoryOrganProductPurchaseRecord(organId, purchaseId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+109
-9
@@ -1,13 +1,18 @@
|
|||||||
package com.cf.imes.module.system.service.pay;
|
package com.cf.imes.module.system.service.pay;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.date.DatePattern;
|
import cn.hutool.core.date.DatePattern;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.cf.imes.framework.common.exception.ServiceException;
|
import com.cf.imes.framework.common.exception.ServiceException;
|
||||||
|
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
|
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
||||||
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.PreviouProductDelayRespVO;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductProcessorRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductProcessorRespVO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||||
@@ -22,6 +27,7 @@ import com.cf.imes.module.system.enums.pay.PayConstants;
|
|||||||
import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
|
import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
|
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
|
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PurchaseRecordStatusEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
||||||
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
|
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
|
||||||
|
|
||||||
@@ -29,11 +35,16 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT;
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT;
|
||||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_BALANCE_INSUFFICIENT;
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_BALANCE_INSUFFICIENT;
|
||||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT;
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT;
|
||||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT;
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT;
|
||||||
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCT_PURCHASE_ENDTIME_BEFORE_DELAYTIME_ERROR;
|
||||||
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCT_PURCHASE_ENDTIME_NOT_ENOUGH_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品购买类型处理器
|
* 产品购买类型处理器
|
||||||
@@ -59,11 +70,19 @@ public class PayProductProcessor {
|
|||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
|
|
||||||
public PayProductProcessor(ProductsDO productsDO, ProductsDetailDO productsDetailDO, PurchaseRecordDO orgInitialPurchaseRecord, OrganAmountDO organAmountDO,
|
private PreviouProductDelayRespVO previouProductDelayRespVO;
|
||||||
Long organId, ChenfengPayConfig payConfig, MybatisIdProperties mybatisIdProperties) {
|
|
||||||
|
private PurchaseRecordDO previousPurchaseRecord;
|
||||||
|
|
||||||
|
public PayProductProcessor(ProductsDO productsDO, ProductsDetailDO productsDetailDO, PurchaseRecordDO orgInitialPurchaseRecord, PreviouProductDelayRespVO previouProductDelayRespVO,
|
||||||
|
OrganAmountDO organAmountDO, Long organId, ChenfengPayConfig payConfig, MybatisIdProperties mybatisIdProperties) {
|
||||||
this.productsDO = productsDO;
|
this.productsDO = productsDO;
|
||||||
this.productsDetailDO = productsDetailDO;
|
this.productsDetailDO = productsDetailDO;
|
||||||
this.orgInitialPurchaseRecord = orgInitialPurchaseRecord;
|
this.orgInitialPurchaseRecord = orgInitialPurchaseRecord;
|
||||||
|
this.previouProductDelayRespVO = previouProductDelayRespVO;
|
||||||
|
if (ObjectUtil.isNotNull(previouProductDelayRespVO.getPreviouPurchaseRecord())) {
|
||||||
|
previousPurchaseRecord = previouProductDelayRespVO.getPreviouPurchaseRecord();
|
||||||
|
}
|
||||||
this.organAmountDO = organAmountDO;
|
this.organAmountDO = organAmountDO;
|
||||||
this.organId = organId;
|
this.organId = organId;
|
||||||
this.payConfig = payConfig;
|
this.payConfig = payConfig;
|
||||||
@@ -149,6 +168,7 @@ public class PayProductProcessor {
|
|||||||
.accountBalanceSpent(price)
|
.accountBalanceSpent(price)
|
||||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
@@ -206,6 +226,7 @@ public class PayProductProcessor {
|
|||||||
.accountBalanceSpent(price)
|
.accountBalanceSpent(price)
|
||||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
@@ -245,7 +266,6 @@ public class PayProductProcessor {
|
|||||||
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
.id(purchaseId)
|
.id(purchaseId)
|
||||||
.organId(organId)
|
.organId(organId)
|
||||||
.organId(organId)
|
|
||||||
.productId(productsDO.getId())
|
.productId(productsDO.getId())
|
||||||
.productName(productsDO.getProductName())
|
.productName(productsDO.getProductName())
|
||||||
.productDetailsId(productsDetailDO.getId())
|
.productDetailsId(productsDetailDO.getId())
|
||||||
@@ -260,10 +280,15 @@ public class PayProductProcessor {
|
|||||||
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
||||||
.alipaySpent(price)
|
.alipaySpent(price)
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 记录前序购买记录id
|
||||||
|
if (ObjectUtil.isNotNull(previousPurchaseRecord)) {
|
||||||
|
purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId());
|
||||||
|
}
|
||||||
|
|
||||||
// 新增第三方支付订单
|
// 新增第三方支付订单
|
||||||
PayOrderDO payOrderDO = goExternalPay(purchaseId, price, PayChannelCodeEnum.ALIPAY_PC);
|
PayOrderDO payOrderDO = goExternalPay(purchaseId, price, PayChannelCodeEnum.ALIPAY_PC);
|
||||||
@@ -296,10 +321,15 @@ public class PayProductProcessor {
|
|||||||
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
||||||
.wechatSpent(price)
|
.wechatSpent(price)
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 记录前序购买记录id
|
||||||
|
if (ObjectUtil.isNotNull(previousPurchaseRecord)) {
|
||||||
|
purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId());
|
||||||
|
}
|
||||||
|
|
||||||
// 新增第三方支付订单
|
// 新增第三方支付订单
|
||||||
PayOrderDO payOrderDO = goExternalPay(purchaseId, price, PayChannelCodeEnum.WECHAT_NATIVE);
|
PayOrderDO payOrderDO = goExternalPay(purchaseId, price, PayChannelCodeEnum.WECHAT_NATIVE);
|
||||||
@@ -337,6 +367,7 @@ public class PayProductProcessor {
|
|||||||
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
||||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
@@ -413,10 +444,15 @@ public class PayProductProcessor {
|
|||||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||||
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 记录前序购买记录id
|
||||||
|
if (ObjectUtil.isNotNull(previousPurchaseRecord)) {
|
||||||
|
purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId());
|
||||||
|
}
|
||||||
|
|
||||||
// 先用余额
|
// 先用余额
|
||||||
if (balance != null && balance.compareTo(BigDecimal.ZERO) > 0) {
|
if (balance != null && balance.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -488,11 +524,15 @@ public class PayProductProcessor {
|
|||||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||||
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 记录前序购买记录id
|
||||||
|
if (ObjectUtil.isNotNull(previousPurchaseRecord)) {
|
||||||
|
purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId());
|
||||||
|
}
|
||||||
|
|
||||||
// 先用余额
|
// 先用余额
|
||||||
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -566,10 +606,15 @@ public class PayProductProcessor {
|
|||||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||||
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
.monthAverageAmount(orgInitialPurchaseRecord.getMonthAverageAmount())
|
||||||
.initial(initialized)
|
.initial(initialized)
|
||||||
|
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||||
.build();
|
.build();
|
||||||
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 记录前序购买记录id
|
||||||
|
if (ObjectUtil.isNotNull(previousPurchaseRecord)) {
|
||||||
|
purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId());
|
||||||
|
}
|
||||||
|
|
||||||
// 先用赠送金
|
// 先用赠送金
|
||||||
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -657,20 +702,37 @@ public class PayProductProcessor {
|
|||||||
* @param giftDurationUnit
|
* @param giftDurationUnit
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static LocalDate calculateEndTime(LocalDate startTime, Integer duration, Integer durationUnit,
|
private LocalDate calculateEndTime(LocalDate startTime, Integer duration, Integer durationUnit,
|
||||||
Integer giftDuration, Integer giftDurationUnit) {
|
Integer giftDuration, Integer giftDurationUnit) {
|
||||||
|
LocalDate endTime = startTime;
|
||||||
// 加正常时间
|
// 加正常时间
|
||||||
if (ObjectUtil.isNotNull(duration) && durationUnit != null) {
|
if (ObjectUtil.isNotNull(duration) && durationUnit != null) {
|
||||||
startTime = addTime(startTime, duration, durationUnit);
|
endTime = addTime(startTime, duration, durationUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加赠送时间
|
// 加赠送时间
|
||||||
if (ObjectUtil.isNotNull(giftDuration) && giftDurationUnit != null) {
|
if (ObjectUtil.isNotNull(giftDuration) && giftDurationUnit != null) {
|
||||||
startTime = addTime(startTime, giftDuration, giftDurationUnit);
|
endTime = addTime(startTime, giftDuration, giftDurationUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
return startTime;
|
List<ProductDelayRespVO> delayRespVOList = previouProductDelayRespVO.getDelayRespVOList();
|
||||||
|
if (CollUtil.isNotEmpty(delayRespVOList)) {
|
||||||
|
// 根据延期列表计算新的结束时间
|
||||||
|
endTime = calculateDelayEndTime(startTime, endTime, delayRespVOList);
|
||||||
|
}
|
||||||
|
|
||||||
|
PurchaseRecordDO previouPurchaseRecord = previouProductDelayRespVO.getPreviouPurchaseRecord();
|
||||||
|
if (ObjectUtil.isNotNull(previouPurchaseRecord)) {
|
||||||
|
// 如果本次订购的时间小于上次订购的结束时间,提示请勿重复订购
|
||||||
|
LocalDate previouPurchaseRecordEndTime = previouPurchaseRecord.getEndTime();
|
||||||
|
if (endTime.isBefore(previouPurchaseRecordEndTime)) {
|
||||||
|
throw ServiceExceptionUtil.exception(PRODUCT_PURCHASE_ENDTIME_NOT_ENOUGH_ERROR,
|
||||||
|
LocalDateTimeUtil.format(endTime, DatePattern.NORM_DATE_PATTERN),
|
||||||
|
LocalDateTimeUtil.format(previouPurchaseRecordEndTime, DatePattern.NORM_DATE_PATTERN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return endTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -692,6 +754,44 @@ public class PayProductProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据延期列表中最早的产品结束时间和最晚的延期后时间计算新的结束时间
|
||||||
|
*
|
||||||
|
* @param startTime 订购的开始时间
|
||||||
|
* @param endTime 订购的结束时间
|
||||||
|
* @param delayRecordsList 延期列表
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static LocalDate calculateDelayEndTime(LocalDate startTime, LocalDate endTime, List<ProductDelayRespVO> delayRecordsList) {
|
||||||
|
// 筛选出延期列表结束时间排序最早和最晚的
|
||||||
|
ProductDelayRespVO earliestDelayVO = delayRecordsList.stream().min(Comparator.comparing(ProductDelayRespVO::getEndTime)).get();
|
||||||
|
ProductDelayRespVO lastestDelayVO = delayRecordsList.stream().max(Comparator.comparing(ProductDelayRespVO::getDelayTime)).get();
|
||||||
|
|
||||||
|
// 延期结束时间超过续费结束时间,提示重新选择续费时长
|
||||||
|
LocalDate delayEndTime = earliestDelayVO.getEndTime();
|
||||||
|
if (delayEndTime.isAfter(endTime)) {
|
||||||
|
throw ServiceExceptionUtil.exception(PRODUCT_PURCHASE_ENDTIME_BEFORE_DELAYTIME_ERROR,
|
||||||
|
LocalDateTimeUtil.format(delayEndTime, DatePattern.NORM_DATE_PATTERN),
|
||||||
|
LocalDateTimeUtil.format(endTime, DatePattern.NORM_DATE_PATTERN));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 延期区间: [原结束日+1, 延期结束日]
|
||||||
|
LocalDate delayStart = delayEndTime.plusDays(1);
|
||||||
|
LocalDate delayEnd = lastestDelayVO.getDelayTime();
|
||||||
|
|
||||||
|
// 购买区间: [startTime, endTime]
|
||||||
|
LocalDate overlapStart = startTime.isAfter(delayStart) ? startTime : delayStart;
|
||||||
|
LocalDate overlapEnd = endTime.isBefore(delayEnd) ? endTime : delayEnd;
|
||||||
|
|
||||||
|
long overlapDays = 0;
|
||||||
|
if (!overlapEnd.isBefore(overlapStart)) {
|
||||||
|
overlapDays = ChronoUnit.DAYS.between(overlapStart, overlapEnd) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 endTime 扣掉重合天数
|
||||||
|
return endTime.minusDays(overlapDays);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算产品价格
|
* 计算产品价格
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user