lubo 10 mēneši atpakaļ
vecāks
revīzija
a6e8535fe3
18 mainītis faili ar 503 papildinājumiem un 35 dzēšanām
  1. 4 0
      ruoyi-business/src/main/java/com/ruoyi/business/domain/Business.java
  2. 51 0
      ruoyi-business/src/main/java/com/ruoyi/business/enums/BusinessBillType.java
  3. 22 0
      ruoyi-business/src/main/resources/mapper/business/BusinessBalanceRecordMapper.xml
  4. 4 3
      ruoyi-line/src/main/java/com/ruoyi/subsidy/domain/SubsidySharedPoolLog.java
  5. 6 3
      ruoyi-line/src/main/java/com/ruoyi/subsidy/domain/bo/SubsidySharedPoolLogBo.java
  6. 6 4
      ruoyi-line/src/main/java/com/ruoyi/subsidy/domain/vo/SubsidySharedPoolLogVo.java
  7. 55 0
      ruoyi-line/src/main/java/com/ruoyi/subsidy/enums/SharedPoolBehaviorType.java
  8. 3 3
      ruoyi-line/src/main/java/com/ruoyi/subsidy/mapper/SubsidyQueueMapper.java
  9. 11 0
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/ISubsidyCutInService.java
  10. 10 1
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/ISubsidyQueueService.java
  11. 35 1
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/ISubsidySharedPoolService.java
  12. 97 0
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyCutInServiceImpl.java
  13. 1 1
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyModeAutoServiceImpl.java
  14. 1 1
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyModeServiceImpl.java
  15. 118 11
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyQueueServiceImpl.java
  16. 73 2
      ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidySharedPoolServiceImpl.java
  17. 5 5
      ruoyi-line/src/main/resources/mapper/subsidy/SubsidyQueueMapper.xml
  18. 1 0
      ruoyi-user/src/main/java/com/ruoyi/user/enums/BalanceSourceType.java

+ 4 - 0
ruoyi-business/src/main/java/com/ruoyi/business/domain/Business.java

