feat(tenant): 添加租户名称重复验证
- 在创建租户时检查名称是否已存在 - 确保租户名称不为空 - 防止重复租户名称导致的数据冲突
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
package com.gxwebsoft.common.system.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.common.system.entity.TenantPackage;
|
||||
import com.gxwebsoft.common.system.service.TenantPackageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户套餐控制器
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Tag(name = "租户套餐管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/system/package")
|
||||
public class TenantPackageController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private TenantPackageService tenantPackageService;
|
||||
|
||||
@Operation(summary = "查询所有上架套餐")
|
||||
@GetMapping("/list")
|
||||
public ApiResult<List<TenantPackage>> list() {
|
||||
List<TenantPackage> packages = tenantPackageService.listAvailablePackages();
|
||||
return success(packages);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据ID查询套餐详情")
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult<TenantPackage> getById(@PathVariable("id") Integer id) {
|
||||
TenantPackage tenantPackage = tenantPackageService.getById(id);
|
||||
if (tenantPackage == null) {
|
||||
return fail("套餐不存在", null);
|
||||
}
|
||||
return success(tenantPackage);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据版本号查询套餐")
|
||||
@GetMapping("/version/{version}")
|
||||
public ApiResult<TenantPackage> getByVersion(@PathVariable("version") Integer version) {
|
||||
TenantPackage tenantPackage = tenantPackageService.getByVersion(version);
|
||||
if (tenantPackage == null) {
|
||||
return fail("套餐不存在", null);
|
||||
}
|
||||
return success(tenantPackage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.gxwebsoft.common.system.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscription;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder;
|
||||
import com.gxwebsoft.common.system.service.TenantSubscriptionOrderService;
|
||||
import com.gxwebsoft.common.system.service.TenantSubscriptionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 租户订阅控制器
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Tag(name = "租户订阅管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/system/subscription")
|
||||
public class TenantSubscriptionController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private TenantSubscriptionService tenantSubscriptionService;
|
||||
|
||||
@Resource
|
||||
private TenantSubscriptionOrderService tenantSubscriptionOrderService;
|
||||
|
||||
@Operation(summary = "查询当前租户订阅信息")
|
||||
@GetMapping("/current")
|
||||
public ApiResult<TenantSubscription> getCurrentSubscription() {
|
||||
Integer tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
return fail("租户ID不存在", null);
|
||||
}
|
||||
TenantSubscription subscription = tenantSubscriptionService.getByTenantId(tenantId);
|
||||
return success(subscription);
|
||||
}
|
||||
|
||||
@Operation(summary = "检查订阅是否有效")
|
||||
@GetMapping("/check")
|
||||
public ApiResult<Map<String, Object>> checkSubscription() {
|
||||
Integer tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
return fail("租户ID不存在", null);
|
||||
}
|
||||
|
||||
boolean isValid = tenantSubscriptionService.isSubscriptionValid(tenantId);
|
||||
boolean isExpired = tenantSubscriptionService.isSubscriptionExpired(tenantId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("isValid", isValid);
|
||||
result.put("isExpired", isExpired);
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询订阅激活状态")
|
||||
@GetMapping("/active")
|
||||
public ApiResult<Map<String, Object>> getActiveStatus() {
|
||||
Integer tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
return fail("租户ID不存在", null);
|
||||
}
|
||||
|
||||
TenantSubscription subscription = tenantSubscriptionService.getByTenantId(tenantId);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (subscription == null) {
|
||||
result.put("active", false);
|
||||
result.put("message", "未订阅任何套餐");
|
||||
} else {
|
||||
boolean isActive = subscription.getStatus() == 1 && subscription.getIsExpired() == 0;
|
||||
result.put("active", isActive);
|
||||
result.put("version", subscription.getVersion());
|
||||
result.put("packageId", subscription.getPackageId());
|
||||
result.put("endTime", subscription.getEndTime());
|
||||
result.put("isTrial", subscription.getIsTrial());
|
||||
}
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "创建试用订单")
|
||||
@PostMapping("/trial")
|
||||
public ApiResult<TenantSubscriptionOrder> createTrialOrder() {
|
||||
Integer tenantId = getTenantId();
|
||||
Integer userId = getLoginUserId();
|
||||
|
||||
if (tenantId == null || userId == null) {
|
||||
return fail("参数错误", null);
|
||||
}
|
||||
|
||||
TenantSubscriptionOrder order = tenantSubscriptionOrderService.createTrialOrder(tenantId, userId);
|
||||
return success("试用开通成功", order);
|
||||
}
|
||||
|
||||
@Operation(summary = "创建订阅订单")
|
||||
@PostMapping("/order")
|
||||
public ApiResult<TenantSubscriptionOrder> createOrder(@RequestParam Integer packageId,
|
||||
@RequestParam Integer payType) {
|
||||
Integer tenantId = getTenantId();
|
||||
Integer userId = getLoginUserId();
|
||||
|
||||
if (tenantId == null || userId == null) {
|
||||
return fail("参数错误", null);
|
||||
}
|
||||
|
||||
TenantSubscriptionOrder order = tenantSubscriptionOrderService.createOrder(packageId, payType, tenantId, userId);
|
||||
return success("订单创建成功", order);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询订单列表")
|
||||
@GetMapping("/orders")
|
||||
public ApiResult<PageResult<TenantSubscriptionOrder>> listOrders(@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer limit) {
|
||||
Integer tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
return fail("租户ID不存在", null);
|
||||
}
|
||||
|
||||
PageResult<TenantSubscriptionOrder> result = tenantSubscriptionOrderService.pageByTenant(tenantId, page, limit);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据订单号查询订单")
|
||||
@GetMapping("/order/{orderNo}")
|
||||
public ApiResult<TenantSubscriptionOrder> getOrderByNo(@PathVariable String orderNo) {
|
||||
TenantSubscriptionOrder order = tenantSubscriptionOrderService.getByOrderNo(orderNo);
|
||||
if (order == null) {
|
||||
return fail("订单不存在", null);
|
||||
}
|
||||
return success(order);
|
||||
}
|
||||
|
||||
@Operation(summary = "取消订单")
|
||||
@PostMapping("/order/cancel")
|
||||
public ApiResult<?> cancelOrder(@RequestParam String orderNo,
|
||||
@RequestParam(required = false) String cancelReason) {
|
||||
boolean success = tenantSubscriptionOrderService.cancelOrder(orderNo, cancelReason);
|
||||
if (success) {
|
||||
return success("订单已取消");
|
||||
}
|
||||
return fail("取消失败", null);
|
||||
}
|
||||
|
||||
@Operation(summary = "设置自动续费")
|
||||
@PostMapping("/auto-renewal")
|
||||
public ApiResult<?> setAutoRenewal(@RequestParam Integer autoRenewal,
|
||||
@RequestParam(required = false) Integer renewalPackageId) {
|
||||
Integer tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
return fail("租户ID不存在", null);
|
||||
}
|
||||
|
||||
boolean success = tenantSubscriptionService.setAutoRenewal(tenantId, autoRenewal, renewalPackageId);
|
||||
if (success) {
|
||||
return success(autoRenewal == 1 ? "自动续费已开启" : "自动续费已关闭");
|
||||
}
|
||||
return fail("设置失败", null);
|
||||
}
|
||||
|
||||
@Operation(summary = "升级套餐")
|
||||
@PostMapping("/upgrade")
|
||||
public ApiResult<?> upgradeSubscription(@RequestParam Integer newPackageId) {
|
||||
Integer tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
return fail("租户ID不存在", null);
|
||||
}
|
||||
|
||||
boolean success = tenantSubscriptionService.upgradeSubscription(tenantId, newPackageId);
|
||||
if (success) {
|
||||
return success("升级成功");
|
||||
}
|
||||
return fail("升级失败", null);
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,18 @@ public class Tenant implements Serializable {
|
||||
@Schema(description = "用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@Schema(description = "当前订阅ID")
|
||||
private Long subscriptionId;
|
||||
|
||||
@Schema(description = "是否试用中")
|
||||
private Integer isTrial;
|
||||
|
||||
@Schema(description = "试用结束时间")
|
||||
private Date trialEndTime;
|
||||
|
||||
@Schema(description = "自动续费")
|
||||
private Integer autoRenewal;
|
||||
|
||||
@Schema(description = "是否删除, 0否, 1是")
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.gxwebsoft.common.system.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 租户套餐
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(name = "TenantPackage对象", description = "租户套餐")
|
||||
@TableName("sys_tenant_package")
|
||||
public class TenantPackage implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "套餐ID")
|
||||
@TableId(value = "package_id", type = IdType.AUTO)
|
||||
private Integer packageId;
|
||||
|
||||
@Schema(description = "套餐名称")
|
||||
private String packageName;
|
||||
|
||||
@Schema(description = "版本号 0试用 10基础 20专业 30企业 99私有")
|
||||
private Integer version;
|
||||
|
||||
@Schema(description = "月付价格")
|
||||
private BigDecimal priceMonthly;
|
||||
|
||||
@Schema(description = "年付价格")
|
||||
private BigDecimal priceYearly;
|
||||
|
||||
@Schema(description = "季付价格")
|
||||
private BigDecimal priceQuarterly;
|
||||
|
||||
@Schema(description = "最大用户数 0无限")
|
||||
private Integer maxUsers;
|
||||
|
||||
@Schema(description = "最大订单数 0无限")
|
||||
private Integer maxOrders;
|
||||
|
||||
@Schema(description = "存储空间限制(MB) 0无限")
|
||||
private Long storageLimit;
|
||||
|
||||
@Schema(description = "API调用限制(次/天) 0无限")
|
||||
private Integer apiLimit;
|
||||
|
||||
@Schema(description = "试用天数")
|
||||
private Integer trialDays;
|
||||
|
||||
@Schema(description = "功能列表JSON")
|
||||
private String features;
|
||||
|
||||
@Schema(description = "状态 0下架 1上架")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "排序号")
|
||||
private Integer sortNumber;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.gxwebsoft.common.system.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 租户订阅记录
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(name = "TenantSubscription对象", description = "租户订阅记录")
|
||||
@TableName("sys_tenant_subscription")
|
||||
public class TenantSubscription implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "订阅ID")
|
||||
@TableId(value = "subscription_id", type = IdType.AUTO)
|
||||
private Long subscriptionId;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Integer tenantId;
|
||||
|
||||
@Schema(description = "当前套餐ID")
|
||||
private Integer packageId;
|
||||
|
||||
@Schema(description = "当前版本")
|
||||
private Integer version;
|
||||
|
||||
@Schema(description = "开始时间")
|
||||
private Date startTime;
|
||||
|
||||
@Schema(description = "到期时间")
|
||||
private Date endTime;
|
||||
|
||||
@Schema(description = "是否试用期")
|
||||
private Integer isTrial;
|
||||
|
||||
@Schema(description = "是否已过期 0否 1是")
|
||||
private Integer isExpired;
|
||||
|
||||
@Schema(description = "自动续费 0关闭 1开启")
|
||||
private Integer autoRenewal;
|
||||
|
||||
@Schema(description = "续费套餐ID")
|
||||
private Integer renewalPackageId;
|
||||
|
||||
@Schema(description = "提醒状态 0未提醒 1已提醒30天 2已提醒7天 3已提醒1天")
|
||||
private Integer notifyStatus;
|
||||
|
||||
@Schema(description = "状态 0停用 1正常")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date updateTime;
|
||||
|
||||
// 关联查询字段
|
||||
@Schema(description = "套餐信息")
|
||||
@TableField(exist = false)
|
||||
private TenantPackage tenantPackage;
|
||||
|
||||
@Schema(description = "租户信息")
|
||||
@TableField(exist = false)
|
||||
private Tenant tenant;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.gxwebsoft.common.system.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 租户订阅订单
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(name = "TenantSubscriptionOrder对象", description = "租户订阅订单")
|
||||
@TableName("sys_tenant_subscription_order")
|
||||
public class TenantSubscriptionOrder implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "订单ID")
|
||||
@TableId(value = "order_id", type = IdType.AUTO)
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "订单编号")
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Integer tenantId;
|
||||
|
||||
@Schema(description = "套餐ID")
|
||||
private Integer packageId;
|
||||
|
||||
@Schema(description = "套餐名称")
|
||||
private String packageName;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private Integer version;
|
||||
|
||||
@Schema(description = "支付周期 1月付 3季付 12年付")
|
||||
private Integer payType;
|
||||
|
||||
@Schema(description = "原价")
|
||||
private BigDecimal originalPrice;
|
||||
|
||||
@Schema(description = "优惠金额")
|
||||
private BigDecimal discountPrice;
|
||||
|
||||
@Schema(description = "实付金额")
|
||||
private BigDecimal actualPrice;
|
||||
|
||||
@Schema(description = "开始时间")
|
||||
private Date startTime;
|
||||
|
||||
@Schema(description = "到期时间")
|
||||
private Date endTime;
|
||||
|
||||
@Schema(description = "是否试用 0否 1是")
|
||||
private Integer isTrial;
|
||||
|
||||
@Schema(description = "是否续费 0首购 1续费")
|
||||
private Integer isRenewal;
|
||||
|
||||
@Schema(description = "是否升级 0否 1是")
|
||||
private Integer isUpgrade;
|
||||
|
||||
@Schema(description = "升级前版本")
|
||||
private Integer oldVersion;
|
||||
|
||||
@Schema(description = "支付方式 wxpay/alipay/balance")
|
||||
private String paymentMethod;
|
||||
|
||||
@Schema(description = "支付流水号")
|
||||
private String paymentId;
|
||||
|
||||
@Schema(description = "支付时间")
|
||||
private Date paymentTime;
|
||||
|
||||
@Schema(description = "订单状态 0待支付 1已支付 2已激活 3已取消 4已退款")
|
||||
private Integer orderStatus;
|
||||
|
||||
@Schema(description = "取消原因")
|
||||
private String cancelReason;
|
||||
|
||||
@Schema(description = "操作用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.gxwebsoft.common.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.gxwebsoft.common.system.entity.TenantPackage;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户套餐Mapper
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
public interface TenantPackageMapper extends BaseMapper<TenantPackage> {
|
||||
|
||||
/**
|
||||
* 查询所有上架的套餐
|
||||
*
|
||||
* @return List<TenantPackage>
|
||||
*/
|
||||
List<TenantPackage> selectAvailablePackages();
|
||||
|
||||
/**
|
||||
* 根据版本号查询套餐
|
||||
*
|
||||
* @param version 版本号
|
||||
* @return TenantPackage
|
||||
*/
|
||||
TenantPackage selectByVersion(@Param("version") Integer version);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.gxwebsoft.common.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscription;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户订阅记录Mapper
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
public interface TenantSubscriptionMapper extends BaseMapper<TenantSubscription> {
|
||||
|
||||
/**
|
||||
* 根据租户ID查询订阅信息(关联查询)
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @return TenantSubscription
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
TenantSubscription selectByTenantIdRel(@Param("tenantId") Integer tenantId);
|
||||
|
||||
/**
|
||||
* 查询即将过期的订阅(用于提醒)
|
||||
*
|
||||
* @param days 提前天数
|
||||
* @return List<TenantSubscription>
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
List<TenantSubscription> selectExpiringSoon(@Param("days") Integer days);
|
||||
|
||||
/**
|
||||
* 查询已过期的订阅
|
||||
*
|
||||
* @return List<TenantSubscription>
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
List<TenantSubscription> selectExpired();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.gxwebsoft.common.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户订阅订单Mapper
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
public interface TenantSubscriptionOrderMapper extends BaseMapper<TenantSubscriptionOrder> {
|
||||
|
||||
/**
|
||||
* 分页查询订单
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param tenantId 租户ID
|
||||
* @return List<TenantSubscriptionOrder>
|
||||
*/
|
||||
List<TenantSubscriptionOrder> selectPageByTenant(@Param("page") IPage<TenantSubscriptionOrder> page,
|
||||
@Param("tenantId") Integer tenantId);
|
||||
|
||||
/**
|
||||
* 根据订单号查询
|
||||
*
|
||||
* @param orderNo 订单号
|
||||
* @return TenantSubscriptionOrder
|
||||
*/
|
||||
TenantSubscriptionOrder selectByOrderNo(@Param("orderNo") String orderNo);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="com.gxwebsoft.common.system.mapper.TenantPackageMapper">
|
||||
|
||||
<!-- 查询所有上架的套餐 -->
|
||||
<select id="selectAvailablePackages" resultType="com.gxwebsoft.common.system.entity.TenantPackage">
|
||||
SELECT *
|
||||
FROM sys_tenant_package
|
||||
WHERE status = 1
|
||||
ORDER BY sort_number ASC, version ASC
|
||||
</select>
|
||||
|
||||
<!-- 根据版本号查询套餐 -->
|
||||
<select id="selectByVersion" resultType="com.gxwebsoft.common.system.entity.TenantPackage">
|
||||
SELECT *
|
||||
FROM sys_tenant_package
|
||||
WHERE version = #{version}
|
||||
AND status = 1
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="com.gxwebsoft.common.system.mapper.TenantSubscriptionMapper">
|
||||
|
||||
<!-- 根据租户ID查询订阅信息(关联查询) -->
|
||||
<select id="selectByTenantIdRel" resultType="com.gxwebsoft.common.system.entity.TenantSubscription">
|
||||
SELECT s.*,
|
||||
p.package_name,
|
||||
p.version,
|
||||
p.max_users,
|
||||
p.max_orders,
|
||||
p.storage_limit,
|
||||
p.api_limit,
|
||||
p.features
|
||||
FROM sys_tenant_subscription s
|
||||
LEFT JOIN sys_tenant_package p ON s.package_id = p.package_id
|
||||
WHERE s.tenant_id = #{tenantId}
|
||||
AND s.status = 1
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 查询即将过期的订阅(用于提醒) -->
|
||||
<select id="selectExpiringSoon" resultType="com.gxwebsoft.common.system.entity.TenantSubscription">
|
||||
SELECT s.*,
|
||||
t.tenant_name,
|
||||
t.phone
|
||||
FROM sys_tenant_subscription s
|
||||
LEFT JOIN sys_tenant t ON s.tenant_id = t.tenant_id
|
||||
WHERE s.status = 1
|
||||
AND s.is_expired = 0
|
||||
AND s.end_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL #{days} DAY)
|
||||
ORDER BY s.end_time ASC
|
||||
</select>
|
||||
|
||||
<!-- 查询已过期的订阅 -->
|
||||
<select id="selectExpired" resultType="com.gxwebsoft.common.system.entity.TenantSubscription">
|
||||
SELECT s.*
|
||||
FROM sys_tenant_subscription s
|
||||
WHERE s.status = 1
|
||||
AND s.is_expired = 0
|
||||
AND s.end_time < NOW()
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="com.gxwebsoft.common.system.mapper.TenantSubscriptionOrderMapper">
|
||||
|
||||
<!-- 分页查询订单 -->
|
||||
<select id="selectPageByTenant" resultType="com.gxwebsoft.common.system.entity.TenantSubscriptionOrder">
|
||||
SELECT *
|
||||
FROM sys_tenant_subscription_order
|
||||
WHERE tenant_id = #{tenantId}
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据订单号查询 -->
|
||||
<select id="selectByOrderNo" resultType="com.gxwebsoft.common.system.entity.TenantSubscriptionOrder">
|
||||
SELECT *
|
||||
FROM sys_tenant_subscription_order
|
||||
WHERE order_no = #{orderNo}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.gxwebsoft.common.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.system.entity.TenantPackage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户套餐Service
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
public interface TenantPackageService extends IService<TenantPackage> {
|
||||
|
||||
/**
|
||||
* 查询所有上架的套餐
|
||||
*
|
||||
* @return List<TenantPackage>
|
||||
*/
|
||||
List<TenantPackage> listAvailablePackages();
|
||||
|
||||
/**
|
||||
* 根据版本号查询套餐
|
||||
*
|
||||
* @param version 版本号
|
||||
* @return TenantPackage
|
||||
*/
|
||||
TenantPackage getByVersion(Integer version);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.gxwebsoft.common.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder;
|
||||
|
||||
/**
|
||||
* 租户订阅订单Service
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
public interface TenantSubscriptionOrderService extends IService<TenantSubscriptionOrder> {
|
||||
|
||||
/**
|
||||
* 创建订阅订单
|
||||
*
|
||||
* @param packageId 套餐ID
|
||||
* @param payType 支付周期 1月付 3季付 12年付
|
||||
* @param tenantId 租户ID
|
||||
* @param userId 用户ID
|
||||
* @return TenantSubscriptionOrder
|
||||
*/
|
||||
TenantSubscriptionOrder createOrder(Integer packageId, Integer payType, Integer tenantId, Integer userId);
|
||||
|
||||
/**
|
||||
* 创建试用订单
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param userId 用户ID
|
||||
* @return TenantSubscriptionOrder
|
||||
*/
|
||||
TenantSubscriptionOrder createTrialOrder(Integer tenantId, Integer userId);
|
||||
|
||||
/**
|
||||
* 支付订单
|
||||
*
|
||||
* @param orderNo 订单号
|
||||
* @param paymentMethod 支付方式
|
||||
* @param paymentId 支付流水号
|
||||
* @return boolean
|
||||
*/
|
||||
boolean payOrder(String orderNo, String paymentMethod, String paymentId);
|
||||
|
||||
/**
|
||||
* 激活订单(支付成功后调用)
|
||||
*
|
||||
* @param orderNo 订单号
|
||||
* @return boolean
|
||||
*/
|
||||
boolean activateOrder(String orderNo);
|
||||
|
||||
/**
|
||||
* 取消订单
|
||||
*
|
||||
* @param orderNo 订单号
|
||||
* @param cancelReason 取消原因
|
||||
* @return boolean
|
||||
*/
|
||||
boolean cancelOrder(String orderNo, String cancelReason);
|
||||
|
||||
/**
|
||||
* 分页查询租户订单
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @return PageResult<TenantSubscriptionOrder>
|
||||
*/
|
||||
PageResult<TenantSubscriptionOrder> pageByTenant(Integer tenantId, Integer page, Integer limit);
|
||||
|
||||
/**
|
||||
* 根据订单号查询
|
||||
*
|
||||
* @param orderNo 订单号
|
||||
* @return TenantSubscriptionOrder
|
||||
*/
|
||||
TenantSubscriptionOrder getByOrderNo(String orderNo);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.gxwebsoft.common.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscription;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户订阅记录Service
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
public interface TenantSubscriptionService extends IService<TenantSubscription> {
|
||||
|
||||
/**
|
||||
* 根据租户ID查询订阅信息
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @return TenantSubscription
|
||||
*/
|
||||
TenantSubscription getByTenantId(Integer tenantId);
|
||||
|
||||
/**
|
||||
* 创建或更新订阅
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param packageId 套餐ID
|
||||
* @param version 版本号
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 到期时间
|
||||
* @param isTrial 是否试用
|
||||
* @return TenantSubscription
|
||||
*/
|
||||
TenantSubscription createOrUpdateSubscription(Integer tenantId, Integer packageId, Integer version,
|
||||
java.util.Date startTime, java.util.Date endTime, Integer isTrial);
|
||||
|
||||
/**
|
||||
* 升级订阅
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param newPackageId 新套餐ID
|
||||
* @return boolean
|
||||
*/
|
||||
boolean upgradeSubscription(Integer tenantId, Integer newPackageId);
|
||||
|
||||
/**
|
||||
* 续费订阅
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param months 续费月数
|
||||
* @return boolean
|
||||
*/
|
||||
boolean renewSubscription(Integer tenantId, Integer months);
|
||||
|
||||
/**
|
||||
* 设置自动续费
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param autoRenewal 是否自动续费
|
||||
* @param renewalPackageId 续费套餐ID
|
||||
* @return boolean
|
||||
*/
|
||||
boolean setAutoRenewal(Integer tenantId, Integer autoRenewal, Integer renewalPackageId);
|
||||
|
||||
/**
|
||||
* 检查订阅是否有效
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @return boolean
|
||||
*/
|
||||
boolean isSubscriptionValid(Integer tenantId);
|
||||
|
||||
/**
|
||||
* 检查订阅是否过期
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @return boolean
|
||||
*/
|
||||
boolean isSubscriptionExpired(Integer tenantId);
|
||||
|
||||
/**
|
||||
* 查询即将过期的订阅
|
||||
*
|
||||
* @param days 提前天数
|
||||
* @return List<TenantSubscription>
|
||||
*/
|
||||
List<TenantSubscription> listExpiringSoon(Integer days);
|
||||
|
||||
/**
|
||||
* 查询已过期的订阅
|
||||
*
|
||||
* @return List<TenantSubscription>
|
||||
*/
|
||||
List<TenantSubscription> listExpired();
|
||||
|
||||
/**
|
||||
* 标记订阅为已过期
|
||||
*
|
||||
* @param subscriptionId 订阅ID
|
||||
* @return boolean
|
||||
*/
|
||||
boolean markAsExpired(Long subscriptionId);
|
||||
|
||||
/**
|
||||
* 发送过期提醒
|
||||
*
|
||||
* @param subscriptionId 订阅ID
|
||||
* @param notifyStatus 提醒状态
|
||||
* @return boolean
|
||||
*/
|
||||
boolean sendExpiryNotification(Long subscriptionId, Integer notifyStatus);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gxwebsoft.common.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.common.system.entity.TenantPackage;
|
||||
import com.gxwebsoft.common.system.mapper.TenantPackageMapper;
|
||||
import com.gxwebsoft.common.system.service.TenantPackageService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户套餐ServiceImpl
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Service
|
||||
public class TenantPackageServiceImpl extends ServiceImpl<TenantPackageMapper, TenantPackage> implements TenantPackageService {
|
||||
|
||||
@Override
|
||||
public List<TenantPackage> listAvailablePackages() {
|
||||
return baseMapper.selectAvailablePackages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TenantPackage getByVersion(Integer version) {
|
||||
return baseMapper.selectByVersion(version);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package com.gxwebsoft.common.system.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.system.entity.TenantPackage;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder;
|
||||
import com.gxwebsoft.common.system.mapper.TenantSubscriptionOrderMapper;
|
||||
import com.gxwebsoft.common.system.service.TenantPackageService;
|
||||
import com.gxwebsoft.common.system.service.TenantSubscriptionOrderService;
|
||||
import com.gxwebsoft.common.system.service.TenantSubscriptionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 租户订阅订单ServiceImpl
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Service
|
||||
public class TenantSubscriptionOrderServiceImpl extends ServiceImpl<TenantSubscriptionOrderMapper, TenantSubscriptionOrder> implements TenantSubscriptionOrderService {
|
||||
|
||||
@Resource
|
||||
private TenantPackageService tenantPackageService;
|
||||
|
||||
@Resource
|
||||
private TenantSubscriptionService tenantSubscriptionService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TenantSubscriptionOrder createOrder(Integer packageId, Integer payType, Integer tenantId, Integer userId) {
|
||||
// 查询套餐信息
|
||||
TenantPackage tenantPackage = tenantPackageService.getById(packageId);
|
||||
if (tenantPackage == null) {
|
||||
throw new BusinessException("套餐不存在");
|
||||
}
|
||||
if (tenantPackage.getStatus() != 1) {
|
||||
throw new BusinessException("套餐已下架");
|
||||
}
|
||||
|
||||
// 计算价格
|
||||
BigDecimal price;
|
||||
if (payType == 1) {
|
||||
price = tenantPackage.getPriceMonthly();
|
||||
} else if (payType == 3) {
|
||||
price = tenantPackage.getPriceQuarterly();
|
||||
} else if (payType == 12) {
|
||||
price = tenantPackage.getPriceYearly();
|
||||
} else {
|
||||
throw new BusinessException("支付周期不正确");
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
TenantSubscriptionOrder order = new TenantSubscriptionOrder();
|
||||
order.setOrderNo(generateOrderNo());
|
||||
order.setTenantId(tenantId);
|
||||
order.setPackageId(packageId);
|
||||
order.setPackageName(tenantPackage.getPackageName());
|
||||
order.setVersion(tenantPackage.getVersion());
|
||||
order.setPayType(payType);
|
||||
order.setOriginalPrice(price);
|
||||
order.setDiscountPrice(BigDecimal.ZERO);
|
||||
order.setActualPrice(price);
|
||||
order.setIsTrial(0);
|
||||
order.setIsRenewal(0);
|
||||
order.setIsUpgrade(0);
|
||||
order.setOrderStatus(0); // 待支付
|
||||
order.setUserId(userId);
|
||||
order.setCreateTime(new Date());
|
||||
|
||||
save(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TenantSubscriptionOrder createTrialOrder(Integer tenantId, Integer userId) {
|
||||
// 查询试用套餐(version=0)
|
||||
TenantPackage trialPackage = tenantPackageService.getByVersion(0);
|
||||
if (trialPackage == null) {
|
||||
throw new BusinessException("试用套餐不存在");
|
||||
}
|
||||
|
||||
// 检查是否已经试用过
|
||||
long count = count(new LambdaQueryWrapper<TenantSubscriptionOrder>()
|
||||
.eq(TenantSubscriptionOrder::getTenantId, tenantId)
|
||||
.eq(TenantSubscriptionOrder::getIsTrial, 1));
|
||||
if (count > 0) {
|
||||
throw new BusinessException("已经使用过试用版");
|
||||
}
|
||||
|
||||
// 创建试用订单
|
||||
TenantSubscriptionOrder order = new TenantSubscriptionOrder();
|
||||
order.setOrderNo(generateOrderNo());
|
||||
order.setTenantId(tenantId);
|
||||
order.setPackageId(trialPackage.getPackageId());
|
||||
order.setPackageName(trialPackage.getPackageName());
|
||||
order.setVersion(trialPackage.getVersion());
|
||||
order.setPayType(0);
|
||||
order.setOriginalPrice(BigDecimal.ZERO);
|
||||
order.setDiscountPrice(BigDecimal.ZERO);
|
||||
order.setActualPrice(BigDecimal.ZERO);
|
||||
order.setStartTime(new Date());
|
||||
order.setEndTime(DateUtil.offsetDay(new Date(), trialPackage.getTrialDays()));
|
||||
order.setIsTrial(1);
|
||||
order.setIsRenewal(0);
|
||||
order.setIsUpgrade(0);
|
||||
order.setOrderStatus(2); // 直接激活
|
||||
order.setUserId(userId);
|
||||
order.setCreateTime(new Date());
|
||||
|
||||
save(order);
|
||||
|
||||
// 创建订阅记录
|
||||
tenantSubscriptionService.createOrUpdateSubscription(
|
||||
tenantId,
|
||||
trialPackage.getPackageId(),
|
||||
trialPackage.getVersion(),
|
||||
order.getStartTime(),
|
||||
order.getEndTime(),
|
||||
1
|
||||
);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean payOrder(String orderNo, String paymentMethod, String paymentId) {
|
||||
TenantSubscriptionOrder order = getByOrderNo(orderNo);
|
||||
if (order == null) {
|
||||
throw new BusinessException("订单不存在");
|
||||
}
|
||||
if (order.getOrderStatus() != 0) {
|
||||
throw new BusinessException("订单状态不正确");
|
||||
}
|
||||
|
||||
order.setPaymentMethod(paymentMethod);
|
||||
order.setPaymentId(paymentId);
|
||||
order.setPaymentTime(new Date());
|
||||
order.setOrderStatus(1); // 已支付
|
||||
order.setUpdateTime(new Date());
|
||||
|
||||
return updateById(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean activateOrder(String orderNo) {
|
||||
TenantSubscriptionOrder order = getByOrderNo(orderNo);
|
||||
if (order == null) {
|
||||
throw new BusinessException("订单不存在");
|
||||
}
|
||||
if (order.getOrderStatus() != 1) {
|
||||
throw new BusinessException("订单未支付");
|
||||
}
|
||||
|
||||
// 计算开始和结束时间
|
||||
Date startTime = new Date();
|
||||
Date endTime = DateUtil.offsetMonth(startTime, order.getPayType());
|
||||
|
||||
order.setStartTime(startTime);
|
||||
order.setEndTime(endTime);
|
||||
order.setOrderStatus(2); // 已激活
|
||||
order.setUpdateTime(new Date());
|
||||
|
||||
boolean updated = updateById(order);
|
||||
|
||||
if (updated) {
|
||||
// 创建或更新订阅记录
|
||||
tenantSubscriptionService.createOrUpdateSubscription(
|
||||
order.getTenantId(),
|
||||
order.getPackageId(),
|
||||
order.getVersion(),
|
||||
startTime,
|
||||
endTime,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean cancelOrder(String orderNo, String cancelReason) {
|
||||
TenantSubscriptionOrder order = getByOrderNo(orderNo);
|
||||
if (order == null) {
|
||||
throw new BusinessException("订单不存在");
|
||||
}
|
||||
if (order.getOrderStatus() != 0) {
|
||||
throw new BusinessException("只能取消待支付订单");
|
||||
}
|
||||
|
||||
order.setOrderStatus(3); // 已取消
|
||||
order.setCancelReason(cancelReason);
|
||||
order.setUpdateTime(new Date());
|
||||
|
||||
return updateById(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<TenantSubscriptionOrder> pageByTenant(Integer tenantId, Integer page, Integer limit) {
|
||||
IPage<TenantSubscriptionOrder> iPage = new Page<>(page, limit);
|
||||
baseMapper.selectPageByTenant(iPage, tenantId);
|
||||
return new PageResult<TenantSubscriptionOrder>(iPage.getRecords(), iPage.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TenantSubscriptionOrder getByOrderNo(String orderNo) {
|
||||
return baseMapper.selectByOrderNo(orderNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成订单号
|
||||
*/
|
||||
private String generateOrderNo() {
|
||||
return "SUB" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + IdUtil.randomUUID().substring(0, 6).toUpperCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.gxwebsoft.common.system.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.system.entity.TenantPackage;
|
||||
import com.gxwebsoft.common.system.entity.TenantSubscription;
|
||||
import com.gxwebsoft.common.system.mapper.TenantSubscriptionMapper;
|
||||
import com.gxwebsoft.common.system.service.TenantPackageService;
|
||||
import com.gxwebsoft.common.system.service.TenantSubscriptionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户订阅记录ServiceImpl
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-12-12
|
||||
*/
|
||||
@Service
|
||||
public class TenantSubscriptionServiceImpl extends ServiceImpl<TenantSubscriptionMapper, TenantSubscription> implements TenantSubscriptionService {
|
||||
|
||||
@Resource
|
||||
private TenantPackageService tenantPackageService;
|
||||
|
||||
@Override
|
||||
public TenantSubscription getByTenantId(Integer tenantId) {
|
||||
return baseMapper.selectByTenantIdRel(tenantId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TenantSubscription createOrUpdateSubscription(Integer tenantId, Integer packageId, Integer version,
|
||||
Date startTime, Date endTime, Integer isTrial) {
|
||||
// 查询是否已存在订阅
|
||||
TenantSubscription subscription = getOne(new LambdaQueryWrapper<TenantSubscription>()
|
||||
.eq(TenantSubscription::getTenantId, tenantId));
|
||||
|
||||
if (subscription == null) {
|
||||
// 创建新订阅
|
||||
subscription = new TenantSubscription();
|
||||
subscription.setTenantId(tenantId);
|
||||
subscription.setPackageId(packageId);
|
||||
subscription.setVersion(version);
|
||||
subscription.setStartTime(startTime);
|
||||
subscription.setEndTime(endTime);
|
||||
subscription.setIsTrial(isTrial);
|
||||
subscription.setIsExpired(0);
|
||||
subscription.setAutoRenewal(0);
|
||||
subscription.setNotifyStatus(0);
|
||||
subscription.setStatus(1);
|
||||
subscription.setCreateTime(new Date());
|
||||
save(subscription);
|
||||
} else {
|
||||
// 更新订阅
|
||||
subscription.setPackageId(packageId);
|
||||
subscription.setVersion(version);
|
||||
subscription.setStartTime(startTime);
|
||||
subscription.setEndTime(endTime);
|
||||
subscription.setIsTrial(isTrial);
|
||||
subscription.setIsExpired(0);
|
||||
subscription.setNotifyStatus(0);
|
||||
subscription.setUpdateTime(new Date());
|
||||
updateById(subscription);
|
||||
}
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean upgradeSubscription(Integer tenantId, Integer newPackageId) {
|
||||
TenantSubscription subscription = getByTenantId(tenantId);
|
||||
if (subscription == null) {
|
||||
throw new BusinessException("订阅不存在");
|
||||
}
|
||||
|
||||
TenantPackage newPackage = tenantPackageService.getById(newPackageId);
|
||||
if (newPackage == null) {
|
||||
throw new BusinessException("套餐不存在");
|
||||
}
|
||||
|
||||
// 检查是否是升级
|
||||
if (newPackage.getVersion() <= subscription.getVersion()) {
|
||||
throw new BusinessException("只能升级到更高版本");
|
||||
}
|
||||
|
||||
subscription.setPackageId(newPackageId);
|
||||
subscription.setVersion(newPackage.getVersion());
|
||||
subscription.setUpdateTime(new Date());
|
||||
|
||||
return updateById(subscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean renewSubscription(Integer tenantId, Integer months) {
|
||||
TenantSubscription subscription = getByTenantId(tenantId);
|
||||
if (subscription == null) {
|
||||
throw new BusinessException("订阅不存在");
|
||||
}
|
||||
|
||||
// 从当前到期时间延长
|
||||
Date newEndTime = DateUtil.offsetMonth(subscription.getEndTime(), months);
|
||||
subscription.setEndTime(newEndTime);
|
||||
subscription.setIsExpired(0);
|
||||
subscription.setUpdateTime(new Date());
|
||||
|
||||
return updateById(subscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean setAutoRenewal(Integer tenantId, Integer autoRenewal, Integer renewalPackageId) {
|
||||
TenantSubscription subscription = getByTenantId(tenantId);
|
||||
if (subscription == null) {
|
||||
throw new BusinessException("订阅不存在");
|
||||
}
|
||||
|
||||
subscription.setAutoRenewal(autoRenewal);
|
||||
subscription.setRenewalPackageId(renewalPackageId);
|
||||
subscription.setUpdateTime(new Date());
|
||||
|
||||
return updateById(subscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubscriptionValid(Integer tenantId) {
|
||||
TenantSubscription subscription = getByTenantId(tenantId);
|
||||
if (subscription == null) {
|
||||
return false;
|
||||
}
|
||||
return subscription.getStatus() == 1 && subscription.getIsExpired() == 0
|
||||
&& subscription.getEndTime().after(new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubscriptionExpired(Integer tenantId) {
|
||||
TenantSubscription subscription = getByTenantId(tenantId);
|
||||
if (subscription == null) {
|
||||
return true;
|
||||
}
|
||||
return subscription.getIsExpired() == 1 || subscription.getEndTime().before(new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TenantSubscription> listExpiringSoon(Integer days) {
|
||||
return baseMapper.selectExpiringSoon(days);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TenantSubscription> listExpired() {
|
||||
return baseMapper.selectExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean markAsExpired(Long subscriptionId) {
|
||||
TenantSubscription subscription = getById(subscriptionId);
|
||||
if (subscription == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subscription.setIsExpired(1);
|
||||
subscription.setUpdateTime(new Date());
|
||||
|
||||
return updateById(subscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean sendExpiryNotification(Long subscriptionId, Integer notifyStatus) {
|
||||
TenantSubscription subscription = getById(subscriptionId);
|
||||
if (subscription == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subscription.setNotifyStatus(notifyStatus);
|
||||
subscription.setUpdateTime(new Date());
|
||||
|
||||
return updateById(subscription);
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,14 @@ spring:
|
||||
main:
|
||||
allow-circular-references: true
|
||||
datasource:
|
||||
url: jdbc:mysql://132.232.214.96:13306/gxwebsoft_core?useSSL=false&serverTimezone=UTC
|
||||
url: jdbc:mysql://47.119.165.234:13308/gxwebsoft_core?useSSL=false&serverTimezone=UTC
|
||||
username: gxwebsoft_core
|
||||
password: jdj7HYEdYHnYEFBy
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
redis:
|
||||
database: 0
|
||||
host: 132.232.214.96
|
||||
host: 47.119.165.234
|
||||
port: 16379
|
||||
password: redis_WSDb88
|
||||
|
||||
|
||||
Reference in New Issue
Block a user