diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 2f2adb61..f0dd54be 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -15,16 +15,16 @@ import com.ai.da.model.vo.PersonalHomepageVO; import com.ai.da.service.AccountService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -139,21 +139,21 @@ public class AccountController { @Operation(summary = "aws状态检测") @GetMapping("/healthy") @ResponseStatus(HttpStatus.OK) - public Response> checkStatus(){ - Map returnMap = new HashMap<>(); - returnMap.put("code",200); + public Response> checkStatus() { + Map returnMap = new HashMap<>(); + returnMap.put("code", 200); return Response.success(returnMap); } @Operation(summary = "查询账号到期时间") @PostMapping("/getExpiredTime") - public Response getExpiredTime(){ + public Response getExpiredTime() { return Response.success(accountService.getExpiredTime()); } @Operation(summary = "免密登录") @PostMapping("/noLoginRequired") - public Response noLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request){ + public Response noLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { return Response.success(accountService.noLoginRequired(noLoginRequiredDTO, request)); } @@ -191,6 +191,7 @@ public class AccountController { /** * 参与活动 获取福利 + * * @return */ /* @Operation(summary = "参与活动 获取福利") @@ -201,7 +202,7 @@ public class AccountController { @Operation(summary = "将用户账号过期时间设置为过期当天的23:59:59") @GetMapping("/setUserValidToDayEnd") - public Response> setUserValidToDayEnd(){ + public Response> setUserValidToDayEnd() { return Response.success(accountService.setUserValidToDayEnd()); } @@ -223,19 +224,19 @@ public class AccountController { @Operation(summary = "获取个人主页信息") @GetMapping("/personalHomepage") - public Response getPersonalHomepage(@RequestParam("id") Long id){ + public Response getPersonalHomepage(@RequestParam("id") Long id) { return Response.success(accountService.getPersonalHomepage(id)); } @Operation(summary = "getUsernameModifyTimes") @GetMapping("/getNicknameModifyTimes") - public Response getNicknameModifyTimes(){ + public Response getNicknameModifyTimes() { return Response.success(accountService.getNicknameModifyTimes()); } @Operation(summary = "editUserName") @GetMapping("/editUserName") - public Response editUserName(@RequestParam("newUserName") String newUserName){ + public Response editUserName(@RequestParam("newUserName") String newUserName) { accountService.editUserName(newUserName); return Response.success("success"); } diff --git a/src/main/java/com/ai/da/controller/SubscriptionPlanController.java b/src/main/java/com/ai/da/controller/SubscriptionPlanController.java index a5fab146..c91aa1d1 100644 --- a/src/main/java/com/ai/da/controller/SubscriptionPlanController.java +++ b/src/main/java/com/ai/da/controller/SubscriptionPlanController.java @@ -82,7 +82,7 @@ public class SubscriptionPlanController { @Operation(summary = "activeSubscriptionPlan") @GetMapping("/activeSubscriptionPlan") public Response activeSubscriptionPlan() { - subscriptionPlanService.activeSubscriptionPlan(); + subscriptionPlanService.activeSubscriptionPlan(null); return Response.success(); } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Account.java b/src/main/java/com/ai/da/mapper/primary/entity/Account.java index 940aa7f0..e8bdee97 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Account.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Account.java @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.Getter; import lombok.experimental.Accessors; import java.io.Serializable; @@ -76,13 +77,13 @@ public class Account implements Serializable { /** * 创建时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date createDate; /** * 更新时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date updateDate; private Integer isTrial; @@ -142,4 +143,26 @@ public class Account implements Serializable { private String givenName; private Long subscriptionPlanId; + + // 在类内部定义的枚举 + @Getter + public enum SystemRole { + VISITOR("游客", 0), + YEARLY("年付用户", 1), + MONTHLY("月付用户", 2), + TRIAL("试用用户", 3), + EVENT_USER("参加活动获取30天有效期和6000个积分的用户", 4), + ENTERPRISE_ADMIN("企业管理员账号", 5), + ENTERPRISE_SUB("企业子账号", 6), + EDUCATION_ADMIN("学校管理员", 7), + EDUCATION_SUB("学校子账号", 8); + + private final String desc; + private final int code; + + SystemRole(String desc, int code) { + this.desc = desc; + this.code = code; + } + } } diff --git a/src/main/java/com/ai/da/service/SubscriptionPlanService.java b/src/main/java/com/ai/da/service/SubscriptionPlanService.java index 67affc27..6ce8ac89 100644 --- a/src/main/java/com/ai/da/service/SubscriptionPlanService.java +++ b/src/main/java/com/ai/da/service/SubscriptionPlanService.java @@ -26,7 +26,7 @@ public interface SubscriptionPlanService extends IService { void switchSubAccSubscriptionPlan(Long subscriptionPlanId, Long subAccId); - void activeSubscriptionPlan(); + void activeSubscriptionPlan(Long planId); void expireSubscription(); } diff --git a/src/main/java/com/ai/da/service/impl/SubscriptionPlanServiceImpl.java b/src/main/java/com/ai/da/service/impl/SubscriptionPlanServiceImpl.java index 507d35d1..fec8dbd5 100644 --- a/src/main/java/com/ai/da/service/impl/SubscriptionPlanServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/SubscriptionPlanServiceImpl.java @@ -21,6 +21,7 @@ import com.ai.da.service.SubscriptionPlanService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -28,6 +29,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import java.math.BigDecimal; @@ -37,11 +39,9 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; +import static com.ai.da.mapper.primary.entity.Account.SystemRole.EDUCATION_SUB; import static com.ai.da.mapper.primary.entity.SubscriptionPlan.SubscriptionStatus.ACTIVE; import static com.ai.da.mapper.primary.entity.SubscriptionPlan.SubscriptionStatus.PENDING; @@ -80,7 +80,7 @@ public class SubscriptionPlanServiceImpl extends ServiceImpl().lambda() + .eq(Account::getId, plan.getAdminAccId()) + .eq(Account::getSubscriptionPlanId, plan.getId()) + ); + } + + private void syncAdminAccount(Account admin, SubscriptionPlan plan) { + long planEndMillis = toMillis(plan.getCurrentPeriodEnd()); + + if (!Objects.equals(admin.getValidEndTime(), planEndMillis)) { + admin.setValidEndTime(planEndMillis); + } + + if (admin.getCreditsUsageLimit().compareTo(plan.getCreditLimit()) != 0) { + // 这里计算修改前后的差值,上限增长,则差为正,上限下降,则差为负; + BigDecimal delta = plan.getCreditLimit() + .subtract(admin.getCreditsUsageLimit()); + + // 因为管理员的积分中可能包含自己购买的积分,所以这里直接将差值添加到管理员的credit中 + admin.setCredits(admin.getCredits().add(delta)); + admin.setCreditsUsageLimit(plan.getCreditLimit()); + } + + accountMapper.updateById(admin); + } + + private void syncSubAccounts(SubscriptionPlan plan) { + accountMapper.update( + null, + new UpdateWrapper().lambda() + .set(Account::getValidEndTime, toMillis(plan.getCurrentPeriodEnd())) + .eq(Account::getSubscriptionPlanId, plan.getId()) + .eq(Account::getSystemUser, EDUCATION_SUB.getCode()) + ); + } + + // ===================== 辅助方法 ===================== + + private long countExistingSubAccounts(Long planId) { + return accountMapper.selectCount( + new QueryWrapper().lambda() + .eq(Account::getSubscriptionPlanId, planId) + .eq(Account::getSystemUser, EDUCATION_SUB.getCode()) + ); + } + + private boolean isToday(Long timestampSeconds) { + return timestampSeconds >= getTodayStartTimestamp() + && timestampSeconds < getTodayEndTimestamp(); + } + + private long toMillis(Long seconds) { + return seconds * 1000; } @Override @@ -407,7 +561,7 @@ public class SubscriptionPlanServiceImpl extends ServiceImpl todayActivePlans = findTodayActivePlans(); + // 支持按id激活 + List todayActivePlans = new ArrayList<>(); + if (Objects.nonNull(planId)) { + SubscriptionPlan subscriptionPlan = baseMapper.selectById(planId); + if (Objects.nonNull(subscriptionPlan)){ + todayActivePlans.add(subscriptionPlan); + } + } else { + // 1. 扫描所有的订阅计划的开始时间currentPeriodStart,找出今天开始生效的计划 + todayActivePlans = findTodayActivePlans(); - if (CollectionUtils.isEmpty(todayActivePlans)) { - log.info("今日没有需要生效的订阅计划"); - return; + if (CollectionUtils.isEmpty(todayActivePlans)) { + log.info("今日没有需要生效的订阅计划"); + return; + } + + log.info("发现{}个今日生效的订阅计划", todayActivePlans.size()); } - log.info("发现{}个今日生效的订阅计划", todayActivePlans.size()); // 2. 处理每个今天开始生效的订阅计划 for (SubscriptionPlan plan : todayActivePlans) { diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 0218ebe1..7b1c0603 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -209,6 +209,10 @@ end.time.must.be.later.than.the.start.time=The subscription end time must be lat please.specify.the.organizationId=Please specify the organizationId. switch.failed.sub-account.not.under.your.active.subscription=Switch failed. Sub-account not under your active subscription. Sub-accounts.cannot.be.admins=Sub-accounts in a subscription cannot be designated as admins. +only.subscription.plans.with.a.PENDING.status.can.have.their.start.time.modified=Only subscription plans with a PENDING status can have their start time modified. +the.subscription.end.date.can.be.extended.only.not.reduced=The subscription end date can be extended only, not reduced. +total.sub-account.quota.cannot.be.lower.than.existing.sub-accounts=Total sub-account quota cannot be lower than existing sub-accounts. +the.credit.limit.set.cannot.be.lower.than.the.amount.of.credits.already.used=The credit limit set cannot be lower than the amount of credits already used. # 可能会报异常 # Informative: diff --git a/src/main/resources/messages_zh.properties b/src/main/resources/messages_zh.properties index 1922707b..66a2ba01 100644 --- a/src/main/resources/messages_zh.properties +++ b/src/main/resources/messages_zh.properties @@ -205,6 +205,10 @@ end.time.must.be.later.than.the.start.time=订阅结束时间必须晚于开始 please.specify.the.organizationId=请指定organizationId switch.failed.sub-account.not.under.your.active.subscription=切换失败,该子账号不属于您当前管理的订阅计划 Sub-accounts.cannot.be.admins=在订阅中的子账号不能被指定为管理员 +only.subscription.plans.with.a.PENDING.status.can.have.their.start.time.modified=只有PENDING状态的订阅计划可以修改订阅开始时间 +the.subscription.end.date.can.be.extended.only.not.reduced=订阅的到期时间不能缩短,只能延长 +total.sub-account.quota.cannot.be.lower.than.existing.sub-accounts=设置的子账号总数量不能低于现存已添加的子账号数量 +the.credit.limit.set.cannot.be.lower.than.the.amount.of.credits.already.used=设置的积分上限不能低于已使用的积分量 # 可能会报异常 # Informative: