|
|
@@ -0,0 +1,187 @@
|
|
|
+package com.ruoyi.app.mendian;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.ruoyi.common.exception.ServiceException;
|
|
|
+import com.ruoyi.common.utils.MessageUtils;
|
|
|
+import com.ruoyi.system.domain.*;
|
|
|
+import com.ruoyi.system.dto.PromotionActivitySaveRequest;
|
|
|
+import com.ruoyi.system.service.*;
|
|
|
+import com.ruoyi.system.utils.AuthContext;
|
|
|
+import org.apache.ibatis.builder.MapperBuilderAssistant;
|
|
|
+import org.junit.jupiter.api.*;
|
|
|
+import org.junit.jupiter.params.ParameterizedTest;
|
|
|
+import org.junit.jupiter.params.provider.ValueSource;
|
|
|
+import org.mockito.MockedStatic;
|
|
|
+import org.springframework.test.util.ReflectionTestUtils;
|
|
|
+import java.util.Set;
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
+
|
|
|
+/** 使用真实授权校验,只替换数据库范围解析;覆盖每个管理入口的正反例。 */
|
|
|
+class MerchantBusinessScopeTest {
|
|
|
+ MerchantStoreAccessService access;
|
|
|
+ IPromotionCouponBatchService coupons;
|
|
|
+ IPromotionActivityService activities;
|
|
|
+ IOperatingHoursService hours;
|
|
|
+ IVipQuanyiService vip;
|
|
|
+ ISalesPromotionService sales;
|
|
|
+ IPosReviewService reviews;
|
|
|
+ ShPromotionCouponController coupon = new ShPromotionCouponController();
|
|
|
+ ShPromotionActivityController activity = new ShPromotionActivityController();
|
|
|
+ OperatingHoursController hour = new OperatingHoursController();
|
|
|
+ ShQuanyiController quanyi = new ShQuanyiController();
|
|
|
+ ShSalesPromotionController sale = new ShSalesPromotionController();
|
|
|
+ ShPosReviewController review = new ShPosReviewController();
|
|
|
+ MockedStatic<AuthContext> auth;
|
|
|
+ MockedStatic<MessageUtils> messages;
|
|
|
+
|
|
|
+ @BeforeEach void setup() {
|
|
|
+ auth = mockStatic(AuthContext.class);
|
|
|
+ auth.when(AuthContext::requireUserId).thenReturn(55L);
|
|
|
+ messages = mockStatic(MessageUtils.class);
|
|
|
+ messages.when(() -> MessageUtils.message(anyString())).thenAnswer(i -> i.getArgument(0));
|
|
|
+ access = mock(MerchantStoreAccessService.class, CALLS_REAL_METHODS);
|
|
|
+ doReturn(new MerchantAccessContext(55L, 10L, false, Set.of(101L))).when(access).resolveBusinessScope(55L);
|
|
|
+ coupons = mock(IPromotionCouponBatchService.class);
|
|
|
+ activities = mock(IPromotionActivityService.class);
|
|
|
+ hours = mock(IOperatingHoursService.class);
|
|
|
+ vip = mock(IVipQuanyiService.class);
|
|
|
+ sales = mock(ISalesPromotionService.class);
|
|
|
+ reviews = mock(IPosReviewService.class);
|
|
|
+ for (Object c : new Object[]{coupon, activity, hour, quanyi, sale, review}) {
|
|
|
+ ReflectionTestUtils.setField(c, "merchantStoreAccessService", access);
|
|
|
+ }
|
|
|
+ ReflectionTestUtils.setField(coupon, "promotionCouponBatchService", coupons);
|
|
|
+ ReflectionTestUtils.setField(activity, "promotionActivityService", activities);
|
|
|
+ ReflectionTestUtils.setField(hour, "operatingHoursService", hours);
|
|
|
+ ReflectionTestUtils.setField(quanyi, "vipQuanyiService", vip);
|
|
|
+ ReflectionTestUtils.setField(quanyi, "vipUserQuanyiService", mock(IVipUserQuanyiService.class));
|
|
|
+ IPosStoreService stores = mock(IPosStoreService.class);
|
|
|
+ PosStore store = new PosStore(); store.setUserId(10L);
|
|
|
+ when(stores.getById(101L)).thenReturn(store);
|
|
|
+ ReflectionTestUtils.setField(quanyi, "storeService", stores);
|
|
|
+ ReflectionTestUtils.setField(sale, "salesPromotionService", sales);
|
|
|
+ ReflectionTestUtils.setField(sale, "posOrderMapper", mock(com.ruoyi.system.mapper.PosOrderMapper.class));
|
|
|
+ ReflectionTestUtils.setField(review, "posReviewService", reviews);
|
|
|
+ for (Class<?> type : new Class<?>[]{PromotionCouponBatch.class, VipQuanyi.class, VipUserQuanyi.class,
|
|
|
+ SalesPromotion.class, PosOrder.class, PosReview.class}) {
|
|
|
+ TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "test"), type);
|
|
|
+ }
|
|
|
+ when(hours.insertOperatingHoursReturnId(any())).thenReturn(1L);
|
|
|
+ when(coupons.page(any(Page.class), any())).thenReturn(new Page<PromotionCouponBatch>());
|
|
|
+ when(activities.selectActivityPage(any(), any(), any(), any())).thenReturn(new Page<PromotionActivity>());
|
|
|
+ when(vip.page(any(Page.class), any())).thenReturn(new Page<VipQuanyi>());
|
|
|
+ when(sales.page(any(Page.class), any())).thenReturn(new Page<SalesPromotion>());
|
|
|
+ when(reviews.page(any(Page.class), any())).thenReturn(new Page<PosReview>());
|
|
|
+ recordStore(101L);
|
|
|
+ }
|
|
|
+
|
|
|
+ void recordStore(Long storeId) {
|
|
|
+ PromotionCouponBatch c = new PromotionCouponBatch(); c.setId(1L); c.setStoreId(storeId);
|
|
|
+ when(coupons.getById(1L)).thenReturn(c); when(coupons.selectBatchWithRule(1L)).thenReturn(c);
|
|
|
+ PromotionActivity a = new PromotionActivity(); a.setId(1L); a.setStoreId(storeId); a.setType(5);
|
|
|
+ when(activities.getById(1L)).thenReturn(a);
|
|
|
+ OperatingHours h = new OperatingHours(); h.setId(1L); h.setMdId(storeId);
|
|
|
+ when(hours.selectOperatingHoursById(1L)).thenReturn(h);
|
|
|
+ VipQuanyi v = new VipQuanyi(); v.setId(1L); v.setShId(storeId); v.setType("1");
|
|
|
+ when(vip.selectVipQuanyiById(1L)).thenReturn(v);
|
|
|
+ SalesPromotion s = new SalesPromotion(); s.setId(1L); s.setShId(storeId); s.setType("1");
|
|
|
+ when(sales.selectSalesPromotionById(1L)).thenReturn(s);
|
|
|
+ PosReview r = new PosReview(); r.setId(1L); r.setMdId(storeId);
|
|
|
+ when(reviews.selectPosReviewById(1L)).thenReturn(r);
|
|
|
+ }
|
|
|
+
|
|
|
+ @AfterEach void cleanup() { auth.close(); messages.close(); }
|
|
|
+
|
|
|
+ @ParameterizedTest
|
|
|
+ @ValueSource(strings = {"couponList", "couponGet", "couponAdd", "couponEdit", "couponEnd", "couponDelete",
|
|
|
+ "activityList", "activityGet", "activityAdd", "activityEdit", "activityEnd", "activityDelete",
|
|
|
+ "hoursAdd", "hoursEdit", "hoursDelete", "vipList", "vipGet", "vipAdd", "vipEdit", "vipDelete",
|
|
|
+ "salesList", "salesGet", "salesAdd", "salesEdit", "salesDelete", "reviewGet", "reviewEdit", "reviewDelete"})
|
|
|
+ void eachManagementEntryAllowsAuthorizedStoreAndRejectsRevokedScope(String entry) {
|
|
|
+ assertDoesNotThrow(() -> request(entry));
|
|
|
+ doReturn(new MerchantAccessContext(55L, 10L, false, Set.of())).when(access).resolveBusinessScope(55L);
|
|
|
+ assertThrows(ServiceException.class, () -> request(entry), entry);
|
|
|
+ }
|
|
|
+
|
|
|
+ @ParameterizedTest @ValueSource(strings = {"couponEdit", "activityEdit", "hoursEdit", "vipEdit", "salesEdit", "reviewEdit"})
|
|
|
+ void ownRequestStoreCannotHideForeignPersistedRecord(String entry) {
|
|
|
+ recordStore(999L);
|
|
|
+ assertThrows(ServiceException.class, () -> request(entry));
|
|
|
+ verify(coupons, never()).updateBatch(any(), any(PromotionCouponRule.class));
|
|
|
+ verify(activities, never()).updateActivity(any(), any(), any());
|
|
|
+ verify(hours, never()).updateOperatingHours(any());
|
|
|
+ verify(vip, never()).updateVipQuanyi(any());
|
|
|
+ verify(sales, never()).updateSalesPromotion(any());
|
|
|
+ verify(reviews, never()).updatePosReview(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test void batchDeleteChecksAllRecordsBeforeMutation() {
|
|
|
+ VipQuanyi other = new VipQuanyi(); other.setId(2L); other.setShId(999L);
|
|
|
+ when(vip.selectVipQuanyiById(2L)).thenReturn(other);
|
|
|
+ assertThrows(ServiceException.class, () -> quanyi.remove("token", new Long[]{1L, 2L}));
|
|
|
+ verify(vip, never()).deleteVipQuanyiByIds(any());
|
|
|
+ PosReview otherReview = new PosReview(); otherReview.setMdId(999L);
|
|
|
+ when(reviews.selectPosReviewById(2L)).thenReturn(otherReview);
|
|
|
+ assertThrows(ServiceException.class, () -> review.remove("token", new Long[]{1L, 2L}));
|
|
|
+ verify(reviews, never()).deletePosReviewByIds(any());
|
|
|
+ SalesPromotion otherSales = new SalesPromotion(); otherSales.setShId(999L);
|
|
|
+ when(sales.selectSalesPromotionById(2L)).thenReturn(otherSales);
|
|
|
+ assertThrows(ServiceException.class, () -> sale.remove("token", new Long[]{1L, 2L}));
|
|
|
+ verify(sales, never()).deleteSalesPromotionByIds(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test void emptyReviewScopeDoesNotQueryAllReviews() {
|
|
|
+ doReturn(new MerchantAccessContext(55L, 10L, false, Set.of())).when(access).resolveBusinessScope(55L);
|
|
|
+ assertEquals(200, review.list("token", 1, 10).get("code"));
|
|
|
+ verify(reviews, never()).page(any(Page.class), any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test void missingRecordFailsClosed() {
|
|
|
+ assertThrows(ServiceException.class, () -> coupon.getInfo("token", 99L));
|
|
|
+ assertThrows(ServiceException.class, () -> hour.delHours("token", 99L));
|
|
|
+ assertThrows(ServiceException.class, () -> review.getInfo("token", 99L));
|
|
|
+ }
|
|
|
+
|
|
|
+ void request(String entry) {
|
|
|
+ PromotionCouponBatch c = new PromotionCouponBatch(); c.setId(1L); c.setStoreId(101L);
|
|
|
+ PromotionActivitySaveRequest a = new PromotionActivitySaveRequest(); a.setId(1L); a.setStoreId(101L); a.setType(1);
|
|
|
+ OperatingHours h = new OperatingHours(); h.setId(1L); h.setMdId(101L);
|
|
|
+ VipQuanyi v = new VipQuanyi(); v.setId(1L); v.setShId(101L);
|
|
|
+ SalesPromotion s = new SalesPromotion(); s.setId(1L); s.setShId(101L);
|
|
|
+ PosReview r = new PosReview(); r.setId(1L); r.setMdId(101L);
|
|
|
+ switch (entry) {
|
|
|
+ case "couponList" -> coupon.list("token",1,10,101L,null,null);
|
|
|
+ case "couponGet" -> coupon.getInfo("token",1L);
|
|
|
+ case "couponAdd" -> coupon.add("token",c);
|
|
|
+ case "couponEdit" -> coupon.edit("token",c);
|
|
|
+ case "couponEnd" -> coupon.offShelf("token",1L);
|
|
|
+ case "couponDelete" -> coupon.remove("token",1L);
|
|
|
+ case "activityList" -> activity.list("token",1,10,101L,null,null);
|
|
|
+ case "activityGet" -> activity.getInfo("token",1L);
|
|
|
+ case "activityAdd" -> activity.add("token",a);
|
|
|
+ case "activityEdit" -> activity.edit("token",a);
|
|
|
+ case "activityEnd" -> activity.end("token",1L);
|
|
|
+ case "activityDelete" -> activity.remove("token",1L);
|
|
|
+ case "hoursAdd" -> hour.addHours("token",h);
|
|
|
+ case "hoursEdit" -> hour.setHours("token",h);
|
|
|
+ case "hoursDelete" -> hour.delHours("token",1L);
|
|
|
+ case "vipList" -> quanyi.list("token",1,10,"zh",101L);
|
|
|
+ case "vipGet" -> quanyi.getInfo("token",1L);
|
|
|
+ case "vipAdd" -> quanyi.add("token",v);
|
|
|
+ case "vipEdit" -> quanyi.edit("token",v);
|
|
|
+ case "vipDelete" -> quanyi.remove("token",new Long[]{1L});
|
|
|
+ case "salesList" -> sale.list("token",1,10,"zh",101L);
|
|
|
+ case "salesGet" -> sale.getInfo("token",1L);
|
|
|
+ case "salesAdd" -> sale.add("token",s);
|
|
|
+ case "salesEdit" -> sale.edit("token",s);
|
|
|
+ case "salesDelete" -> sale.remove("token",new Long[]{1L});
|
|
|
+ case "reviewGet" -> review.getInfo("token",1L);
|
|
|
+ case "reviewEdit" -> review.edit("token",r);
|
|
|
+ case "reviewDelete" -> review.remove("token",new Long[]{1L});
|
|
|
+ default -> throw new IllegalArgumentException(entry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|