package com.tourguide.modules.order.service; import com.tourguide.modules.operation.entity.OperationScenicSpot; import com.tourguide.modules.operation.entity.ScenicPricing; import com.tourguide.modules.operation.mapper.OperationScenicSpotMapper; import com.tourguide.modules.operation.mapper.ScenicPricingMapper; import com.tourguide.modules.order.domain.OrderStatus; import com.tourguide.modules.order.entity.TourOrder; import com.tourguide.modules.order.mapper.TourOrderMapper; import com.tourguide.modules.system.service.GuideNotificationService; import com.tourguide.modules.user.entity.GuideReceivingSession; import com.tourguide.modules.user.entity.GuideUser; import com.tourguide.modules.user.mapper.GuideRealtimeStatusMapper; import com.tourguide.modules.user.mapper.GuideReceivingSessionMapper; import com.tourguide.modules.user.mapper.GuideUserMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class GuideOrderMatchingServiceTest { private TourOrderMapper orderMapper; private GuideReceivingSessionMapper sessionMapper; private GuideUserMapper guideUserMapper; private GuideRealtimeStatusMapper realtimeStatusMapper; private OperationScenicSpotMapper scenicMapper; private ScenicPricingMapper pricingMapper; private GuideOrderEarningSnapshotService earningSnapshotService; private GuideNotificationService notificationService; private GuideOrderMatchingService service; @BeforeEach void setUp() { orderMapper = mock(TourOrderMapper.class); sessionMapper = mock(GuideReceivingSessionMapper.class); guideUserMapper = mock(GuideUserMapper.class); realtimeStatusMapper = mock(GuideRealtimeStatusMapper.class); scenicMapper = mock(OperationScenicSpotMapper.class); pricingMapper = mock(ScenicPricingMapper.class); earningSnapshotService = mock(GuideOrderEarningSnapshotService.class); notificationService = mock(GuideNotificationService.class); service = new GuideOrderMatchingService(orderMapper, sessionMapper, guideUserMapper, realtimeStatusMapper, scenicMapper, pricingMapper, earningSnapshotService, notificationService); } @Test void shouldAssignSecondGroupOrderToInServiceSessionWhileCapacityRemains() { TourOrder firstOrder = groupOrder(1L); TourOrder secondOrder = groupOrder(2L); GuideReceivingSession session = receivingSession("RECEIVING", 0); ScenicPricing pricing = groupPricing(); OperationScenicSpot scenic = scenicSpot(); GuideUser guide = guide(); when(orderMapper.selectForUpdate(1L)).thenReturn(firstOrder); when(orderMapper.selectForUpdate(2L)).thenReturn(secondOrder); when(sessionMapper.selectMatchCandidates(11L, 12L, "GROUP", "GROUP_PREMIUM")) .thenReturn(Collections.singletonList(session)); when(pricingMapper.selectById(30L)).thenReturn(pricing); when(scenicMapper.selectById(11L)).thenReturn(scenic); when(guideUserMapper.selectById(7L)).thenReturn(guide); when(sessionMapper.reserveGroupCapacity(eq(41L), eq(1), eq(2), any(LocalDateTime.class), any(LocalDateTime.class), any(LocalDateTime.class))).thenReturn(1); assertThat(service.match(1L)).isTrue(); assertThat(firstOrder.getStatus()).isEqualTo(OrderStatus.PENDING_MEETING.getCode()); session.setStatus("IN_SERVICE"); session.setCurrentPeopleCount(1); assertThat(service.match(2L)).isTrue(); assertThat(secondOrder.getGuideId()).isEqualTo(7L); assertThat(secondOrder.getReceivingSessionId()).isEqualTo(41L); assertThat(secondOrder.getStatus()).isEqualTo(OrderStatus.IN_SERVICE.getCode()); assertThat(secondOrder.getServiceStartedAt()).isNotNull(); verify(notificationService).notifyOrderAssigned(secondOrder); } private TourOrder groupOrder(Long id) { TourOrder order = new TourOrder(); order.setId(id); order.setScenicSpotId(11L); order.setMeetingPointId(12L); order.setServicePackageId(30L); order.setOrderType("GROUP_PREMIUM"); order.setPeopleCount(1); order.setStatus(OrderStatus.PENDING_ACCEPT.getCode()); return order; } private GuideReceivingSession receivingSession(String status, int peopleCount) { GuideReceivingSession session = new GuideReceivingSession(); session.setId(41L); session.setGuideId(7L); session.setScenicSpotId(11L); session.setMeetingPointId(12L); session.setReceivingMode("GROUP"); session.setServiceTypes("GROUP_PREMIUM"); session.setStatus(status); session.setCurrentPeopleCount(peopleCount); return session; } private ScenicPricing groupPricing() { ScenicPricing pricing = new ScenicPricing(); pricing.setId(30L); pricing.setScenicSpotId(11L); pricing.setServiceType("GROUP_PREMIUM"); pricing.setMaxParticipants(2); pricing.setDiscountPrice(new BigDecimal("86.00")); return pricing; } private OperationScenicSpot scenicSpot() { OperationScenicSpot scenic = new OperationScenicSpot(); scenic.setId(11L); scenic.setFirstOrderLeadMinutes(10); scenic.setVisitorNoOrderMinutes(6); return scenic; } private GuideUser guide() { GuideUser guide = new GuideUser(); guide.setId(7L); guide.setRealName("导游"); guide.setMobile("13800000000"); return guide; } }