diff --git a/src/main/java/com/gxwebsoft/common/system/controller/SubscriptionOrderController.java b/src/main/java/com/gxwebsoft/common/system/controller/SubscriptionOrderController.java new file mode 100644 index 0000000..7b026b6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/SubscriptionOrderController.java @@ -0,0 +1,195 @@ +package com.gxwebsoft.common.system.controller; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.SubscriptionOrderParam; +import com.gxwebsoft.common.system.result.SubscriptionPriceResult; +import com.gxwebsoft.common.system.service.SettingService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.List; + +/** + * 订阅订单接口 + */ +@Tag(name = "订阅订单") +@RestController +@RequestMapping("/api/system/subscription-order") +public class SubscriptionOrderController extends BaseController { + + @Resource + private SettingService settingService; + + @Operation(summary = "计算订阅订单价格") + @PostMapping("/calculate-price") + public ApiResult calculatePrice(@RequestBody SubscriptionOrderParam param) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + if (param.getPackageId() == null) { + return fail("套餐ID不能为空", null); + } + + JSONObject config = loadSubscriptionConfig(); + final SubscriptionPriceResult result = buildPriceResult(param, config); + return success(result); + } + + /** + * 从配置表读取订阅套餐配置(尝试多种key以兼容历史数据) + */ + private JSONObject loadSubscriptionConfig() { + final List keys = Arrays.asList("subscription", "subscription-package", "subscriptionOrder"); + for (String key : keys) { + try { + JSONObject cfg = settingService.getBySettingKey(key); + if (cfg != null) { + return cfg; + } + } catch (Exception ignored) { + } + } + return new JSONObject(); + } + + /** + * 计算价格结果 + */ + private SubscriptionPriceResult buildPriceResult(SubscriptionOrderParam param, JSONObject config) { + BigDecimal originalPrice = resolveBasePrice(param.getPackageId(), config); + BigDecimal factor = BigDecimal.ONE; + StringBuilder remark = new StringBuilder(); + + if (config == null || config.isEmpty()) { + remark.append("未查询到订阅价格配置,已按0元试算;"); + } + if (originalPrice.compareTo(BigDecimal.ZERO) == 0 && config != null && !config.isEmpty()) { + remark.append("未找到套餐价格,已按0元试算;"); + } + + if (isTrue(param.getIsRenewal())) { + BigDecimal renewalFactor = resolveFactor(config, "renewalDiscount"); + factor = factor.multiply(renewalFactor); + remark.append("续费系数:").append(renewalFactor).append(";"); + } + + if (isTrue(param.getIsUpgrade())) { + BigDecimal upgradeFactor = resolveFactor(config, "upgradeDiscount"); + factor = factor.multiply(upgradeFactor); + remark.append("升级系数:").append(upgradeFactor).append(";"); + } + + BigDecimal payTypeFactor = resolvePayTypeFactor(config, param.getPayType()); + factor = factor.multiply(payTypeFactor); + if (param.getPayType() != null) { + remark.append("支付系数:").append(payTypeFactor).append(";"); + } + + BigDecimal payPrice = originalPrice.multiply(factor).setScale(2, RoundingMode.HALF_UP); + BigDecimal discount = originalPrice.subtract(payPrice); + if (discount.compareTo(BigDecimal.ZERO) < 0) { + discount = BigDecimal.ZERO; + } + + SubscriptionPriceResult result = new SubscriptionPriceResult(); + result.setPackageId(param.getPackageId()); + result.setIsRenewal(param.getIsRenewal()); + result.setIsUpgrade(param.getIsUpgrade()); + result.setPayType(param.getPayType()); + result.setOriginalPrice(originalPrice.setScale(2, RoundingMode.HALF_UP)); + result.setTotalPrice(originalPrice.setScale(2, RoundingMode.HALF_UP)); + result.setPayPrice(payPrice); + result.setDiscountAmount(discount.setScale(2, RoundingMode.HALF_UP)); + result.setRemark(remark.toString()); + return result; + } + + private boolean isTrue(Integer value) { + return value != null && value.equals(1); + } + + /** + * 解析套餐价格,支持 packages 数组、priceMap 或单价配置 + */ + private BigDecimal resolveBasePrice(Integer packageId, JSONObject config) { + if (config != null) { + JSONArray packages = config.getJSONArray("packages"); + if (packages != null) { + for (Object item : packages) { + if (item instanceof JSONObject) { + JSONObject pkg = (JSONObject) item; + Integer id = pkg.getInteger("id"); + if (id == null) { + id = pkg.getInteger("packageId"); + } + if (packageId.equals(id)) { + BigDecimal price = pkg.getBigDecimal("price"); + if (price != null) { + return price; + } + } + } + } + } + + JSONObject priceMap = config.getJSONObject("priceMap"); + if (priceMap != null) { + BigDecimal price = priceMap.getBigDecimal(packageId.toString()); + if (price != null) { + return price; + } + } + + BigDecimal fallbackPrice = config.getBigDecimal("price"); + if (fallbackPrice != null) { + return fallbackPrice; + } + } + return BigDecimal.ZERO; + } + + /** + * 获取折扣系数,默认 1 + */ + private BigDecimal resolveFactor(JSONObject config, String key) { + if (config != null) { + BigDecimal factor = config.getBigDecimal(key); + if (factor != null) { + return factor; + } + } + return BigDecimal.ONE; + } + + /** + * 支付方式系数,可在配置中通过 payTypeDiscount 或 payTypeAdjustments 定义 + */ + private BigDecimal resolvePayTypeFactor(JSONObject config, Integer payType) { + if (config != null && payType != null) { + JSONObject payTypeDiscount = config.getJSONObject("payTypeDiscount"); + if (payTypeDiscount == null) { + payTypeDiscount = config.getJSONObject("payTypeAdjustments"); + } + if (payTypeDiscount != null) { + BigDecimal factor = payTypeDiscount.getBigDecimal(payType.toString()); + if (factor != null) { + return factor; + } + } + } + return BigDecimal.ONE; + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/SubscriptionOrderParam.java b/src/main/java/com/gxwebsoft/common/system/param/SubscriptionOrderParam.java new file mode 100644 index 0000000..9aec2ca --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/SubscriptionOrderParam.java @@ -0,0 +1,24 @@ +package com.gxwebsoft.common.system.param; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 订阅订单价格试算入参 + */ +@Data +@Schema(description = "订阅订单价格试算参数") +public class SubscriptionOrderParam { + + @Schema(description = "是否续费,1=续费 0=新购") + private Integer isRenewal; + + @Schema(description = "是否升级,1=升级 0=非升级") + private Integer isUpgrade; + + @Schema(description = "套餐ID") + private Integer packageId; + + @Schema(description = "支付方式") + private Integer payType; +} diff --git a/src/main/java/com/gxwebsoft/common/system/result/SubscriptionPriceResult.java b/src/main/java/com/gxwebsoft/common/system/result/SubscriptionPriceResult.java new file mode 100644 index 0000000..0dc2a57 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/result/SubscriptionPriceResult.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 订阅订单价格试算结果 + */ +@Data +@Schema(description = "订阅订单价格试算结果") +public class SubscriptionPriceResult { + + @Schema(description = "套餐ID") + private Integer packageId; + + @Schema(description = "是否续费,1=续费 0=新购") + private Integer isRenewal; + + @Schema(description = "是否升级,1=升级 0=非升级") + private Integer isUpgrade; + + @Schema(description = "支付方式") + private Integer payType; + + @Schema(description = "原价") + private BigDecimal originalPrice; + + @Schema(description = "优惠金额") + private BigDecimal discountAmount; + + @Schema(description = "应付金额") + private BigDecimal payPrice; + + @Schema(description = "总价(同原价,用于兼容前端字段)") + private BigDecimal totalPrice; + + @Schema(description = "价格说明") + private String remark; +}