diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java index 6f559ab4..6b5dcf29 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java @@ -11,7 +11,6 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; -import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -492,7 +491,7 @@ public class DateTimeUtils { return -1; } } - + /** * 判断指定时间是否在两个时间点之间(包含边界) * @@ -602,6 +601,27 @@ public class DateTimeUtils { } } + public static boolean isActivityTimeValid(Date starTime, Date endTime, Date checkTime) { + log.debug("检查活动时间有效性 - 开始时间: {}, 结束时间: {}, 检查时间: {}", starTime, endTime, checkTime); + + if (starTime == null || endTime == null) { + log.error("活动时间验证失败 - 开始时间或结束时间为null. 开始时间: {}, 结束时间: {}", starTime, endTime); + return false; + } + + if (checkTime == null) { + checkTime = new Date(); + log.warn("检查时间为空,使用当前时间: {}", checkTime); + } + + boolean isValid = !checkTime.before(starTime) && !checkTime.after(endTime); + log.debug("活动时间验证结果: {} (检查时间>=开始时间, 检查时间<=结束时间)", + isValid); + + return isValid; + } + + public static void main(String[] args) { // System.out.println(convertLklDate("2021-02-19")); // 2025-01-02 // System.out.println(convertLklDate("2021-2-3")); // 2025-01-02 @@ -632,29 +652,29 @@ public class DateTimeUtils { // System.out.println("当前时间是否在工作时间内:" + isWorkTime); // System.out.println("多个时间段的交集结果:" + isNight); - - System.out.println("=== 测试 findTimeIntersection ==="); - - // 测试正常交集情况 - List> timeList1 = new ArrayList<>(); - timeList1.add(Pair.of("06:00", "17:00")); - timeList1.add(Pair.of("10:00", "18:00")); - - Pair intersection1 = findTimeInterSection(timeList1); - System.out.println("交集结果1: " + intersection1); // 应该是 10:00 - 17:00 - -// 测试无交集情况 - List> timeList2 = new ArrayList<>(); - timeList2.add(Pair.of("09:00", "12:00")); - timeList2.add(Pair.of("13:00", "17:00")); - - Pair intersection2 = findTimeInterSection(timeList2); - System.out.println("交集结果2: " + intersection2); // 应该是null - -// 测试空列表 - Pair intersection3 = findTimeInterSection(null); - System.out.println("交集结果3 (null输入): " + intersection3); // 应该是null - +// +// System.out.println("=== 测试 findTimeIntersection ==="); +// +// // 测试正常交集情况 +// List> timeList1 = new ArrayList<>(); +// timeList1.add(Pair.of("06:00", "17:00")); +// timeList1.add(Pair.of("10:00", "18:00")); +// +// Pair intersection1 = findTimeInterSection(timeList1); +// System.out.println("交集结果1: " + intersection1); // 应该是 10:00 - 17:00 +// +//// 测试无交集情况 +// List> timeList2 = new ArrayList<>(); +// timeList2.add(Pair.of("09:00", "12:00")); +// timeList2.add(Pair.of("13:00", "17:00")); +// +// Pair intersection2 = findTimeInterSection(timeList2); +// System.out.println("交集结果2: " + intersection2); // 应该是null +// +//// 测试空列表 +// Pair intersection3 = findTimeInterSection(null); +// System.out.println("交集结果3 (null输入): " + intersection3); // 应该是null +// } } \ No newline at end of file diff --git a/mall-common/src/test/com/suisung/mall/common/phone/DistributedLockHelperTest.java b/mall-common/src/test/com/suisung/mall/common/phone/DistributedLockHelperTest.java new file mode 100644 index 00000000..9fc90167 --- /dev/null +++ b/mall-common/src/test/com/suisung/mall/common/phone/DistributedLockHelperTest.java @@ -0,0 +1,349 @@ +package com.suisung.mall.common.utils; + +import com.suisung.mall.core.web.service.RedisService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * DistributedLockHelper综合测试套件 + */ +public class DistributedLockHelperTest { + + private DistributedLockHelper lockHelper; + + @Mock + private RedisService redisService; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + lockHelper = new DistributedLockHelper(); + ReflectionTestUtils.setField(lockHelper, "redisService", redisService); + System.out.println("=== 初始化测试环境 ==="); + } + + @Test + public void testTryLock_Success() { + System.out.println("开始执行: testTryLock_Success"); + + // 给定条件 + String lockKey = "test_lock"; + long expireTimeSec = 30L; + String expectedKey = "distributed_lock:" + lockKey; + System.out.println("测试参数 - 锁键: " + lockKey + ", 过期时间: " + expireTimeSec + "秒"); + + // 当调用时 + when(redisService.set(anyString(), anyString(), anyLong())).thenReturn(true); + boolean result = lockHelper.tryLock(lockKey, expireTimeSec); + System.out.println("获取锁结果: " + (result ? "成功" : "失败")); + + // 那么验证 + assertTrue(result, "锁应该成功获取"); + verify(redisService).set(eq(expectedKey), anyString(), eq(expireTimeSec)); + System.out.println("验证通过: Redis set 方法被正确调用"); + System.out.println("测试完成: testTryLock_Success\n"); + } + + @Test + public void testTryLock_Failure() { + System.out.println("开始执行: testTryLock_Failure"); + + // 给定条件 + String lockKey = "test_lock"; + long expireTimeSec = 30L; + System.out.println("测试参数 - 锁键: " + lockKey + ", 过期时间: " + expireTimeSec + "秒"); + + // 当调用时 + when(redisService.set(anyString(), anyString(), anyLong())).thenThrow(new RuntimeException("Redis错误")); + System.out.println("模拟Redis异常: Redis错误"); + + // 那么验证 + assertThrows(RuntimeException.class, () -> { + lockHelper.tryLock(lockKey, expireTimeSec); + }, "应该抛出RuntimeException"); + System.out.println("验证通过: 正确捕获了RuntimeException"); + System.out.println("测试完成: testTryLock_Failure\n"); + } + + @Test + public void testReleaseLock_Success() { + System.out.println("开始执行: testReleaseLock_Success"); + + // 给定条件 + String lockKey = "test_lock"; + String expectedKey = "distributed_lock:" + lockKey; + String lockValue = "uuid:1"; + System.out.println("测试参数 - 锁键: " + lockKey + ", 锁值: " + lockValue); + + // 设置线程本地变量 + ReflectionTestUtils.setField(lockHelper, "LOCK_VALUE_HOLDER", + new ThreadLocal() { + @Override + protected String initialValue() { + return lockValue; + } + }); + + when(redisService.get(expectedKey)).thenReturn(lockValue); + System.out.println("模拟Redis get返回值: " + lockValue); + + // 当调用时 + lockHelper.releaseLock(lockKey); + System.out.println("执行锁释放操作"); + + // 那么验证 + verify(redisService).del(expectedKey); + System.out.println("验证通过: Redis del 方法被正确调用"); + System.out.println("测试完成: testReleaseLock_Success\n"); + } + + @Test + public void testReleaseLock_WrongOwner() { + System.out.println("开始执行: testReleaseLock_WrongOwner"); + + // 给定条件 + String lockKey = "test_lock"; + String expectedKey = "distributed_lock:" + lockKey; + String currentValue = "uuid:1"; + String threadValue = "uuid:2"; // 不同的值 + System.out.println("测试参数 - 当前锁值: " + currentValue + ", 线程锁值: " + threadValue); + + // 设置线程本地变量 + ReflectionTestUtils.setField(lockHelper, "LOCK_VALUE_HOLDER", + new ThreadLocal() { + @Override + protected String initialValue() { + return threadValue; + } + }); + + when(redisService.get(expectedKey)).thenReturn(currentValue); + System.out.println("模拟Redis中当前锁值: " + currentValue); + + // 当调用时 + lockHelper.releaseLock(lockKey); + System.out.println("执行锁释放操作"); + + // 那么验证 + verify(redisService, never()).del(anyString()); + System.out.println("验证通过: Redis del 方法未被调用(防止误删)"); + System.out.println("测试完成: testReleaseLock_WrongOwner\n"); + } + + @Test + public void testConcurrentAccess_SingleLockAcquirer() throws InterruptedException { + System.out.println("开始执行: testConcurrentAccess_SingleLockAcquirer"); + + // 给定条件 + String lockKey = "concurrent_test_lock"; + int threadCount = 10; + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + CountDownLatch latch = new CountDownLatch(threadCount); + AtomicInteger successCounter = new AtomicInteger(0); + System.out.println("测试参数 - 并发线程数: " + threadCount + ", 锁键: " + lockKey); + + // 模拟Redis并发访问行为 + when(redisService.set(anyString(), anyString(), anyLong())) + .thenAnswer(invocation -> { + // 只有第一次调用成功,其余都失败 + boolean result = successCounter.get() == 0; + if (result) { + System.out.println("线程[" + Thread.currentThread().getName() + "] 成功获取锁"); + } + return result; + }); + System.out.println("模拟Redis行为: 只允许一个线程获取锁"); + + // 当执行时 + for (int i = 0; i < threadCount; i++) { + final int threadId = i; + executor.submit(() -> { + try { + System.out.println("启动线程[" + threadId + "]"); + if (lockHelper.tryLock(lockKey, 30)) { + int count = successCounter.incrementAndGet(); + System.out.println("线程[" + threadId + "] 获取锁成功,当前成功计数: " + count); + lockHelper.releaseLock(lockKey); + System.out.println("线程[" + threadId + "] 释放锁"); + } else { + System.out.println("线程[" + threadId + "] 获取锁失败"); + } + } finally { + latch.countDown(); + System.out.println("线程[" + threadId + "] 执行完毕,剩余线程数: " + (latch.getCount())); + } + }); + } + + boolean completed = latch.await(5, TimeUnit.SECONDS); + executor.shutdown(); + System.out.println("所有线程执行完成: " + (completed ? "正常结束" : "超时结束")); + + // 那么验证 + int successCount = successCounter.get(); + assertEquals(1, successCount, "应该只有一个线程获得锁"); + System.out.println("验证通过: 实际成功获取锁的线程数为 " + successCount); + System.out.println("测试完成: testConcurrentAccess_SingleLockAcquirer\n"); + } + + @Test + public void testAutoRenewalFunctionality() throws InterruptedException { + System.out.println("开始执行: testAutoRenewalFunctionality"); + + // 给定条件 + String lockKey = "auto_renew_test_lock"; + long expireTimeSec = 5L; + long maxHoldTimeSec = 10L; + System.out.println("测试参数 - 锁键: " + lockKey + ", 过期时间: " + expireTimeSec + "秒, 最大持有时间: " + maxHoldTimeSec + "秒"); + + when(redisService.set(anyString(), anyString(), anyLong())).thenReturn(true); + when(redisService.get(anyString())).thenReturn("mock-value"); + System.out.println("模拟Redis set/get操作成功"); + + // 当调用时 + DistributedLockHelper.LockHolder lockHolder = + lockHelper.tryLockWithAutoRenew(lockKey, expireTimeSec, maxHoldTimeSec); + System.out.println("获取带自动续期功能的锁"); + + assertNotNull(lockHolder, "锁持有者不应为空"); + System.out.println("锁持有者创建成功"); + + // 等待可能的续期操作 + System.out.println("等待3秒观察自动续期行为..."); + Thread.sleep(3000); + + // 那么验证 + verify(redisService, atLeastOnce()).expire(anyString(), anyLong()); + System.out.println("验证通过: Redis expire 方法至少被调用一次"); + + // 清理 + lockHolder.close(); + System.out.println("关闭锁持有者,清理资源"); + System.out.println("测试完成: testAutoRenewalFunctionality\n"); + } + + @Test + public void testLockHolderAutoClose() { + System.out.println("开始执行: testLockHolderAutoClose"); + + // 给定条件 + String lockKey = "auto_close_test_lock"; + System.out.println("测试参数 - 锁键: " + lockKey); + + when(redisService.set(anyString(), anyString(), anyLong())).thenReturn(true); + when(redisService.get(anyString())).thenReturn("mock-value"); + System.out.println("模拟Redis操作成功"); + + // 当调用时 + System.out.println("使用try-with-resources语法获取锁"); + try (DistributedLockHelper.LockHolder holder = + lockHelper.tryLockWithAutoRenew(lockKey, 30, 300)) { + assertNotNull(holder, "锁持有者不应为空"); + System.out.println("锁持有者创建成功"); + } + System.out.println("try-with-resources块结束,自动调用close方法"); + + // 那么验证 + verify(redisService).del(anyString()); + System.out.println("验证通过: Redis del 方法被正确调用"); + System.out.println("测试完成: testLockHolderAutoClose\n"); + } + + @Test + public void testMultipleLocksIndependence() { + System.out.println("开始执行: testMultipleLocksIndependence"); + + // 给定条件 + String lockKey1 = "lock_1"; + String lockKey2 = "lock_2"; + System.out.println("测试参数 - 锁键1: " + lockKey1 + ", 锁键2: " + lockKey2); + + when(redisService.set(anyString(), anyString(), anyLong())).thenReturn(true); + System.out.println("模拟Redis set操作成功"); + + // 当调用时 + boolean lock1Acquired = lockHelper.tryLock(lockKey1, 30); + System.out.println("获取第一个锁: " + (lock1Acquired ? "成功" : "失败")); + + boolean lock2Acquired = lockHelper.tryLock(lockKey2, 30); + System.out.println("获取第二个锁: " + (lock2Acquired ? "成功" : "失败")); + + // 那么验证 + assertTrue(lock1Acquired, "第一个锁应该成功获取"); + assertTrue(lock2Acquired, "第二个锁应该成功获取"); + System.out.println("两个锁都成功获取"); + + // 验证它们是不同的键 + verify(redisService).set(eq("distributed_lock:" + lockKey1), anyString(), eq(30L)); + verify(redisService).set(eq("distributed_lock:" + lockKey2), anyString(), eq(30L)); + System.out.println("验证通过: 两个独立的锁键都被正确设置"); + System.out.println("测试完成: testMultipleLocksIndependence\n"); + } + + @Test + public void testThreadIsolation() throws InterruptedException { + System.out.println("开始执行: testThreadIsolation"); + + // 给定条件 + String lockKey = "thread_isolation_lock"; + ExecutorService executor = Executors.newFixedThreadPool(2); + CountDownLatch latch = new CountDownLatch(2); + AtomicInteger[] results = new AtomicInteger[]{new AtomicInteger(0), new AtomicInteger(0)}; + System.out.println("测试参数 - 锁键: " + lockKey + ", 线程数: 2"); + + when(redisService.set(anyString(), anyString(), anyLong())).thenReturn(true); + System.out.println("模拟Redis set操作成功"); + + // 当执行时 + System.out.println("启动两个线程竞争同一个锁"); + for (int i = 0; i < 2; i++) { + final int threadIndex = i; + executor.submit(() -> { + try { + System.out.println("线程[" + threadIndex + "] 尝试获取锁"); + if (lockHelper.tryLock(lockKey, 30)) { + int count = results[threadIndex].incrementAndGet(); + System.out.println("线程[" + threadIndex + "] 获取锁成功,计数: " + count); + // 持有锁一段时间 + Thread.sleep(100); + System.out.println("线程[" + threadIndex + "] 持有锁100ms后释放"); + lockHelper.releaseLock(lockKey); + System.out.println("线程[" + threadIndex + "] 释放锁"); + } else { + System.out.println("线程[" + threadIndex + "] 获取锁失败"); + } + } catch (InterruptedException e) { + System.out.println("线程[" + threadIndex + "] 被中断"); + Thread.currentThread().interrupt(); + } finally { + latch.countDown(); + System.out.println("线程[" + threadIndex + "] 执行完毕"); + } + }); + } + + boolean completed = latch.await(5, TimeUnit.SECONDS); + executor.shutdown(); + System.out.println("所有线程执行完成: " + (completed ? "正常结束" : "超时结束")); + + // 那么验证 - 两个线程都应该能够在不同时间获得锁 + int result0 = results[0].get(); + int result1 = results[1].get(); + assertEquals(1, result0, "线程0应该获得一次锁"); + assertEquals(1, result1, "线程1应该获得一次锁"); + System.out.println("验证通过: 线程0获得锁次数=" + result0 + ", 线程1获得锁次数=" + result1); + System.out.println("测试完成: testThreadIsolation\n"); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/ShopActivityCutpriceService.java b/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/ShopActivityCutpriceService.java index 30a64a88..8c958650 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/ShopActivityCutpriceService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/ShopActivityCutpriceService.java @@ -33,11 +33,11 @@ public interface ShopActivityCutpriceService extends IBaseService canDoOrderCutPriceActivity(Integer ac_id, Integer order_user_id); + Pair canDoOrderCutPriceActivity(Integer activity_id, Integer order_user_id); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityCutpriceServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityCutpriceServiceImpl.java index ebf700c7..ce6a23a2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityCutpriceServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityCutpriceServiceImpl.java @@ -25,6 +25,7 @@ import com.suisung.mall.common.modules.activity.ShopActivityGroupbooking; import com.suisung.mall.common.modules.activity.ShopActivityGroupbookingHistory; import com.suisung.mall.common.modules.store.ShopStoreActivityBase; import com.suisung.mall.common.utils.CheckUtil; +import com.suisung.mall.common.utils.DateTimeUtils; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; @@ -314,7 +315,7 @@ public class ShopActivityCutpriceServiceImpl extends BaseServiceImpl activityBaseList; QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("activity_state", StateCode.ACTIVITY_STATE_WAITING); - queryWrapper.le("activity_starttime", new Date()); + queryWrapper.in("activity_state", StateCode.ACTIVITY_STATE_WAITING, StateCode.ACTIVITY_STATE_NORMAL); +// queryWrapper.le("activity_starttime", new Date()); while (CollUtil.isNotEmpty(activityBaseList = shopStoreActivityBaseService.lists(queryWrapper, page, 20).getRecords())) { for (ShopStoreActivityBase storeActivityBase : activityBaseList) { + if (storeActivityBase.getActivity_state() != null + && storeActivityBase.getActivity_state().intValue() == StateCode.ACTIVITY_STATE_WAITING + && DateTimeUtils.isActivityTimeValid(storeActivityBase.getActivity_starttime(), storeActivityBase.getActivity_endtime(), new Date())) { + Boolean result = transactionTemplate.execute(status -> { + storeActivityBase.setActivity_state(StateCode.ACTIVITY_STATE_NORMAL); + Map activityBaseMap = Convert.toMap(String.class, Object.class, storeActivityBase); - Boolean result = transactionTemplate.execute(status -> { - storeActivityBase.setActivity_state(StateCode.ACTIVITY_STATE_NORMAL); - Map activityBaseMap = Convert.toMap(String.class, Object.class, storeActivityBase); + if (!shopStoreActivityBaseService.editActivityBase(storeActivityBase.getActivity_id(), activityBaseMap)) { + status.isRollbackOnly(); + return false; + } - if (!shopStoreActivityBaseService.editActivityBase(storeActivityBase.getActivity_id(), activityBaseMap)) { - status.isRollbackOnly(); - return false; + return true; + }); + + if (Boolean.FALSE.equals(result)) { + logger.error(String.format("activity_id : %s 开启出错", storeActivityBase.getActivity_id())); } - - return true; - }); - - if (Boolean.FALSE.equals(result)) { - logger.error(String.format("activity_id : %s 开启出错", storeActivityBase.getActivity_id())); } + + if (storeActivityBase.getActivity_state() != null + && storeActivityBase.getActivity_state().intValue() == StateCode.ACTIVITY_STATE_NORMAL + && !DateTimeUtils.isActivityTimeValid(storeActivityBase.getActivity_starttime(), storeActivityBase.getActivity_endtime(), new Date())) { + + Boolean result = transactionTemplate.execute(status -> { + storeActivityBase.setActivity_state(StateCode.ACTIVITY_STATE_FINISHED); + Map activityBaseMap = Convert.toMap(String.class, Object.class, storeActivityBase); + + if (!shopStoreActivityBaseService.editActivityBase(storeActivityBase.getActivity_id(), activityBaseMap)) { + status.isRollbackOnly(); + return false; + } + + return true; + }); + + if (Boolean.FALSE.equals(result)) { + logger.error(String.format("activity_id : %s 设置过期出错", storeActivityBase.getActivity_id())); + } + } + } try { @@ -65,8 +90,18 @@ public class UpdateActivityStatusJob extends QuartzJobBean { page++; } + // 砍价活动时间到,更新砍价订单的过期状态 + autoUpdateCutPriceStateJob(); + } + + /** + * 只针对:砍价活动时间到,更新砍价订单的过期状态 + */ + private void autoUpdateCutPriceStateJob() { + ShopActivityCutpriceService shopActivityCutpriceService = SpringUtil.getBean(ShopActivityCutpriceService.class); // 活动时间到更新砍价订单的过期状态 shopActivityCutpriceService.autoUpdateCutPriceStateJob(); - } + + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java index 144bb79e..12d5cc15 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java @@ -1607,6 +1607,29 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl canDoOrderCutPriceActivity = shopActivityCutpriceService.canDoOrderCutPriceActivity(activityId, userId); + if (!canDoOrderCutPriceActivity.getFirst()) { + logger.error("检查活动是否达标:{}", canDoOrderCutPriceActivity.getSecond()); + throw new ApiException(I18nUtil._("活动已过期或未砍到底价,暂无法提交订单。")); + } + + cartData.put("ac_id", acId); // shop_activity_cutprice 活动参与记录的自增id + cartData.put("activity_id", activityId); + cartData.put("activity_type", StateCode.ACTIVITY_TYPE_CUTPRICE); + } + // 添加保存订单(关键方法) List orderIdRow = addOrder(cartData, true, false, null); @@ -1632,25 +1655,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl canDoOrderCutPriceActivity = shopActivityCutpriceService.canDoOrderCutPriceActivity(acId, userId); - if (!canDoOrderCutPriceActivity.getFirst()) { - logger.error(canDoOrderCutPriceActivity.getSecond()); - throw new ApiException(I18nUtil._("砍价活动未达标,请继续努力,再提交订单。")); - } - } // 判断是否拼团购买 if (gbId != null) { @@ -6680,6 +6684,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl=开始时间, 检查时间<=结束时间)", +// isValid); +// +// return isValid; +// } - if (checkTime == null) { - checkTime = new Date(); - } - - return !checkTime.before(starTime) && !checkTime.after(endTime); - } @Override public Map listsMarketing() { @@ -4460,10 +4467,9 @@ public class ShopStoreActivityBaseServiceImpl extends BaseServiceImpl() + .eq("activity_id", activity_id) + .set("activity_state", activity_state)); if (result) { logger.info("活动状态更新成功,活动ID: {},新状态: {}", activity_id, activity_state); @@ -4488,26 +4494,22 @@ public class ShopStoreActivityBaseServiceImpl extends BaseServiceImpl item_row = shopStoreActivityItemService.find(itemQueryWrapper); - List item_id_row = item_row.stream().filter(s->s.getActivity_item_state().equals(StateCode.ACTIVITY_STATE_NORMAL)).map(s -> s.getItem_id()).distinct().collect(Collectors.toList()); + List item_id_row = item_row.stream().filter(s -> s.getActivity_item_state().equals(StateCode.ACTIVITY_STATE_NORMAL)).map(s -> s.getItem_id()).distinct().collect(Collectors.toList()); List activity_id_row = item_row.stream().map(s -> s.getActivity_id()).distinct().collect(Collectors.toList()); List used_id_row = new ArrayList<>(); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java index dd0b8419..cedc24aa 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java @@ -48,6 +48,7 @@ import com.suisung.mall.common.pojo.dto.StoreBizTimeInfoDTO; import com.suisung.mall.common.service.impl.BaiduMapServiceImpl; import com.suisung.mall.common.utils.*; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.activity.service.ShopActivityCutpriceService; import com.suisung.mall.shop.base.service.AccountBaseConfigService; import com.suisung.mall.shop.base.service.ShopBaseProductTagService; import com.suisung.mall.shop.base.service.ShopBaseStoreCategoryService; @@ -139,6 +140,11 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl lists = shopStoreActivityBaseService.lists(queryWrapper, 1, 500); + Page lists = shopStoreActivityBaseService.lists(queryWrapper, 1, 200); + + // Optimized version with improved code quality and readability + List filteredActivities = new ArrayList<>(); + for (ShopStoreActivityBase activity : lists.getRecords()) { + // Check if it's a cut-price activity that needs validation + if (activity.getActivity_type_id() != null + && activity.getActivity_type_id() == StateCode.ACTIVITY_TYPE_CUTPRICE) { + + // Validate cut-price activity stock and expiration + Pair checkStockResult = shopActivityCutpriceService.checkCutPriceExpiredAndStock(activity); + if (checkStockResult != null && !checkStockResult.getFirst()) { + // Insufficient stock or expired - update activity state to finished + shopStoreActivityBaseService.updateActivityState(activity.getActivity_id(), StateCode.ACTIVITY_STATE_FINISHED); + continue; // Skip adding this activity to results + } + } + + // Add valid activities to filtered list + filteredActivities.add(activity); + } + + // Update the page records with filtered results + lists.setRecords(filteredActivities); + Map data = toMobileResult(lists); ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();