|
@@ -0,0 +1,147 @@
|
|
|
|
|
+package com.ruoyi.app.pay;
|
|
|
|
|
+
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
|
|
|
+import com.ruoyi.app.pay.dto.QsBillingDto;
|
|
|
|
|
+import com.ruoyi.common.utils.DictUtils;
|
|
|
|
|
+import com.ruoyi.common.utils.MessageUtils;
|
|
|
|
|
+import com.ruoyi.system.domain.*;
|
|
|
|
|
+import com.ruoyi.system.domain.flash.FlashDeliveryOrder;
|
|
|
|
|
+import com.ruoyi.system.domain.vo.BillDTO;
|
|
|
|
|
+import com.ruoyi.system.mapper.UserBillingMapper;
|
|
|
|
|
+import com.ruoyi.system.mapper.flash.FlashDeliveryOrderMapper;
|
|
|
|
|
+import com.ruoyi.system.service.*;
|
|
|
|
|
+import com.ruoyi.system.utils.JwtUtil;
|
|
|
|
|
+import org.junit.jupiter.api.*;
|
|
|
|
|
+import org.mockito.*;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+
|
|
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
|
+import static org.mockito.ArgumentMatchers.*;
|
|
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
|
|
+
|
|
|
|
|
+/** Exercises the public day/week/month API rather than a private enrichment helper. */
|
|
|
|
|
+class UserBillingFlashDeliveryTest {
|
|
|
|
|
+ @Mock UserBillingMapper bills;
|
|
|
|
|
+ @Mock FlashDeliveryOrderMapper flashOrders;
|
|
|
|
|
+ @Mock IPosOrderService foodOrders;
|
|
|
|
|
+ @Mock IPosOrderRatingService foodRatings;
|
|
|
|
|
+ @Mock IInfoUserService users;
|
|
|
|
|
+ @Mock IUserBillingService billingService;
|
|
|
|
|
+ @InjectMocks UserBillingController controller;
|
|
|
|
|
+ private AutoCloseable mocks;
|
|
|
|
|
+ private MockedStatic<DictUtils> dictionaries;
|
|
|
|
|
+ private MockedStatic<MessageUtils> messages;
|
|
|
|
|
+ private MockedConstruction<JwtUtil> tokens;
|
|
|
|
|
+ private UserBilling flashBill;
|
|
|
|
|
+ private FlashDeliveryOrder flashOrder;
|
|
|
|
|
+
|
|
|
|
|
+ @BeforeEach void setup() {
|
|
|
|
|
+ mocks = MockitoAnnotations.openMocks(this);
|
|
|
|
|
+ dictionaries = mockStatic(DictUtils.class);
|
|
|
|
|
+ dictionaries.when(() -> DictUtils.getDictCache("sys_qs_freight_bl")).thenReturn(null);
|
|
|
|
|
+ messages = mockStatic(MessageUtils.class);
|
|
|
|
|
+ tokens = mockConstruction(JwtUtil.class, (jwt, context) -> when(jwt.getusid("token")).thenReturn("8"));
|
|
|
|
|
+ var rider = new InfoUser(); rider.setUserId(8L); rider.setUserType("2");
|
|
|
|
|
+ when(users.getById(8L)).thenReturn(rider);
|
|
|
|
|
+ flashBill = new UserBilling(); flashBill.setUserId(8L); flashBill.setDdId("98178900000000001");
|
|
|
|
|
+ flashBill.setOrderSource("FLASH"); flashBill.setType("0"); flashBill.setUserType("2");
|
|
|
|
|
+ flashBill.setAmount(160.0);
|
|
|
|
|
+ flashBill.setCretim(new java.util.Date(1_000L));
|
|
|
|
|
+ flashOrder = new FlashDeliveryOrder(); flashOrder.setId(10L); flashOrder.setRiderId(8L);
|
|
|
|
|
+ flashOrder.setOrderNo("98178900000000001"); flashOrder.setDistanceMeters(3200);
|
|
|
|
|
+ flashOrder.setAmount(160L); flashOrder.setTipAmount(20L); flashOrder.setRiderStars(4.5); flashOrder.setPayType("6");
|
|
|
|
|
+ flashOrder.setPaymentStatus(0);
|
|
|
|
|
+ when(flashOrders.selectList(any(Wrapper.class))).thenReturn(List.of(flashOrder));
|
|
|
|
|
+ when(bills.getdaylist(eq(8L), anyString(), isNull(), eq(0L), eq(10L))).thenReturn(List.of(flashBill));
|
|
|
|
|
+ when(bills.getmeeklist(eq(8L), anyString(), isNull(), eq(0L), eq(10L))).thenReturn(List.of(flashBill));
|
|
|
|
|
+ when(bills.getmatlist(eq(8L), anyString(), isNull(), eq(0L), eq(10L))).thenReturn(List.of(flashBill));
|
|
|
|
|
+ var summary = new BillDTO(); summary.setSul(1); summary.setShouru(160); summary.setCommission(0); summary.setTax(0);
|
|
|
|
|
+ when(bills.getdaysum(eq(8L), anyString(), isNull())).thenReturn(summary);
|
|
|
|
|
+ when(bills.getmeeksum(eq(8L), anyString(), isNull())).thenReturn(summary);
|
|
|
|
|
+ when(bills.getmatsum(eq(8L), anyString(), isNull())).thenReturn(summary);
|
|
|
|
|
+ }
|
|
|
|
|
+ @AfterEach void cleanup() throws Exception {
|
|
|
|
|
+ tokens.close(); messages.close(); dictionaries.close(); mocks.close();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test void flashDayBillHasFlashDistanceFreightAndRating() {
|
|
|
|
|
+ var result = controller.getzddaylist("token", 1L, 10L, "2026-09-30", false, null);
|
|
|
|
|
+ assertFlash((com.alibaba.fastjson.JSONObject) result.get("data"));
|
|
|
|
|
+ // A flash order must not be treated as a food order by enrichment queries.
|
|
|
|
|
+ verify(foodOrders, never()).list(any(Wrapper.class));
|
|
|
|
|
+ verifyNoInteractions(foodRatings);
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void flashWeekBillUsesSameEnrichment() {
|
|
|
|
|
+ assertFlash((com.alibaba.fastjson.JSONObject) controller.getzdmeeklist("token", 1L, 10L, "2026-09-30", false, null).get("data"));
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void flashMonthBillUsesSameEnrichment() {
|
|
|
|
|
+ assertFlash((com.alibaba.fastjson.JSONObject) controller.getzdmatlist("token", 1L, 10L, "2026-09", false, null).get("data"));
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void mixedBillsPreserveFoodDetailsWithoutLeakingThemIntoFlash() {
|
|
|
|
|
+ var foodBill = new UserBilling(); foodBill.setDdId("991789000000000"); foodBill.setAmount(80.0);
|
|
|
|
|
+ when(bills.getdaylist(eq(8L), anyString(), isNull(), eq(0L), eq(10L))).thenReturn(List.of(foodBill, flashBill));
|
|
|
|
|
+ var food = new PosOrder(); food.setDdId("991789000000000"); food.setFreight(80.0); food.setJvli(2.5);
|
|
|
|
|
+ when(foodOrders.list(any(Wrapper.class))).thenReturn(List.of(food));
|
|
|
|
|
+ var data = (com.alibaba.fastjson.JSONObject) controller.getzddaylist("token", 1L, 10L, "2026-09-30", false, null).get("data");
|
|
|
|
|
+ List<QsBillingDto> list = (List<QsBillingDto>) data.get("list");
|
|
|
|
|
+ assertEquals("FOOD", list.get(0).getOrderSource());
|
|
|
|
|
+ assertEquals(80.0, list.get(0).getFreight()); assertEquals(2.5, list.get(0).getJvli());
|
|
|
|
|
+ assertEquals("FLASH", list.get(1).getOrderSource());
|
|
|
|
|
+ assertEquals(140.0, list.get(1).getFreight()); assertEquals(3.2, list.get(1).getJvli());
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void genericBillListKeepsPlatformWalletBalanceSeparateFromDirectIncome() {
|
|
|
|
|
+ var page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<UserBilling>(1, 10);
|
|
|
|
|
+ page.setRecords(List.of(flashBill));
|
|
|
|
|
+ when(billingService.page(any(com.baomidou.mybatisplus.extension.plugins.pagination.Page.class), any(Wrapper.class)))
|
|
|
|
|
+ .thenReturn(page);
|
|
|
|
|
+ when(billingService.getUserBalance(8L)).thenReturn(new java.math.BigDecimal("77.00"));
|
|
|
|
|
+ var data = (com.alibaba.fastjson.JSONObject) controller.getUsbalance("token", 1, 10, false, "").get("data");
|
|
|
|
|
+ assertEquals(new java.math.BigDecimal("77.00"), data.get("sum"));
|
|
|
|
|
+ var list = (com.alibaba.fastjson.JSONArray) data.get("list");
|
|
|
|
|
+ assertEquals("FLASH", list.getJSONObject(0).getString("orderSource"));
|
|
|
|
|
+ assertEquals(160.0, list.getJSONObject(0).getDouble("amount"));
|
|
|
|
|
+ verifyNoInteractions(foodOrders);
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void flashDetailLookupRestrictsBothRiderAndOrderNumber() {
|
|
|
|
|
+ com.baomidou.mybatisplus.core.metadata.TableInfoHelper.initTableInfo(
|
|
|
|
|
+ new org.apache.ibatis.builder.MapperBuilderAssistant(new com.baomidou.mybatisplus.core.MybatisConfiguration(), "test"),
|
|
|
|
|
+ FlashDeliveryOrder.class);
|
|
|
|
|
+ controller.getzddaylist("token", 1L, 10L, "2026-09-30", false, null);
|
|
|
|
|
+ var query = ArgumentCaptor.forClass(com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper.class);
|
|
|
|
|
+ verify(flashOrders).selectList(query.capture());
|
|
|
|
|
+ String sql = query.getValue().getSqlSegment();
|
|
|
|
|
+ assertTrue(sql.contains("rider_id ="), sql); assertTrue(sql.contains("order_no IN"), sql);
|
|
|
|
|
+ assertTrue(query.getValue().getParamNameValuePairs().containsValue(8L));
|
|
|
|
|
+ assertTrue(query.getValue().getParamNameValuePairs().containsValue("98178900000000001"));
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void missingFlashOrderDoesNotHideRecordedIncomeOrFallBackToFood() {
|
|
|
|
|
+ when(flashOrders.selectList(any(Wrapper.class))).thenReturn(List.of());
|
|
|
|
|
+ var data = (com.alibaba.fastjson.JSONObject) controller.getzddaylist("token", 1L, 10L, "2026-09-30", false, null).get("data");
|
|
|
|
|
+ var list = (List<QsBillingDto>) data.get("list");
|
|
|
|
|
+ assertEquals(160.0, list.get(0).getAmount()); assertEquals("FLASH", list.get(0).getOrderSource());
|
|
|
|
|
+ assertNull(list.get(0).getFlashOrderId()); assertNull(list.get(0).getFreight());
|
|
|
|
|
+ verify(foodOrders, never()).list(any(Wrapper.class));
|
|
|
|
|
+ verifyNoInteractions(foodRatings);
|
|
|
|
|
+ }
|
|
|
|
|
+ @Test void legacyWalletBillListDoesNotLookUpFlashNumbersInFoodOrders() {
|
|
|
|
|
+ var walletController = new WalletController();
|
|
|
|
|
+ org.springframework.test.util.ReflectionTestUtils.setField(walletController, "userBillingService", billingService);
|
|
|
|
|
+ org.springframework.test.util.ReflectionTestUtils.setField(walletController, "posOrderService", foodOrders);
|
|
|
|
|
+ var page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<UserBilling>(1, 10);
|
|
|
|
|
+ page.setRecords(List.of(flashBill));
|
|
|
|
|
+ when(billingService.page(any(com.baomidou.mybatisplus.core.metadata.IPage.class), any(Wrapper.class))).thenReturn(page);
|
|
|
|
|
+ walletController.getUserBills("token", 1, 10, "0");
|
|
|
|
|
+ verifyNoInteractions(foodOrders);
|
|
|
|
|
+ }
|
|
|
|
|
+ private void assertFlash(com.alibaba.fastjson.JSONObject data) {
|
|
|
|
|
+ List<QsBillingDto> list = (List<QsBillingDto>) data.get("list");
|
|
|
|
|
+ assertEquals(1, list.size());
|
|
|
|
|
+ var bill = list.get(0);
|
|
|
|
|
+ assertEquals("FLASH", bill.getOrderSource()); assertEquals(160.0, bill.getAmount());
|
|
|
|
|
+ assertEquals(10L, bill.getFlashOrderId()); assertEquals(20L, bill.getTipAmount());
|
|
|
|
|
+ assertEquals(0, bill.getPaymentStatus());
|
|
|
|
|
+ assertEquals(140.0, bill.getFreight()); assertEquals(3.2, bill.getJvli());
|
|
|
|
|
+ assertEquals(4.5, bill.getQsStarts()); assertEquals("6", bill.getPayType());
|
|
|
|
|
+ }
|
|
|
|
|
+}
|