| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- package com.ruoyi.app.order;
- import com.baomidou.mybatisplus.core.conditions.Wrapper;
- import com.ruoyi.app.order.dto.AdminOrderActionRequest;
- import com.ruoyi.app.order.dto.AdminOrderStatusContext;
- import com.ruoyi.app.order.dto.AdminOrderStatusUpdateRequest;
- import com.ruoyi.common.exception.ServiceException;
- import com.ruoyi.system.domain.PosOrder;
- import com.ruoyi.system.domain.PosOrderOmgPayment;
- import com.ruoyi.system.domain.PosOrderOmgRefund;
- import com.ruoyi.system.service.IPosOrderOmgPaymentService;
- import com.ruoyi.system.service.IPosOrderOmgRefundService;
- import com.ruoyi.system.service.IPosOrderService;
- import com.ruoyi.system.service.IPointsTransactionService;
- import com.ruoyi.system.service.IUserWalletService;
- import com.ruoyi.system.utils.OrderLogHelper;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import java.util.List;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertFalse;
- import static org.junit.jupiter.api.Assertions.assertNotNull;
- import static org.junit.jupiter.api.Assertions.assertThrows;
- import static org.junit.jupiter.api.Assertions.assertTrue;
- import static org.mockito.ArgumentMatchers.any;
- import static org.mockito.ArgumentMatchers.anyInt;
- import static org.mockito.ArgumentMatchers.anyLong;
- import static org.mockito.ArgumentMatchers.anyString;
- import static org.mockito.Mockito.doAnswer;
- import static org.mockito.Mockito.mock;
- import static org.mockito.Mockito.never;
- import static org.mockito.Mockito.verify;
- import static org.mockito.Mockito.when;
- class OrderLifecycleServiceTest {
- private IPosOrderService posOrderService;
- private OrderService billingService;
- private OrderLogHelper orderLogHelper;
- private IUserWalletService userWalletService;
- private IPointsTransactionService pointsTransactionService;
- private IPosOrderOmgPaymentService omgPaymentService;
- private IPosOrderOmgRefundService omgRefundService;
- private OrderLifecycleService service;
- @BeforeEach
- void setUp() {
- posOrderService = mock(IPosOrderService.class);
- billingService = mock(OrderService.class);
- orderLogHelper = mock(OrderLogHelper.class);
- userWalletService = mock(IUserWalletService.class);
- pointsTransactionService = mock(IPointsTransactionService.class);
- omgPaymentService = mock(IPosOrderOmgPaymentService.class);
- omgRefundService = mock(IPosOrderOmgRefundService.class);
- service = new OrderLifecycleService(posOrderService, billingService, orderLogHelper,
- userWalletService, pointsTransactionService, omgPaymentService, omgRefundService);
- }
- @Test
- void exposesOnlyLegalNextOrderAndDeliveryStates() {
- PosOrder order = deliveryOrder();
- when(posOrderService.getById(10L)).thenReturn(order);
- PosOrderOmgPayment payment = new PosOrderOmgPayment();
- payment.setId(1L);
- payment.setPayStatus(1);
- when(omgPaymentService.getLatestByDdId(order.getDdId())).thenReturn(payment);
- when(omgRefundService.listByPayment(1L)).thenReturn(List.of());
- AdminOrderStatusContext context = service.getStatusContext(10L);
- assertEquals(List.of(2L), context.getAllowedOrderStates());
- assertEquals(List.of(2L, 3L), context.getAllowedDeliveryStatuses());
- assertTrue(context.getCanRefundOmg());
- assertFalse(context.getCanConfirmOfflinePayment());
- }
- @Test
- void marksDeliveryAsDeliveredAndCompletesExactlyOnce() {
- PosOrder order = deliveryOrder();
- when(posOrderService.getById(10L)).thenReturn(order);
- doAnswer(invocation -> {
- PosOrder update = invocation.getArgument(0);
- order.setState(update.getState());
- order.setDeliveryStatus(update.getDeliveryStatus());
- order.setPayStatus(update.getPayStatus());
- order.setAfterSaleStatus(update.getAfterSaleStatus());
- order.setSdTime(update.getSdTime());
- return true;
- }).when(posOrderService).update(any(PosOrder.class), any(Wrapper.class));
- AdminOrderStatusUpdateRequest request = statusRequest(2L, 2L, 1L, 0L);
- request.setTargetDeliveryStatus(3L);
- request.setReason("骑手端漏操作");
- AdminOrderStatusContext context = service.updateStatus(10L, request, 99L, "平台管理员");
- assertEquals(3L, context.getState());
- assertEquals(3L, context.getDeliveryStatus());
- assertNotNull(context.getSdTime());
- verify(billingService).setSanghuBilling(order);
- verify(billingService).setQishouBilling(order);
- verify(orderLogHelper).logSync(anyString(), anyInt(), anyLong(), anyString(), anyString());
- }
- @Test
- void staleSnapshotHasNoSideEffects() {
- PosOrder order = deliveryOrder();
- order.setPayStatus(0L);
- when(posOrderService.getById(10L)).thenReturn(order);
- AdminOrderStatusUpdateRequest request = statusRequest(2L, 2L, 1L, 0L);
- request.setTargetDeliveryStatus(3L);
- request.setReason("陈旧页面提交");
- ServiceException error = assertThrows(ServiceException.class,
- () -> service.updateStatus(10L, request, 99L, "平台管理员"));
- assertTrue(error.getMessage().contains("状态已变化"));
- verify(posOrderService, never()).update(any(PosOrder.class), any(Wrapper.class));
- verify(billingService, never()).setSanghuBilling(any());
- verify(orderLogHelper, never()).logSync(anyString(), anyInt(), any(), anyString(), anyString());
- }
- @Test
- void casFailureAfterReadHasNoSideEffects() {
- PosOrder order = deliveryOrder();
- when(posOrderService.getById(10L)).thenReturn(order);
- when(posOrderService.update(any(PosOrder.class), any(Wrapper.class))).thenReturn(false);
- AdminOrderStatusUpdateRequest request = statusRequest(2L, 2L, 1L, 0L);
- request.setTargetDeliveryStatus(3L);
- request.setReason("并发提交");
- ServiceException error = assertThrows(ServiceException.class,
- () -> service.updateStatus(10L, request, 99L, "平台管理员"));
- assertTrue(error.getMessage().contains("状态已变化"));
- verify(billingService, never()).setSanghuBilling(any());
- verify(orderLogHelper, never()).logSync(anyString(), anyInt(), any(), anyString(), anyString());
- }
- @Test
- void rejectsDeliveryRollback() {
- PosOrder order = deliveryOrder();
- when(posOrderService.getById(10L)).thenReturn(order);
- AdminOrderStatusUpdateRequest request = statusRequest(2L, 2L, 1L, 0L);
- request.setTargetDeliveryStatus(1L);
- request.setReason("错误回退");
- assertThrows(ServiceException.class,
- () -> service.updateStatus(10L, request, 99L, "平台管理员"));
- verify(posOrderService, never()).update(any(PosOrder.class), any(Wrapper.class));
- }
- @Test
- void confirmsOnlyOfflinePayment() {
- PosOrder order = pickupOrder("1", 0L);
- when(posOrderService.getById(20L)).thenReturn(order);
- doAnswer(invocation -> {
- PosOrder update = invocation.getArgument(0);
- order.setPayStatus(update.getPayStatus());
- return true;
- }).when(posOrderService).update(any(PosOrder.class), any(Wrapper.class));
- AdminOrderStatusContext context = service.confirmOfflinePayment(20L,
- actionRequest(2L, null, 0L, 0L, "门店已收现金"), 99L, "平台管理员");
- assertEquals(1L, context.getPayStatus());
- verify(orderLogHelper).logSync(anyString(), anyInt(), anyLong(), anyString(), anyString());
- }
- @Test
- void rejectsOmgOrderFromOfflinePaymentPath() {
- PosOrder order = pickupOrder("7", 0L);
- when(posOrderService.getById(20L)).thenReturn(order);
- assertThrows(ServiceException.class, () -> service.confirmOfflinePayment(20L,
- actionRequest(2L, null, 0L, 0L, "不能伪造在线支付"), 99L, "平台管理员"));
- verify(posOrderService, never()).update(any(PosOrder.class), any(Wrapper.class));
- }
- @Test
- void offlineRefundSynchronizesAllBusinessStates() {
- PosOrder order = pickupOrder("1", 1L);
- order.setState(1L);
- when(posOrderService.getById(20L)).thenReturn(order);
- doAnswer(invocation -> {
- PosOrder update = invocation.getArgument(0);
- order.setState(update.getState());
- order.setPayStatus(update.getPayStatus());
- order.setAfterSaleStatus(update.getAfterSaleStatus());
- return true;
- }).when(posOrderService).update(any(PosOrder.class), any(Wrapper.class));
- AdminOrderStatusContext context = service.confirmOfflineRefund(20L,
- actionRequest(1L, null, 1L, 0L, "已现场退还现金"), 99L, "平台管理员");
- assertEquals(4L, context.getState());
- assertEquals(2L, context.getPayStatus());
- assertEquals(3L, context.getAfterSaleStatus());
- }
- @Test
- void completedOrderCannotBeRefunded() {
- PosOrder order = pickupOrder("1", 1L);
- order.setState(3L);
- when(posOrderService.getById(20L)).thenReturn(order);
- assertThrows(ServiceException.class, () -> service.confirmOfflineRefund(20L,
- actionRequest(3L, null, 1L, 0L, "申请退款"), 99L, "平台管理员"));
- verify(posOrderService, never()).update(any(PosOrder.class), any(Wrapper.class));
- }
- @Test
- void blankReasonIsRejectedBeforeAnyWrite() {
- PosOrder order = pickupOrder("1", 0L);
- when(posOrderService.getById(20L)).thenReturn(order);
- assertThrows(ServiceException.class, () -> service.confirmOfflinePayment(20L,
- actionRequest(2L, null, 0L, 0L, " "), 99L, "平台管理员"));
- verify(posOrderService, never()).update(any(PosOrder.class), any(Wrapper.class));
- }
- @Test
- void riderDeliveryCompletesCashOrderAndPreservesInvariant() {
- PosOrder order = deliveryOrder();
- order.setPayType("1");
- order.setCollectPayment("1");
- order.setPayStatus(0L);
- when(posOrderService.getById(10L)).thenReturn(order);
- doAnswer(invocation -> {
- PosOrder update = invocation.getArgument(0);
- order.setState(update.getState());
- order.setDeliveryStatus(update.getDeliveryStatus());
- order.setPayStatus(update.getPayStatus());
- order.setSdTime(update.getSdTime());
- return true;
- }).when(posOrderService).update(any(PosOrder.class), any(Wrapper.class));
- AdminOrderStatusContext context = service.completeDeliveryByRider(10L, 88L, "骑手甲");
- assertEquals(3L, context.getState());
- assertEquals(3L, context.getDeliveryStatus());
- assertEquals(1L, context.getPayStatus());
- verify(billingService).setSanghuBilling(order);
- verify(billingService).setQishouBilling(order);
- }
- @Test
- void synchronizesSystemOmgRefundToAllThreeBusinessStates() {
- PosOrder order = pickupOrder("7", 1L);
- order.setState(1L);
- when(posOrderService.getById(20L)).thenReturn(order);
- doAnswer(invocation -> {
- PosOrder update = invocation.getArgument(0);
- order.setState(update.getState());
- order.setPayStatus(update.getPayStatus());
- order.setAfterSaleStatus(update.getAfterSaleStatus());
- return true;
- }).when(posOrderService).update(any(PosOrder.class), any(Wrapper.class));
- AdminOrderStatusContext context = service.finalizeSystemOmgRefund(20L);
- assertEquals(4L, context.getState());
- assertEquals(2L, context.getPayStatus());
- assertEquals(3L, context.getAfterSaleStatus());
- verify(orderLogHelper).logSync(anyString(), anyInt(), any(), anyString(), anyString());
- }
- @Test
- void exposesManualRefundLocalCompensationAfterLedgerAlreadyCompleted() {
- PosOrder order = pickupOrder("7", 1L);
- order.setState(1L);
- PosOrderOmgPayment payment = new PosOrderOmgPayment();
- payment.setId(3L);
- payment.setPayStatus(3);
- payment.setPayType("ATM_TAISHIN");
- PosOrderOmgRefund completed = new PosOrderOmgRefund();
- completed.setRtnCode(1);
- when(posOrderService.getById(20L)).thenReturn(order);
- when(omgPaymentService.getLatestByDdId(order.getDdId())).thenReturn(payment);
- when(omgRefundService.listByPayment(3L)).thenReturn(List.of(completed));
- AdminOrderStatusContext context = service.getStatusContext(20L);
- assertTrue(context.getCanConfirmManualOmgRefund());
- assertFalse(context.getCanRefundOmg());
- assertFalse(context.getManualRefundPending());
- }
- private PosOrder deliveryOrder() {
- PosOrder order = new PosOrder();
- order.setId(10L);
- order.setDdId("202608100001");
- order.setType(0L);
- order.setPayType("7");
- order.setState(2L);
- order.setDeliveryStatus(2L);
- order.setPayStatus(1L);
- order.setAfterSaleStatus(0L);
- order.setQsId(88L);
- order.setShId(66L);
- order.setMdId(77L);
- order.setAmount(100);
- order.setFood("[]");
- order.setFreight(10D);
- return order;
- }
- private PosOrder pickupOrder(String payType, Long payStatus) {
- PosOrder order = new PosOrder();
- order.setId(20L);
- order.setDdId("202608100002");
- order.setType(1L);
- order.setPayType(payType);
- order.setState(2L);
- order.setPayStatus(payStatus);
- order.setAfterSaleStatus(0L);
- return order;
- }
- private AdminOrderStatusUpdateRequest statusRequest(Long state, Long delivery, Long pay, Long afterSale) {
- AdminOrderStatusUpdateRequest request = new AdminOrderStatusUpdateRequest();
- request.setExpectedState(state);
- request.setExpectedDeliveryStatus(delivery);
- request.setExpectedPayStatus(pay);
- request.setExpectedAfterSaleStatus(afterSale);
- return request;
- }
- private AdminOrderActionRequest actionRequest(Long state, Long delivery, Long pay, Long afterSale,
- String reason) {
- AdminOrderActionRequest request = new AdminOrderActionRequest();
- request.setExpectedState(state);
- request.setExpectedDeliveryStatus(delivery);
- request.setExpectedPayStatus(pay);
- request.setExpectedAfterSaleStatus(afterSale);
- request.setReason(reason);
- return request;
- }
- }
|