|
|
@@ -7,6 +7,9 @@ import com.ruoyi.app.order.dto.MultiStoreQuoteView;
|
|
|
import com.ruoyi.common.core.redis.RedisCache;
|
|
|
import com.ruoyi.common.exception.ServiceException;
|
|
|
import com.ruoyi.common.utils.MessageUtils;
|
|
|
+import com.ruoyi.system.domain.FoodSpecRelation;
|
|
|
+import com.ruoyi.system.domain.FoodSpecs;
|
|
|
+import com.ruoyi.system.domain.FoodSpecsValue;
|
|
|
import com.ruoyi.system.domain.InfoAddress;
|
|
|
import com.ruoyi.system.domain.OperatingHours;
|
|
|
import com.ruoyi.system.domain.PosFood;
|
|
|
@@ -26,6 +29,9 @@ import com.ruoyi.system.service.IPromotionCalcService;
|
|
|
import com.ruoyi.system.service.PaymentMethodGateService;
|
|
|
import com.ruoyi.system.service.StallQualificationGateService;
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
+import org.junit.jupiter.params.ParameterizedTest;
|
|
|
+import org.junit.jupiter.params.provider.NullSource;
|
|
|
+import org.junit.jupiter.params.provider.ValueSource;
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
import org.junit.jupiter.api.AfterEach;
|
|
|
import org.mockito.MockedStatic;
|
|
|
@@ -37,6 +43,7 @@ import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
@@ -59,6 +66,8 @@ class MultiStoreCheckoutQuoteServiceTest {
|
|
|
messages = mockStatic(MessageUtils.class);
|
|
|
messages.when(() -> MessageUtils.message(any(String.class)))
|
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
+ messages.when(() -> MessageUtils.message(any(String.class), any(Object[].class)))
|
|
|
+ .thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
}
|
|
|
|
|
|
@AfterEach
|
|
|
@@ -112,7 +121,7 @@ class MultiStoreCheckoutQuoteServiceTest {
|
|
|
for (long id : List.of(11L, 22L)) {
|
|
|
PosFood food = new PosFood();
|
|
|
food.setId(id); food.setMdid(id == 11L ? 1L : 2L);
|
|
|
- food.setPrice(new BigDecimal("50")); food.setStackingUp("0");
|
|
|
+ food.setPrice(new BigDecimal("50")); food.setStackingUp("0"); food.setToExamine("1");
|
|
|
when(foods.selectById(id)).thenReturn(food);
|
|
|
}
|
|
|
when(relations.selectFoodSpecRelationList(any())).thenReturn(List.of());
|
|
|
@@ -148,6 +157,35 @@ class MultiStoreCheckoutQuoteServiceTest {
|
|
|
verify(redis).setCacheObject(any(String.class), any(String.class), eq(5), eq(TimeUnit.MINUTES));
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ void insufficientCandidatesNamesExcludedStoresAndReasons() {
|
|
|
+ when(config.current()).thenReturn(new MultiStoreCheckoutConfig(true, 1000, 5, 5,
|
|
|
+ Map.of(2, new BigDecimal("0.9")), 1));
|
|
|
+ InfoAddress address = new InfoAddress();
|
|
|
+ address.setId(10L); address.setUserId(42L);
|
|
|
+ address.setLatitude(new BigDecimal("22.6000")); address.setLongitude(new BigDecimal("120.3000"));
|
|
|
+ when(addresses.selectById(10L)).thenReturn(address);
|
|
|
+ when(stores.selectById(1L)).thenReturn(store(1, "22.6010", "120.3000"));
|
|
|
+ when(stores.selectById(2L)).thenReturn(store(2, "22.6300", "120.3000"));
|
|
|
+ OperatingHours open = new OperatingHours();
|
|
|
+ open.setMdId(1L); open.setDayOfWeek(LocalDate.now().getDayOfWeek().getValue());
|
|
|
+ open.setIsOpen(true); open.setStartTime("00:00"); open.setEndTime("23:59");
|
|
|
+ when(hours.selectOperatingHoursList(any(OperatingHours.class))).thenReturn(List.of(open));
|
|
|
+ PosFreight fare = new PosFreight();
|
|
|
+ fare.setStartingFare(40L); fare.setStartingDistance(1L); fare.setFreight(10L); fare.setDistance(1L);
|
|
|
+ when(freight.getyunjia()).thenReturn(List.of(fare));
|
|
|
+ when(payments.listAvailable(eq(PaymentMethodGateService.GateScope.MERCHANT), anyLong(), anyLong(), eq(0L)))
|
|
|
+ .thenReturn(List.of(new PaymentMethodGateService.PayMethodOption("COD", "1", true)));
|
|
|
+ MultiStoreQuoteRequest twoStores = new MultiStoreQuoteRequest(10L, true, List.of(
|
|
|
+ new MultiStoreQuoteRequest.Store(1L, null,
|
|
|
+ List.of(new MultiStoreQuoteRequest.Item(11L, 1, List.of())), null, null),
|
|
|
+ new MultiStoreQuoteRequest.Store(2L, null,
|
|
|
+ List.of(new MultiStoreQuoteRequest.Item(22L, 1, List.of())), null, null)));
|
|
|
+ ServiceException failure = assertThrows(ServiceException.class,
|
|
|
+ () -> subject().quote(twoStores, 42L));
|
|
|
+ assertEquals("multi.store.checkout.stores.excluded", failure.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
void merchantFreeDeliveryUsesDiscountedFreightAsSubsidyBase() {
|
|
|
when(config.current()).thenReturn(new MultiStoreCheckoutConfig(true, 1000, 5, 5,
|
|
|
@@ -166,7 +204,7 @@ class MultiStoreCheckoutQuoteServiceTest {
|
|
|
for (long id : List.of(11L, 22L)) {
|
|
|
PosFood food = new PosFood();
|
|
|
food.setId(id); food.setMdid(id == 11L ? 1L : 2L);
|
|
|
- food.setPrice(new BigDecimal("50")); food.setStackingUp("0");
|
|
|
+ food.setPrice(new BigDecimal("50")); food.setStackingUp("0"); food.setToExamine("1");
|
|
|
when(foods.selectById(id)).thenReturn(food);
|
|
|
}
|
|
|
when(relations.selectFoodSpecRelationList(any())).thenReturn(List.of());
|
|
|
@@ -263,7 +301,7 @@ class MultiStoreCheckoutQuoteServiceTest {
|
|
|
for (long id : List.of(11L, 22L)) {
|
|
|
PosFood food = new PosFood();
|
|
|
food.setId(id); food.setMdid(id == 11L ? 1L : 2L);
|
|
|
- food.setPrice(new BigDecimal("50")); food.setStackingUp("0");
|
|
|
+ food.setPrice(new BigDecimal("50")); food.setStackingUp("0"); food.setToExamine("1");
|
|
|
when(foods.selectById(id)).thenReturn(food);
|
|
|
}
|
|
|
when(relations.selectFoodSpecRelationList(any())).thenReturn(List.of());
|
|
|
@@ -283,6 +321,75 @@ class MultiStoreCheckoutQuoteServiceTest {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ void approvedProductsWithReportedSpecSelectionsCanBePriced() {
|
|
|
+ // 复现联调请求:203店9135(规格43)+9136,168店9115(规格15/7)+9078(规格15)。
|
|
|
+ Map<Long, Long> storeByFood = Map.of(9135L, 203L, 9136L, 203L, 9115L, 168L, 9078L, 168L);
|
|
|
+ Map<Long, String> basePrice = Map.of(9135L, "60.00", 9136L, "66.00", 9115L, "60.00", 9078L, "15.00");
|
|
|
+ for (Long id : storeByFood.keySet()) {
|
|
|
+ PosFood food = new PosFood();
|
|
|
+ food.setId(id); food.setMdid(storeByFood.get(id));
|
|
|
+ food.setPrice(new BigDecimal(basePrice.get(id))); food.setStackingUp("0"); food.setToExamine("1");
|
|
|
+ when(foods.selectById(id)).thenReturn(food);
|
|
|
+ }
|
|
|
+ Map<Long, List<Long>> groupsByFood = Map.of(9135L, List.of(20L), 9136L, List.of(),
|
|
|
+ 9115L, List.of(10L, 5L), 9078L, List.of(10L));
|
|
|
+ when(relations.selectFoodSpecRelationList(any())).thenAnswer(call -> {
|
|
|
+ FoodSpecRelation query = call.getArgument(0);
|
|
|
+ return groupsByFood.get(query.getFoodId()).stream().map(id -> {
|
|
|
+ FoodSpecRelation link = new FoodSpecRelation(); link.setSpecsId(id); return link;
|
|
|
+ }).toList();
|
|
|
+ });
|
|
|
+ for (long id : List.of(20L, 10L, 5L)) {
|
|
|
+ FoodSpecs group = new FoodSpecs();
|
|
|
+ group.setId(id); group.setMdId(id == 20L ? 203L : 168L);
|
|
|
+ group.setIsOpen(true); group.setIsDelete(false); group.setState("1"); group.setType("1");
|
|
|
+ when(specs.selectById(id)).thenReturn(group);
|
|
|
+ }
|
|
|
+ for (long id : List.of(43L, 15L, 7L)) {
|
|
|
+ FoodSpecsValue value = new FoodSpecsValue();
|
|
|
+ value.setId(id); value.setParentId(id == 43L ? 20L : id == 15L ? 10L : 5L);
|
|
|
+ value.setIsOpen(true); value.setPrice(new BigDecimal(id == 43L ? "20.00" : "0.00"));
|
|
|
+ when(values.selectById(id)).thenReturn(value);
|
|
|
+ }
|
|
|
+ when(promotions.calculate(any(), eq(42L), any(PromotionDeliveryContext.class))).thenAnswer(call -> {
|
|
|
+ com.ruoyi.system.dto.PromotionCalcRequest request = call.getArgument(0);
|
|
|
+ PromotionDeliveryContext delivery = call.getArgument(2);
|
|
|
+ PromotionCalcResponse result = new PromotionCalcResponse();
|
|
|
+ BigDecimal goods = new BigDecimal(request.getStoreId() == 203L ? "146" : "75");
|
|
|
+ result.setOriginalAmount(goods); result.setFinalAmount(goods);
|
|
|
+ result.setDeliveryFee(delivery.getDeliveryFee()); result.setDeliveryDiscountAmount(BigDecimal.ZERO);
|
|
|
+ result.setCustomerDeliveryFee(delivery.getDeliveryFee());
|
|
|
+ result.setPayableAmount(goods.add(delivery.getDeliveryFee()));
|
|
|
+ return result;
|
|
|
+ });
|
|
|
+ List<MultiStoreQuoteRequest.Store> selected = List.of(
|
|
|
+ new MultiStoreQuoteRequest.Store(203L, null, List.of(
|
|
|
+ new MultiStoreQuoteRequest.Item(9135L, 1, List.of(43L)),
|
|
|
+ new MultiStoreQuoteRequest.Item(9136L, 1, List.of())), null, null),
|
|
|
+ new MultiStoreQuoteRequest.Store(168L, null, List.of(
|
|
|
+ new MultiStoreQuoteRequest.Item(9115L, 1, List.of(15L, 7L)),
|
|
|
+ new MultiStoreQuoteRequest.Item(9078L, 1, List.of(15L))), null, null));
|
|
|
+ assertEquals(new BigDecimal("146"), assertDoesNotThrow(() ->
|
|
|
+ subject().priceFoodForBatch(selected.get(0), 42L, new BigDecimal("36"))).getOriginalAmount());
|
|
|
+ assertEquals(new BigDecimal("75"), assertDoesNotThrow(() ->
|
|
|
+ subject().priceFoodForBatch(selected.get(1), 42L, new BigDecimal("36"))).getOriginalAmount());
|
|
|
+ }
|
|
|
+
|
|
|
+ @ParameterizedTest
|
|
|
+ @NullSource
|
|
|
+ @ValueSource(strings = {"0", "2"})
|
|
|
+ void unapprovedProductsCannotBePricedEvenWhenOnShelf(String approval) {
|
|
|
+ PosFood food = new PosFood();
|
|
|
+ food.setId(11L); food.setMdid(1L); food.setPrice(new BigDecimal("50"));
|
|
|
+ food.setStackingUp("0"); food.setToExamine(approval);
|
|
|
+ when(foods.selectById(11L)).thenReturn(food);
|
|
|
+ when(relations.selectFoodSpecRelationList(any())).thenReturn(List.of());
|
|
|
+ assertThrows(ServiceException.class, () -> subject().priceFoodForBatch(request().stores().get(0),
|
|
|
+ 42L, new BigDecimal("36")));
|
|
|
+ verifyNoInteractions(promotions);
|
|
|
+ }
|
|
|
+
|
|
|
private MultiStoreQuoteRequest request() {
|
|
|
return new MultiStoreQuoteRequest(10L, true, List.of(
|
|
|
new MultiStoreQuoteRequest.Store(1L, null, List.of(new MultiStoreQuoteRequest.Item(11L, 1, List.of())), null, null),
|