From 6d31d535d737ed26c4d9d61cd4e0b5483cb9b0ba Mon Sep 17 00:00:00 2001
From: xin <1099200748@qq.com>
Date: Wed, 17 Sep 2025 19:44:00 +0800
Subject: [PATCH] Merge branch 'refs/heads/master' into xin

---
 oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java  |   19 ---
 oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductInventoryUpdateRequest.java |   13 ++
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java              |    3 
 oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java                   |    7 +
 oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java              |    3 
 oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductInventoryServiceImpl.java |   59 +++++++++++
 oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java                   |    4 
 oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java              |    3 
 oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java          |   16 ++
 oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductStockMapper.java                |   23 ++++
 oying-system/src/main/java/com/oying/modules/pc/product/service/ProductInventoryService.java          |   11 ++
 oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductInventoryController.java          |   54 ++++++++++
 oying-system/src/main/resources/mapper/pc/product/ProductStockMapper.xml                              |   49 +++++++++
 13 files changed, 239 insertions(+), 25 deletions(-)

diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductInventoryUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductInventoryUpdateRequest.java
new file mode 100644
index 0000000..2bc2000
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductInventoryUpdateRequest.java
@@ -0,0 +1,13 @@
+package com.oying.modules.pc.product.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class ProductInventoryUpdateRequest {
+
+    private Long productId;
+    private Integer quantity;
+    private Integer amount;
+    private Long version;
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductStockMapper.java b/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductStockMapper.java
new file mode 100644
index 0000000..227cea8
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductStockMapper.java
@@ -0,0 +1,23 @@
+package com.oying.modules.pc.product.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.oying.modules.pc.product.domain.Product;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface ProductStockMapper extends BaseMapper<Product> {
+
+    List<Product> selectLowStockProducts(@Param("threshold") Integer threshold);
+
+    int updateStock(@Param("productId") Long productId, @Param("quantity") Integer quantity, @Param("version") Long version);
+
+    int increaseStock(@Param("productId") Long productId, @Param("amount") Integer amount, @Param("version") Long version);
+
+    int decreaseStock(@Param("productId") Long productId, @Param("amount") Integer amount, @Param("version") Long version);
+
+    int batchUpdateStock(List<Product> products);
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductInventoryController.java b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductInventoryController.java
new file mode 100644
index 0000000..7d5d4ca
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductInventoryController.java
@@ -0,0 +1,54 @@
+package com.oying.modules.pc.product.rest;
+
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.domain.dto.ProductInventoryUpdateRequest;
+import com.oying.modules.pc.product.service.ProductInventoryService;
+import com.oying.utils.R;
+import io.swagger.annotations.Api;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Optional;
+
+/**
+ * @author lzp
+ * @date 2025-09-10
+ **/
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "商品库存")
+@RequestMapping("/api/pc/product/{productId}/inventory")
+public class ProductInventoryController {
+
+    private final ProductInventoryService productInventoryService;
+
+    @GetMapping
+    public ResponseEntity<?> getStockInfo(@PathVariable Long productId) {
+        return ResponseEntity.ok(R.success(productInventoryService.getProductById(productId)));
+    }
+
+    @PutMapping
+    public ResponseEntity<?> setStock(@PathVariable Long productId, @RequestBody ProductInventoryUpdateRequest request) {
+        Product product = productInventoryService.setStockQuantity(Optional.ofNullable(request.getProductId()).orElse(productId), request.getQuantity(), request.getVersion());
+        return ResponseEntity.ok(R.success(product));
+    }
+
+    @PostMapping("/increase")
+    public ResponseEntity<?> increaseStock(@PathVariable Long productId, @RequestBody ProductInventoryUpdateRequest request) {
+        Product product = productInventoryService.increaseStock(Optional.ofNullable(request.getProductId()).orElse(productId), request.getAmount());
+        return ResponseEntity.ok(R.success(product));
+    }
+
+    @PostMapping("/decrease")
+    public ResponseEntity<?> decreaseStock(@PathVariable Long productId, @RequestBody ProductInventoryUpdateRequest request) {
+        Product product = productInventoryService.decreaseStock(Optional.ofNullable(request.getProductId()).orElse(productId), request.getAmount());
+        return ResponseEntity.ok(R.success(product));
+    }
+
+    @GetMapping("/sufficient")
+    public ResponseEntity<?> checkStockSufficient(@PathVariable Long productId, @RequestParam Integer requiredAmount) {
+        boolean isSufficient = productInventoryService.isStockSufficient(productId, requiredAmount);
+        return ResponseEntity.ok(R.success(isSufficient));
+    }
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductInventoryService.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductInventoryService.java
new file mode 100644
index 0000000..c425722
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductInventoryService.java
@@ -0,0 +1,11 @@
+package com.oying.modules.pc.product.service;
+
+import com.oying.modules.pc.product.domain.Product;
+
+public interface ProductInventoryService {
+    Product getProductById(Long id);
+    Product setStockQuantity(Long product, Integer quantity, Long version);
+    Product increaseStock(Long product, Integer amount);
+    Product decreaseStock(Long product, Integer amount);
+    boolean isStockSufficient(Long productId, Integer requiredAmount);
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java
index a610f1d..026338f 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java
@@ -33,6 +33,13 @@
     List<Product> queryAll(ProductQueryCriteria criteria);
 
     /**
+     * 根据ID查询数据
+     * @param productId ID
+     * @return product
+     */
+    Product getProduct(Long productId);
+
+    /**
     * 创建
     * @param resources /
     */
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductInventoryServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductInventoryServiceImpl.java
new file mode 100644
index 0000000..896cb23
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductInventoryServiceImpl.java
@@ -0,0 +1,59 @@
+package com.oying.modules.pc.product.service.impl;
+
+import com.oying.modules.pc.product.domain.Product;
+import com.oying.modules.pc.product.mapper.ProductStockMapper;
+import com.oying.modules.pc.product.service.ProductInventoryService;
+import com.oying.modules.pc.product.service.ProductService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class ProductInventoryServiceImpl implements ProductInventoryService {
+
+    private final ProductStockMapper productStockMapper;
+    private final ProductService productService;
+
+    @Override
+    public Product getProductById(Long productId) {
+        return productService.getProduct(productId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Product setStockQuantity(Long productId, Integer quantity, Long version) {
+        Product existingProduct = this.getProductById(productId);
+        productStockMapper.updateStock(productId, quantity, existingProduct.getVersion());
+        return this.getProductById(productId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Product increaseStock(Long productId, Integer amount) {
+        Product existingProduct = this.getProductById(productId);
+        productStockMapper.increaseStock(productId, amount, existingProduct.getVersion());
+        return getProductById(productId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Product decreaseStock(Long productId, Integer amount) {
+        Product existingProduct = this.getProductById(productId);
+        if (existingProduct.getStockQuantity() < amount) {
+            throw new RuntimeException("库存不足,当前库存: " + existingProduct.getStockQuantity() + ", 请求数量: " + amount);
+        }
+        productStockMapper.decreaseStock(productId, amount, existingProduct.getVersion());
+        return getProductById(productId);
+    }
+
+    @Override
+    public boolean isStockSufficient(Long productId, Integer requiredAmount) {
+        if (requiredAmount == null || requiredAmount <= 0) {
+            throw new IllegalArgumentException("需求数量必须大于0");
+        }
+        Product existingProduct = this.getProductById(productId);
+        return existingProduct.getStockQuantity() >= requiredAmount;
+    }
+
+}
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java
index 24ed038..e4eef20 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java
@@ -1,11 +1,9 @@
 package com.oying.modules.pc.product.service.impl;
 
 import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.ObjUtil;
 import com.alibaba.fastjson2.JSON;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.oying.exception.BadRequestException;
-import com.oying.exception.EntityNotFoundException;
 import com.oying.modules.pc.common.core.constrant.AuditStatusEnum;
 import com.oying.modules.pc.product.converter.ProductImageAssembler;
 import com.oying.modules.pc.product.converter.ProductLabelAssembler;
@@ -30,7 +28,6 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -77,7 +74,7 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void update(ProductMerchantUpdateRequest request) {
-        Product existingProduct = this.findOrThrow(request.getProductId());
+        Product existingProduct = productService.getProduct(request.getProductId());
         this.validateApprovedStatus(existingProduct.getShelfStatus());
         this.processImagesUpdate(request);
         this.processLabelsUpdate(request);
@@ -88,18 +85,16 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateImages(ProductMerchantUpdateRequest request) {
-        Product existingProduct = this.findOrThrow(request.getProductId());
+        Product existingProduct = productService.getProduct(request.getProductId());
         this.validateApprovedStatus(existingProduct.getShelfStatus());
-        this.findOrThrow(request.getProductId());
         this.processImagesUpdate(request);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateLabels(ProductMerchantUpdateRequest request) {
-        Product existingProduct = this.findOrThrow(request.getProductId());
+        Product existingProduct = productService.getProduct(request.getProductId());
         this.validateApprovedStatus(existingProduct.getShelfStatus());
-        this.findOrThrow(request.getProductId());
         this.processImagesUpdate(request);
     }
 
@@ -160,14 +155,6 @@
         } catch (Exception e) {
             log.error("处理商品审核结果异常", e);
         }
-    }
-
-    private Product findOrThrow(Long productId) {
-        Product existingProduct = productService.getById(productId);
-        if (ObjUtil.isEmpty(existingProduct)) {
-            throw new EntityNotFoundException(Product.class, "id", Optional.ofNullable(productId).map(Object::toString).orElse("null"));
-        }
-        return existingProduct;
     }
 
     private void processImagesUpdate(ProductMerchantUpdateRequest request) {
diff --git a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java
index 879e105..5e609ea 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java
@@ -1,8 +1,10 @@
 package com.oying.modules.pc.product.service.impl;
 
+import cn.hutool.core.util.ObjUtil;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.oying.exception.EntityNotFoundException;
 import com.oying.modules.pc.product.domain.Product;
 import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
 import com.oying.modules.pc.product.mapper.ProductMapper;
@@ -16,10 +18,7 @@
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * @author lzp
@@ -43,6 +42,15 @@
     }
 
     @Override
+    public Product getProduct(Long productId) {
+        Product existingProduct = getById(productId);
+        if (ObjUtil.isEmpty(existingProduct)) {
+            throw new EntityNotFoundException(Product.class, "id", Optional.ofNullable(productId).map(Object::toString).orElse("null"));
+        }
+        return existingProduct;
+    }
+
+    @Override
     @Transactional(rollbackFor = Exception.class)
     public void create(Product resources) {
         productMapper.insert(resources);
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java b/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java
index 4d21d17..b2e5dea 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java
@@ -14,10 +14,12 @@
         Store store = new Store();
         BeanUtil.copyProperties(request, store, CopyOptions.create().setIgnoreNullValue(true));
 
-        store.setMerchantId(SecurityUtils.getCurrentUserId());
+        // 由前端传入,不允许修改
+        //store.setMerchantId(SecurityUtils.getCurrentUserId());
         Long logoUploadFileId = request.getLogoUploadFileId();
         store.setLogoImageId(logoUploadFileId);
         store.setLogoImageUrl(ImageUtils.getPublicObjectUrl(logoUploadFileId));
+
         Long coverUploadFileId = request.getCoverUploadFileId();
         store.setCoverImageId(coverUploadFileId);
         store.setCoverImageUrl(ImageUtils.getPublicObjectUrl(coverUploadFileId));
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java
index 05c2404..a99b340 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java
@@ -23,6 +23,9 @@
     @ApiModelProperty(value = "店铺简称", example = "永辉超市(新纪元店)")
     private String storeShortName;*/
 
+    @ApiModelProperty(value = "商户ID")
+    private Long merchantId;
+
     @NotNull
     @ApiModelProperty(value = "店铺LOGO文件ID", example = "14567785444763247876234")
     private Long logoUploadFileId;
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java
index bf35cd7..de71ed4 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java
@@ -26,9 +26,6 @@
     @ApiModelProperty(value = "店铺ID")
     private Long storeId;
 
-    @ApiModelProperty(value = "商户ID")
-    private Long merchantId;
-
     @ApiModelProperty(value = "平台类目")
     private Long platformCategoryId;
 
diff --git a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java
index 4b09b6a..b89bb58 100644
--- a/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java
+++ b/oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java
@@ -21,6 +21,7 @@
 import com.oying.utils.PageUtil;
 import com.oying.utils.SecurityUtils;
 import com.oying.utils.StringUtils;
+import com.oying.utils.enums.StoreRole;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -262,7 +263,7 @@
         StoreUser storeUser = new StoreUser();
         storeUser.setStoreId(storeId);
         storeUser.setUserId(SecurityUtils.getCurrentUserId());
-        storeUser.setRoleType("");
+        storeUser.setRoleType(StoreRole.ADMIN.getRole());
         storeUser.setPermissions("");
         storeUserMapper.insert(storeUser);
         return true;
diff --git a/oying-system/src/main/resources/mapper/pc/product/ProductStockMapper.xml b/oying-system/src/main/resources/mapper/pc/product/ProductStockMapper.xml
new file mode 100644
index 0000000..c712189
--- /dev/null
+++ b/oying-system/src/main/resources/mapper/pc/product/ProductStockMapper.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.oying.modules.pc.product.mapper.ProductStockMapper">
+
+    <!-- 更新库存 -->
+    <update id="updateStock">
+        UPDATE pc_product SET
+            stock_quantity = #{quantity},
+            version = version + 1
+        WHERE
+            product_id = #{productId} AND version = #{version}
+    </update>
+
+    <!-- 批量更新库存 -->
+    <update id="batchUpdateStock" parameterType="list">
+        <foreach collection="list" item="item" index="index" separator=";">
+            UPDATE products
+            SET stock_quantity = #{item.quantity}, version = version + 1
+            WHERE
+            product_id = #{item.productId} AND version = #{item.version}
+        </foreach>
+    </update>
+
+    <!-- 增加库存 -->
+    <update id="increaseStock">
+        UPDATE pc_product SET
+            stock_quantity = stock_quantity + #{amount},
+            version = version + 1
+        WHERE
+            product_id = #{productId} AND version = #{version}
+    </update>
+
+    <!-- 减少库存 -->
+    <update id="decreaseStock">
+        UPDATE pc_product SET
+            stock_quantity = stock_quantity - #{amount},
+            version = version + 1
+        WHERE
+            product_id = #{productId} AND version = #{version}
+    </update>
+
+    <!-- 查询最低库存商品 -->
+    <select id="selectLowStockProducts">
+        SELECT * FROM products
+        WHERE stock_quantity <![CDATA[ <= ]]> #{threshold}
+        ORDER BY stock_quantity ASC
+    </select>
+
+</mapper>
\ No newline at end of file

--
Gitblit v1.9.3