Bladeren bron

feat(hisStore): 添加商品限购功能

- 在 FsStoreProductAttrValue 和 FsStoreProductAttrValueScrm 模型中添加限购量字段
- 在 FsStoreOrderScrmMapper 中添加查询用户已购买数量的方法
- 在 FsStoreOrderScrmServiceImpl 中实现限购检查逻辑
- 更新 FsStoreProductScrmMapper 和 FsStoreProductScrmServiceImpl,支持查询商品限购信息
xw 1 maand geleden
bovenliggende
commit
ab339771bf

+ 3 - 2
fs-service/src/main/java/com/fs/his/domain/FsStoreProductAttrValue.java

@@ -3,8 +3,6 @@ package com.fs.his.domain;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import java.math.BigDecimal;
 import java.util.Map;
@@ -93,6 +91,9 @@ public class FsStoreProductAttrValue extends BaseEntity
 
     private Map<String, String> detail;
 
+    @Excel(name = "限购量")
+    private Integer purchaseLimit;
+
 
 
 }

+ 15 - 3
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductAttrValueScrm.java

@@ -1,8 +1,5 @@
 package com.fs.hisStore.domain;
 
-import java.math.BigDecimal;
-import java.util.Map;
-
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
@@ -10,6 +7,9 @@ import lombok.EqualsAndHashCode;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 
+import java.math.BigDecimal;
+import java.util.Map;
+
 /**
  * 商品属性值对象 fs_store_product_attr_value
  *
@@ -119,6 +119,18 @@ public class FsStoreProductAttrValueScrm extends BaseEntity
     /** 需要多少积分兑换 */
     @Excel(name = "需要多少积分兑换")
     private Integer giveIntegral;
+
+    @Excel(name = "限购量")
+    private Integer purchaseLimit;
+
+    public Integer getPurchaseLimit() {
+        return purchaseLimit;
+    }
+
+    public void setPurchaseLimit(Integer purchaseLimit) {
+        this.purchaseLimit = purchaseLimit;
+    }
+
     public void setDetail(Map<String, String> detail) {
         this.detail = detail;
     }

+ 14 - 5
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java

@@ -1,17 +1,13 @@
 package com.fs.hisStore.mapper;
 
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
 import com.alibaba.fastjson.JSONObject;
 import com.fs.api.param.OrderListParam;
 import com.fs.api.vo.OrderListVO;
 import com.fs.company.param.CompanyStatisticsParam;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.his.vo.FsStoreOrderExcelVO;
-import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.domain.FsStoreOrderItemScrm;
+import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.domain.ReportScrm;
 import com.fs.hisStore.param.*;
 import com.fs.hisStore.vo.*;
@@ -19,6 +15,10 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
 /**
  * 订单Mapper接口
  *
@@ -1240,4 +1240,13 @@ public interface FsStoreOrderScrmMapper
      * @return list
      * **/
     List<FsStoreOrderDeliveryNoteExportVO> getDeliveryNote(@Param("maps") FsStoreOrderParam maps);
+
+    /**
+     * 查询用户已购买某商品的数量
+     * @param userId 用户ID
+     * @param productAttrValueId 商品属性值ID
+     * @return 已购买数量
+     */
+    Integer selectUserPurchasedCount(@Param("userId") Long userId,
+                                     @Param("productAttrValueId") Long productAttrValueId);
 }

+ 11 - 8
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java

@@ -1,21 +1,19 @@
 package com.fs.hisStore.mapper;
 
-import java.util.List;
-
-import com.fs.common.annotation.Log;
-import com.fs.common.enums.BusinessType;
 import com.fs.his.param.FsStoreProductListSParam;
 import com.fs.his.vo.FsStoreProductListSVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.hisStore.domain.FsStoreProductRuleScrm;
-import com.fs.statis.dto.ModifyMoreDTO;
 import com.fs.hisStore.domain.FsStoreProductScrm;
 import com.fs.hisStore.param.FsStoreProductQueryParam;
 import com.fs.hisStore.vo.*;
