|
|
@@ -0,0 +1,105 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.etotem.cfc.entity.ProductOrder;
|
|
|
+import com.etotem.cfc.entity.ProductSku;
|
|
|
+import com.etotem.cfc.entity.ProductSkuComboItem;
|
|
|
+import com.etotem.cfc.service.InventoryService;
|
|
|
+import com.etotem.cfc.service.ProductOrderService;
|
|
|
+import com.etotem.cfc.service.ProductService;
|
|
|
+import com.etotem.cfc.service.ProductSkuService;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.springframework.test.util.ReflectionTestUtils;
|
|
|
+
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组合 SKU 支付扣减 / 退款回补单测(TDD)。
|
|
|
+ * 关键断言:子 SKU 与子商品分别扣减/回补,父商品库存不参与扣减与回补。
|
|
|
+ */
|
|
|
+class ProductOrderComboStockTest {
|
|
|
+
|
|
|
+ private ProductOrderService orderService;
|
|
|
+ private ProductSkuService skuService;
|
|
|
+ private ProductService productService;
|
|
|
+ private InventoryService inventoryService;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ void setUp() {
|
|
|
+ orderService = new ProductOrderService();
|
|
|
+ skuService = mock(ProductSkuService.class);
|
|
|
+ productService = mock(ProductService.class);
|
|
|
+ inventoryService = mock(InventoryService.class);
|
|
|
+ ReflectionTestUtils.setField(orderService, "productSkuService", skuService);
|
|
|
+ ReflectionTestUtils.setField(orderService, "productService", productService);
|
|
|
+ ReflectionTestUtils.setField(orderService, "inventoryService", inventoryService);
|
|
|
+ }
|
|
|
+
|
|
|
+ private ProductSku combo() {
|
|
|
+ ProductSkuComboItem a = new ProductSkuComboItem();
|
|
|
+ a.setChildProductId(10L); a.setChildSkuId(100L); a.setQuantity(2);
|
|
|
+ ProductSkuComboItem b = new ProductSkuComboItem();
|
|
|
+ b.setChildProductId(11L); b.setChildSkuId(null); b.setQuantity(1);
|
|
|
+ ProductSku sku = new ProductSku();
|
|
|
+ sku.setId(9L);
|
|
|
+ sku.setComboItems(Arrays.asList(a, b));
|
|
|
+ return sku;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ProductOrder order() {
|
|
|
+ ProductOrder o = new ProductOrder();
|
|
|
+ o.setId(77L);
|
|
|
+ o.setOrderNo("PO1");
|
|
|
+ o.setSkuId(9L);
|
|
|
+ o.setQuantity(3);
|
|
|
+ return o;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void deductComboStock_childSku_decreasesSkuAndRecordsOutbound() {
|
|
|
+ when(skuService.decreaseStock(100L, 6)).thenReturn(true);
|
|
|
+ when(productService.decreaseStock(11L, 3)).thenReturn(true);
|
|
|
+
|
|
|
+ orderService.deductComboStock(combo(), order(), "PO1");
|
|
|
+
|
|
|
+ verify(skuService).decreaseStock(100L, 6);
|
|
|
+ verify(inventoryService).recordOutbound(10L, 100L, 6, "order", 77L, null, "组合出库:PO1");
|
|
|
+ verify(productService).decreaseStock(11L, 3);
|
|
|
+ verify(inventoryService).recordOutbound(11L, null, 3, "order", 77L, null, "组合出库:PO1");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void deductComboStock_insufficient_throws() {
|
|
|
+ when(skuService.decreaseStock(100L, 6)).thenReturn(false);
|
|
|
+
|
|
|
+ assertThrows(RuntimeException.class, () -> orderService.deductComboStock(combo(), order(), "PO1"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void restockComboOrder_nonCombo_returnsFalse() {
|
|
|
+ when(skuService.getById(9L)).thenReturn(new ProductSku());
|
|
|
+ when(skuService.hasComboItems(any())).thenReturn(false);
|
|
|
+
|
|
|
+ assertFalse(orderService.restockComboOrder(order()));
|
|
|
+ verify(productService, never()).increaseStock(anyLong(), anyInt());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void restockComboOrder_combo_restocksChildrenOnly() {
|
|
|
+ ProductSku sku = combo();
|
|
|
+ when(skuService.getById(9L)).thenReturn(sku);
|
|
|
+ when(skuService.hasComboItems(sku)).thenReturn(true);
|
|
|
+
|
|
|
+ assertTrue(orderService.restockComboOrder(order()));
|
|
|
+
|
|
|
+ verify(skuService).increaseStock(100L, 6);
|
|
|
+ verify(inventoryService).recordRefundInbound(10L, 100L, 6, "order", 77L, null, "组合退款入库:PO1");
|
|
|
+ verify(productService).increaseStock(11L, 3);
|
|
|
+ // 父商品(order.productId)不得回补:本用例未设置 productId,仍断言未调用
|
|
|
+ verify(productService, never()).increaseStock(null, 3);
|
|
|
+ }
|
|
|
+}
|