Prechádzať zdrojové kódy

feat: 库存管理 - 订单集成(支付/取消/退款库存流水 + bundle穿透)

Xiaogang Liao 1 mesiac pred
rodič
commit
c97ceeee83

+ 54 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/ProductOrderService.java

@@ -10,6 +10,7 @@ import com.etotem.cfc.dto.ProductOrderDTO;
 import com.etotem.cfc.entity.AfterSalesRequest;
 import com.etotem.cfc.entity.AssessmentProduct;
 import com.etotem.cfc.entity.Product;
+import com.etotem.cfc.entity.ProductBundleItem;
 import com.etotem.cfc.entity.ProductGiftRule;
 import com.etotem.cfc.entity.ProductOrder;
 import com.etotem.cfc.entity.User;
@@ -20,7 +21,9 @@ import com.etotem.cfc.service.SupplyHierarchyService;
 import com.etotem.cfc.mapper.ProductMapper;
 import com.etotem.cfc.mapper.ProductOrderMapper;
 import com.etotem.cfc.mapper.UserMapper;
+import com.etotem.cfc.entity.ProductBundleItem;
 import com.etotem.cfc.entity.ProductSku;
+import com.etotem.cfc.mapper.ProductBundleItemMapper;
 import com.etotem.cfc.service.ProductSkuService;
 import com.etotem.cfc.service.CommissionService;
 import com.etotem.cfc.service.AssessmentProductService;
@@ -63,6 +66,12 @@ public class ProductOrderService {
     @Resource
     private ProductSkuService productSkuService;
 
+    @Resource
+    private InventoryService inventoryService;
+
+    @Resource
+    private ProductBundleItemMapper bundleItemMapper;
+
     @Resource
     private CommissionService commissionService;
 
@@ -124,6 +133,13 @@ public class ProductOrderService {
                 && product.getStock() < dto.getQuantity()) {
             return Result.error("库存不足");
         }
+        // 套餐商品:检查子商品库存
+        if ("bundle".equals(product.getProductType())) {
+            Result<String> bundleCheck = inventoryService.checkBundleStock(product.getId(), dto.getQuantity());
+            if (bundleCheck.getCode() != 200) {
+                return Result.error(bundleCheck.getMessage());
+            }
+        }
         // 校验最小购买数量
         if (product.getMinQuantity() != null && product.getMinQuantity() > 1
                 && dto.getQuantity() < product.getMinQuantity()) {
@@ -190,6 +206,13 @@ public class ProductOrderService {
                     && product.getStock() < item.getQuantity()) {
                 return Result.error("库存不足: " + product.getName());
             }
+            // 套餐商品:检查子商品库存
+            if ("bundle".equals(product.getProductType())) {
+                Result<String> bundleCheck = inventoryService.checkBundleStock(product.getId(), item.getQuantity());
+                if (bundleCheck.getCode() != 200) {
+                    return Result.error(bundleCheck.getMessage());
+                }
+            }
             int unitPrice = product.getPrice();
             if (item.getSkuId() != null) {
                 ProductSku sku = productSkuService.getById(item.getSkuId());
@@ -313,6 +336,32 @@ public class ProductOrderService {
                 orderMapper.updateById(order);
                 throw new RuntimeException("库存不足");
             }
+            // 记录出库流水
+            inventoryService.recordOutbound(order.getProductId(), null, order.getQuantity(),
+                    "order", order.getId(), null, "订单支付:" + orderNo);
+        } else if (paidProduct != null && "bundle".equals(paidProduct.getProductType())) {
+            // 套餐商品:穿透到子商品扣减库存
+            List<ProductBundleItem> bundleItems = bundleItemMapper.selectList(
+                    new LambdaQueryWrapper<ProductBundleItem>()
+                            .eq(ProductBundleItem::getBundleProductId, paidProduct.getId()));
+            for (ProductBundleItem bi : bundleItems) {
+                int need = bi.getQuantity() * order.getQuantity();
+                if (bi.getChildSkuId() != null) {
+                    boolean skuOk = productSkuService.decreaseStock(bi.getChildSkuId(), need);
+                    if (!skuOk) {
+                        throw new RuntimeException("套餐子商品库存不足: bundleItemId=" + bi.getId());
+                    }
+                    inventoryService.recordOutbound(bi.getChildProductId(), bi.getChildSkuId(), need,
+                            "order", order.getId(), null, "套餐出库:" + orderNo);
+                } else {
+                    boolean stockOk = productService.decreaseStock(bi.getChildProductId(), need);
+                    if (!stockOk) {
+                        throw new RuntimeException("套餐子商品库存不足: bundleItemId=" + bi.getId());
+                    }
+                    inventoryService.recordOutbound(bi.getChildProductId(), null, need,
+                            "order", order.getId(), null, "套餐出库:" + orderNo);
+                }
+            }
         }
         order.setStatus("paid");
         order.setTransactionId(transactionId);
@@ -412,6 +461,9 @@ public class ProductOrderService {
         orderMapper.updateById(order);
         // Restore stock on cancel
         productService.increaseStock(order.getProductId(), order.getQuantity());
+        // 记录退款入库流水
+        inventoryService.recordRefundInbound(order.getProductId(), null, order.getQuantity(),
+                "order", order.getId(), null, "取消订单:" + orderNo);
         return Result.success("订单已取消");
     }
 
@@ -514,6 +566,8 @@ public class ProductOrderService {
         order.setUpdatedAt(new Date());
         orderMapper.updateById(order);
         productService.increaseStock(order.getProductId(), order.getQuantity());
+        inventoryService.recordRefundInbound(order.getProductId(), null, order.getQuantity(),
+                "order", order.getId(), adminId, "退款:" + orderNo);
         syncAfterSalesRequestStatus(orderNo, "approved", adminId);
         log.info("退款完成: orderNo={}, adminId={}", orderNo, adminId);
         return Result.success("退款已处理");