+import com.fs.statis.dto.ModifyMoreDTO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
+import java.util.List;
+
 /**
  * 商品Mapper接口
  *
@@ -72,8 +70,12 @@ public interface FsStoreProductScrmMapper
      */
     public int deleteFsStoreProductByIds(Long[] productIds);
     @Select({"<script> " +
-            "select p.*,pc.cate_name  from fs_store_product_scrm p left join fs_store_product_category_scrm pc on p.cate_id=pc.cate_id   " +
-            "where 1=1 " +
+            "SELECT p.*, pc.cate_name, " +
+            "MIN(av.purchase_limit) AS purchase_limit " + // 取最小限购量
+            "FROM fs_store_product_scrm p " +
+            "LEFT JOIN fs_store_product_category_scrm pc ON p.cate_id = pc.cate_id " +
+            "LEFT JOIN fs_store_product_attr_value_scrm av ON p.product_id = av.product_id " +
+            "WHERE 1=1 " +
             "<if test = 'maps.productName != null and  maps.productName !=\"\"    '> " +
             "and p.product_name like CONCAT('%',#{maps.productName},'%') " +
             "</if>" +
@@ -89,7 +91,8 @@ public interface FsStoreProductScrmMapper
             "<if test = 'maps.companyIds != null and maps.companyIds != \"\" '> " +
             "and find_in_set(#{maps.companyIds}, p.company_ids) " +
             "</if>" +
-            " order by p.product_id desc "+
+            "group by p.product_id " + // 按商品分组
+            "order by p.product_id desc "+
             "</script>"})
     List<FsStoreProductListVO> selectFsStoreProductListVO(@Param("maps") FsStoreProductScrm fsStoreProduct);
 

+ 14 - 8
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java

@@ -1,10 +1,5 @@
 package com.fs.hisStore.service;
 
-import java.math.BigDecimal;
-import java.text.ParseException;
-import java.util.List;
-import java.util.Map;
-
 import com.alibaba.fastjson.JSONObject;
 import com.fs.api.param.OrderListParam;
 import com.fs.api.vo.OrderListVO;
@@ -12,10 +7,9 @@ import com.fs.common.core.domain.R;
 import com.fs.company.domain.CompanyUser;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.erp.domain.ErpOrder;
-import com.fs.his.domain.FsStorePayment;
 import com.fs.his.param.FsStoreOrderSalesParam;
+import com.fs.his.vo.FsPrescribeVO;
 import com.fs.his.vo.FsStoreOrderExcelVO;
-import com.fs.hisStore.config.StoreConfig;
 import com.fs.hisStore.domain.FsStoreOrderItemScrm;
 import com.fs.hisStore.domain.FsStoreOrderLogsScrm;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
@@ -27,7 +21,10 @@ import com.fs.hisStore.dto.StoreOrderExpressExportDTO;
 import com.fs.hisStore.param.*;
 import com.fs.hisStore.vo.*;
 
-import com.fs.his.vo.FsPrescribeVO;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 订单Service接口
@@ -99,6 +96,15 @@ public interface IFsStoreOrderScrmService
 
     FsStoreOrderComputeDTO computedOrder(long parseLong, FsStoreOrderComputedParam param);
 
+
+    /**
+     * 查询用户对某个商品规格的已购买数量
+     * @param userId 用户ID
+     * @param productAttrValueId 商品规格ID
+     * @return 已购买数量
+     */
+    Integer selectUserPurchasedCount(Long userId, Long productAttrValueId);
+
     R createOrder(long userId, FsStoreOrderCreateParam param);
 
     R createOrderByPrescribe(Long prescribeId);

+ 50 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -591,6 +591,14 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 .build();
     }
 
+    @Override
+    public Integer selectUserPurchasedCount(Long userId, Long productAttrValueId) {
+        if (userId == null || productAttrValueId == null) {
+            return 0;
+        }
+        return fsStoreOrderMapper.selectUserPurchasedCount(userId, productAttrValueId);
+    }
+
 
     @Override
     @Transactional
