|
|
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.dromara.backstage.api.domain.vo.*;
|
|
|
+import org.dromara.common.core.constant.ApiErrorTypeConstants;
|
|
|
import org.dromara.common.core.domain.R;
|
|
|
import org.dromara.common.core.domain.model.ErrorInfo;
|
|
|
import org.dromara.common.core.enums.TradeStatusEnum;
|
|
|
@@ -22,8 +23,10 @@ import java.math.RoundingMode;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
import java.util.function.Supplier;
|
|
|
|
|
|
@@ -41,6 +44,7 @@ import java.util.function.Supplier;
|
|
|
@RequiredArgsConstructor
|
|
|
public class CardConsumeValidation {
|
|
|
private static final BigDecimal PERCENT_DIVISOR = new BigDecimal("100.0");
|
|
|
+ private static final long VALIDATION_TIMEOUT = 300;
|
|
|
private static final Map<String, String> MEAL_TYPE_NAMES = ConsumeConstants.mealNameMap;
|
|
|
private final CommonCheck commonCheck;
|
|
|
private final ValidationParam validationParam;
|
|
|
@@ -50,12 +54,14 @@ public class CardConsumeValidation {
|
|
|
RemoteMealTypeVo mealTypeVo,
|
|
|
XfCardLimitedVo cardLimitedVo, Map<String, Boolean> mapCardLimited) {
|
|
|
|
|
|
- // public R<ErrorInfo> cardValidation(CardConsumeValidationContext validationContext) {
|
|
|
+ // public R<ErrorInfo> cardValidation(CardConsumeValidationContext validationContext) {
|
|
|
// 1.初始化验证上下文
|
|
|
CardConsumeValidationContext validationContext = CardConsumeValidationContext.create(bo, termVo, userCardVo, mealTypeVo.getTypeId());
|
|
|
+ CardConsumeValidationContext discountCtx = CardConsumeValidationContext.create(bo, termVo, userCardVo, mealTypeVo.getTypeId());
|
|
|
+ CardConsumeValidationContext limitedCtx = CardConsumeValidationContext.create(bo, termVo, userCardVo, mealTypeVo.getTypeId());
|
|
|
|
|
|
// 2. 执行异步验证链
|
|
|
- R<ErrorInfo> result = executeCardValidationChain(validationContext);
|
|
|
+ R<ErrorInfo> result = executeCardValidationChain(validationContext, discountCtx, limitedCtx);
|
|
|
// if (R.isSuccess(result)) {
|
|
|
// dealCardQuota(validationContext);
|
|
|
// }
|
|
|
@@ -69,33 +75,40 @@ public class CardConsumeValidation {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- private R<ErrorInfo> executeCardValidationChain(CardConsumeValidationContext ctx) {
|
|
|
+ private R<ErrorInfo> executeCardValidationChain(CardConsumeValidationContext ctx, CardConsumeValidationContext discountCtx,
|
|
|
+ CardConsumeValidationContext limitedCtx) {
|
|
|
// 创建验证任务列表
|
|
|
List<Supplier<R<ErrorInfo>>> validationTasks = new ArrayList<>();
|
|
|
- validationTasks.add(() -> dealCardDiscount(ctx));
|
|
|
- validationTasks.add(() -> dealCardLimited(ctx));
|
|
|
+
|
|
|
+ validationTasks.add(() -> dealCardDiscount(discountCtx));
|
|
|
+ validationTasks.add(() -> dealCardLimited(limitedCtx));
|
|
|
|
|
|
// 用于存储第一个错误结果
|
|
|
AtomicReference<R<ErrorInfo>> firstError = new AtomicReference<>(null);
|
|
|
-
|
|
|
// 使用CountDownLatch跟踪任务完成
|
|
|
CountDownLatch latch = new CountDownLatch(validationTasks.size());
|
|
|
+ AtomicBoolean cancelled = new AtomicBoolean(false);
|
|
|
|
|
|
// 提交所有验证任务
|
|
|
- for (Supplier<R<ErrorInfo>> task : validationTasks) {
|
|
|
+ for (int i = 0, j = validationTasks.size(); i < j; i++) {
|
|
|
+ final int taskIndex = i;
|
|
|
+ final Supplier<R<ErrorInfo>> task = validationTasks.get(taskIndex);
|
|
|
taskExecutor.execute(() -> {
|
|
|
+ if (cancelled.get()) {
|
|
|
+ latch.countDown();
|
|
|
+ return;
|
|
|
+ }
|
|
|
try {
|
|
|
R<ErrorInfo> result = task.get();
|
|
|
// 如果发现错误且尚未设置错误结果
|
|
|
- if (result != null && R.isError(result) &&
|
|
|
- firstError.compareAndSet(null, result)) {
|
|
|
- // 取消其他任务(通过中断)
|
|
|
- taskExecutor.getThreadPoolExecutor().getQueue().clear();
|
|
|
+ if (result != null && R.isError(result) && firstError.compareAndSet(null, result)) {
|
|
|
+ log.warn("{} 验证失败: {}", getTaskName(taskIndex), result);
|
|
|
+ triggerCancellation(cancelled, taskIndex);
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- log.error("卡片消费校验:", e);
|
|
|
+ log.error("任务 {} 执行异常", getTaskName(taskIndex), e);
|
|
|
if (firstError.compareAndSet(null, commonCheck.createError(TradeStatusEnum.SysError))) {
|
|
|
- taskExecutor.getThreadPoolExecutor().getQueue().clear();
|
|
|
+ triggerCancellation(cancelled, taskIndex);
|
|
|
}
|
|
|
} finally {
|
|
|
latch.countDown();
|
|
|
@@ -105,16 +118,23 @@ public class CardConsumeValidation {
|
|
|
|
|
|
try {
|
|
|
// 等待所有任务完成或超时
|
|
|
- if (!latch.await(300, TimeUnit.MILLISECONDS)) {
|
|
|
- return commonCheck.createError(TradeStatusEnum.VALIDATION_TIMEOUT);
|
|
|
+ if (!latch.await(VALIDATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
|
|
|
+ log.warn("任务超时 ({} ms)", VALIDATION_TIMEOUT);
|
|
|
+ triggerCancellation(cancelled, -1);
|
|
|
}
|
|
|
|
|
|
// 返回第一个发现的错误,如果没有错误则返回成功
|
|
|
- // return firstError.get() != null ? firstError.get() : R.ok();
|
|
|
- if(firstError.get() != null){
|
|
|
+ if (firstError.get() != null) {
|
|
|
return firstError.get();
|
|
|
} else {
|
|
|
- return dealCardQuota(ctx);
|
|
|
+ // 将限次与折扣验证数据合并到主上下文
|
|
|
+ mergeValidationResults(ctx, discountCtx, limitedCtx);
|
|
|
+ // 限额验证
|
|
|
+ R<ErrorInfo> result = dealCardQuota(ctx);
|
|
|
+ if (R.isError(result)) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ return R.ok();
|
|
|
}
|
|
|
} catch (InterruptedException e) {
|
|
|
Thread.currentThread().interrupt();
|
|
|
@@ -123,8 +143,71 @@ public class CardConsumeValidation {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private String getTaskName(int taskIndex) {
|
|
|
+ return switch (taskIndex) {
|
|
|
+ case 0 -> "卡类折扣验证";
|
|
|
+ case 1 -> "卡类限次验证";
|
|
|
+ case 2 -> "卡类限额验证";
|
|
|
+ default -> "未知任务";
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private void triggerCancellation(AtomicBoolean cancelled, int triggerTask) {
|
|
|
+ // 确保只触发一次取消操作
|
|
|
+ if (cancelled.compareAndSet(false, true)) {
|
|
|
+ // 记录触发取消的任务信息
|
|
|
+ String taskName = getTaskName(triggerTask);
|
|
|
+ if (triggerTask >= 0) {
|
|
|
+ log.warn("任务 [{}] 触发取消操作: {}", triggerTask, taskName);
|
|
|
+ } else {
|
|
|
+ log.warn("超时触发取消操作");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清空任务队列(取消未开始的任务)
|
|
|
+ int cancelledCount = taskExecutor.getThreadPoolExecutor().getQueue().size();
|
|
|
+ taskExecutor.getThreadPoolExecutor().getQueue().clear();
|
|
|
+ log.info("已取消 {} 个待执行任务", cancelledCount);
|
|
|
+
|
|
|
+ // 中断正在运行的任务
|
|
|
+ // 获取所有活动线程
|
|
|
+ Set<Thread> activeThreads = Thread.getAllStackTraces().keySet();
|
|
|
+ String threadPoolPrefix = taskExecutor.getThreadNamePrefix();
|
|
|
+
|
|
|
+ int interruptedCount = 0;
|
|
|
+
|
|
|
+ for (Thread thread : activeThreads) {
|
|
|
+ // 只中断本线程池创建的线程
|
|
|
+ if (thread.getName().startsWith(threadPoolPrefix)) {
|
|
|
+ if (!thread.isInterrupted()) {
|
|
|
+ thread.interrupt();
|
|
|
+ interruptedCount++;
|
|
|
+ log.debug("已发送中断信号给线程: {}", thread.getName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("已向 {} 个运行中的任务发送中断信号", interruptedCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void mergeValidationResults(CardConsumeValidationContext mainCtx,
|
|
|
+ CardConsumeValidationContext discountCtx,
|
|
|
+ CardConsumeValidationContext limitedCtx) {
|
|
|
+ // 合并折扣计算结果
|
|
|
+ mainCtx.setHasDiscount(discountCtx.getHasDiscount());
|
|
|
+ mainCtx.setDiscountMoney(discountCtx.getDiscountMoney());
|
|
|
+ // 合并限次计算结果
|
|
|
+ mainCtx.setHasLimited(limitedCtx.getHasLimited());
|
|
|
+ }
|
|
|
+
|
|
|
// region 卡片折扣处理
|
|
|
private R<ErrorInfo> dealCardDiscount(CardConsumeValidationContext ctx) {
|
|
|
+ if (Thread.currentThread().isInterrupted()) {
|
|
|
+ log.debug("折扣计算任务被取消,提前退出");
|
|
|
+ return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
|
|
|
+ "折扣计算任务被取消,提前退出", "折扣计算任务被取消,提前退出");
|
|
|
+ }
|
|
|
if (!validationParam.getRATE_CONSUME()) {
|
|
|
log.debug("全局折扣功能未启用,跳过折扣验证");
|
|
|
return R.ok();
|
|
|
@@ -145,21 +228,26 @@ public class CardConsumeValidation {
|
|
|
String cardType = String.valueOf(ctx.getCardType());
|
|
|
Long mealType = Long.valueOf(ctx.getLastMeal());
|
|
|
RemoteDiscountVo discountVo = discountVos.stream()
|
|
|
- .filter(p -> cardType.equals(p.getCardType())
|
|
|
- && mealType.equals(p.getMealType())
|
|
|
- && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
|
|
|
- ;
|
|
|
-
|
|
|
- XfCardLimitedVo cardLimitedVo = ctx.getCardLimitedVo();
|
|
|
- if (discountVo != null) {
|
|
|
- ctx.setHasDiscount(Boolean.TRUE);
|
|
|
- ctx.discountMoney = getDisCountMoney(cardLimitedVo, ctx.getConsumeMoney(), discountVo);
|
|
|
+ .filter(p -> cardType.equals(p.getCardType())
|
|
|
+ && mealType.equals(p.getMealType())
|
|
|
+ && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
|
|
|
+ try {
|
|
|
+ XfCardLimitedVo cardLimitedVo = ctx.getCardLimitedVo();
|
|
|
+ if (discountVo != null) {
|
|
|
+ ctx.setHasDiscount(Boolean.TRUE);
|
|
|
+ ctx.discountMoney = getDisCountMoney(cardLimitedVo, ctx.getConsumeMoney(), discountVo);
|
|
|
+ return R.ok();
|
|
|
+ } else {
|
|
|
+ log.debug("卡片[{}]未配置折扣,跳过折扣验证", ctx.getCardNo());
|
|
|
+ }
|
|
|
+
|
|
|
return R.ok();
|
|
|
- } else {
|
|
|
- log.debug("卡片[{}]未配置折扣,跳过折扣验证", ctx.getCardNo());
|
|
|
+ } catch (Exception e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ log.debug("折扣计算任务异常", e);
|
|
|
+ return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
|
|
|
+ "折扣计算任务异常", e.getMessage());
|
|
|
}
|
|
|
-
|
|
|
- return R.ok();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -191,13 +279,18 @@ public class CardConsumeValidation {
|
|
|
// 4. 计算折扣金额(统一处理精度)
|
|
|
BigDecimal discountFactor = selectedRate.divide(PERCENT_DIVISOR, 2, RoundingMode.HALF_UP);
|
|
|
return consumeValue
|
|
|
- .multiply(discountFactor)
|
|
|
- .setScale(2, RoundingMode.HALF_UP);
|
|
|
+ .multiply(discountFactor)
|
|
|
+ .setScale(2, RoundingMode.HALF_UP);
|
|
|
}
|
|
|
// endregion
|
|
|
|
|
|
//region 卡片限次处理
|
|
|
private R<ErrorInfo> dealCardLimited(CardConsumeValidationContext ctx) {
|
|
|
+ if (Thread.currentThread().isInterrupted()) {
|
|
|
+ log.debug("卡片限次验证任务被取消,提前退出");
|
|
|
+ return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
|
|
|
+ "卡片限次验证任务被取消,提前退出", "卡片限次验证任务被取消,提前退出");
|
|
|
+ }
|
|
|
if (!validationParam.getXC_CONSUME()) {
|
|
|
log.debug("全局限次功能未启用,跳过限次验证");
|
|
|
return R.ok();
|
|
|
@@ -216,33 +309,40 @@ public class CardConsumeValidation {
|
|
|
}
|
|
|
Long cardType = ctx.getCardType();
|
|
|
RemoteLimitedVo limitedVo = limitedCards.stream()
|
|
|
- .filter(p -> cardType.equals(p.getCardType())
|
|
|
- && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
|
|
|
+ .filter(p -> cardType.equals(p.getCardType())
|
|
|
+ && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
|
|
|
if (limitedVo == null) {
|
|
|
return R.ok();
|
|
|
}
|
|
|
|
|
|
ctx.setHasLimited(Boolean.TRUE);
|
|
|
- // 日限次校验
|
|
|
- R<ErrorInfo> dailyCheck = checkDailyLimit(limitedVo, ctx.getCardLimitedVo().getDayCount());
|
|
|
- if (dailyCheck != null) {
|
|
|
- return dailyCheck;
|
|
|
- }
|
|
|
+ try {
|
|
|
+ // 日限次校验
|
|
|
+ R<ErrorInfo> dailyCheck = checkDailyLimit(limitedVo, ctx.getCardLimitedVo().getDayCount());
|
|
|
+ if (dailyCheck != null) {
|
|
|
+ return dailyCheck;
|
|
|
+ }
|
|
|
|
|
|
- // 餐类限次检查
|
|
|
- return checkMealLimit(limitedVo, ctx.getLastMeal(), ctx.getCardLimitedVo().getMealCount());
|
|
|
+ // 餐类限次检查
|
|
|
+ return checkMealLimit(limitedVo, ctx.getLastMeal(), ctx.getCardLimitedVo().getMealCount());
|
|
|
+ } catch (Exception e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ log.debug("卡片限次验证任务异常", e);
|
|
|
+ return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
|
|
|
+ "卡片限次验证任务异常", e.getMessage());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查每日消费次数限制。
|
|
|
*
|
|
|
- * @param limitedVo 卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费次数或金额)。
|
|
|
- * 通过此对象可以获取卡片的每日消费限制规则。
|
|
|
+ * @param limitedVo 卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费次数或金额)。
|
|
|
+ * 通过此对象可以获取卡片的每日消费限制规则。
|
|
|
* @param currentDayCount 当前日期内的消费次数或金额,表示在当天已经发生的消费总量。
|
|
|
* 这个参数用于与限制规则进行比较,以判断是否超出限制。
|
|
|
* @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
|
|
|
- * 如果未超出限制,返回成功结果;
|
|
|
- * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
+ * 如果未超出限制,返回成功结果;
|
|
|
+ * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
*/
|
|
|
private R<ErrorInfo> checkDailyLimit(RemoteLimitedVo limitedVo, Long currentDayCount) {
|
|
|
Long dayLimit = limitedVo.getDailyCount();
|
|
|
@@ -255,15 +355,15 @@ public class CardConsumeValidation {
|
|
|
/**
|
|
|
* 检查每餐消费次数限制。
|
|
|
*
|
|
|
- * @param limitedVo 卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费次数或金额)。
|
|
|
- * 通过此对象可以获取卡片的餐次消费限制规则。
|
|
|
- * @param mealType 餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
|
|
|
- * 这个参数决定了要针对哪一类餐次进行消费限制的检查。
|
|
|
+ * @param limitedVo 卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费次数或金额)。
|
|
|
+ * 通过此对象可以获取卡片的餐次消费限制规则。
|
|
|
+ * @param mealType 餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
|
|
|
+ * 这个参数决定了要针对哪一类餐次进行消费限制的检查。
|
|
|
* @param currentMealCount 当前餐次内的消费次数或金额,表示在当前餐次已经发生的消费总量。
|
|
|
* 这个参数用于与限制规则进行比较,以判断是否超出限制。
|
|
|
* @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
|
|
|
- * 如果未超出限制,返回成功结果;
|
|
|
- * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
+ * 如果未超出限制,返回成功结果;
|
|
|
+ * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
*/
|
|
|
private R<ErrorInfo> checkMealLimit(RemoteLimitedVo limitedVo, String mealType, Long currentMealCount) {
|
|
|
Map<String, Long> mealLimits = Map.of(
|
|
|
@@ -280,7 +380,7 @@ public class CardConsumeValidation {
|
|
|
|
|
|
if (currentMealCount >= mealLimit) {
|
|
|
String mealName = MEAL_TYPE_NAMES.getOrDefault(mealType, "未知餐次");
|
|
|
- return commonCheck.createError(TradeStatusEnum.MealLimitTimes,String.format("卡类%s次数限制", mealName));
|
|
|
+ return commonCheck.createError(TradeStatusEnum.MealLimitTimes, String.format("卡类%s次数限制", mealName));
|
|
|
}
|
|
|
return R.ok();
|
|
|
}
|
|
|
@@ -306,37 +406,37 @@ public class CardConsumeValidation {
|
|
|
}
|
|
|
Long cardType = ctx.getCardType();
|
|
|
RemoteQuotaVo quotaVo = quotaCards.stream()
|
|
|
- .filter(p -> cardType.equals(p.getCardType())
|
|
|
- && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
|
|
|
+ .filter(p -> cardType.equals(p.getCardType())
|
|
|
+ && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
|
|
|
if (quotaVo == null) {
|
|
|
return R.ok();
|
|
|
}
|
|
|
|
|
|
ctx.setHasQuota(Boolean.TRUE);
|
|
|
// 日限额校验
|
|
|
- R<ErrorInfo> dailyCheck = checkDailyQuota(quotaVo, ctx.getCardLimitedVo().getDayMoney(),ctx.getConsumeMoney());
|
|
|
+ R<ErrorInfo> dailyCheck = checkDailyQuota(quotaVo, ctx.getCardLimitedVo().getDayMoney(), ctx.getDiscountMoney());
|
|
|
if (dailyCheck != null) {
|
|
|
return dailyCheck;
|
|
|
}
|
|
|
|
|
|
// 餐类限额检查
|
|
|
- return checkMealQuota(quotaVo, ctx.getLastMeal(),ctx.getCardLimitedVo().getMealMoney(),ctx.getConsumeMoney());
|
|
|
+ return checkMealQuota(quotaVo, ctx.getLastMeal(), ctx.getCardLimitedVo().getMealMoney(), ctx.getDiscountMoney());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查每日消费额度限制。
|
|
|
* 如果设置的日限额>0 并且当天已消费金额+当餐消费的金额比设置的大,则超额不能消费
|
|
|
- * @param quotaVo 卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费额度或金额)。
|
|
|
- * 通过此对象可以获取卡片的每日消费限制规则。
|
|
|
- * @param dayMoney 当前日期内的消费额度或金额,表示在当天已经发生的消费总量。
|
|
|
- * 这个参数用于与限制规则进行比较,以判断是否超出限制。
|
|
|
- * @param consumeMoney 消费金额
|
|
|
*
|
|
|
+ * @param quotaVo 卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费额度或金额)。
|
|
|
+ * 通过此对象可以获取卡片的每日消费限制规则。
|
|
|
+ * @param dayMoney 当前日期内的消费额度或金额,表示在当天已经发生的消费总量。
|
|
|
+ * 这个参数用于与限制规则进行比较,以判断是否超出限制。
|
|
|
+ * @param consumeMoney 消费金额
|
|
|
* @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
|
|
|
- * 如果未超出限制,返回成功结果;
|
|
|
- * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
+ * 如果未超出限制,返回成功结果;
|
|
|
+ * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
*/
|
|
|
- private R<ErrorInfo> checkDailyQuota(RemoteQuotaVo quotaVo, BigDecimal dayMoney,BigDecimal consumeMoney) {
|
|
|
+ private R<ErrorInfo> checkDailyQuota(RemoteQuotaVo quotaVo, BigDecimal dayMoney, BigDecimal consumeMoney) {
|
|
|
BigDecimal dayQuotaMoney = quotaVo.getDailyMoney();
|
|
|
if (dayQuotaMoney.compareTo(BigDecimal.ZERO) > 0 && dayQuotaMoney.compareTo(dayMoney.add(consumeMoney)) < 0) {
|
|
|
return commonCheck.createError(TradeStatusEnum.DayLimitMoney, "卡类日限制额度");
|
|
|
@@ -347,17 +447,17 @@ public class CardConsumeValidation {
|
|
|
/**
|
|
|
* 检查每餐消费额度限制。
|
|
|
*
|
|
|
- * @param quotaVo 卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费额度或金额)。
|
|
|
- * 通过此对象可以获取卡片的餐次消费限制规则。
|
|
|
- * @param mealType 餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
|
|
|
- * 这个参数决定了要针对哪一类餐次进行消费限制的检查。
|
|
|
- * @param mealMoney 当 当前餐次内的消费额度或金额,表示在当前餐次已经发生的消费总量。
|
|
|
+ * @param quotaVo 卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费额度或金额)。
|
|
|
+ * 通过此对象可以获取卡片的餐次消费限制规则。
|
|
|
+ * @param mealType 餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
|
|
|
+ * 这个参数决定了要针对哪一类餐次进行消费限制的检查。
|
|
|
+ * @param mealMoney 当 当前餐次内的消费额度或金额,表示在当前餐次已经发生的消费总量。
|
|
|
* @param consumeMoney 当 当前餐次的消费金额。表示在当前餐次中再次消费的金额
|
|
|
* @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
|
|
|
- * 如果未超出限制,返回成功结果;
|
|
|
- * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
+ * 如果未超出限制,返回成功结果;
|
|
|
+ * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
|
|
|
*/
|
|
|
- private R<ErrorInfo> checkMealQuota(RemoteQuotaVo quotaVo, String mealType, BigDecimal mealMoney,BigDecimal consumeMoney) {
|
|
|
+ private R<ErrorInfo> checkMealQuota(RemoteQuotaVo quotaVo, String mealType, BigDecimal mealMoney, BigDecimal consumeMoney) {
|
|
|
Map<String, BigDecimal> mealQuotas = Map.of(
|
|
|
"1", quotaVo.getOneMoney(),
|
|
|
"2", quotaVo.getTwoMoney(),
|
|
|
@@ -370,7 +470,7 @@ public class CardConsumeValidation {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- if (mealQuota.compareTo(BigDecimal.ZERO)>0) {
|
|
|
+ if (mealQuota.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
if (mealQuota.compareTo(mealMoney.add(consumeMoney)) < 0) {
|
|
|
String mealName = MEAL_TYPE_NAMES.getOrDefault(mealType, "未知餐次");
|
|
|
return commonCheck.createError(TradeStatusEnum.MealLimitMoney, String.format("卡类%s额度限制", mealName));
|