xin
2025-09-17 6d31d535d737ed26c4d9d61cd4e0b5483cb9b0ba
Merge branch 'refs/heads/master' into xin
6 files added
7 files modified
264 ■■■■■ changed files
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductInventoryUpdateRequest.java 13 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductStockMapper.java 23 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductInventoryController.java 54 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductInventoryService.java 11 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductService.java 7 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductInventoryServiceImpl.java 59 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java 19 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductServiceImpl.java 16 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java 4 ●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCreateRequest.java 3 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java 3 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreServiceImpl.java 3 ●●●● patch | view | raw | blame | history
oying-system/src/main/resources/mapper/pc/product/ProductStockMapper.xml 49 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductInventoryUpdateRequest.java
New file
@@ -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;
}
oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductStockMapper.java
New file
@@ -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);
}
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductInventoryController.java
New file
@@ -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));
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductInventoryService.java
New file
@@ -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);
}
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 /
    */
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductInventoryServiceImpl.java
New file
@@ -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;
    }
}
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) {
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);
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));
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;
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;
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;
oying-system/src/main/resources/mapper/pc/product/ProductStockMapper.xml
New file
@@ -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>