@@ -603,8 +611,49 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 //        Integer totalNum = 0;
         BigDecimal integral = BigDecimal.ZERO;
         if (cartIds != null) {
-            //获取购物车列表
+            // 获取购物车列表
             List<FsStoreCartQueryVO> carts = redisCache.getCacheObject("orderCarts:" + param.getOrderKey());
+
+            // 限购检查
+            Map<Long, Integer> purchaseLimitMap = new HashMap<>(); // 存储规格ID和本次购买数量
+
+            for (FsStoreCartQueryVO cart : carts) {
+                // 检查商品规格是否限购
+                FsStoreProductAttrValueScrm attrValue = attrValueService.selectFsStoreProductAttrValueById(cart.getProductAttrValueId());
+
+                if (attrValue != null && attrValue.getPurchaseLimit() != null && attrValue.getPurchaseLimit() > 0) {
+                    // 查询用户已购买该规格的数量
+                    Integer purchasedCount = this.selectUserPurchasedCount(userId, cart.getProductAttrValueId());
+                    if (purchasedCount == null) {
+                        purchasedCount = 0;
+                    }
+
+                    // 获取该规格在购物车中已累计的数量(处理同一购物车中相同规格多次出现的情况)
+                    int currentCartCount = purchaseLimitMap.getOrDefault(cart.getProductAttrValueId(), 0);
+                    int newCartCount = currentCartCount + cart.getCartNum();
+
+                    // 计算总购买数量(已购买 + 本次购物车中该规格的总数量)
+                    int totalPurchased = purchasedCount + newCartCount;
+
+                    // 检查是否超过限购数量
+                    if (totalPurchased > attrValue.getPurchaseLimit()) {
+                        int remaining = attrValue.getPurchaseLimit() - purchasedCount;
+                        String message = "商品规格【" + attrValue.getSku() + "】限购" + attrValue.getPurchaseLimit() + "件";
+                        message += ",您已购买" + purchasedCount + "件";
+
+                        if (remaining > 0) {
+                            message += ",本次最多可购买" + remaining + "件";
+                        } else {
+                            message += ",已达到购买上限";
+                        }
+
+                        return R.error(message);
+                    }
+
+                    // 更新购物车中该规格的数量
+                    purchaseLimitMap.put(cart.getProductAttrValueId(), newCartCount);
+                }
+            }
             //获取地址
             FsUserAddressScrm address = userAddressMapper.selectFsUserAddressById(param.getAddressId());
             //生成分布式唯一值

+ 13 - 10
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java

@@ -1,9 +1,5 @@
 package com.fs.hisStore.service.impl;
 
-import java.math.BigDecimal;
-import java.util.*;
-import java.util.stream.Collectors;
-
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -11,9 +7,7 @@ import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.BeanCopyUtils;
-import com.fs.common.annotation.Log;
 import com.fs.common.core.domain.R;
-import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.DateUtils;
@@ -26,24 +20,31 @@ import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsStoreProductExcelVO;
 import com.fs.his.vo.FsStoreProductListSVO;
 import com.fs.his.vo.OptionsVO;
-import com.fs.hisStore.domain.*;
-import com.fs.hisStore.mapper.*;
-import com.fs.statis.dto.ModifyMoreDTO;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsStoreProductRuleScrm;
+import com.fs.hisStore.domain.FsStoreProductScrm;
 import com.fs.hisStore.dto.ProductArrtDTO;
 import com.fs.hisStore.dto.ProductAttrCountDto;
+import com.fs.hisStore.mapper.*;
 import com.fs.hisStore.param.FsStoreProductAddEditParam;
 import com.fs.hisStore.param.FsStoreProductQueryParam;
 import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
+import com.fs.hisStore.service.IFsStoreProductScrmService;
 import com.fs.hisStore.vo.*;
+import com.fs.statis.dto.ModifyMoreDTO;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
-import com.fs.hisStore.service.IFsStoreProductScrmService;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
 /**
  * 商品Service业务层处理
  *
@@ -256,6 +257,7 @@ public class FsStoreProductScrmServiceImpl implements IFsStoreProductScrmService
             valueMap.put("cost", 0);
             valueMap.put("otPrice", 0);
             valueMap.put("stock", 0);
+            valueMap.put("purchaseLimit", 0);
             valueMap.put("barCode", "");
             valueMap.put("groupBarCode", "");
             valueMap.put("agentPrice", 0);
@@ -283,6 +285,7 @@ public class FsStoreProductScrmServiceImpl implements IFsStoreProductScrmService
                     valueMap.put("otPrice", values.get(0).getOtPrice());
                     valueMap.put("agentPrice", values.get(0).getAgentPrice());
                     valueMap.put("stock", values.get(0).getStock());
+                    valueMap.put("purchaseLimit", values.get(0).getPurchaseLimit());
                     valueMap.put("barCode", values.get(0).getBarCode());
                     valueMap.put("groupBarCode", values.get(0).getGroupBarCode());
                     valueMap.put("weight", values.get(0).getWeight());

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreProductListVO.java

@@ -78,4 +78,6 @@ public class FsStoreProductListVO  implements Serializable
      * 所属公司
      */
     private String companyName;
+
+    private String purchaseLimit;
 }

