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、软件购买定价规则自动展示1~10月的价格和参考定价中年的展示;3、产品管理和定价管理适配新的需求入参;
This commit is contained in:
+1
@@ -474,6 +474,7 @@ public class ErrorCodeConstants {
|
||||
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, "组织下存在当前产品的待支付记录,请确认或取消支付后再次发起软件购买");
|
||||
public static final ErrorCode PRODUCT_PRICE_NULL_ERROR = new ErrorCode(1_002_045_013, "产品建议价格为空,请联系客服");
|
||||
|
||||
//=========== 广告相关 1-002-046-000 ============
|
||||
public static final ErrorCode ADVERTISEMENT_POSITION_NO_EXIST = new ErrorCode(1_002_046_001, "广告所选放置位置不存在");
|
||||
|
||||
+7
-8
@@ -33,31 +33,30 @@ public class ProductsController {
|
||||
|
||||
@PutMapping("")
|
||||
@Operation(summary = "新建产品")
|
||||
public CommonResult<Long> createProducts(@RequestParam("productName") String productName) {
|
||||
return success(productsService.create(productName));
|
||||
public CommonResult<Long> createProducts(@Valid @RequestBody ProductSaveReqVO updateReqVO) {
|
||||
return success(productsService.create(updateReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("")
|
||||
@Operation(summary = "更新产品")
|
||||
public CommonResult<Boolean> updateProducts(@Valid @RequestBody ProductSaveReqVO updateReqVO) {
|
||||
ProductsDO productsDO = BeanUtils.toBean(updateReqVO, ProductsDO.class);
|
||||
productsService.update(productsDO);
|
||||
productsService.update(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/freeze")
|
||||
@Operation(summary = "下架产品")
|
||||
public CommonResult<Boolean> freezeProducts(@Valid Long id) {
|
||||
ProductsDO productsDO = new ProductsDO().setId(id).setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
|
||||
productsService.update(productsDO);
|
||||
ProductSaveReqVO updateReqVO = new ProductSaveReqVO().setId(id).setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
|
||||
productsService.update(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/melt")
|
||||
@Operation(summary = "上架产品")
|
||||
public CommonResult<Boolean> meltProducts(@Valid Long id) {
|
||||
ProductsDO productsDO = new ProductsDO().setId(id).setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
|
||||
productsService.update(productsDO);
|
||||
ProductSaveReqVO updateReqVO = new ProductSaveReqVO().setId(id).setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
|
||||
productsService.update(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -74,8 +74,8 @@ public class ProductsDetailController {
|
||||
@Parameter(name = "organId", description = "组织编号", required = true, example = "1")
|
||||
@Parameter(name = "productId", description = "产品编号", required = true, example = "1")
|
||||
public CommonResult<List<ProductDetailsRespVO>> getOrgProductDetailList(@RequestParam("organId") Long organId, @RequestParam("productId") Long productId) {
|
||||
List<ProductsDetailDO> pageResult = purchaseService.getOrgProductDetailList(organId, productId);
|
||||
return success(BeanUtils.toBean(pageResult, ProductDetailsRespVO.class));
|
||||
List<ProductDetailsRespVO> pageResult = purchaseService.getOrgProductDetailList(organId, productId);
|
||||
return success(pageResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -6,6 +6,7 @@ import com.cf.imes.module.system.validation.products.ProductStatus;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 产品表 products Response VO")
|
||||
@@ -34,4 +35,7 @@ public class ProductRespVO {
|
||||
@ExcelProperty("编辑时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@Schema(description = "建议价格")
|
||||
@ExcelProperty("建议价格")
|
||||
private BigDecimal price;
|
||||
}
|
||||
|
||||
+13
@@ -2,11 +2,17 @@ package com.cf.imes.module.system.controller.admin.funds.products.vo.product;
|
||||
|
||||
import com.cf.imes.module.system.validation.products.ProductStatus;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 产品表 product新增/修改 Request VO")
|
||||
@Data
|
||||
public class ProductSaveReqVO {
|
||||
@@ -19,6 +25,13 @@ public class ProductSaveReqVO {
|
||||
@Size(max = 64, message = "产品名称长度不能超过64")
|
||||
private String productName;
|
||||
|
||||
@Schema(description = "产品建议价格")
|
||||
@NotNull(message = "产品建议价格不能为空")
|
||||
@DecimalMin(value = "0.01", message = "产品建议价格必须大于零")
|
||||
@DecimalMax(value = "100000", message = "产品建议价格不能超过十万")
|
||||
@Digits(integer = 6, fraction = 2, message = "产品建议价格格式不正确")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ProductStatus
|
||||
private Integer status;
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class ProductDetailsRespVO {
|
||||
private Integer purchaseType;
|
||||
|
||||
@Schema(description = "购买时长", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private String duration;
|
||||
private Integer duration;
|
||||
|
||||
@Schema(description = "产品时长单位,0:年、1:月", example = "1")
|
||||
private Integer durationUnit;
|
||||
|
||||
+4
-23
@@ -1,8 +1,7 @@
|
||||
package com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails;
|
||||
|
||||
import com.cf.imes.framework.common.validation.NumberValid;
|
||||
import com.cf.imes.module.system.enums.products.ProductsPurchaseTypeEnum;
|
||||
import com.cf.imes.module.system.validation.products.ProductDurationUnitValid;
|
||||
import com.cf.imes.module.system.validation.products.ProductType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
@@ -24,46 +23,28 @@ public class ProductDetailsSaveReqVO {
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "购买方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "购买方式不能为空")
|
||||
@ProductType
|
||||
private Integer purchaseType;
|
||||
private Integer purchaseType = ProductsPurchaseTypeEnum.DURATION.getStatus();
|
||||
|
||||
@Schema(description = "产品时间,格式:时长值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private String duration;
|
||||
|
||||
@Schema(description = "产品时长单位,0:年、1:月", example = "1")
|
||||
@Schema(description = "产品时长单位,0:年", example = "1")
|
||||
@ProductDurationUnitValid
|
||||
private Integer durationUnit;
|
||||
|
||||
@Schema(description = "产品产量", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
|
||||
private BigDecimal output;
|
||||
|
||||
@Schema(description = "赠送时间,格式:时长值 - 时间单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private String giftDuration;
|
||||
|
||||
@Schema(description = "赠送时长单位,0:年、1:月", example = "1")
|
||||
@ProductDurationUnitValid
|
||||
private Integer giftDurationUnit;
|
||||
|
||||
@Schema(description = "赠送产量", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
|
||||
private BigDecimal giftOutput;
|
||||
|
||||
@Schema(description = "产品原价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "产品原价不能为空")
|
||||
@NumberValid(name = "产品原价")
|
||||
private BigDecimal originalPrice;
|
||||
|
||||
@Schema(description = "折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.8")
|
||||
@DecimalMax(value = "100", message = "折扣必须小于等于100")
|
||||
@DecimalMin(value = "0", message = "折扣必须大于等于0")
|
||||
@Digits(integer = 3, fraction = 0, message = "折扣必须是0 ~ 100间的整数")
|
||||
@NotNull(message = "折扣不能为空")
|
||||
private BigDecimal discount;
|
||||
|
||||
@Schema(description = "产品现价", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
|
||||
@NotNull(message = "产品现价不能为空")
|
||||
@NumberValid(name = "产品现价")
|
||||
private BigDecimal currentPrice;
|
||||
|
||||
@Schema(description = "是否特惠", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean isDiscounted;
|
||||
|
||||
|
||||
-6
@@ -1,6 +1,5 @@
|
||||
package com.cf.imes.module.system.controller.admin.funds.purchase.vo;
|
||||
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -18,9 +17,4 @@ public class OrgEarliestPurchaseProductRespVO {
|
||||
* 购买记录
|
||||
*/
|
||||
private PurchaseRecordDO purchaseRecordDO;
|
||||
|
||||
/**
|
||||
* 产品定价规则
|
||||
*/
|
||||
private ProductsDetailDO productsDetailDO;
|
||||
}
|
||||
|
||||
+2
-2
@@ -116,7 +116,7 @@ public class OrganController {
|
||||
|
||||
Long organId = bean.getId();
|
||||
// 查询当次列表组织下的所有购买记录
|
||||
List<OrganPagePurchaseRespVO> orgPurchaseList = BeanUtil.copyToList(purchaseService.getOrgPurchaseList(Set.of(organId)), OrganPagePurchaseRespVO.class);
|
||||
List<OrganPagePurchaseRespVO> orgPurchaseList = BeanUtil.copyToList(purchaseService.getOrgPurchaseNotInitialList(Set.of(organId)), OrganPagePurchaseRespVO.class);
|
||||
// 查询购买记录下的延期记录
|
||||
orgPurchaseList.forEach(p -> {
|
||||
List<ProductDelayRespVO> delayRecordsByPurchaseId = productDelayService.getRecordsByPurchaseId(p.getId(), organId);
|
||||
@@ -143,7 +143,7 @@ public class OrganController {
|
||||
|
||||
Set<Long> organIds = bean.getList().stream().map(OrganRespVO::getId).collect(Collectors.toSet());
|
||||
// 查询当次列表组织下的所有购买记录
|
||||
List<PurchaseRecordDO> orgPurchaseList = purchaseService.getOrgPurchaseList(organIds);
|
||||
List<PurchaseRecordDO> orgPurchaseList = purchaseService.getOrgPurchaseNotInitialList(organIds);
|
||||
// 匹配到对应的组织下
|
||||
bean.getList().forEach(e -> {
|
||||
List<OrganPagePurchaseRespVO> purchaseRespVOList = orgPurchaseList.stream()
|
||||
|
||||
-9
@@ -8,7 +8,6 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Schema(description = "管理后台 - 组织创建购买产品 Request VO")
|
||||
@Data
|
||||
@@ -17,18 +16,10 @@ public class OrganCreateProductPurchaseReqVO {
|
||||
@NotNull(message = "产品编号不能为空", groups = {OrganSaveCreateGroup.class})
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "定价规则编号", example = "1")
|
||||
@NotNull(message = "定价规则编号不能为空", groups = {OrganSaveCreateGroup.class})
|
||||
private Long productDetailsId;
|
||||
|
||||
@Schema(description = "产品购买金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "产品购买金额不能为空", groups = {OrganSaveCreateGroup.class})
|
||||
@DecimalMin(value = "0.01", message = "产品购买金额必须大于零")
|
||||
@DecimalMax(value = "100000", message = "产品购买金额不能超过十万")
|
||||
@Digits(integer = 6, fraction = 2, message = "产品购买金额格式不正确")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "产品有效时间")
|
||||
@NotNull(message = "产品有效时间不能为空", groups = {OrganSaveCreateGroup.class})
|
||||
private LocalDate productExpireDate;
|
||||
}
|
||||
|
||||
+4
-1
@@ -3,7 +3,6 @@ package com.cf.imes.module.system.controller.admin.pay.vo;
|
||||
import com.cf.imes.module.system.validation.pay.PayProductChannelCodeValid;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -23,6 +22,10 @@ public class PayProductOrderUnifiedReqVO {
|
||||
@NotNull(message = "产品定价规则编号不能为空")
|
||||
private Long productDetailsId;
|
||||
|
||||
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "产品ID不能为空")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品支付渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@PayProductChannelCodeValid
|
||||
@NotNull(message = "产品支付渠道编码不能为空")
|
||||
|
||||
+6
-2
@@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
/**
|
||||
* 产品表 products DO
|
||||
@@ -47,6 +49,8 @@ public class ProductsDO extends BaseDO {
|
||||
*/
|
||||
private Integer softwareId;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 建议价格
|
||||
*/
|
||||
private BigDecimal price;
|
||||
}
|
||||
|
||||
-20
@@ -56,36 +56,16 @@ public class ProductsDetailDO extends BaseDO {
|
||||
@TableField("`output`")
|
||||
private BigDecimal output;
|
||||
|
||||
/**
|
||||
* 赠送时间
|
||||
*/
|
||||
private Integer giftDuration;
|
||||
|
||||
/**
|
||||
* 赠送时间单位
|
||||
*/
|
||||
private Integer giftDurationUnit;
|
||||
|
||||
/**
|
||||
* 赠送产量
|
||||
*/
|
||||
private BigDecimal giftOutput;
|
||||
|
||||
/**
|
||||
* 产品原价
|
||||
*/
|
||||
private BigDecimal originalPrice;
|
||||
|
||||
/**
|
||||
* 折扣
|
||||
*/
|
||||
private BigDecimal discount;
|
||||
|
||||
/**
|
||||
* 产品现价
|
||||
*/
|
||||
private BigDecimal currentPrice;
|
||||
|
||||
/**
|
||||
* 是否特惠: 0否1是
|
||||
*/
|
||||
|
||||
-3
@@ -22,12 +22,9 @@ public interface ProductsDetailMapper extends BaseMapperX<ProductsDetailDO> {
|
||||
.eqIfPresent(ProductsDetailDO::getPurchaseType, reqVO.getPurchaseType())
|
||||
.eqIfPresent(ProductsDetailDO::getProductId, reqVO.getProductId())
|
||||
.eqIfPresent(ProductsDetailDO::getDuration, reqVO.getDuration())
|
||||
.eqIfPresent(ProductsDetailDO::getGiftDuration, reqVO.getGiftDuration())
|
||||
.eqIfPresent(ProductsDetailDO::getOutput, reqVO.getOutput())
|
||||
.eqIfPresent(ProductsDetailDO::getGiftOutput, reqVO.getGiftOutput())
|
||||
.eqIfPresent(ProductsDetailDO::getOriginalPrice, reqVO.getOriginalPrice())
|
||||
.eqIfPresent(ProductsDetailDO::getDiscount, reqVO.getDiscount())
|
||||
.eqIfPresent(ProductsDetailDO::getCurrentPrice, reqVO.getCurrentPrice())
|
||||
.eqIfPresent(ProductsDetailDO::getIsDiscounted, reqVO.getIsDiscounted())
|
||||
.eqIfPresent(ProductsDetailDO::getDeleted, false)
|
||||
);
|
||||
|
||||
+3
@@ -45,6 +45,7 @@ public interface PurchaseRecordMapper extends BaseMapperX<PurchaseRecordDO> {
|
||||
.eqIfPresent(PurchaseRecordDO::getPurchaseDuration, pageReqVO.getPurchaseDuration())
|
||||
.betweenIfPresent(PurchaseRecordDO::getCreateTime, pageReqVO.getCreateTime())
|
||||
.likeIfPresent(PurchaseRecordDO::getCreator, pageReqVO.getCreator())
|
||||
.ne(PurchaseRecordDO::getInitial, true)
|
||||
.orderByDesc(PurchaseRecordDO::getCreateTime));
|
||||
|
||||
}
|
||||
@@ -63,6 +64,7 @@ public interface PurchaseRecordMapper extends BaseMapperX<PurchaseRecordDO> {
|
||||
.eq(PurchaseRecordDO::getOrganId, SecurityFrameworkUtils.getUserOrganId())
|
||||
.eq(PurchaseRecordDO::getDeleted, false)
|
||||
.in(PurchaseRecordDO::getIsInvocing, InvoiceStatusEnum.INVOICABLE.getCode(), InvoiceStatusEnum.INVOICINGFAILED.getCode())
|
||||
.ne(PurchaseRecordDO::getInitial, true)
|
||||
.orderByDesc(PurchaseRecordDO::getCreateTime)
|
||||
);
|
||||
|
||||
@@ -109,6 +111,7 @@ public interface PurchaseRecordMapper extends BaseMapperX<PurchaseRecordDO> {
|
||||
.eqIfPresent(PurchaseRecordDO::getOrganId, pageReqVO.getOrganId())
|
||||
.eqIfPresent(PurchaseRecordDO::getCreator, pageReqVO.getOperator())
|
||||
.eq(PurchaseRecordDO::getDeleted, false)
|
||||
.ne(PurchaseRecordDO::getInitial, true)
|
||||
.orderByDesc(PurchaseRecordDO::getCreateTime)
|
||||
.select(PurchaseRecordDO::getId, PurchaseRecordDO::getOrganId, PurchaseRecordDO::getTotalAmount, PurchaseRecordDO::getAccountBalanceSpent, PurchaseRecordDO::getAlipaySpent,
|
||||
PurchaseRecordDO::getWechatSpent, PurchaseRecordDO::getGiftMoneySpent, PurchaseRecordDO::getCreator, PurchaseRecordDO::getCreateTime)
|
||||
|
||||
+2
@@ -10,4 +10,6 @@ public class PayConstants {
|
||||
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_PRODUCT_DETAIL_AUTO_GENERATE_MONTH_ID_FORMAT = "1759029544%d"; // 1~12月定价规则自动生成ID格式
|
||||
}
|
||||
+9
-4
@@ -40,10 +40,6 @@ public enum ProductDurationUnitEnum implements IntArrayValuable, BaseEnum {
|
||||
return Objects.equals(YEAR.code, name);
|
||||
}
|
||||
|
||||
public static boolean isMonth(String name) {
|
||||
return Objects.equals(MONTH.code, name);
|
||||
}
|
||||
|
||||
public static ProductDurationUnitEnum fromStatus(Integer status) {
|
||||
return Arrays.stream(values())
|
||||
.filter(bean -> Objects.equals(bean.code, status))
|
||||
@@ -61,4 +57,13 @@ public enum ProductDurationUnitEnum implements IntArrayValuable, BaseEnum {
|
||||
ProductDurationUnitEnum unit = fromStatus(status);
|
||||
return unit != null ? unit.getDesc() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要筛选的类型:年
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static ProductDurationUnitEnum[] validArr() {
|
||||
return new ProductDurationUnitEnum[]{YEAR};
|
||||
}
|
||||
}
|
||||
|
||||
+3
-8
@@ -187,16 +187,11 @@ public class OrganAmountServiceImpl implements OrganAmountService {
|
||||
// 查询组织最晚还有效的产品购买记录
|
||||
OrgEarliestPurchaseProductRespVO orgEarliestProductDetail = purchaseService.getOrgEarliestProductDetail(organId);
|
||||
if (ObjectUtil.isNotNull(orgEarliestProductDetail)) {
|
||||
// 购买记录
|
||||
// 查询对应购买记录
|
||||
PurchaseRecordDO purchaseRecordDO = orgEarliestProductDetail.getPurchaseRecordDO();
|
||||
// 购买记录关联的定价规则
|
||||
ProductsDetailDO productsDetailDO = orgEarliestProductDetail.getProductsDetailDO();
|
||||
|
||||
organAmountRespVO.setProductEfficientDate(LocalDateTimeUtil.format(purchaseRecordDO.getEndTime(), NORM_DATETIME_FORMATTER));
|
||||
organAmountRespVO.setDuration(productsDetailDO.getDuration());
|
||||
organAmountRespVO.setDurationUnit(productsDetailDO.getDurationUnit());
|
||||
organAmountRespVO.setGiftDuration(productsDetailDO.getGiftDuration());
|
||||
organAmountRespVO.setGiftDurationUnit(productsDetailDO.getGiftDurationUnit());
|
||||
organAmountRespVO.setDuration(purchaseRecordDO.getPurchaseDuration());
|
||||
organAmountRespVO.setDurationUnit(purchaseRecordDO.getPurchaseDurationUnit());
|
||||
}
|
||||
|
||||
// 查询可开票金额
|
||||
|
||||
+9
-1
@@ -8,7 +8,7 @@ import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 产品明细表 product_details Service 接口
|
||||
@@ -67,4 +67,12 @@ public interface ProductsDetailService {
|
||||
* @param productId
|
||||
*/
|
||||
ProductsDO validateProductExist(Long productId);
|
||||
|
||||
/**
|
||||
* 获取产品1年定价的折扣
|
||||
*
|
||||
* @param productId
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getProductDetailOneYearDiscount(Long productId);
|
||||
}
|
||||
|
||||
+21
-34
@@ -1,11 +1,14 @@
|
||||
package com.cf.imes.module.system.service.funds.products;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
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.exception.util.ServiceExceptionUtil;
|
||||
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;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||
@@ -19,8 +22,8 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
|
||||
@@ -49,14 +52,7 @@ public class ProductsDetailServiceImpl implements ProductsDetailService {
|
||||
if (ProductsPurchaseTypeEnum.DURATION.getStatus().equals(createReqVO.getPurchaseType())) {
|
||||
// 校验时长
|
||||
checkDuration(createReqVO.getDuration(), createReqVO.getDurationUnit());
|
||||
// 校验赠送时长
|
||||
String giftDuration = createReqVO.getGiftDuration();
|
||||
if (StringUtils.isNotEmpty(giftDuration)) {
|
||||
checkDuration(giftDuration, createReqVO.getGiftDurationUnit());
|
||||
}
|
||||
|
||||
// 校验现价计算是否正确
|
||||
calculateDiscount(createReqVO.getOriginalPrice(), createReqVO.getCurrentPrice(), createReqVO.getDiscount());
|
||||
// 查询是否有重复的定价
|
||||
checkProductDetails(createReqVO);
|
||||
|
||||
@@ -81,14 +77,6 @@ public class ProductsDetailServiceImpl implements ProductsDetailService {
|
||||
if (updateReqVO.getPurchaseType().equals(ProductsPurchaseTypeEnum.DURATION.getStatus())) {
|
||||
// 校验时长
|
||||
checkDuration(updateReqVO.getDuration(), updateReqVO.getDurationUnit());
|
||||
// 校验赠送时长
|
||||
String giftDuration = updateReqVO.getGiftDuration();
|
||||
if (StringUtils.isNotEmpty(giftDuration)) {
|
||||
checkDuration(giftDuration, updateReqVO.getGiftDurationUnit());
|
||||
}
|
||||
|
||||
// 校验现价计算是否正确
|
||||
calculateDiscount(updateReqVO.getOriginalPrice(), updateReqVO.getCurrentPrice(), updateReqVO.getDiscount());
|
||||
// 校验同时长是否还有其他的定价规则
|
||||
checkProductDetails(updateReqVO);
|
||||
|
||||
@@ -97,7 +85,12 @@ public class ProductsDetailServiceImpl implements ProductsDetailService {
|
||||
throw exception(PRODUCTS_OUTPUT_NOT_SUPPORT);
|
||||
}
|
||||
|
||||
productDetailsMapper.updateById(BeanUtils.toBean(updateReqVO, ProductsDetailDO.class));
|
||||
productDetailsMapper.update(new LambdaUpdateWrapper<ProductsDetailDO>()
|
||||
.eq(ProductsDetailDO::getId, updateReqVO.getId())
|
||||
.set(ProductsDetailDO::getDiscount, updateReqVO.getDiscount())
|
||||
.set(ProductsDetailDO::getDuration, updateReqVO.getDuration())
|
||||
.set(ProductsDetailDO::getDurationUnit, updateReqVO.getDurationUnit())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -228,22 +221,16 @@ public class ProductsDetailServiceImpl implements ProductsDetailService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算折扣是否正确
|
||||
*
|
||||
* @param originalPrice 原价
|
||||
* @param currentPrice 当前价格
|
||||
* @param discount 折扣(百分比)
|
||||
*/
|
||||
private void calculateDiscount(BigDecimal originalPrice, BigDecimal currentPrice, BigDecimal discount) {
|
||||
// 校验当前价格是否正确
|
||||
// 计算期望现价 = 原价 * 折扣 /100(保留2位小数)
|
||||
BigDecimal expectedPrice = originalPrice.multiply(discount).divide(new BigDecimal(100)).setScale(2, RoundingMode.DOWN);
|
||||
|
||||
if (currentPrice.compareTo(expectedPrice) != 0) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCTS_DETAIL_CURRENTPRICE_CALCULATE_ERROR, expectedPrice);
|
||||
@Override
|
||||
public BigDecimal getProductDetailOneYearDiscount(Long productId) {
|
||||
ProductsDetailDO productsDetailDO = productDetailsMapper.selectOne(new LambdaQueryWrapper<ProductsDetailDO>()
|
||||
.eq(ProductsDetailDO::getProductId, productId)
|
||||
.eq(ProductsDetailDO::getDuration, 1)
|
||||
.eq(ProductsDetailDO::getDurationUnit, ProductDurationUnitEnum.YEAR.getCode()));
|
||||
if (ObjectUtil.isNotNull(productsDetailDO)) {
|
||||
return productsDetailDO.getDiscount();
|
||||
} else {
|
||||
return BigDecimal.valueOf(100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-3
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.service.funds.products;
|
||||
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductSaveReqVO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
@@ -16,17 +17,17 @@ public interface ProductsService {
|
||||
/**
|
||||
* 创建产品
|
||||
*
|
||||
* @param productName 产品名称
|
||||
* @param saveReqVO
|
||||
* @return 编号
|
||||
*/
|
||||
Long create(@Valid String productName);
|
||||
Long create(ProductSaveReqVO saveReqVO);
|
||||
|
||||
/**
|
||||
* 更新产品
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void update(@Valid ProductsDO updateReqVO);
|
||||
void update(ProductSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除产品
|
||||
|
||||
+15
-5
@@ -3,8 +3,11 @@ package com.cf.imes.module.system.service.funds.products;
|
||||
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;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductSaveReqVO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||
import com.cf.imes.module.system.dal.mysql.funds.products.ProductsMapper;
|
||||
import com.cf.imes.module.system.enums.products.ProductStatusEnum;
|
||||
@@ -32,12 +35,14 @@ public class ProductsServiceImpl implements ProductsService {
|
||||
private ProductsMapper productsMapper;
|
||||
|
||||
@Override
|
||||
public Long create(String productName) {
|
||||
public Long create(ProductSaveReqVO createReqVO) {
|
||||
String productName = createReqVO.getProductName();
|
||||
// 校验产品名称唯一
|
||||
validateProductNameUnique(null, productName);
|
||||
|
||||
ProductsDO productsDO = new ProductsDO()
|
||||
.setProductName(productName)
|
||||
.setPrice(createReqVO.getPrice())
|
||||
.setStatus(ProductStatusEnum.PRODUCT_WAITING_UPDATES.getStatus())
|
||||
.setSoftwareId(0);
|
||||
productsMapper.insert(productsDO);
|
||||
@@ -47,7 +52,7 @@ public class ProductsServiceImpl implements ProductsService {
|
||||
|
||||
|
||||
@Override
|
||||
public void update(ProductsDO updateReqVO) {
|
||||
public void update(ProductSaveReqVO updateReqVO) {
|
||||
Long updateReqVOId = updateReqVO.getId();
|
||||
String productName = updateReqVO.getProductName();
|
||||
// 目标状态
|
||||
@@ -63,9 +68,14 @@ public class ProductsServiceImpl implements ProductsService {
|
||||
if (ProductStatusEnum.PRODUCT_UPDATES.getStatus().equals(status) && !ProductStatusEnum.isProductDelis(updateReqVOStatus)) {
|
||||
throw exception(PRODUCTS_NO_UPDATE);
|
||||
}
|
||||
|
||||
productsMapper.updateById(updateReqVO);
|
||||
|
||||
ProductsDO productsDO = BeanUtils.toBean(updateReqVO, ProductsDO.class);
|
||||
productsMapper.updateById(productsDO);
|
||||
productsMapper.update(new LambdaUpdateWrapperX<ProductsDO>()
|
||||
.eq(ProductsDO::getId, updateReqVOId)
|
||||
.setIfPresent(ProductsDO::getProductName, productName)
|
||||
.setIfPresent(ProductsDO::getPrice, updateReqVO.getPrice())
|
||||
.set(ProductsDO::getStatus, updateReqVOStatus)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -2,13 +2,13 @@ package com.cf.imes.module.system.service.funds.purchase;
|
||||
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalSalesAmountRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.PurchaseRecordPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.PurchaseRecordRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.SalesDetailRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.SalesDetailsPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganCreateProductPurchaseReqVO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -82,12 +82,12 @@ public interface PurchaseService {
|
||||
void createOrgInitProductPurchaseRecord(Long organId, List<OrganCreateProductPurchaseReqVO> productPurchaseReqVOS);
|
||||
|
||||
/**
|
||||
* 查询组织下的产品购买记录
|
||||
* 查询组织下的非首购的产品购买记录
|
||||
*
|
||||
* @param organIds
|
||||
* @return
|
||||
*/
|
||||
List<PurchaseRecordDO> getOrgPurchaseList(Set<Long> organIds);
|
||||
List<PurchaseRecordDO> getOrgPurchaseNotInitialList(Set<Long> organIds);
|
||||
|
||||
/**
|
||||
* 查询销售总额
|
||||
@@ -131,7 +131,7 @@ public interface PurchaseService {
|
||||
* @param organId
|
||||
* @return
|
||||
*/
|
||||
List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId);
|
||||
List<ProductDetailsRespVO> getOrgProductDetailList(Long organId, Long productId);
|
||||
|
||||
/**
|
||||
* 作废历史组织产品购买记录
|
||||
|
||||
+113
-86
@@ -13,6 +13,7 @@ import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalSalesAmountRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.PurchaseRecordPageReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.PurchaseRecordRespVO;
|
||||
@@ -23,7 +24,6 @@ import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||
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.mysql.funds.products.ProductsDetailMapper;
|
||||
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.PayProductChannelCodeEnum;
|
||||
@@ -46,7 +46,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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_PRICE_NULL_ERROR;
|
||||
import static com.cf.imes.module.system.enums.pay.PayConstants.PAY_PRODUCT_DETAIL_AUTO_GENERATE_MONTH_ID_FORMAT;
|
||||
|
||||
/**
|
||||
* @author 软件购买接口 实现类
|
||||
@@ -58,9 +59,6 @@ public class PurchaseServiceImpl implements PurchaseService {
|
||||
@Resource
|
||||
private PurchaseRecordMapper purchaseRecordMapper;
|
||||
|
||||
@Resource
|
||||
private ProductsDetailMapper productsDetailMapper;
|
||||
|
||||
@Resource
|
||||
private ProductsDetailService productsDetailService;
|
||||
|
||||
@@ -139,7 +137,7 @@ public class PurchaseServiceImpl implements PurchaseService {
|
||||
// 延期记录是按自增id逆序的,第一条的延期后时间作为产品到期时间
|
||||
purchaseRecordDO.setEndTime(recordsByPurchaseId.get(0).getDelayTime());
|
||||
}
|
||||
return new OrgEarliestPurchaseProductRespVO(purchaseRecordDO, productsDetailMapper.selectById(purchaseRecordDO.getProductDetailsId()));
|
||||
return new OrgEarliestPurchaseProductRespVO(purchaseRecordDO);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -152,53 +150,35 @@ public class PurchaseServiceImpl implements PurchaseService {
|
||||
@Override
|
||||
public void createOrgInitProductPurchaseRecord(Long organId, List<OrganCreateProductPurchaseReqVO> productPurchaseReqVOS) {
|
||||
for (OrganCreateProductPurchaseReqVO purchaseReqVO : productPurchaseReqVOS) {
|
||||
// 1、校验定价
|
||||
ProductsDetailDO productsDetailDO = productsDetailService.validateProductDetailsExists(purchaseReqVO.getProductDetailsId());
|
||||
|
||||
// 2、校验产品
|
||||
Long productId = productsDetailDO.getProductId();
|
||||
// 1、校验产品
|
||||
Long productId = purchaseReqVO.getProductId();
|
||||
ProductsDO productsDO = productsDetailService.validateProductExist(productId);
|
||||
|
||||
// 3、创建购买记录
|
||||
// 2、创建购买记录
|
||||
|
||||
// 输入的价格
|
||||
BigDecimal price = purchaseReqVO.getPrice();
|
||||
// 月均单价
|
||||
BigDecimal monthAverageAmount;
|
||||
// 计算后总价
|
||||
BigDecimal totalAmount = price;
|
||||
/**
|
||||
* ①:首次订购满1年:
|
||||
* 总价 = 输入金额
|
||||
* 月均单价 = 输入金额 / (12 * duration)
|
||||
* ②:不满1年按月份计算
|
||||
* 总价 = 输入金额
|
||||
* 月均单价 = 输入金额 / duration
|
||||
*/
|
||||
Integer duration = productsDetailDO.getDuration();
|
||||
switch (ProductDurationUnitEnum.fromStatus(productsDetailDO.getDurationUnit())) {
|
||||
case YEAR -> monthAverageAmount = price.divide(new BigDecimal(duration * 12), 2, RoundingMode.DOWN);
|
||||
case MONTH -> monthAverageAmount = price.divide(new BigDecimal(duration), 2, RoundingMode.DOWN);
|
||||
default -> throw new ServiceException(PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT);
|
||||
}
|
||||
// 首次订购默认是1年的价格,月均单价/10(赠送两个月)
|
||||
BigDecimal monthAverageAmount = price.divide(new BigDecimal(10), 2, RoundingMode.DOWN);
|
||||
|
||||
long purchaseId = IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId();
|
||||
|
||||
LocalDate now = LocalDate.now();
|
||||
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||
.id(purchaseId)
|
||||
.organId(organId)
|
||||
.productId(productId)
|
||||
.productName(productsDO.getProductName())
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(duration)
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(LocalDate.now())
|
||||
.endTime(purchaseReqVO.getProductExpireDate())
|
||||
.productDetailsId(0L)
|
||||
.purchaseDuration(1)
|
||||
.purchaseDurationUnit(ProductDurationUnitEnum.YEAR.getCode())
|
||||
.startTime(now)
|
||||
// 组织创建时的套餐购买默认过期
|
||||
.endTime(now.minusDays(1))
|
||||
.paymentMethod(PayProductChannelCodeEnum.ORGAN_CREATE.getCode())
|
||||
.totalAmount(totalAmount)
|
||||
.totalAmount(price)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.originalAmount(price)
|
||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||
.initial(true)
|
||||
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||
.build();
|
||||
@@ -207,10 +187,11 @@ public class PurchaseServiceImpl implements PurchaseService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PurchaseRecordDO> getOrgPurchaseList(Set<Long> organIds) {
|
||||
public List<PurchaseRecordDO> getOrgPurchaseNotInitialList(Set<Long> organIds) {
|
||||
return purchaseRecordMapper.selectList(new LambdaQueryWrapper<PurchaseRecordDO>()
|
||||
.in(PurchaseRecordDO::getOrganId, organIds)
|
||||
.eq(PurchaseRecordDO::getStatus, PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||
.ne(PurchaseRecordDO::getInitial, true)
|
||||
.eq(PurchaseRecordDO::getDeleted, false));
|
||||
}
|
||||
|
||||
@@ -265,9 +246,9 @@ public class PurchaseServiceImpl implements PurchaseService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductsDetailDO> getOrgProductDetailList(Long organId, Long productId) {
|
||||
public List<ProductDetailsRespVO> getOrgProductDetailList(Long organId, Long productId) {
|
||||
// 校验产品
|
||||
productsDetailService.validateProductExist(productId);
|
||||
ProductsDO productsDO = productsDetailService.validateProductExist(productId);
|
||||
|
||||
// 查询产品下的所有定价规则
|
||||
ProductDetailsPageReqVO pageReqVO = new ProductDetailsPageReqVO();
|
||||
@@ -278,64 +259,110 @@ public class PurchaseServiceImpl implements PurchaseService {
|
||||
// 查询组织下的首次订购产品记录
|
||||
PurchaseRecordDO orgInitialPurchaseRecord = getOrgInitialPurchaseRecord(organId, productId);
|
||||
if (ObjectUtil.isNull(orgInitialPurchaseRecord)) {
|
||||
return page.getList();
|
||||
return getInitialProductDetailList(productsDO, page.getList());
|
||||
}
|
||||
|
||||
List<ProductsDetailDO> resultList = new ArrayList<>();
|
||||
for (ProductsDetailDO detailDO : page.getList()) {
|
||||
ProductsDetailDO newDetailDO = BeanUtils.toBean(detailDO, ProductsDetailDO.class);
|
||||
List<ProductDetailsRespVO> resultList = new ArrayList<>();
|
||||
|
||||
// 月均单价
|
||||
BigDecimal monthAverageAmount = orgInitialPurchaseRecord.getMonthAverageAmount();
|
||||
// 月均单价
|
||||
BigDecimal monthAverageAmount = orgInitialPurchaseRecord.getMonthAverageAmount();
|
||||
// 1年定价
|
||||
BigDecimal totalAmount = orgInitialPurchaseRecord.getTotalAmount();
|
||||
// 定价中有的,以年数量*组织定价*折扣展示
|
||||
List<ProductDetailsRespVO> productDetailRespVOList = new ArrayList<>();
|
||||
for (ProductsDetailDO detailDO : page.getList()) {
|
||||
ProductDetailsRespVO newDetailRespVO = BeanUtils.toBean(detailDO, ProductDetailsRespVO.class);
|
||||
// 折扣
|
||||
BigDecimal discount = detailDO.getDiscount();
|
||||
// 需要支付的总价
|
||||
BigDecimal totalAmount;
|
||||
|
||||
// 重新计算购买价格
|
||||
switch (ProductDurationUnitEnum.fromStatus(detailDO.getDurationUnit())) {
|
||||
case YEAR -> totalAmount = monthAverageAmount
|
||||
.multiply(new BigDecimal(10))
|
||||
.multiply(new BigDecimal(detailDO.getDuration()))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
case MONTH -> {
|
||||
int months = detailDO.getDuration();
|
||||
if (months >= 12) {
|
||||
// 转换成年 + 剩余月
|
||||
int years = months / 12;
|
||||
int remainMonths = months % 12;
|
||||
case YEAR -> {
|
||||
Integer duration = detailDO.getDuration();
|
||||
// 原价
|
||||
BigDecimal originalPrice = totalAmount.multiply(BigDecimal.valueOf(duration));
|
||||
newDetailRespVO.setOriginalPrice(originalPrice);
|
||||
// 折扣价格
|
||||
newDetailRespVO.setCurrentPrice(originalPrice.multiply(discount).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
|
||||
productDetailRespVOList.add(newDetailRespVO);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 默认展示1到10月的价格
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
ProductDetailsRespVO detailRespVO = new ProductDetailsRespVO();
|
||||
detailRespVO.setId(Long.parseLong(String.format(PAY_PRODUCT_DETAIL_AUTO_GENERATE_MONTH_ID_FORMAT, i)));
|
||||
detailRespVO.setProductId(productId);
|
||||
detailRespVO.setDuration(i);
|
||||
detailRespVO.setDurationUnit(ProductDurationUnitEnum.MONTH.getCode());
|
||||
// 价格:月均单价*月数量
|
||||
BigDecimal price = monthAverageAmount.multiply(BigDecimal.valueOf(i));
|
||||
// 有一年的折扣要把月价格做折算
|
||||
detailRespVO.setCurrentPrice(price);
|
||||
detailRespVO.setOriginalPrice(price);
|
||||
resultList.add(detailRespVO);
|
||||
}
|
||||
resultList.addAll(productDetailRespVOList);
|
||||
|
||||
// 整年部分:用年逻辑(10 个月价)
|
||||
BigDecimal yearPart = monthAverageAmount
|
||||
.multiply(new BigDecimal(10))
|
||||
.multiply(new BigDecimal(years))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 剩余月部分:用月逻辑
|
||||
BigDecimal monthPart = remainMonths == 0
|
||||
? BigDecimal.ZERO
|
||||
: monthAverageAmount
|
||||
.multiply(new BigDecimal(remainMonths))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
/**
|
||||
* 拼接没有首次购买记录的定价方式列表
|
||||
*
|
||||
* @param productsDO
|
||||
* @param productsDetailDOS
|
||||
* @return
|
||||
*/
|
||||
private List<ProductDetailsRespVO> getInitialProductDetailList(ProductsDO productsDO, List<ProductsDetailDO> productsDetailDOS) {
|
||||
List<ProductDetailsRespVO> resultList = new ArrayList<>();
|
||||
// 没有首次购买记录的产品,展示的总价是产品建议价格
|
||||
// 1年定价
|
||||
BigDecimal totalAmount = productsDO.getPrice();
|
||||
if(ObjectUtil.isNull(totalAmount)) {
|
||||
throw new ServiceException(PRODUCT_PRICE_NULL_ERROR);
|
||||
}
|
||||
// 月均单价
|
||||
BigDecimal monthAverageAmount = totalAmount.divide(new BigDecimal(10), 2, RoundingMode.DOWN);
|
||||
|
||||
totalAmount = yearPart.add(monthPart);
|
||||
} else {
|
||||
// 小于 12 个月直接按月逻辑
|
||||
totalAmount = monthAverageAmount
|
||||
.multiply(new BigDecimal(months))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
}
|
||||
List<ProductDetailsRespVO> productDetailRespVOList = new ArrayList<>();
|
||||
for (ProductsDetailDO detailDO : productsDetailDOS) {
|
||||
ProductDetailsRespVO newDetailRespVO = BeanUtils.toBean(detailDO, ProductDetailsRespVO.class);
|
||||
// 折扣
|
||||
BigDecimal discount = detailDO.getDiscount();
|
||||
// 重新计算购买价格
|
||||
switch (ProductDurationUnitEnum.fromStatus(detailDO.getDurationUnit())) {
|
||||
case YEAR -> {
|
||||
Integer duration = detailDO.getDuration();
|
||||
// 原价
|
||||
BigDecimal originalPrice = totalAmount.multiply(BigDecimal.valueOf(duration));
|
||||
newDetailRespVO.setOriginalPrice(originalPrice);
|
||||
// 折扣价格
|
||||
newDetailRespVO.setCurrentPrice(originalPrice.multiply(discount).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
|
||||
productDetailRespVOList.add(newDetailRespVO);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
default -> throw new ServiceException(PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT);
|
||||
}
|
||||
newDetailDO.setCurrentPrice(totalAmount);
|
||||
newDetailDO.setOriginalPrice(totalAmount);
|
||||
resultList.add(newDetailDO);
|
||||
}
|
||||
|
||||
// 默认展示1到10月的价格
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
ProductDetailsRespVO detailRespVO = new ProductDetailsRespVO();
|
||||
detailRespVO.setId(Long.parseLong(String.format(PAY_PRODUCT_DETAIL_AUTO_GENERATE_MONTH_ID_FORMAT, i)));
|
||||
detailRespVO.setProductId(productsDO.getId());
|
||||
detailRespVO.setDuration(i);
|
||||
detailRespVO.setDurationUnit(ProductDurationUnitEnum.MONTH.getCode());
|
||||
// 价格:月均单价*月数量
|
||||
BigDecimal price = monthAverageAmount.multiply(BigDecimal.valueOf(i));
|
||||
// 有一年的折扣要把月价格做折算
|
||||
detailRespVO.setCurrentPrice(price);
|
||||
detailRespVO.setOriginalPrice(price);
|
||||
resultList.add(detailRespVO);
|
||||
}
|
||||
resultList.addAll(productDetailRespVOList);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
|
||||
+32
-2
@@ -38,6 +38,7 @@ import com.cf.imes.module.system.controller.admin.funds.products.vo.product.Prod
|
||||
import com.cf.imes.module.system.dal.dataobject.funds.delay.ProductDelayRecordDO;
|
||||
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.enums.pay.ProductDurationUnitEnum;
|
||||
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.controller.admin.pay.vo.PayProductOrderUnifiedReqVO;
|
||||
@@ -111,6 +112,9 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
// 外部payNo正则
|
||||
private static final Pattern pattern = Pattern.compile("P(\\d+)O");
|
||||
|
||||
// 自动生成定价id正则
|
||||
private static final Pattern productDetailIdPattern = Pattern.compile("^1759029544(\\d+)$");
|
||||
|
||||
@Resource
|
||||
private PayHandlerFactory payHandlerFactory;
|
||||
|
||||
@@ -169,10 +173,12 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
ValidationUtils.validate(validator, payProductOrderUnifiedReqVO);
|
||||
|
||||
// 校验产品和产品明细
|
||||
ProductsDetailDO productsDetailDO = productsDetailService.validateProductDetailsExists(payProductOrderUnifiedReqVO.getProductDetailsId());
|
||||
Long productId = productsDetailDO.getProductId();
|
||||
Long productId = payProductOrderUnifiedReqVO.getProductId();
|
||||
ProductsDO productsDO = productsDetailService.validateProductExist(productId);
|
||||
|
||||
// 解析产品定价明细
|
||||
ProductsDetailDO productsDetailDO = analyzeProductDetail(productId, payProductOrderUnifiedReqVO.getProductDetailsId());
|
||||
|
||||
// 检查机构产品购买锁
|
||||
String purchaseLockKey = String.format(RedisKeyConstants.PRODUCT_PURCHASE_LOCK_KEY, organId, productId);
|
||||
boolean lockResult = redisLockUtil.redissonLock(purchaseLockKey, chenfengCacheProperties.getLockWaitTime(), chenfengCacheProperties.getLockTimeout());
|
||||
@@ -250,6 +256,30 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析定价规则,年从数据库取,月就手动拼
|
||||
*
|
||||
* @param productDetailId
|
||||
* @return
|
||||
*/
|
||||
private ProductsDetailDO analyzeProductDetail(Long productId, Long productDetailId) {
|
||||
// productDetailId符合规则PPAG%d
|
||||
Matcher matcher = productDetailIdPattern.matcher(String.valueOf(productDetailId));
|
||||
if (matcher.find()) {
|
||||
// 取PPAG后的数字,是订购月份
|
||||
String monthDuration = matcher.group(1);
|
||||
ProductsDetailDO monthDetail = new ProductsDetailDO();
|
||||
monthDetail.setId(productDetailId);
|
||||
monthDetail.setDuration(Integer.parseInt(monthDuration));
|
||||
monthDetail.setDurationUnit(ProductDurationUnitEnum.MONTH.getCode());
|
||||
// 获取产品下的1年的折扣
|
||||
monthDetail.setDiscount(productsDetailService.getProductDetailOneYearDiscount(productId));
|
||||
return monthDetail;
|
||||
} else {
|
||||
return productsDetailService.validateProductDetailsExists(productDetailId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理前序购买记录:
|
||||
* 1、需要第三方支付,当前购买记录状态为待支付,等第三方回调/超期轮训处理到的时候标记为成功还是失败
|
||||
|
||||
+60
-81
@@ -94,6 +94,9 @@ public class PayProductProcessor {
|
||||
// 本地订购产品的月均单价
|
||||
private BigDecimal monthAverageAmount = BigDecimal.ZERO;
|
||||
|
||||
// 原始价格
|
||||
private BigDecimal originalPrice;
|
||||
|
||||
public PayProductProcessor(ProductsDO productsDO, ProductsDetailDO productsDetailDO, PurchaseRecordDO orgInitialPurchaseRecord, PreviouProductDelayRespVO previouProductDelayRespVO,
|
||||
OrganAmountDO organAmountDO, Long organId, ChenfengPayConfig payConfig, MybatisIdProperties mybatisIdProperties) {
|
||||
this.productsDO = productsDO;
|
||||
@@ -104,8 +107,7 @@ public class PayProductProcessor {
|
||||
previousPurchaseRecord = previouProductDelayRespVO.getPreviouPurchaseRecord();
|
||||
// 上一次订购产品的结束时间进行计算
|
||||
endTime = previousPurchaseRecord.getEndTime();
|
||||
endTime = calculateEndTime(productsDetailDO.getDuration(), productsDetailDO.getDurationUnit(),
|
||||
productsDetailDO.getGiftDuration(), productsDetailDO.getGiftDurationUnit());
|
||||
endTime = calculateEndTime(productsDetailDO.getDuration(), productsDetailDO.getDurationUnit());
|
||||
}
|
||||
this.organAmountDO = organAmountDO;
|
||||
this.organId = organId;
|
||||
@@ -125,9 +127,7 @@ public class PayProductProcessor {
|
||||
if (initialPurchaseExist) {
|
||||
price = computePrice(orgInitialPurchaseRecord, productsDetailDO);
|
||||
} else {
|
||||
price = productsDetailDO.getCurrentPrice();
|
||||
// 首次订购计算月均单价
|
||||
monthAverageAmount = computeInitialProductPayMonthAverageAmount(price);
|
||||
price = computeInitialProductPayAmount();
|
||||
// 首次购买记录是空,那么当前就是首次订购
|
||||
initialized = true;
|
||||
}
|
||||
@@ -184,13 +184,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.accountBalanceSpent(price)
|
||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||
@@ -244,13 +242,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.accountBalanceSpent(price)
|
||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||
@@ -301,13 +297,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.alipaySpent(price)
|
||||
.initial(initialized)
|
||||
@@ -340,13 +334,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.wechatSpent(price)
|
||||
.initial(initialized)
|
||||
@@ -384,13 +376,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayProductChannelCodeEnum.BALANCE_AND_GIFT.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.isInvocing(InvoiceStatusEnum.INVOICABLE.getCode())
|
||||
.initial(initialized)
|
||||
@@ -464,13 +454,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum) ? PayProductChannelCodeEnum.BALANCE_AND_GIFT_AND_ALIPAY.getCode() : PayProductChannelCodeEnum.BALANCE_AND_GIFT_AND_WECHAT.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.initial(initialized)
|
||||
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||
@@ -543,13 +531,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum) ? PayProductChannelCodeEnum.GIFT_AND_ALIPAY.getCode() : PayProductChannelCodeEnum.GIFT_AND_WECHAT.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.initial(initialized)
|
||||
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||
@@ -624,13 +610,11 @@ public class PayProductProcessor {
|
||||
.productDetailsId(productsDetailDO.getId())
|
||||
.purchaseDuration(productsDetailDO.getDuration())
|
||||
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||
.giftDuration(productsDetailDO.getGiftDuration())
|
||||
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.paymentMethod(PayProductChannelCodeEnum.BALANCE_AND_GIFT.getCode())
|
||||
.totalAmount(price)
|
||||
.originalAmount(productsDetailDO.getCurrentPrice())
|
||||
.originalAmount(originalPrice)
|
||||
.monthAverageAmount(monthAverageAmount)
|
||||
.initial(initialized)
|
||||
.status(PurchaseRecordStatusEnum.ACTIVE.getStatus())
|
||||
@@ -723,12 +707,9 @@ public class PayProductProcessor {
|
||||
*
|
||||
* @param duration
|
||||
* @param durationUnit
|
||||
* @param giftDuration
|
||||
* @param giftDurationUnit
|
||||
* @return
|
||||
*/
|
||||
private LocalDate calculateEndTime(Integer duration, Integer durationUnit,
|
||||
Integer giftDuration, Integer giftDurationUnit) {
|
||||
private LocalDate calculateEndTime(Integer duration, Integer durationUnit) {
|
||||
LocalDate today = LocalDate.now();
|
||||
// 1、 计算延期后的实际有效期
|
||||
LocalDate maxDelayEnd = endTime;
|
||||
@@ -758,11 +739,6 @@ public class PayProductProcessor {
|
||||
endTime = addTime(purchaseStart, duration, durationUnit);
|
||||
}
|
||||
|
||||
// 加赠送时间
|
||||
if (ObjectUtil.isNotNull(giftDuration) && giftDurationUnit != null) {
|
||||
endTime = addTime(endTime, giftDuration, giftDurationUnit);
|
||||
}
|
||||
|
||||
// 5. 扣掉延期天数
|
||||
long delayDays = 0L;
|
||||
if (CollUtil.isNotEmpty(delayRespVOList)) {
|
||||
@@ -889,7 +865,7 @@ public class PayProductProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算产品价格
|
||||
* 计算有首购记录的产品价格
|
||||
*
|
||||
* @param orgInitialPurchaseRecord 首次购买记录
|
||||
* @param productsDetailDO 本次购买产品的定价规则
|
||||
@@ -899,52 +875,35 @@ public class PayProductProcessor {
|
||||
// 月均单价
|
||||
monthAverageAmount = orgInitialPurchaseRecord.getMonthAverageAmount();
|
||||
|
||||
// 首购的定价
|
||||
BigDecimal initialPurchaseRecordTotalAmount = orgInitialPurchaseRecord.getTotalAmount();
|
||||
|
||||
// 定价规则的折扣
|
||||
BigDecimal discount = productsDetailDO.getDiscount();
|
||||
|
||||
BigDecimal totalAmount;
|
||||
/**
|
||||
* ①:续费订购满1年:
|
||||
* 总价 = 月均单价 * 10 * duration * 折扣 /100,保留两位小数
|
||||
* 原始价格 = 订购总价 * duration
|
||||
* 现价 = 原始价格 * 折扣 /100,保留两位小数
|
||||
* ②:不满1年按月份计算
|
||||
* 总价 = 月均单价 * duration * 折扣 /100,保留两位小数
|
||||
* 原始价格 = 月均单价 * duration
|
||||
* 现价 = 原始价格 * 折扣 /100,保留两位小数
|
||||
*/
|
||||
switch (ProductDurationUnitEnum.fromStatus(productsDetailDO.getDurationUnit())) {
|
||||
case YEAR -> totalAmount = monthAverageAmount
|
||||
.multiply(new BigDecimal(10))
|
||||
.multiply(new BigDecimal(productsDetailDO.getDuration()))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
case YEAR -> {
|
||||
originalPrice = initialPurchaseRecordTotalAmount
|
||||
.multiply(BigDecimal.valueOf(productsDetailDO.getDuration()));
|
||||
totalAmount = originalPrice
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
}
|
||||
case MONTH -> {
|
||||
int months = productsDetailDO.getDuration();
|
||||
if (months >= 12) {
|
||||
// 转换成年 + 剩余月
|
||||
int years = months / 12;
|
||||
int remainMonths = months % 12;
|
||||
|
||||
// 整年部分:用年逻辑(10 个月价)
|
||||
BigDecimal yearPart = monthAverageAmount
|
||||
.multiply(new BigDecimal(10))
|
||||
.multiply(new BigDecimal(years))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
|
||||
// 剩余月部分:用月逻辑
|
||||
BigDecimal monthPart = remainMonths == 0
|
||||
? BigDecimal.ZERO
|
||||
: monthAverageAmount
|
||||
.multiply(new BigDecimal(remainMonths))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
|
||||
totalAmount = yearPart.add(monthPart);
|
||||
} else {
|
||||
// 小于 12 个月直接按月逻辑
|
||||
totalAmount = monthAverageAmount
|
||||
.multiply(new BigDecimal(months))
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
}
|
||||
originalPrice = monthAverageAmount
|
||||
.multiply(BigDecimal.valueOf(productsDetailDO.getDuration()));
|
||||
totalAmount = originalPrice
|
||||
.multiply(discount)
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.DOWN);
|
||||
}
|
||||
default -> throw new ServiceException(PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT);
|
||||
}
|
||||
@@ -953,17 +912,37 @@ public class PayProductProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算首次订购的月均单价
|
||||
* 计算首次订购的价格
|
||||
*/
|
||||
private BigDecimal computeInitialProductPayMonthAverageAmount(BigDecimal price) {
|
||||
private BigDecimal computeInitialProductPayAmount() {
|
||||
// 订购数量
|
||||
Integer duration = productsDetailDO.getDuration();
|
||||
BigDecimal monthAverageAmount;
|
||||
// 产品订购价格
|
||||
BigDecimal orgPurchasePrice = productsDO.getPrice();
|
||||
// 折扣
|
||||
BigDecimal discount = productsDetailDO.getDiscount();
|
||||
|
||||
BigDecimal totalAmount;
|
||||
switch (ProductDurationUnitEnum.fromStatus(productsDetailDO.getDurationUnit())) {
|
||||
case YEAR -> monthAverageAmount = price.divide(new BigDecimal(duration * 12), 2, RoundingMode.DOWN);
|
||||
case MONTH -> monthAverageAmount = price.divide(new BigDecimal(duration), 2, RoundingMode.DOWN);
|
||||
case YEAR -> {
|
||||
// 原价
|
||||
originalPrice = orgPurchasePrice.multiply(BigDecimal.valueOf(duration));
|
||||
// 折扣价格 = 原价 * 折扣
|
||||
totalAmount = originalPrice.multiply(discount);
|
||||
// 月均单价 = 折扣价格 / 10
|
||||
monthAverageAmount = originalPrice.divide(new BigDecimal(10), 2, RoundingMode.DOWN);
|
||||
}
|
||||
case MONTH -> {
|
||||
// 月均单价 = 订购价格 / 10
|
||||
monthAverageAmount = orgPurchasePrice.divide(new BigDecimal(10), 2, RoundingMode.DOWN);
|
||||
// 原价
|
||||
originalPrice = monthAverageAmount.multiply(BigDecimal.valueOf(duration));
|
||||
// 折扣价格 = 原价 * 折扣
|
||||
totalAmount = originalPrice.multiply(discount);
|
||||
}
|
||||
default -> throw new ServiceException(PRODUCTS_DETAIL_DURATION_UNIT_NOT_SUPPORT);
|
||||
}
|
||||
return monthAverageAmount;
|
||||
return totalAmount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ public class ProductDurationUnitValidator implements ConstraintValidator<Product
|
||||
if (ObjectUtil.isNull(value)) {
|
||||
return true;
|
||||
}
|
||||
for (ProductDurationUnitEnum unitEnum : ProductDurationUnitEnum.values()) {
|
||||
for (ProductDurationUnitEnum unitEnum : ProductDurationUnitEnum.validArr()) {
|
||||
if (Objects.equals(unitEnum.getCode(), value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@
|
||||
END
|
||||
) AS invoiced
|
||||
from purchase_record
|
||||
where organ_id = #{organId} and deleted = false;
|
||||
where organ_id = #{organId} and deleted = false and initial != true;
|
||||
</select>
|
||||
|
||||
<select id="getInvoicableAmount" resultType="java.math.BigDecimal">
|
||||
@@ -58,7 +58,7 @@
|
||||
sum(total_amount - gift_money_spent) as amount,
|
||||
sum(gift_money_spent) as giftAmount
|
||||
from purchase_record
|
||||
where deleted = false;
|
||||
where deleted = false and initial != true;
|
||||
</select>
|
||||
|
||||
<select id="getTotalRechargeUsageAmount" resultType="java.math.BigDecimal">
|
||||
|
||||
Reference in New Issue
Block a user