|
@@ -11,6 +11,8 @@ import com.ruoyi.app.flashdelivery.dto.FlashDeliveryDeliverRequest;
|
|
|
import com.ruoyi.app.flashdelivery.dto.FlashDeliveryRiderOrderPageView;
|
|
import com.ruoyi.app.flashdelivery.dto.FlashDeliveryRiderOrderPageView;
|
|
|
import com.ruoyi.app.flashdelivery.route.FlashDeliveryRouteService;
|
|
import com.ruoyi.app.flashdelivery.route.FlashDeliveryRouteService;
|
|
|
import com.ruoyi.app.flashdelivery.route.RouteDistance;
|
|
import com.ruoyi.app.flashdelivery.route.RouteDistance;
|
|
|
|
|
+import com.ruoyi.app.order.RiderDeliveryExclusivityService;
|
|
|
|
|
+import com.ruoyi.app.order.RiderDeliveryLockService;
|
|
|
import com.ruoyi.system.domain.InfoUser;
|
|
import com.ruoyi.system.domain.InfoUser;
|
|
|
import com.ruoyi.system.domain.flash.FlashDeliveryOrder;
|
|
import com.ruoyi.system.domain.flash.FlashDeliveryOrder;
|
|
|
import com.ruoyi.system.domain.flash.FlashDeliveryOrderImage;
|
|
import com.ruoyi.system.domain.flash.FlashDeliveryOrderImage;
|
|
@@ -40,6 +42,7 @@ import java.util.Date;
|
|
|
|
|
|
|
|
import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.ACCEPTED;
|
|
import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.ACCEPTED;
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
|
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
@@ -55,6 +58,7 @@ import static org.mockito.Mockito.verify;
|
|
|
import static org.mockito.Mockito.when;
|
|
import static org.mockito.Mockito.when;
|
|
|
import static org.mockito.Mockito.doAnswer;
|
|
import static org.mockito.Mockito.doAnswer;
|
|
|
import static org.mockito.Mockito.inOrder;
|
|
import static org.mockito.Mockito.inOrder;
|
|
|
|
|
+import static org.mockito.Mockito.doThrow;
|
|
|
|
|
|
|
|
class FlashDeliveryApplicationServiceTest {
|
|
class FlashDeliveryApplicationServiceTest {
|
|
|
private static ConfigurableListableBeanFactory originalBeanFactory;
|
|
private static ConfigurableListableBeanFactory originalBeanFactory;
|
|
@@ -155,6 +159,8 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
@Test
|
|
@Test
|
|
|
void scheduledCreateGeneratesUserOnlyPinAndStoresSenderProof() {
|
|
void scheduledCreateGeneratesUserOnlyPinAndStoresSenderProof() {
|
|
|
Fixture fixture = new Fixture();
|
|
Fixture fixture = new Fixture();
|
|
|
|
|
+ when(fixture.userMapper.selectOrdinaryUserIdsByNormalizedPhone("0922222222"))
|
|
|
|
|
+ .thenReturn(List.of(88L));
|
|
|
when(fixture.pricingMapper.selectCurrent("HELP_SEND")).thenReturn(List.of(pricing()));
|
|
when(fixture.pricingMapper.selectCurrent("HELP_SEND")).thenReturn(List.of(pricing()));
|
|
|
when(fixture.routeService.calculate(any(), any())).thenReturn(new RouteDistance(3200, 600, "ROUTE"));
|
|
when(fixture.routeService.calculate(any(), any())).thenReturn(new RouteDistance(3200, 600, "ROUTE"));
|
|
|
doAnswer(invocation -> {
|
|
doAnswer(invocation -> {
|
|
@@ -178,6 +184,7 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
verify(fixture.orderMapper).insert(saved.capture());
|
|
verify(fixture.orderMapper).insert(saved.capture());
|
|
|
assertEquals("SCHEDULED", saved.getValue().getDeliveryMode());
|
|
assertEquals("SCHEDULED", saved.getValue().getDeliveryMode());
|
|
|
assertEquals("DOCUMENT", saved.getValue().getPackageType());
|
|
assertEquals("DOCUMENT", saved.getValue().getPackageType());
|
|
|
|
|
+ assertEquals(88L, saved.getValue().getReceiverUserId());
|
|
|
assertEquals(1L, saved.getValue().getPricingId());
|
|
assertEquals(1L, saved.getValue().getPricingId());
|
|
|
assertEquals("00:00", saved.getValue().getPricingStartTime());
|
|
assertEquals("00:00", saved.getValue().getPricingStartTime());
|
|
|
assertEquals("24:00", saved.getValue().getPricingEndTime());
|
|
assertEquals("24:00", saved.getValue().getPricingEndTime());
|
|
@@ -198,7 +205,7 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
when(fixture.orderMapper.selectPage(any(com.baomidou.mybatisplus.core.metadata.IPage.class),
|
|
when(fixture.orderMapper.selectPage(any(com.baomidou.mybatisplus.core.metadata.IPage.class),
|
|
|
any(Wrapper.class))).thenReturn(source);
|
|
any(Wrapper.class))).thenReturn(source);
|
|
|
|
|
|
|
|
- var result = fixture.service.userOrders(7L, 1, 10);
|
|
|
|
|
|
|
+ var result = fixture.service.userOrders(7L, 1, 10, null);
|
|
|
|
|
|
|
|
ArgumentCaptor<com.baomidou.mybatisplus.core.conditions.query.QueryWrapper> query =
|
|
ArgumentCaptor<com.baomidou.mybatisplus.core.conditions.query.QueryWrapper> query =
|
|
|
ArgumentCaptor.forClass(com.baomidou.mybatisplus.core.conditions.query.QueryWrapper.class);
|
|
ArgumentCaptor.forClass(com.baomidou.mybatisplus.core.conditions.query.QueryWrapper.class);
|
|
@@ -213,6 +220,64 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
assertEquals(112L, result.getRecords().get(0).getAmount());
|
|
assertEquals(112L, result.getRecords().get(0).getAmount());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void createDoesNotBindReceiverWhenNormalizedPhoneMatchesMultipleUsers() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ when(fixture.pricingMapper.selectCurrent("HELP_SEND")).thenReturn(List.of(pricing()));
|
|
|
|
|
+ when(fixture.routeService.calculate(any(), any())).thenReturn(new RouteDistance(3200, 600, "ROUTE"));
|
|
|
|
|
+ when(fixture.userMapper.selectOrdinaryUserIdsByNormalizedPhone("886912345678"))
|
|
|
|
|
+ .thenReturn(List.of(88L, 99L));
|
|
|
|
|
+ doAnswer(invocation -> {
|
|
|
|
|
+ FlashDeliveryOrder order = invocation.getArgument(0);
|
|
|
|
|
+ order.setId(99L);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }).when(fixture.orderMapper).insert(any(FlashDeliveryOrder.class));
|
|
|
|
|
+ FlashDeliveryCreateRequest request = createRequest();
|
|
|
|
|
+ request.getDelivery().setPhone("+886 912-345-678");
|
|
|
|
|
+
|
|
|
|
|
+ fixture.service.create(7L, request);
|
|
|
|
|
+
|
|
|
|
|
+ ArgumentCaptor<FlashDeliveryOrder> saved = ArgumentCaptor.forClass(FlashDeliveryOrder.class);
|
|
|
|
|
+ verify(fixture.orderMapper).insert(saved.capture());
|
|
|
|
|
+ assertNull(saved.getValue().getReceiverUserId());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void createLeavesReceiverUnboundWhenPhoneHasNoRegisteredUser() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ when(fixture.pricingMapper.selectCurrent("HELP_SEND")).thenReturn(List.of(pricing()));
|
|
|
|
|
+ when(fixture.routeService.calculate(any(), any())).thenReturn(new RouteDistance(3200, 600, "ROUTE"));
|
|
|
|
|
+ when(fixture.userMapper.selectOrdinaryUserIdsByNormalizedPhone("0922222222"))
|
|
|
|
|
+ .thenReturn(List.of());
|
|
|
|
|
+ doAnswer(invocation -> {
|
|
|
|
|
+ FlashDeliveryOrder order = invocation.getArgument(0);
|
|
|
|
|
+ order.setId(99L);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }).when(fixture.orderMapper).insert(any(FlashDeliveryOrder.class));
|
|
|
|
|
+
|
|
|
|
|
+ fixture.service.create(7L, createRequest());
|
|
|
|
|
+
|
|
|
|
|
+ ArgumentCaptor<FlashDeliveryOrder> saved = ArgumentCaptor.forClass(FlashDeliveryOrder.class);
|
|
|
|
|
+ verify(fixture.orderMapper).insert(saved.capture());
|
|
|
|
|
+ assertNull(saved.getValue().getReceiverUserId());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ @SuppressWarnings({"rawtypes", "unchecked"})
|
|
|
|
|
+ void receiverListFiltersByCreationTimeReceiverBinding() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ when(fixture.orderMapper.selectPage(any(com.baomidou.mybatisplus.core.metadata.IPage.class),
|
|
|
|
|
+ any(Wrapper.class))).thenReturn(new Page<FlashDeliveryOrder>());
|
|
|
|
|
+
|
|
|
|
|
+ fixture.service.userOrders(88L, 1, 10, "receiver");
|
|
|
|
|
+
|
|
|
|
|
+ ArgumentCaptor<com.baomidou.mybatisplus.core.conditions.query.QueryWrapper> query =
|
|
|
|
|
+ ArgumentCaptor.forClass(com.baomidou.mybatisplus.core.conditions.query.QueryWrapper.class);
|
|
|
|
|
+ verify(fixture.orderMapper).selectPage(any(com.baomidou.mybatisplus.core.metadata.IPage.class), query.capture());
|
|
|
|
|
+ assertTrue(query.getValue().getSqlSegment().toLowerCase().contains("receiver_user_id"));
|
|
|
|
|
+ assertTrue(query.getValue().getParamNameValuePairs().values().contains(88L));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Test
|
|
@Test
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
|
void riderNewTaskUsesFoodOrderParametersAndReturnsPrototypeCardSummary() {
|
|
void riderNewTaskUsesFoodOrderParametersAndReturnsPrototypeCardSummary() {
|
|
@@ -439,6 +504,36 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
verify(fixture.logMapper, never()).selectList(any());
|
|
verify(fixture.logMapper, never()).selectList(any());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void matchedReceiverCanViewAndConfirmButCannotCancelOrder() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ FlashDeliveryOrder order = order(10L, "DELIVERED");
|
|
|
|
|
+ order.setReceiverUserId(88L);
|
|
|
|
|
+ when(fixture.orderMapper.selectById(10L)).thenReturn(order);
|
|
|
|
|
+ when(fixture.orderMapper.transitionByParticipant(eq(10L), eq(88L), eq("DELIVERED"),
|
|
|
|
|
+ eq("COMPLETED"), any(Date.class))).thenReturn(1);
|
|
|
|
|
+ when(fixture.imageMapper.selectList(any(Wrapper.class))).thenReturn(List.of());
|
|
|
|
|
+
|
|
|
|
|
+ assertDoesNotThrow(() -> fixture.service.userDetail(88L, 10L));
|
|
|
|
|
+ assertDoesNotThrow(() -> fixture.service.confirmReceipt(88L, 10L));
|
|
|
|
|
+ assertThrows(ServiceException.class,
|
|
|
|
|
+ () -> fixture.service.userCancel(88L, 10L, new com.ruoyi.app.flashdelivery.dto.FlashDeliveryReasonRequest()));
|
|
|
|
|
+ verify(fixture.orderMapper).transitionByParticipant(eq(10L), eq(88L), eq("DELIVERED"),
|
|
|
|
|
+ eq("COMPLETED"), any(Date.class));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void orderWithoutCreationTimeReceiverBindingIsNotClaimedLater() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ FlashDeliveryOrder historicalOrder = order(10L, "DELIVERED");
|
|
|
|
|
+ historicalOrder.setReceiverUserId(null);
|
|
|
|
|
+ when(fixture.orderMapper.selectById(10L)).thenReturn(historicalOrder);
|
|
|
|
|
+
|
|
|
|
|
+ assertThrows(ServiceException.class, () -> fixture.service.userDetail(88L, 10L));
|
|
|
|
|
+
|
|
|
|
|
+ verify(fixture.userMapper, never()).selectOrdinaryUserIdsByNormalizedPhone(any());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Test
|
|
@Test
|
|
|
void pickupRejectsMissingProofBeforeChangingState() {
|
|
void pickupRejectsMissingProofBeforeChangingState() {
|
|
|
Fixture fixture = new Fixture();
|
|
Fixture fixture = new Fixture();
|
|
@@ -459,11 +554,43 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
InfoUser rider = new InfoUser();
|
|
InfoUser rider = new InfoUser();
|
|
|
rider.setUserId(8L);
|
|
rider.setUserId(8L);
|
|
|
rider.setUserType("2");
|
|
rider.setUserType("2");
|
|
|
|
|
+ rider.setDeliveryType("FLASH");
|
|
|
when(fixture.userMapper.selectInfoUserByUserId(8L)).thenReturn(rider);
|
|
when(fixture.userMapper.selectInfoUserByUserId(8L)).thenReturn(rider);
|
|
|
|
|
+ when(fixture.orderMapper.selectById(10L)).thenReturn(order(10L, "WAITING_ACCEPTANCE"));
|
|
|
when(fixture.orderMapper.accept(eq(10L), eq(8L), any())).thenReturn(0);
|
|
when(fixture.orderMapper.accept(eq(10L), eq(8L), any())).thenReturn(0);
|
|
|
|
|
|
|
|
assertThrows(RuntimeException.class, () -> fixture.service.accept(8L, 10L));
|
|
assertThrows(RuntimeException.class, () -> fixture.service.accept(8L, 10L));
|
|
|
- verify(fixture.orderMapper, never()).selectById(10L);
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void flashAcceptUsesRiderLockAndChecksExclusivityBeforeAtomicUpdate() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ rider(fixture, 8L);
|
|
|
|
|
+ FlashDeliveryOrder waiting = order(10L, "WAITING_ACCEPTANCE");
|
|
|
|
|
+ FlashDeliveryOrder accepted = order(10L, ACCEPTED);
|
|
|
|
|
+ accepted.setRiderId(8L);
|
|
|
|
|
+ when(fixture.orderMapper.selectById(10L)).thenReturn(waiting, accepted);
|
|
|
|
|
+ when(fixture.orderMapper.accept(eq(10L), eq(8L), any(Date.class))).thenReturn(1);
|
|
|
|
|
+
|
|
|
|
|
+ fixture.service.accept(8L, 10L);
|
|
|
|
|
+
|
|
|
|
|
+ InOrder order = inOrder(fixture.lockService, fixture.exclusivityService, fixture.orderMapper);
|
|
|
|
|
+ order.verify(fixture.lockService).withLock(eq(8L), any(RiderDeliveryLockService.LockedCall.class));
|
|
|
|
|
+ order.verify(fixture.exclusivityService).assertCanAcceptFlash(8L, "HELP_SEND");
|
|
|
|
|
+ order.verify(fixture.orderMapper).accept(eq(10L), eq(8L), any(Date.class));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void flashExclusiveConflictDoesNotUpdateOrder() {
|
|
|
|
|
+ Fixture fixture = new Fixture();
|
|
|
|
|
+ rider(fixture, 8L);
|
|
|
|
|
+ when(fixture.orderMapper.selectById(10L)).thenReturn(order(10L, "WAITING_ACCEPTANCE"));
|
|
|
|
|
+ doThrow(new ServiceException("exclusive"))
|
|
|
|
|
+ .when(fixture.exclusivityService).assertCanAcceptFlash(8L, "HELP_SEND");
|
|
|
|
|
+
|
|
|
|
|
+ assertThrows(ServiceException.class, () -> fixture.service.accept(8L, 10L));
|
|
|
|
|
+
|
|
|
|
|
+ verify(fixture.orderMapper, never()).accept(any(), any(), any());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
@@ -722,6 +849,7 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
InfoUser rider = new InfoUser();
|
|
InfoUser rider = new InfoUser();
|
|
|
rider.setUserId(riderId);
|
|
rider.setUserId(riderId);
|
|
|
rider.setUserType("2");
|
|
rider.setUserType("2");
|
|
|
|
|
+ rider.setDeliveryType("FLASH");
|
|
|
when(fixture.userMapper.selectInfoUserByUserId(riderId)).thenReturn(rider);
|
|
when(fixture.userMapper.selectInfoUserByUserId(riderId)).thenReturn(rider);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -776,13 +904,19 @@ class FlashDeliveryApplicationServiceTest {
|
|
|
final FlashDeliveryOrderLogMapper logMapper = mock(FlashDeliveryOrderLogMapper.class);
|
|
final FlashDeliveryOrderLogMapper logMapper = mock(FlashDeliveryOrderLogMapper.class);
|
|
|
final InfoUserMapper userMapper = mock(InfoUserMapper.class);
|
|
final InfoUserMapper userMapper = mock(InfoUserMapper.class);
|
|
|
final FlashDeliveryRouteService routeService = mock(FlashDeliveryRouteService.class);
|
|
final FlashDeliveryRouteService routeService = mock(FlashDeliveryRouteService.class);
|
|
|
|
|
+ final RiderDeliveryLockService lockService = mock(RiderDeliveryLockService.class);
|
|
|
|
|
+ final RiderDeliveryExclusivityService exclusivityService = mock(RiderDeliveryExclusivityService.class);
|
|
|
final FlashDeliveryApplicationService service = new FlashDeliveryApplicationService(
|
|
final FlashDeliveryApplicationService service = new FlashDeliveryApplicationService(
|
|
|
orderMapper, pricingMapper, imageMapper, logMapper, userMapper,
|
|
orderMapper, pricingMapper, imageMapper, logMapper, userMapper,
|
|
|
- routeService, new FlashDeliveryPricingCalculator());
|
|
|
|
|
|
|
+ routeService, new FlashDeliveryPricingCalculator(), lockService, exclusivityService);
|
|
|
|
|
|
|
|
Fixture() {
|
|
Fixture() {
|
|
|
when(pricingMapper.lockServiceType(any()))
|
|
when(pricingMapper.lockServiceType(any()))
|
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
|
|
+ when(lockService.withLock(any(), any())).thenAnswer(invocation -> {
|
|
|
|
|
+ RiderDeliveryLockService.LockedCall<?> call = invocation.getArgument(1);
|
|
|
|
|
+ return call.call();
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|