+ 11 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml

@@ -1079,4 +1079,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY o.id
         LIMIT 10000;
     </select>
+    <select id="selectUserPurchasedCount" resultType="java.lang.Integer">
+        SELECT IFNULL(SUM(oi.num), 0)
+        FROM fs_store_order_item_scrm oi
+        INNER JOIN fs_store_order_scrm o ON oi.order_id = o.id
+        INNER JOIN fs_store_cart_scrm c ON oi.cart_id = c.id  -- 新增关联
+        WHERE o.user_id = #{userId}
+          AND c.product_attr_value_id = #{productAttrValueId}  -- 使用购物车的规格ID
+          AND o.status NOT IN (-2, -3)
+          AND o.paid = 1
+          AND o.is_del = 0
+    </select>
 </mapper>

+ 6 - 1
fs-service/src/main/resources/mapper/hisStore/FsStoreProductAttrValueScrmMapper.xml

@@ -23,10 +23,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="brokerageTwo"    column="brokerage_two"    />
         <result property="brokerageThree"    column="brokerage_three"    />
         <result property="integral"    column="integral"    />
+        <result property="purchaseLimit" column="purchase_limit" />
     </resultMap>
 
     <sql id="selectFsStoreProductAttrValueVo">
-        select id, product_id, sku, stock, sales, price, image, cost,agent_price, bar_code,group_bar_code, ot_price, weight, volume, brokerage, brokerage_two,brokerage_three, integral,has_deposit_feature_type,deposit_amount,on_behalf_payment_amount from fs_store_product_attr_value_scrm
+        select id, product_id, sku, stock, sales, price, image, cost,agent_price, bar_code,group_bar_code, ot_price, weight, volume, brokerage, brokerage_two,brokerage_three, integral,has_deposit_feature_type,deposit_amount,on_behalf_payment_amount,purchase_limit from fs_store_product_attr_value_scrm
     </sql>
 
     <select id="selectFsStoreProductAttrValueList" parameterType="FsStoreProductAttrValueScrm" resultMap="FsStoreProductAttrValueResult">
@@ -48,6 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="brokerageTwo != null "> and brokerage_two = #{brokerageTwo}</if>
             <if test="brokerageThree != null "> and brokerage_three = #{brokerageThree}</if>
             <if test="integral != null "> and integral = #{integral}</if>
+            <if test="purchaseLimit != null "> and purchase_limit = #{purchaseLimit}</if>
         </where>
     </select>
 
@@ -79,6 +81,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="hasDepositFeatureType != null">has_deposit_feature_type,</if>
             <if test="depositAmount != null">deposit_amount,</if>
             <if test="onBehalfPaymentAmount != null">on_behalf_payment_amount,</if>
+            <if test="purchaseLimit != null">purchase_limit,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="productId != null">#{productId},</if>
@@ -101,6 +104,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="hasDepositFeatureType != null">#{hasDepositFeatureType},</if>
             <if test="depositAmount != null">#{depositAmount},</if>
             <if test="onBehalfPaymentAmount != null">#{onBehalfPaymentAmount},</if>
+            <if test="purchaseLimit != null">#{purchaseLimit},</if>
          </trim>
     </insert>
 
@@ -127,6 +131,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="hasDepositFeatureType != null">has_deposit_feature_type = #{hasDepositFeatureType},</if>
             <if test="depositAmount != null">deposit_amount = #{depositAmount},</if>
             <if test="onBehalfPaymentAmount != null">on_behalf_payment_amount = #{onBehalfPaymentAmount},</if>
+            <if test="purchaseLimit != null">purchase_limit = #{purchaseLimit},</if>
         </trim>
         where id = #{id}
     </update>