@@ -240,6 +240,10 @@ public class Business extends BaseEntity {
      * 是否闭店
      */
     private Boolean closeStatus;
+    /**
+     * 账户当前可用余额
+     */
+    private BigDecimal balance;
 
 
     /**

+ 51 - 0
ruoyi-business/src/main/java/com/ruoyi/business/enums/BusinessBillType.java

@@ -0,0 +1,51 @@
+package com.ruoyi.business.enums;
+
+import com.ruoyi.common.enums.IIntegerEnum;
+
+import java.util.Objects;
+
+/**
+ * 账单类型(0,支出,1收入)
+ */
+public enum BusinessBillType implements IIntegerEnum<Integer> {
+    OUT(0, "支出"),
+    IN(1, "收入");
+
+    private Integer code;
+
+    private String msg;
+
+    BusinessBillType(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    @Override
+    public Integer getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMsg() {
+        return msg;
+    }
+
+
+    public static BusinessBillType getByCode(int code, BusinessBillType[] values) {
+        for (BusinessBillType value : values) {
+            if (Objects.equals(code, value.getCode())) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    public static BusinessBillType getByCode(int code) {
+        for (BusinessBillType value : BusinessBillType.values()) {
+            if (Objects.equals(code, value.getCode())) {
+                return value;
+            }
+        }
+        return null;
+    }
+}

+ 22 - 0
ruoyi-business/src/main/resources/mapper/business/BusinessBalanceRecordMapper.xml

@@ -0,0 +1,22 @@
+<?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.ruoyi.business.mapper.BusinessBalanceRecordMapper">
+
+    <resultMap type="com.ruoyi.business.domain.BusinessBalanceRecord" id="BusinessBalanceRecordResult">
+        <result property="id" column="id"/>
+        <result property="businessId" column="business_id"/>
+        <result property="billType" column="bill_type"/>
+        <result property="entryBeforeBalance" column="entry_before_balance"/>
+        <result property="entryAfterBalance" column="entry_after_balance"/>
+        <result property="entryValue" column="entry_value"/>
+        <result property="sourceType" column="source_type"/>
+        <result property="sourceId" column="source_id"/>
+        <result property="sourceCode" column="source_code"/>
+        <result property="remark" column="remark"/>
+        <result property="createTime" column="create_time"/>
+    </resultMap>
+
+
+</mapper>

+ 4 - 3
ruoyi-line/src/main/java/com/ruoyi/subsidy/domain/SubsidySharedPoolLog.java

@@ -2,6 +2,7 @@ package com.ruoyi.subsidy.domain;
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.ruoyi.common.core.domain.BaseTimeEntity;
+import com.ruoyi.subsidy.enums.SharedPoolBehaviorType;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import java.io.Serializable;
@@ -27,11 +28,11 @@ public class SubsidySharedPoolLog extends BaseTimeEntity {
      * 均摊池日志ID
      */
     @TableId(value = "shared_log_id")
-    private Integer sharedLogId;
+    private Long sharedLogId;
     /**
      * 均摊池ID
      */
-    private Integer sharedId;
+    private Long sharedId;
     /**
      * 商户ID
      */
@@ -51,7 +52,7 @@ public class SubsidySharedPoolLog extends BaseTimeEntity {
     /**
      * 发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)
      */
-    private Integer behaviorType;
+    private SharedPoolBehaviorType behaviorType;
     /**
      * 用户订单ID
      */

+ 6 - 3
ruoyi-line/src/main/java/com/ruoyi/subsidy/domain/bo/SubsidySharedPoolLogBo.java

@@ -3,8 +3,10 @@ package com.ruoyi.subsidy.domain.bo;
 import com.ruoyi.common.core.domain.BaseTimeEntity;
 import com.ruoyi.common.core.validate.AddGroup;
 import com.ruoyi.common.core.validate.EditGroup;
+import com.ruoyi.subsidy.enums.SharedPoolBehaviorType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import javax.validation.constraints.*;
@@ -20,6 +22,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
  * @author lubo
  * @date 2025-11-19
  */
+@Builder
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ApiModel("商户均摊池增减日志业务对象")
@@ -30,14 +33,14 @@ public class SubsidySharedPoolLogBo extends BaseTimeEntity {
      */
     @ApiModelProperty(value = "均摊池日志ID", required = true)
     @NotNull(message = "均摊池日志ID不能为空", groups = { EditGroup.class })
-    private Integer sharedLogId;
+    private Long sharedLogId;
 
     /**
      * 均摊池ID
      */
     @ApiModelProperty(value = "均摊池ID", required = true)
     @NotNull(message = "均摊池ID不能为空", groups = { AddGroup.class, EditGroup.class })
-    private Integer sharedId;
+    private Long sharedId;
 
     /**
      * 商户ID
@@ -72,7 +75,7 @@ public class SubsidySharedPoolLogBo extends BaseTimeEntity {
      */
     @ApiModelProperty(value = "发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)", required = true)
     @NotNull(message = "发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)不能为空", groups = { AddGroup.class, EditGroup.class })
-    private Integer behaviorType;
+    private SharedPoolBehaviorType behaviorType;
 
     /**
      * 用户订单ID

+ 6 - 4
ruoyi-line/src/main/java/com/ruoyi/subsidy/domain/vo/SubsidySharedPoolLogVo.java

@@ -5,6 +5,8 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.ruoyi.common.annotation.ExcelDictFormat;
 import com.ruoyi.common.convert.ExcelDictConvert;
+import com.ruoyi.common.core.domain.BaseVo;
+import com.ruoyi.subsidy.enums.SharedPoolBehaviorType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -20,7 +22,7 @@ import java.util.Date;
 @Data
 @ApiModel("商户均摊池增减日志视图对象")
 @ExcelIgnoreUnannotated
-public class SubsidySharedPoolLogVo {
+public class SubsidySharedPoolLogVo extends BaseVo {
 
     private static final long serialVersionUID = 1L;
 
@@ -29,14 +31,14 @@ public class SubsidySharedPoolLogVo {
      */
     @ExcelProperty(value = "均摊池日志ID")
     @ApiModelProperty("均摊池日志ID")
-    private Integer sharedLogId;
+    private Long sharedLogId;
 
     /**
      * 均摊池ID
      */
     @ExcelProperty(value = "均摊池ID")
     @ApiModelProperty("均摊池ID")
-    private Integer sharedId;
+    private Long sharedId;
 
     /**
      * 商户ID
@@ -71,7 +73,7 @@ public class SubsidySharedPoolLogVo {
      */
     @ExcelProperty(value = "发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)")
     @ApiModelProperty("发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)")
-    private Integer behaviorType;
+    private SharedPoolBehaviorType behaviorType;
 
     /**
      * 用户订单ID

+ 55 - 0
ruoyi-line/src/main/java/com/ruoyi/subsidy/enums/SharedPoolBehaviorType.java

@@ -0,0 +1,55 @@
+package com.ruoyi.subsidy.enums;
+
+import com.ruoyi.common.enums.IIntegerEnum;
+
+import java.util.Objects;
+
+/**
+ * 发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)
+ * @author lubo
+ */
+public enum SharedPoolBehaviorType implements IIntegerEnum<Integer> {
+    // 发生改变的行为(0用户下单产生的均摊补贴,1结算给用户补贴,2剩余返还给商家)
+    USER_ORDER_SUBSIDY(0, "用户下单产生的均摊补贴"),
+    SETTLEMENT_SUBSIDY(1, "结算给用户补贴"),
+    REFUND_SUBSIDY(2, "剩余返还给商家");
+
+
+    private Integer code;
+
+    private String msg;
+
+    SharedPoolBehaviorType(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    @Override
+    public Integer getCode() {
+        return code;
+    }
+
+
+    @Override
+    public String getMsg() {
+        return msg;
+    }
+
+    public static SharedPoolBehaviorType getByCode(Integer code, SharedPoolBehaviorType[] values) {
+        for (SharedPoolBehaviorType value : values) {
+            if (Objects.equals(code, value.getCode())) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    public static SharedPoolBehaviorType getByCode(Integer code) {
+        for (SharedPoolBehaviorType value : SharedPoolBehaviorType.values()) {
+            if (Objects.equals(code, value.getCode())) {
+                return value;
+            }
+        }
+        return null;
+    }
+}

+ 3 - 3
ruoyi-line/src/main/java/com/ruoyi/subsidy/mapper/SubsidyQueueMapper.java

@@ -5,6 +5,8 @@ import com.ruoyi.subsidy.domain.vo.SubsidyQueueVo;
 import com.ruoyi.common.core.mapper.BaseMapperPlus;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * 补贴排队Mapper接口
  *
@@ -13,7 +15,5 @@ import org.apache.ibatis.annotations.Param;
  */
 public interface SubsidyQueueMapper extends BaseMapperPlus<SubsidyQueueMapper, SubsidyQueue, SubsidyQueueVo> {
 
-    Long validQueueCountAndLock(@Param("businessId") Long businessId);
-
-    SubsidyQueue validFirstQueue(@Param("businessId") Long businessId);
+    List<Long> validQueueIds(@Param("businessId") Long businessId);
 }

+ 11 - 0
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/ISubsidyCutInService.java

@@ -1,11 +1,13 @@
 package com.ruoyi.subsidy.service;
 
+import com.ruoyi.onlineorder.domain.OnlineOrder;
 import com.ruoyi.subsidy.domain.SubsidyCutIn;
 import com.ruoyi.subsidy.domain.vo.SubsidyCutInVo;
 import com.ruoyi.subsidy.domain.bo.SubsidyCutInBo;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.domain.PageQuery;
 
+import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.List;
 
@@ -87,4 +89,13 @@ public interface ISubsidyCutInService {
      * @return
      */
     SubsidyCutIn validFirstSubsidyCutIn(Long businessId);
+
+    /**
+     * 补贴插队处理
+     * @param order
+     * @param firstSubsidyCutIn
+     * @param subsidyCutIn
+     * @return
+     */
+    BigDecimal subsidyCutInHandle(OnlineOrder order, SubsidyCutIn firstSubsidyCutIn, BigDecimal subsidyCutIn);
 }

+ 10 - 1
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/ISubsidyQueueService.java

@@ -7,6 +7,7 @@ import com.ruoyi.subsidy.domain.bo.SubsidyQueueBo;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.domain.PageQuery;
 
+import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.List;
 
@@ -81,7 +82,7 @@ public interface ISubsidyQueueService {
      * @param businessId 商家ID
      * @return 排队数量
      */
-    Long validQueueCount(Long businessId);
+    Long validQueueCount(Long businessId,Boolean excludeCutIn);
 
     /**
      * 获取当前商家的排队数量(上锁)
@@ -97,4 +98,12 @@ public interface ISubsidyQueueService {
      * @param order 订单
      */
     void createQueue(OnlineOrder order);
+
+    /**
+     * 补满并踢出队列
+     * @param businessId 商家ID
+     * @param originalQueueId 排队ID
+     * @param actualAddSubsidyAmount 实际增加补贴金额
+     */
+    void fillUpKickOut(Long businessId, Long originalQueueId, BigDecimal actualAddSubsidyAmount);
 }

+ 35 - 1
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/ISubsidySharedPoolService.java

@@ -1,5 +1,6 @@
 package com.ruoyi.subsidy.service;
 
+import com.ruoyi.onlineorder.domain.OnlineOrder;
 import com.ruoyi.subsidy.domain.SubsidySharedPool;
 import com.ruoyi.subsidy.domain.vo.SubsidySharedPoolVo;
 import com.ruoyi.subsidy.domain.bo.SubsidySharedPoolBo;
@@ -7,6 +8,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.subsidy.enums.SharedSettlementMode;
 
+import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -82,7 +84,39 @@ public interface ISubsidySharedPoolService {
      * @param businessId 商家id
      * @param expireTimeDate 到期时间
      */
-    SubsidySharedPool initSharedPool(Long businessId, Date expireTimeDate);
+    SubsidySharedPool initSharedPool(Long businessId, Date expireTimeDate, BigDecimal sharedSubsidy);
 
+    /**
+     * 结算
+     *
+     * @param sharedId 均摊池id
+     * @param sharedSettlementMode 结算方式
+     */
     void settlement(Long sharedId, SharedSettlementMode sharedSettlementMode);
+
+    /**
+     * 存入均摊池
+     *
+     * @param order 用户订单
+     * @param sharedSubsidy 充值金额
+     */
+    void deposit(OnlineOrder order, BigDecimal sharedSubsidy);
+
+
+    /**
+     * 获取商户的均摊池
+     *
+     * @param businessId 商家id
+     * @return 均摊池
+     */
+    SubsidySharedPool loadSharedPool(Long businessId);
+
+
+    /**
+     * 获取商户的均摊池
+     *
+     * @param businessId 商家id
+     * @return 均摊池
+     */
+    SubsidySharedPool loadSharedPoolAndLock(Long businessId);
 }

+ 97 - 0
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyCutInServiceImpl.java

@@ -2,16 +2,25 @@ package com.ruoyi.subsidy.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.BeanCopyUtils;
+import com.ruoyi.common.utils.MathUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.domain.PageQuery;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.onlineorder.domain.OnlineOrder;
+import com.ruoyi.subsidy.domain.SubsidyQueue;
 import com.ruoyi.subsidy.enums.SubsidyStatus;
+import com.ruoyi.subsidy.service.ISubsidyQueueService;
+import com.ruoyi.user.domain.bo.UserChangeBalanceBo;
+import com.ruoyi.user.enums.BalanceSourceType;
+import com.ruoyi.user.service.IUserService;
 import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import com.ruoyi.subsidy.domain.bo.SubsidyCutInBo;
 import com.ruoyi.subsidy.domain.vo.SubsidyCutInVo;
@@ -20,6 +29,9 @@ import com.ruoyi.subsidy.mapper.SubsidyCutInMapper;
 import com.ruoyi.subsidy.service.ISubsidyCutInService;
 import com.ruoyi.subsidy.exception.SubsidyCutInExceptionEnum;
 
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Collection;
@@ -36,6 +48,12 @@ public class SubsidyCutInServiceImpl implements ISubsidyCutInService {
 
     private final SubsidyCutInMapper baseMapper;
 
+    @Lazy
+    @Resource
+    private ISubsidyQueueService subsidyQueueService ;
+
+    private final IUserService userService;
+
     /**
      * 查询补贴插队分页
      *
@@ -194,4 +212,83 @@ public class SubsidyCutInServiceImpl implements ISubsidyCutInService {
         );
     }
 
+    @Override
+    public BigDecimal subsidyCutInHandle(OnlineOrder order, SubsidyCutIn firstSubsidyCutIn, BigDecimal subsidyCutIn) {
+        if(firstSubsidyCutIn == null)
+        {
+            return subsidyCutIn;
+        }
+        if(order == null)
+        {
+            return subsidyCutIn;
+        }
+
+        do{
+            if (subsidyCutIn.compareTo(BigDecimal.ZERO) <= 0) {
+                return BigDecimal.ZERO;
+            }
+            SubsidyCutIn firstQueue = firstSubsidyCutIn;
+            if(firstQueue == null)
+            {
+                return subsidyCutIn;
+            }
+            //应补贴金额
+            BigDecimal shouldSubsidyAmount = firstQueue.getCutInShouldSubsidyAmount();
+            //已补贴金额
+            BigDecimal actualSubsidyAmount = firstQueue.getActualSubsidyAmount();
+            //当前排队用户的剩余补贴金额
+            BigDecimal currentQueueSubsidyAmount = MathUtils.subtract(shouldSubsidyAmount, actualSubsidyAmount);
+            BigDecimal actualAddSubsidyAmount = BigDecimal.ZERO;
+            if (subsidyCutIn.compareTo(currentQueueSubsidyAmount) >= 0) {
+                //如果超出了应补贴金额=====================//
+                //计算给下一个排队用户的补贴金额
+                subsidyCutIn = MathUtils.subtract(subsidyCutIn, currentQueueSubsidyAmount);
+                firstQueue.setActualSubsidyAmount(shouldSubsidyAmount);
+                firstQueue.setSubsidyStatus(SubsidyStatus.COMPLETE);
+                firstQueue.setQueueOrder(0);
+                firstQueue.setCompleteTime(new Date());
+                this.baseMapper.updateById(firstQueue);
+                actualAddSubsidyAmount = currentQueueSubsidyAmount;
+                validQueueOrderRearrange(order.getBusinessId(),firstQueue.getCutInId());
+                if(firstQueue.getOriginalQueueId()!=null) {
+                    subsidyQueueService.fillUpKickOut(order.getBusinessId(), firstQueue.getOriginalQueueId(),actualAddSubsidyAmount);
+                }
+
+            } else {
+                //如果小于应补贴金额=====================//
+                actualAddSubsidyAmount = subsidyCutIn;
+                subsidyCutIn = BigDecimal.ZERO;
+                firstQueue.setActualSubsidyAmount(MathUtils.add(actualSubsidyAmount, actualAddSubsidyAmount));
+                this.baseMapper.updateById(firstQueue);
+            }
+
+            //用户余额增加
+            userService.changeUserBalance(UserChangeBalanceBo.builder()
+                .userId(firstQueue.getUserId())
+                .entryValue(actualAddSubsidyAmount)
+                .isAdd(true)
+                .sourceType(BalanceSourceType.SUBSIDY)
+                .sourceId(firstQueue.getOrderId())
+                .sourceCode(firstQueue.getOrderNo())
+                .remark("消费排队补贴")
+                .build());
+
+            firstSubsidyCutIn = this.validFirstSubsidyCutIn(order.getBusinessId());
+        } while (true);
+    }
+
+    private void validQueueOrderRearrange(Long businessId, Long excludeCutInId) {
+
+        SubsidyCutIn branchCutInQueue = new SubsidyCutIn();
+        branchCutInQueue.setQueueOrder(branchCutInQueue.getQueueOrder() - 1);
+
+        this.baseMapper.update(branchCutInQueue, new LambdaUpdateWrapper<SubsidyCutIn>()
+            .eq(SubsidyCutIn::getCurrentBusinessId, businessId)
+            .eq(SubsidyCutIn::getSubsidyStatus, SubsidyStatus.WAITING)
+            .ne(SubsidyCutIn::getCutInId, excludeCutInId)
+            .orderByAsc(SubsidyCutIn::getQueueOrder)
+            .set(SubsidyCutIn::getQueueOrder, branchCutInQueue.getQueueOrder())
+        );
+    }
+
 }

+ 1 - 1
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyModeAutoServiceImpl.java

@@ -193,7 +193,7 @@ public class SubsidyModeAutoServiceImpl implements ISubsidyModeAutoService {
         }
 
         if( ObjectUtil.isNotNull(entity.getMaxQueueCount())) {
-            Long count = subsidyQueueService.validQueueCount(entity.getBusinessId());
+            Long count = subsidyQueueService.validQueueCount(entity.getBusinessId(),false);
             if (count >= entity.getMaxQueueCount())
             {
                 // 最大排队人数需要大于当前排队人数

+ 1 - 1
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyModeServiceImpl.java

@@ -152,7 +152,7 @@ public class SubsidyModeServiceImpl implements ISubsidyModeService {
         if(add.getDefaulted() && add.getSharedMode() && !add.getImmediateArrival())
         {
             //开启均摊池
-            return subsidySharedPoolService.initSharedPool(add.getBusinessId(), getExpireTimeDate(add.getSettlementHour()));
+            return subsidySharedPoolService.initSharedPool(add.getBusinessId(), getExpireTimeDate(add.getSettlementHour()),BigDecimal.ZERO);
         }
         return null;
     }

+ 118 - 11
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidyQueueServiceImpl.java

@@ -20,6 +20,7 @@ import com.ruoyi.subsidy.enums.SubsidyCancelType;
 import com.ruoyi.subsidy.enums.SubsidyStatus;
 import com.ruoyi.subsidy.service.ISubsidyCutInService;
 import com.ruoyi.subsidy.service.ISubsidyModeService;
+import com.ruoyi.subsidy.service.ISubsidySharedPoolService;
 import com.ruoyi.user.domain.bo.UserChangeBalanceBo;
 import com.ruoyi.user.enums.BalanceSourceType;
 import com.ruoyi.user.service.IUserService;
@@ -67,6 +68,10 @@ public class SubsidyQueueServiceImpl implements ISubsidyQueueService {
     @Resource
     private IUserService userService;
 
+    @Lazy
+    @Resource
+    private ISubsidySharedPoolService subsidySharedPoolService;
+
     /**
      * 查询补贴排队分页
      *
@@ -205,13 +210,15 @@ public class SubsidyQueueServiceImpl implements ISubsidyQueueService {
     }
 
     @Override
-    public Long validQueueCount(Long businessId) {
+    public Long validQueueCount(Long businessId, Boolean excludeCutIn) {
         return this.baseMapper.selectCount(new LambdaQueryWrapper<SubsidyQueue>()
             .eq(SubsidyQueue::getCurrentBusinessId, businessId)
             .eq(SubsidyQueue::getSubsidyStatus, SubsidyStatus.WAITING)
+            .eq(excludeCutIn, SubsidyQueue::getCutIn, false)
         );
     }
 
+
     /**
      * 获取商家当前排队人数
      *
@@ -220,7 +227,11 @@ public class SubsidyQueueServiceImpl implements ISubsidyQueueService {
      */
     @Override
     public Long validQueueCountAndLock(Long businessId) {
-        return this.baseMapper.validQueueCountAndLock(businessId);
+        return this.baseMapper.selectCount(new LambdaQueryWrapper<SubsidyQueue>()
+            .eq(SubsidyQueue::getCurrentBusinessId, businessId)
+            .eq(SubsidyQueue::getSubsidyStatus, SubsidyStatus.WAITING)
+            .last("for update")
+        );
     }
 
     @Override
@@ -274,14 +285,14 @@ public class SubsidyQueueServiceImpl implements ISubsidyQueueService {
 
             //排队均摊补贴金额
             BigDecimal sharedSubsidy = MathUtils.subtract(subsidyQueue, firstSubsidy);
-            BigDecimal sharedSubsidyReturnAmount = sharedSubsidyHandle(order.getBusinessId(), sharedSubsidy);
+            BigDecimal sharedSubsidyReturnAmount = sharedSubsidyHandle(order, currentMode,sharedSubsidy);
             if (sharedSubsidyReturnAmount.compareTo(BigDecimal.ZERO) > 0) {
                 shouldSubsidyAmount = MathUtils.subtract(shouldSubsidyAmount, sharedSubsidyReturnAmount);
             }
         }
 
         if (ObjectUtil.isNotNull(firstSubsidyCutIn) && subsidyCutIn.compareTo(BigDecimal.ZERO) > 0) {
-            BigDecimal returnAmount = subsidyCutInHandle(firstSubsidyCutIn, subsidyCutIn);
+            BigDecimal returnAmount = subsidyCutInService.subsidyCutInHandle(order,firstSubsidyCutIn, subsidyCutIn);
             if (returnAmount.compareTo(BigDecimal.ZERO) > 0) {
                 shouldSubsidyAmount = MathUtils.subtract(shouldSubsidyAmount, returnAmount);
             }
@@ -290,25 +301,121 @@ public class SubsidyQueueServiceImpl implements ISubsidyQueueService {
         // 有了商家的实际补贴金额,就可以计算商家当前这个订单的实际所得
         // 实际所得 = 订单金额- 商家实际补贴金额(让利)- 平台服务费(5%)
 
+    }
 
+    @Override
+    public void fillUpKickOut(Long businessId, Long originalQueueId, BigDecimal actualAddSubsidyAmount) {
+        SubsidyQueue subsidyQueue = loadById(originalQueueId, false);
+        if(subsidyQueue==null)
+        {
+            return;
+        }
 
+        subsidyQueue.setActualSubsidyAmount(subsidyQueue.getActualSubsidyAmount().add(actualAddSubsidyAmount));
+        subsidyQueue.setSubsidyStatus(SubsidyStatus.COMPLETE);
+        subsidyQueue.setQueueOrder(0);
+        subsidyQueue.setCompleteTime(new Date());
+        this.baseMapper.updateById(subsidyQueue);
+        //改变剩下对列的值
+        validQueueOrderRearrange(businessId,subsidyQueue.getQueueId());
     }
 
-    private BigDecimal subsidyCutInHandle(SubsidyCutIn firstSubsidyCutIn, BigDecimal subsidyCutIn) {
-        return BigDecimal.ZERO;
-    }
 
     /**
      * 均摊补贴金额
      *
-     * @param businessId    商家id
+     * @param order 订单
      * @param sharedSubsidy 排队均摊补贴金额
      * @return 结余
      */
-    private BigDecimal sharedSubsidyHandle(Long businessId, BigDecimal sharedSubsidy) {
+    private BigDecimal sharedSubsidyHandle(OnlineOrder order ,SubsidyMode currentMode, BigDecimal sharedSubsidy) {
+        if(currentMode.getImmediateArrival())
+        {
+            if(sharedSubsidy.compareTo(BigDecimal.ZERO)==0)
+            {
+                return BigDecimal.ZERO;
+            }
+
+            while (true)
+            {
+                if(sharedSubsidy.compareTo(BigDecimal.ZERO)==0)
+                {
+                    return BigDecimal.ZERO;
+                }
+
+                //立即到账人数
+                List<Long> validQueueIds = this.validQueueIds(order.getBusinessId());
+                int queueCount = validQueueIds.size();
+                if(queueCount==0)
+                {
+                    return sharedSubsidy;
+                }
+                //均摊平均值
+                BigDecimal sharedSubsidyAverage = MathUtils.divide(sharedSubsidy,new BigDecimal(queueCount));
+                if(sharedSubsidyAverage.compareTo(BigDecimal.ZERO)==0)
+                {
+                    //这里是为了避免 0.01/2 = 0.0
+                    return sharedSubsidy;
+                }
+                for (Long validQueueId : validQueueIds)
+                {
+                    SubsidyQueue firstQueue = this.loadById(validQueueId,false);
+                    //应补贴金额
+                    BigDecimal shouldSubsidyAmount = firstQueue.getShouldSubsidyAmount();
+                    //已补贴金额
+                    BigDecimal actualSubsidyAmount = firstQueue.getActualSubsidyAmount();
+                    //当前排队用户的剩余补贴金额
+                    BigDecimal currentQueueSubsidyAmount = MathUtils.subtract(shouldSubsidyAmount, actualSubsidyAmount);
+                    //实际排队用户增加的补贴金额
+                    BigDecimal actualAddSubsidyAmount = BigDecimal.ZERO;
+                    if (sharedSubsidyAverage.compareTo(currentQueueSubsidyAmount) >= 0) {
+                        //如果超出了应补贴金额=====================//
+                        //计算剩剩余补贴金额
+
+                        firstQueue.setActualSubsidyAmount(shouldSubsidyAmount);
+                        firstQueue.setSubsidyStatus(SubsidyStatus.COMPLETE);
+                        firstQueue.setQueueOrder(0);
+                        firstQueue.setCompleteTime(new Date());
+                        this.baseMapper.updateById(firstQueue);
+                        actualAddSubsidyAmount = currentQueueSubsidyAmount;
+                        sharedSubsidy = MathUtils.subtract(sharedSubsidy, currentQueueSubsidyAmount);
+                        //改变剩下对列的值
+                        validQueueOrderRearrange(order.getBusinessId(),firstQueue.getQueueId());
+                    } else {
+                        //如果小于应补贴金额=====================//
+                        actualAddSubsidyAmount = sharedSubsidyAverage;
+                        firstQueue.setActualSubsidyAmount(MathUtils.add(actualSubsidyAmount, sharedSubsidyAverage));
+                        this.baseMapper.updateById(firstQueue);
+                        sharedSubsidy = MathUtils.subtract(sharedSubsidy, sharedSubsidyAverage);
+                    }
+
+                    //用户余额增加
+                    userService.changeUserBalance(UserChangeBalanceBo.builder()
+                        .userId(firstQueue.getUserId())
+                        .entryValue(actualAddSubsidyAmount)
+                        .isAdd(true)
+                        .sourceType(BalanceSourceType.SHARED_SUBSIDY)
+                        .sourceId(firstQueue.getOrderId())
+                        .sourceCode(firstQueue.getOrderNo())
+                        .remark("消费排队均摊补贴")
+                        .build());
+                }
+            }
+
+        }
+        else
+        {
+            //存到均摊池
+            subsidySharedPoolService.deposit(order, sharedSubsidy);
+
+        }
         return BigDecimal.ZERO;
     }
 
+    private List<Long> validQueueIds(Long businessId) {
+        return this.baseMapper.validQueueIds(businessId);
+    }
+
     /**
      * 创建自己的排队
      *
@@ -384,9 +491,9 @@ public class SubsidyQueueServiceImpl implements ISubsidyQueueService {
             } else {
                 //如果小于应补贴金额=====================//
                 actualAddSubsidyAmount = firstSubsidy;
-                firstSubsidy = BigDecimal.ZERO;
-                firstQueue.setActualSubsidyAmount(MathUtils.add(actualSubsidyAmount, firstSubsidy));
+                firstQueue.setActualSubsidyAmount(MathUtils.add(actualSubsidyAmount, actualAddSubsidyAmount));
                 this.baseMapper.updateById(firstQueue);
+                firstSubsidy = BigDecimal.ZERO;
             }
 
             //用户余额增加

+ 73 - 2
ruoyi-line/src/main/java/com/ruoyi/subsidy/service/impl/SubsidySharedPoolServiceImpl.java

@@ -11,7 +11,13 @@ import com.ruoyi.common.core.domain.PageQuery;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.onlineorder.domain.OnlineOrder;
+import com.ruoyi.subsidy.domain.bo.SubsidyModeConversionLogBo;
+import com.ruoyi.subsidy.domain.bo.SubsidySharedPoolLogBo;
+import com.ruoyi.subsidy.enums.SharedPoolBehaviorType;
 import com.ruoyi.subsidy.enums.SharedSettlementMode;
+import com.ruoyi.subsidy.service.ISubsidyModeConversionLogService;
+import com.ruoyi.subsidy.service.ISubsidySharedPoolLogService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import com.ruoyi.subsidy.domain.bo.SubsidySharedPoolBo;
@@ -38,6 +44,7 @@ import java.util.Collection;
 public class SubsidySharedPoolServiceImpl implements ISubsidySharedPoolService {
 
     private final SubsidySharedPoolMapper baseMapper;
+    private final ISubsidySharedPoolLogService subsidySharedPoolLogService ;
 
     /**
      * 查询商户均摊池分页
@@ -159,10 +166,10 @@ public class SubsidySharedPoolServiceImpl implements ISubsidySharedPoolService {
     }
 
     @Override
-    public SubsidySharedPool initSharedPool(Long businessId, Date expireTimeDate) {
+    public SubsidySharedPool initSharedPool(Long businessId, Date expireTimeDate,BigDecimal sharedSubsidy) {
         SubsidySharedPoolBo subsidySharedPoolBo = new SubsidySharedPoolBo();
         subsidySharedPoolBo.setBusinessId(businessId);
-        subsidySharedPoolBo.setTotalSharedAmount(BigDecimal.ZERO);
+        subsidySharedPoolBo.setTotalSharedAmount(sharedSubsidy);
         subsidySharedPoolBo.setExpireTime(expireTimeDate);
         subsidySharedPoolBo.setReturnBusinessAmount(BigDecimal.ZERO);
         subsidySharedPoolBo.setSettlemented(false);
@@ -186,4 +193,68 @@ public class SubsidySharedPoolServiceImpl implements ISubsidySharedPoolService {
 
     }
 
+    @Override
+    public void deposit(OnlineOrder order, BigDecimal sharedSubsidy) {
+        SubsidySharedPool subsidySharedPool = loadSharedPoolAndLock(order.getBusinessId());
+        if(subsidySharedPool==null)
+        {
+            subsidySharedPool = initSharedPool(order.getBusinessId(), DateUtils.getNowDate(),sharedSubsidy);
+            subsidySharedPoolLogService.insertByBo(SubsidySharedPoolLogBo.builder()
+                .sharedId(subsidySharedPool.getSharedId())
+                .businessId(order.getBusinessId())
+                .orderId(order.getOrderId())
+                .orderNo(order.getOrderNo())
+                .behaviorType(SharedPoolBehaviorType.USER_ORDER_SUBSIDY)
+                .prevValue(BigDecimal.ZERO)
+                .changeValue(sharedSubsidy)
+                .resultValue(subsidySharedPool.getTotalSharedAmount().add(sharedSubsidy))
+                .remark("用户下单产生的均摊补贴,在不是立即补贴的均摊模式下,先存入均摊池")
+                .build());
+        }
+        else {
+            subsidySharedPoolLogService.insertByBo(SubsidySharedPoolLogBo.builder()
+                .sharedId(subsidySharedPool.getSharedId())
+                .businessId(order.getBusinessId())
+                .orderId(order.getOrderId())
+                .orderNo(order.getOrderNo())
+                .behaviorType(SharedPoolBehaviorType.USER_ORDER_SUBSIDY)
+                .prevValue(subsidySharedPool.getTotalSharedAmount())
+                .changeValue(sharedSubsidy)
+                .resultValue(subsidySharedPool.getTotalSharedAmount().add(sharedSubsidy))
+                .remark("用户下单产生的均摊补贴,在不是立即补贴的均摊模式下,先存入均摊池")
+                .build());
+
+            subsidySharedPool.setTotalSharedAmount(subsidySharedPool.getTotalSharedAmount().add(sharedSubsidy));
+            this.baseMapper.updateById(subsidySharedPool);
+        }
+
+
+    }
+
+    @Override
+    public SubsidySharedPool loadSharedPool(Long businessId) {
+        return this.baseMapper.selectOne(new LambdaQueryWrapper<SubsidySharedPool>()
+            .eq(SubsidySharedPool::getBusinessId, businessId)
+            .eq(SubsidySharedPool::getSettlemented, false)
+            .last("limit 1")
+        );
+    }
+
+    @Override
+    public SubsidySharedPool loadSharedPoolAndLock(Long businessId) {
+        boolean exists = this.baseMapper.exists(new LambdaQueryWrapper<SubsidySharedPool>().eq(SubsidySharedPool::getBusinessId, businessId)
+            .eq(SubsidySharedPool::getSettlemented, false)
+        );
+        if(!exists)
+        {
+            return this.baseMapper.selectOne(new LambdaQueryWrapper<SubsidySharedPool>()
+                .eq(SubsidySharedPool::getBusinessId, businessId)
+                .eq(SubsidySharedPool::getSettlemented, false)
+                .last("limit 1 for update")
+            );
+        }
+        return null;
+    }
+
+
 }

+ 5 - 5
ruoyi-line/src/main/resources/mapper/subsidy/SubsidyQueueMapper.xml

@@ -36,11 +36,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="updateTime" column="update_time"/>
     </resultMap>
 
-    <select id="validQueueCountAndLock" resultType="java.lang.Long">
-        select count(1) from tb_subsidy_queue
+    <select id="validQueueIds" resultType="java.lang.Long">
+        select queue_id from tb_subsidy_queue
         where current_business_id = #{businessId}
-        and  subsidy_status = 0
-        for update
+        and subsidy_status = 0
+        and cut_in = 0
+        order by queue_order asc
     </select>
-
 </mapper>

+ 1 - 0
ruoyi-user/src/main/java/com/ruoyi/user/enums/BalanceSourceType.java

@@ -17,6 +17,7 @@ public enum BalanceSourceType implements IIntegerEnum {
     CONSUME(3, "订单消费"),
     //消费排队补贴
     SUBSIDY(4, "消费排队补贴"),
+    SHARED_SUBSIDY(5, "消费排队均摊补贴"),
     ;
 
     @EnumValue