Prechádzať zdrojové kódy

调整对账相关代码

codingliang 1 rok pred
rodič
commit
1fd89ce787
21 zmenil súbory, kde vykonal 864 pridanie a 63 odobranie
  1. 1 1
      src/main/java/com/sqx/SecureApiTest.java
  2. 5 0
      src/main/java/com/sqx/common/constant/RedisKey.java
  3. 6 1
      src/main/java/com/sqx/modules/errand/dao/UserInfoDao.java
  4. 8 1
      src/main/java/com/sqx/modules/errand/service/UserInfoService.java
  5. 6 0
      src/main/java/com/sqx/modules/errand/service/impl/UserInfoServiceImpl.java
  6. 6 0
      src/main/java/com/sqx/modules/goods/service/GoodsShopService.java
  7. 9 3
      src/main/java/com/sqx/modules/goods/service/impl/GoodsShopServiceImpl.java
  8. 57 2
      src/main/java/com/sqx/modules/reconciliation/mapper/PlatformBillMapper.java
  9. 33 0
      src/main/java/com/sqx/modules/reconciliation/model/CashOutRecordBO.java
  10. 29 0
      src/main/java/com/sqx/modules/reconciliation/model/IndentOrderDataBO.java
  11. 44 0
      src/main/java/com/sqx/modules/reconciliation/model/OrderDataBO.java
  12. 22 24
      src/main/java/com/sqx/modules/reconciliation/model/PlatformBill.java
  13. 24 0
      src/main/java/com/sqx/modules/reconciliation/model/ShopMoneyRecordBO.java
  14. 24 0
      src/main/java/com/sqx/modules/reconciliation/model/SysGiftRecordBO.java
  15. 24 0
      src/main/java/com/sqx/modules/reconciliation/model/UserMoneyBalanceBO.java
  16. 10 1
      src/main/java/com/sqx/modules/reconciliation/service/PlatformBillService.java
  17. 380 4
      src/main/java/com/sqx/modules/reconciliation/service/impl/PlatformBillServiceImpl.java
  18. 40 26
      src/main/java/com/sqx/scheduler/reconciliation/BillsScheduler.java
  19. 10 0
      src/main/resources/mapper/errand/UserInfoMapper.xml
  20. 97 0
      src/main/resources/mapper/reconciliation/PlatformBillMapper.xml
  21. 29 0
      src/test/java/PlatformBillTest.java

+ 1 - 1
src/main/java/com/sqx/SecureApiTest.java

@@ -31,7 +31,7 @@ public class SecureApiTest {
         String encrypt = cipherUtils.encrypt(content, key, iv);
         System.out.println(encrypt);
 
-        String decrypt = cipherUtils.decrypt("RPX3_v1bTP4fLfrEMWHegBp_pJPh8TGDaN-SHZFjyyK_HLRIAt_wQrgWX95ZeHDKoTgvtRYcMKaTRs5YHDXFZM9GChuubOvCkwygP1ubQl4=", key, iv);
+        String decrypt = cipherUtils.decrypt("9VpteiNMuNImeaAxLv5NiJcPB5Y8bueaf2v6IGVR5Quv5S0Xyqg8RjCZqZAnQ6X6rGGt9Q8-PfcUXsFr-6l0-NKET9ttEn9Kos_i8qzGj1g=", key, iv);
         System.out.println(decrypt);
     }
 

+ 5 - 0
src/main/java/com/sqx/common/constant/RedisKey.java

@@ -92,4 +92,9 @@ public interface RedisKey {
      * 订单超时锁
      */
     String TIME_OUT_LOCK = "wm:time:out:lock:%s";
+
+    /**
+     * 平台账单锁
+     */
+    String PLATFORM_BILL_LOCK = "wm:lock:platform-bill";
 }

+ 6 - 1
src/main/java/com/sqx/modules/errand/dao/UserInfoDao.java

@@ -9,11 +9,11 @@ import com.sqx.modules.app.entity.UserMoneyDetails;
 import com.sqx.modules.errand.entity.ErrandEvaluate;
 import com.sqx.modules.errand.entity.TbIndent;
 import com.sqx.modules.errand.entity.TrainingCenter;
-import com.sqx.modules.order.entity.Evaluate;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 @Mapper
 public interface UserInfoDao extends BaseMapper<ErrandEvaluate> {
@@ -68,4 +68,9 @@ public interface UserInfoDao extends BaseMapper<ErrandEvaluate> {
 
     void updateNewUserFlagWm(Long userId);
 
+    /**
+     * 查询已经通过审核的所有骑手信息
+     * @return 骑手信息
+     */
+    List<UserEntity> getAllRiderInfo();
 }

+ 8 - 1
src/main/java/com/sqx/modules/errand/service/UserInfoService.java

@@ -4,6 +4,8 @@ import com.sqx.common.utils.Result;
 import com.sqx.modules.app.entity.UserEntity;
 import com.sqx.modules.errand.entity.Feedback;
 
+import java.util.List;
+
 public interface UserInfoService {
 
     UserEntity findUserInfoById(Long userId);
@@ -41,5 +43,10 @@ public interface UserInfoService {
     Result selectCashDeposit(Long userId, Integer page, Integer limit, Integer classify);
 
     Result getNewUserRedPacketWm(Long userId);
-    
+
+    /**
+     * 查询所有骑手用户信息
+     * @return 骑手用户
+     */
+    List<UserEntity> getAllRiderInfo();
 }

+ 6 - 0
src/main/java/com/sqx/modules/errand/service/impl/UserInfoServiceImpl.java

@@ -33,6 +33,7 @@ import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 
 @Service
 public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, ErrandEvaluate> implements UserInfoService {
@@ -290,6 +291,11 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, ErrandEvaluate
     }
 
     @Override
+    public List<UserEntity> getAllRiderInfo() {
+        return baseMapper.getAllRiderInfo();
+    }
+
+    @Override
     public Result updateCoordinate(Long userId, double lng, double lat) {
         userInfoDao.updateCoordinate(userId, lng, lat);
         return Result.success();

+ 6 - 0
src/main/java/com/sqx/modules/goods/service/GoodsShopService.java

@@ -57,4 +57,10 @@ public interface GoodsShopService extends IService<GoodsShop> {
      * @return 店铺信息
      */
     GoodsShop getByAdminUserId(Long adminUserId);
+
+    /**
+     * 查询所有正常状态下的店铺
+     * @return 店铺列表
+     */
+    List<GoodsShop> getAllShops();
 }

+ 9 - 3
src/main/java/com/sqx/modules/goods/service/impl/GoodsShopServiceImpl.java

@@ -3,8 +3,8 @@ package com.sqx.modules.goods.service.impl;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -40,8 +40,6 @@ import com.sqx.modules.order.dao.AppOrderDao;
 import com.sqx.modules.order.dao.OrderGoodsDao;
 import com.sqx.modules.order.entity.OrderGoods;
 import com.sqx.modules.order.entity.TbOrder;
-import com.sqx.modules.shop.service.ShopMessageService;
-import com.sqx.modules.shop.service.ShopTypeService;
 import com.sqx.modules.sys.dao.SysUserDao;
 import com.sqx.modules.sys.entity.SysUserEntity;
 import com.sqx.modules.sys.service.SysUserRoleService;
@@ -569,4 +567,12 @@ public class GoodsShopServiceImpl extends ServiceImpl<GoodsShopDao, GoodsShop> i
     public GoodsShop getByAdminUserId(Long adminUserId) {
         return baseMapper.getByAdminUserId(adminUserId);
     }
+
+    @Override
+    public List<GoodsShop> getAllShops() {
+        LambdaQueryWrapper<GoodsShop> queryWrapper = Wrappers.lambdaQuery();
+        // 1 表示店铺已经通过审核
+        queryWrapper.eq(GoodsShop::getStatus, 1);
+        return list(queryWrapper);
+    }
 }

+ 57 - 2
src/main/java/com/sqx/modules/reconciliation/mapper/PlatformBillMapper.java

@@ -1,13 +1,20 @@
 package com.sqx.modules.reconciliation.mapper;
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.sqx.modules.reconciliation.model.IndentOrderDataBO;
+import com.sqx.modules.reconciliation.model.OrderDataBO;
 import com.sqx.modules.reconciliation.model.PlatformBill;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.sqx.modules.reconciliation.model.PlatformBillDto;
 import com.sqx.modules.reconciliation.model.RiderBillVo;
 import com.sqx.modules.reconciliation.model.ShopBillVo;
-import org.apache.ibatis.annotations.*;
+import com.sqx.modules.reconciliation.model.CashOutRecordBO;
+import com.sqx.modules.reconciliation.model.ShopMoneyRecordBO;
+import com.sqx.modules.reconciliation.model.SysGiftRecordBO;
+import com.sqx.modules.reconciliation.model.UserMoneyBalanceBO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -41,4 +48,52 @@ public interface PlatformBillMapper extends BaseMapper<PlatformBill> {
     List<PlatformBill> excelPlatformBillList(@Param("params") PlatformBillDto query);
 
     Integer updateRiderStartMoney(@Param("dayId") String dayId);
+
+    /**
+     * 获取指定日期的订单统计数据
+     * @param startTime 开始时间
+     * @param endTime 截止时间
+     * @return 订单数据
+     */
+    List<OrderDataBO> getOrderData(@Param("startTime") String startTime, @Param("endTime") String endTime);
+
+    /**
+     * 获取指定日期的店铺收入记录
+     * @param startTime 开始时间
+     * @param endTime 截止时间
+     * @return 收入记录
+     */
+    List<ShopMoneyRecordBO> getShopMoneyRecord(@Param("startTime") String startTime, @Param("endTime") String endTime);
+
+    /**
+     * 获取用户指定日期的提现记录
+     * @param startTime 开始时间
+     * @param endTime 截止时间
+     * @return 提现记录
+     */
+    List<CashOutRecordBO> getCashOutRecord(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("userIds") List<Long> userIds);
+
+    /**
+     * 获取指定日期的店铺余额记录
+     * @param userIds 店铺用户id
+     * @return 余额记录
+     */
+    List<UserMoneyBalanceBO> getUserMoneyBalance(@Param("userIds") List<Long> userIds);
+
+    /**
+     * 获取指定日期的跑腿订单数据
+     * @param startTime 开始时间
+     * @param endTime 截止时间
+     * @return 跑腿订单统计数据
+     */
+    List<IndentOrderDataBO> getIndentOrderData(@Param("startTime") String startTime, @Param("endTime") String endTime);
+
+    /**
+     * 获取用户指定日期的系统赠送、扣减金额
+     * @param startTime 开始时间
+     * @param endTime 截止时间
+     * @param userIds 用户id集合
+     * @return 系统赠送、扣减金额记录
+     */
+    List<SysGiftRecordBO> getSysGiftRecord(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("userIds") List<Long> userIds);
 }

+ 33 - 0
src/main/java/com/sqx/modules/reconciliation/model/CashOutRecordBO.java

@@ -0,0 +1,33 @@
+package com.sqx.modules.reconciliation.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 提现记录
+ * @author codingliang
+ * @date 2025-03-21
+ */
+@Data
+public class CashOutRecordBO {
+    /**
+     * 用户id
+     */
+    private Long userId;
+
+    /**
+     * 商家提现金额
+     */
+    private BigDecimal payouts;
+
+    /**
+     * 商家提现手续费
+     */
+    private BigDecimal payoutsRates;
+
+    /**
+     * 商家提现次数
+     */
+    private Integer payoutsCount;
+}

+ 29 - 0
src/main/java/com/sqx/modules/reconciliation/model/IndentOrderDataBO.java

@@ -0,0 +1,29 @@
+package com.sqx.modules.reconciliation.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 跑腿订单统计数据
+ * @author codingliang
+ * @date 2025-03-22
+ */
+@Data
+public class IndentOrderDataBO {
+
+    /**
+     * 骑手用户id
+     */
+    private Long userId;
+
+    /**
+     * 总金额
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 订单数量
+     */
+    private Integer orderCount;
+}

+ 44 - 0
src/main/java/com/sqx/modules/reconciliation/model/OrderDataBO.java

@@ -0,0 +1,44 @@
+package com.sqx.modules.reconciliation.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 订单统计数据
+ * @author codingliang
+ * @date 2025-03-21
+ */
+@Data
+public class OrderDataBO {
+
+    /**
+     * 店铺id
+     */
+    private Long shopId;
+
+    /**
+     * 支付总金额
+     */
+    private BigDecimal payAmount;
+
+    /**
+     * 取消订单总金额
+     */
+    private BigDecimal canceledAmount;
+
+    /**
+     * 取消订单数量
+     */
+    private Integer canceledCount;
+
+    /**
+     * 完成订单数量
+     */
+    private Integer completedCount;
+
+    /**
+     * 商家收入
+     */
+    private BigDecimal shopAmount;
+}

+ 22 - 24
src/main/java/com/sqx/modules/reconciliation/model/PlatformBill.java

@@ -1,13 +1,7 @@
 package com.sqx.modules.reconciliation.model;
 
 import com.baomidou.mybatisplus.annotation.IdType;
-import java.util.Date;
-import com.baomidou.mybatisplus.annotation.Version;
 import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.TableField;
-import java.io.Serializable;
-
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -15,6 +9,10 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
 /**
  * <p>
  * 对账管理表
@@ -39,7 +37,7 @@ public class PlatformBill implements Serializable {
     private String dayId;
 
     @ApiModelProperty(value = "关联用户id")
-    private String userId;
+    private Long userId;
 
     @ApiModelProperty(value = "店铺名称")
     private String shopName;
@@ -48,43 +46,43 @@ public class PlatformBill implements Serializable {
     private String type;
 
     @ApiModelProperty(value = "期初金额")
-    private String startMoney;
+    private BigDecimal startMoney;
 
     @ApiModelProperty(value = "总收入")
-    private String revenue;
+    private BigDecimal revenue;
 
     @ApiModelProperty(value = "收入笔数")
-    private String revenueCount;
+    private Integer revenueCount;
 
     @ApiModelProperty(value = "商家提现金额")
-    private String shopPayouts;
+    private BigDecimal shopPayouts;
 
     @ApiModelProperty(value = "商家提现手续费")
-    private String shopPayoutsRates;
+    private BigDecimal shopPayoutsRates;
 
     @ApiModelProperty(value = "商家提现笔数")
-    private String shopPayoutsCount;
+    private Integer shopPayoutsCount;
 
     @ApiModelProperty(value = "骑手提现")
-    private String riderPayouts;
+    private BigDecimal riderPayouts;
 
     @ApiModelProperty(value = "骑手提现手续费")
-    private String riderPayoutsRates;
+    private BigDecimal riderPayoutsRates;
 
     @ApiModelProperty(value = "骑手提现笔数")
-    private String riderPayoutsCount;
+    private Integer riderPayoutsCount;
 
     @ApiModelProperty(value = "退款金额")
-    private String refundMoney;
+    private BigDecimal refundMoney;
 
     @ApiModelProperty(value = "退款笔数")
-    private String refundCount;
+    private Integer refundCount;
 
     @ApiModelProperty(value = "期末金额")
-    private String endMoney;
+    private BigDecimal endMoney;
 
     @ApiModelProperty(value = "平台抽成手续费")
-    private String platformRates;
+    private BigDecimal platformRates;
 
     @ApiModelProperty(value = "创建时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
@@ -95,15 +93,15 @@ public class PlatformBill implements Serializable {
     private Date updateTime;
 
     @ApiModelProperty(value = "系统赠送金额")
-    private String sysGiftAmount;
+    private BigDecimal sysGiftAmount;
 
     @ApiModelProperty(value = "总收益")
-    private String totalIncome;
+    private BigDecimal totalIncome;
 
     @ApiModelProperty(value = "用户支付金额")
-    private String payMoney;
+    private BigDecimal payMoney;
 
     @ApiModelProperty(value = "商户余额")
-    private String shopBalance;
+    private BigDecimal shopBalance;
 
 }

+ 24 - 0
src/main/java/com/sqx/modules/reconciliation/model/ShopMoneyRecordBO.java

@@ -0,0 +1,24 @@
+package com.sqx.modules.reconciliation.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 店铺收入记录
+ * @author codingliang
+ * @date 2025-03-21
+ */
+@Data
+public class ShopMoneyRecordBO {
+
+    /**
+     * 店铺id
+     */
+    private Long shopId;
+
+    /**
+     * 平台抽成手续费
+     */
+    private BigDecimal platformFee;
+}

+ 24 - 0
src/main/java/com/sqx/modules/reconciliation/model/SysGiftRecordBO.java

@@ -0,0 +1,24 @@
+package com.sqx.modules.reconciliation.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 系统赠送/扣减金额
+ * @author codingliang
+ * @date 2025-03-22
+ */
+@Data
+public class SysGiftRecordBO {
+
+    /**
+     * 用户id
+     */
+    private Long userId;
+
+    /**
+     * 赠送-扣减金额
+     */
+    private BigDecimal amount;
+}

+ 24 - 0
src/main/java/com/sqx/modules/reconciliation/model/UserMoneyBalanceBO.java

@@ -0,0 +1,24 @@
+package com.sqx.modules.reconciliation.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 店铺余额
+ * @author codingliang
+ * @date 2025-03-21
+ */
+@Data
+public class UserMoneyBalanceBO {
+
+    /**
+     * 用户id
+     */
+    private Long userId;
+
+    /**
+     * 余额
+     */
+    private BigDecimal balance;
+}

+ 10 - 1
src/main/java/com/sqx/modules/reconciliation/service/PlatformBillService.java

@@ -1,11 +1,13 @@
 package com.sqx.modules.reconciliation.service;
 
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.modules.reconciliation.model.PlatformBill;
-import com.baomidou.mybatisplus.extension.service.IService;
 import com.sqx.modules.reconciliation.model.PlatformBillDto;
 import com.sqx.modules.utils.excel.ExcelData;
 
+import java.time.LocalDate;
+
 /**
  * <p>
  * 对账管理表 服务类
@@ -16,6 +18,13 @@ import com.sqx.modules.utils.excel.ExcelData;
  */
 public interface PlatformBillService extends IService<PlatformBill> {
 
+    /**
+     * 生成对账单
+     * @param date 账单日期
+     * @param cover 是否覆盖 为true是如果当天有对账单则先删除当天账单数据再重新生成
+     */
+    void generatePlatformBill(LocalDate date, boolean cover);
+
     int insertPlatformBill();
 
     PageUtils riderBill(PlatformBillDto platformBillDto);

+ 380 - 4
src/main/java/com/sqx/modules/reconciliation/service/impl/PlatformBillServiceImpl.java

@@ -1,27 +1,55 @@
 package com.sqx.modules.reconciliation.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.utils.DateUtils;
 import com.sqx.common.utils.PageUtils;
-import com.sqx.modules.errand.entity.TbIndent;
-import com.sqx.modules.pay.entity.CashOut;
-import com.sqx.modules.reconciliation.model.PlatformBill;
+import com.sqx.modules.app.entity.UserEntity;
+import com.sqx.modules.errand.service.UserInfoService;
+import com.sqx.modules.goods.entity.GoodsShop;
+import com.sqx.modules.goods.service.GoodsShopService;
 import com.sqx.modules.reconciliation.mapper.PlatformBillMapper;
+import com.sqx.modules.reconciliation.model.CashOutRecordBO;
+import com.sqx.modules.reconciliation.model.IndentOrderDataBO;
+import com.sqx.modules.reconciliation.model.OrderDataBO;
+import com.sqx.modules.reconciliation.model.PlatformBill;
 import com.sqx.modules.reconciliation.model.PlatformBillDto;
 import com.sqx.modules.reconciliation.model.RiderBillVo;
 import com.sqx.modules.reconciliation.model.ShopBillVo;
+import com.sqx.modules.reconciliation.model.ShopMoneyRecordBO;
+import com.sqx.modules.reconciliation.model.SysGiftRecordBO;
+import com.sqx.modules.reconciliation.model.UserMoneyBalanceBO;
 import com.sqx.modules.reconciliation.service.PlatformBillService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sqx.modules.utils.excel.ExcelData;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
 
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -33,8 +61,71 @@ import java.util.List;
  */
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class PlatformBillServiceImpl extends ServiceImpl<PlatformBillMapper, PlatformBill> implements PlatformBillService {
 
+    private final GoodsShopService goodsShopService;
+    private final UserInfoService userInfoService;
+    private final RedissonClient redissonClient;
+    private final PlatformTransactionManager transactionManager;
+
+    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    @Override
+    public void generatePlatformBill(LocalDate date, boolean cover) {
+        RLock lock = redissonClient.getLock(RedisKey.PLATFORM_BILL_LOCK);
+        lock.lock();
+        TransactionStatus status = null;
+        try {
+            // 开启编程式事务
+            status = transactionManager.getTransaction(new DefaultTransactionDefinition());
+
+            // 判断有无当天数据,然后根据策略觉得是否执行覆盖数据还是直接退出
+            LambdaQueryWrapper<PlatformBill> wrapper = Wrappers.lambdaQuery();
+            wrapper.eq(PlatformBill::getDayId, date);
+            if (count(wrapper) > 0) {
+                if (cover) {
+                    // 删除旧数据
+                    remove(wrapper);
+                } else {
+                    return;
+                }
+            }
+
+            // 查询前一天账单
+            LambdaQueryWrapper<PlatformBill> queryWrapper = Wrappers.lambdaQuery();
+            queryWrapper.eq(PlatformBill::getDayId, date.minusDays(1));
+            queryWrapper.eq(PlatformBill::getType, "1");
+            List<PlatformBill> prePlatformBillDataS = list(queryWrapper);
+            Map<Long, PlatformBill> platformBillMap = prePlatformBillDataS.stream().collect(Collectors.toMap(PlatformBill::getUserId, Function.identity()));
+
+            // 查询商户数据
+            List<PlatformBill> shopPlatformBills = queryShopBill(date, platformBillMap);
+
+            // 查询骑手数据
+            List<PlatformBill> riderPlatformBills = queryRiderBill(date, platformBillMap);
+
+            // 计算平台账单数据
+            PlatformBill platformBills = calcPlatformBill(date, shopPlatformBills, riderPlatformBills, prePlatformBillDataS);
+
+            // 合并商户、骑手账单数据
+            Collection<PlatformBill> allPlatformBills = CollUtil.union(shopPlatformBills, riderPlatformBills, Arrays.asList(platformBills));
+
+            // 保存最终结果
+            saveBatch(allPlatformBills);
+
+            transactionManager.commit(status);
+        } catch (Exception e) {
+            if (ObjectUtil.isNotNull(status)) {
+                transactionManager.rollback(status);
+            }
+
+            e.printStackTrace();
+        } finally {
+            lock.unlock();
+        }
+    }
+
     /**
      * @return
      */
@@ -247,5 +338,290 @@ public class PlatformBillServiceImpl extends ServiceImpl<PlatformBillMapper, Pla
         return data;
     }
 
+    /**
+     * 计算平台账单数据
+     *
+     * @param date 账期
+     * @param shopPlatformBills  商家账单数据
+     * @param riderPlatformBills 骑手账单数据
+     * @param prePlatformBills 前一天对账数据
+     * @return 平台账单数据
+     */
+    private PlatformBill calcPlatformBill(LocalDate date, List<PlatformBill> shopPlatformBills, List<PlatformBill> riderPlatformBills, List<PlatformBill> prePlatformBills) {
+        // 账期
+        String accountPeriod = date.toString();
+
+        PlatformBill platformBill = new PlatformBill();
+        platformBill.setDayId(accountPeriod);
+        // 平台对账
+        platformBill.setType("0");
+
+        Optional<PlatformBill> prePlatformBillOptional = prePlatformBills.stream().filter(e -> "0".equals(e.getType())).findFirst();
+
+        // 初始金额
+        if (prePlatformBillOptional.isPresent()) {
+            platformBill.setStartMoney(prePlatformBillOptional.get().getEndMoney());
+        } else {
+            platformBill.setStartMoney(BigDecimal.ZERO);
+        }
+
+        // 订单总收入
+        platformBill.setRevenue(sum(shopPlatformBills, PlatformBill::getRevenue));
+        // 订单总笔数
+        platformBill.setRevenueCount(sumInt(shopPlatformBills, PlatformBill::getRevenueCount));
+        // 商家总提现金额
+        platformBill.setShopPayouts(sum(shopPlatformBills, PlatformBill::getShopPayouts));
+        // 商家总提现手续费
+        platformBill.setShopPayoutsRates(sum(shopPlatformBills, PlatformBill::getShopPayoutsRates));
+        // 商家提现笔数
+        platformBill.setShopPayoutsCount(sumInt(shopPlatformBills, PlatformBill::getShopPayoutsCount));
+        // 骑手总提现金额
+        platformBill.setRiderPayouts(sum(riderPlatformBills, PlatformBill::getRiderPayouts));
+        // 骑手总提现手续费
+        platformBill.setRiderPayoutsRates(sum(riderPlatformBills, PlatformBill::getRiderPayoutsRates));
+        // 骑手提现笔数
+        platformBill.setRiderPayoutsCount(sumInt(riderPlatformBills, PlatformBill::getRiderPayoutsCount));
+        // 退款金额
+        platformBill.setRefundMoney(sum(shopPlatformBills, PlatformBill::getRefundMoney));
+        // 退款笔数
+        platformBill.setRefundCount(sumInt(shopPlatformBills, PlatformBill::getRefundCount));
+        // 平台抽成手续费
+        platformBill.setPlatformRates(sum(shopPlatformBills, PlatformBill::getPlatformRates));
+        // 截止金额
+        platformBill.setEndMoney(platformBill.getRevenue());
+
+        return platformBill;
+    }
+
+    /**
+     * 查询骑手指定日期账单数据
+     * 从跑腿订单中获取:
+     * 收入
+     * 收入笔数
+     * 从提现表中获取
+     * 提现金额
+     * 提现手续费
+     * 提现笔数
+     * 从对账表中获取:
+     * 期初金额:前一天的期末金额
+     * 从用户钱包明细中获取:
+     * 赠送骑手余额
+     * 从用户信息表中获取:
+     * 总收益
+     * 期末金额:等于总收益
+     *
+     * @param date            账单日期
+     * @param platformBillMap 前一天对账数据
+     * @return 骑手对账信息
+     */
+    private List<PlatformBill> queryRiderBill(LocalDate date, Map<Long, PlatformBill> platformBillMap) {
+        // 账期
+        String accountPeriod = date.toString();
+        // 账期开始-截止时间
+        String startTime = DTF.format(date.atTime(0, 0, 0));
+        String endTime = DTF.format(date.atTime(0, 0, 0).plusDays(1));
+
+        // 查询骑手数据
+        List<UserEntity> riderInfos = userInfoService.getAllRiderInfo();
+        List<Long> userIds = riderInfos.stream().map(UserEntity::getUserId).collect(Collectors.toList());
+
+        // 查询跑腿订单数据
+        List<IndentOrderDataBO> indentOrderDataBOS = baseMapper.getIndentOrderData(startTime, endTime);
+        Map<Long, IndentOrderDataBO> indentOrderDataMap = indentOrderDataBOS.stream().collect(Collectors.toMap(IndentOrderDataBO::getUserId, Function.identity()));
+
+        // 查询提现数据
+        List<CashOutRecordBO> riderCashOutRecords = baseMapper.getCashOutRecord(startTime, endTime, userIds);
+        Map<Long, CashOutRecordBO> riderCashOutRecordMap = riderCashOutRecords.stream().collect(Collectors.toMap(CashOutRecordBO::getUserId, Function.identity()));
+
+        // 查询订单赠送金额数据
+        List<SysGiftRecordBO> sysGiftRecordBOS = baseMapper.getSysGiftRecord(startTime, endTime, userIds);
+        Map<Long, SysGiftRecordBO> sysGiftRecordMap = sysGiftRecordBOS.stream().collect(Collectors.toMap(SysGiftRecordBO::getUserId, Function.identity()));
 
+        return riderInfos.stream().map(riderInfo -> {
+            PlatformBill platformBill = new PlatformBill();
+            platformBill.setDayId(accountPeriod);
+            platformBill.setUserId(riderInfo.getUserId());
+            // 骑手对账
+            platformBill.setType("2");
+
+            IndentOrderDataBO indentOrderData = indentOrderDataMap.get(riderInfo.getUserId());
+            if (ObjectUtil.isNotNull(indentOrderData)) {
+                platformBill.setRevenue(indentOrderData.getTotalAmount());
+                platformBill.setRevenueCount(indentOrderData.getOrderCount());
+            } else {
+                platformBill.setRevenue(BigDecimal.ZERO);
+                platformBill.setRevenueCount(0);
+            }
+
+            CashOutRecordBO cashOutRecord = riderCashOutRecordMap.get(riderInfo.getUserId());
+            if (ObjectUtil.isNotNull(cashOutRecord)) {
+                platformBill.setRiderPayouts(cashOutRecord.getPayouts());
+                platformBill.setRiderPayoutsRates(cashOutRecord.getPayoutsRates());
+                platformBill.setRiderPayoutsCount(cashOutRecord.getPayoutsCount());
+            } else {
+                platformBill.setRiderPayouts(BigDecimal.ZERO);
+                platformBill.setRiderPayoutsRates(BigDecimal.ZERO);
+                platformBill.setRiderPayoutsCount(0);
+            }
+
+            SysGiftRecordBO sysGiftRecord = sysGiftRecordMap.get(riderInfo.getUserId());
+            if (ObjectUtil.isNotNull(sysGiftRecord)) {
+                platformBill.setSysGiftAmount(sysGiftRecord.getAmount());
+            } else {
+                platformBill.setSysGiftAmount(BigDecimal.ZERO);
+            }
+
+            PlatformBill preBill = platformBillMap.get(riderInfo.getUserId());
+            if (ObjectUtil.isNotNull(preBill)) {
+                platformBill.setStartMoney(preBill.getEndMoney());
+            } else {
+                platformBill.setStartMoney(BigDecimal.ZERO);
+            }
+
+            platformBill.setTotalIncome(platformBill.getRevenue());
+
+            platformBill.setEndMoney(riderInfo.getBalance());
+
+            return platformBill;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 查询商家指定日期账单数据
+     * 从订单表中获取(当天数据):
+     * 用户实际付款:当天用户实际付款金额
+     * 退款金额:当天退款金额
+     * 退款笔数:当天退款笔数
+     * 收入:当天商家收入
+     * 收入笔数:当天商家收入笔数
+     * 从商家钱包明细表中获取:
+     * 总收益:当天的入账金额(等于订单表里的商家收入)
+     * 平台抽成手续费:当天平台抽成金额
+     * 从提现表中获取(当天数据):
+     * 提现金额:当天提现金额
+     * 提现手续费:当天提现手续费
+     * 提现笔数:当天提现笔数
+     * 从用户信息表中获取:
+     * 账户余额:截止统计时的用户账户余额
+     * 从平台对账表中获取:
+     * 期初金额:前一天的期末金额
+     * 直接复用:
+     * 期末金额:总收益
+     *
+     * @param date            账单日期
+     * @param platformBillMap 前一天账单数据
+     * @return 商家对账单信息
+     */
+    private List<PlatformBill> queryShopBill(LocalDate date, Map<Long, PlatformBill> platformBillMap) {
+        // 账期
+        String accountPeriod = date.toString();
+        // 账期开始-截止时间
+        String startTime = DTF.format(date.atTime(0, 0, 0));
+        String endTime = DTF.format(date.atTime(0, 0, 0).plusDays(1));
+
+        // 获取店铺信息
+        List<GoodsShop> goodsShops = goodsShopService.getAllShops();
+        List<Long> userIds = goodsShops.stream().map(GoodsShop::getUserId).collect(Collectors.toList());
+
+        // 统计订单信息
+        List<OrderDataBO> orderDataBOs = baseMapper.getOrderData(startTime, endTime);
+        Map<Long, OrderDataBO> orderDataMap = orderDataBOs.stream().collect(Collectors.toMap(OrderDataBO::getShopId, Function.identity()));
+
+        // 查询当天平台抽成 抽成数据在user_money_details表中,订单完成时会计算商家收入、平台抽成
+        List<ShopMoneyRecordBO> shopMoneyRecords = baseMapper.getShopMoneyRecord(startTime, endTime);
+        Map<Long, ShopMoneyRecordBO> shopMoneryRecordMap = shopMoneyRecords.stream().collect(Collectors.toMap(ShopMoneyRecordBO::getShopId, Function.identity()));
+
+        // 查询所有商家提现记录
+        List<CashOutRecordBO> shopCashOutRecords = baseMapper.getCashOutRecord(startTime, endTime, userIds);
+        Map<Long, CashOutRecordBO> cashOutRecordMap = shopCashOutRecords.stream().collect(Collectors.toMap(CashOutRecordBO::getUserId, Function.identity()));
+
+        // 查询商户余额
+        List<UserMoneyBalanceBO> userMoneyBalances = baseMapper.getUserMoneyBalance(userIds);
+        Map<Object, UserMoneyBalanceBO> userMoneyBalanceMap = userMoneyBalances.stream().collect(Collectors.toMap(UserMoneyBalanceBO::getUserId, Function.identity()));
+
+
+        // 拼装商家对账数据
+        return goodsShops.stream().map(goodsShop -> {
+            PlatformBill platformBill = new PlatformBill();
+            platformBill.setDayId(accountPeriod);
+            platformBill.setUserId(goodsShop.getUserId());
+            platformBill.setShopName(goodsShop.getShopName());
+            // 商户对账
+            platformBill.setType("1");
+
+            OrderDataBO orderData = orderDataMap.get(goodsShop.getShopId());
+            if (ObjectUtil.isNotNull(orderData)) {
+                platformBill.setRevenue(orderData.getShopAmount());
+                platformBill.setRevenueCount(orderData.getCompletedCount());
+                platformBill.setRefundMoney(orderData.getCanceledAmount());
+                platformBill.setRefundCount(orderData.getCanceledCount());
+                platformBill.setPayMoney(orderData.getPayAmount());
+            } else {
+                platformBill.setRevenue(BigDecimal.ZERO);
+                platformBill.setRevenueCount(0);
+                platformBill.setRefundMoney(BigDecimal.ZERO);
+                platformBill.setRefundCount(0);
+                platformBill.setPayMoney(BigDecimal.ZERO);
+            }
+
+            ShopMoneyRecordBO shopMoneyRecord = shopMoneryRecordMap.get(goodsShop.getShopId());
+            if (ObjectUtil.isNotNull(shopMoneyRecord)) {
+                platformBill.setPlatformRates(shopMoneyRecord.getPlatformFee());
+            } else {
+                platformBill.setPlatformRates(BigDecimal.ZERO);
+            }
+
+            CashOutRecordBO shopCashOutRecord = cashOutRecordMap.get(goodsShop.getUserId());
+            if (ObjectUtil.isNotNull(shopCashOutRecord)) {
+                platformBill.setShopPayouts(shopCashOutRecord.getPayouts());
+                platformBill.setShopPayoutsRates(shopCashOutRecord.getPayoutsRates());
+                platformBill.setShopPayoutsCount(shopCashOutRecord.getPayoutsCount());
+            } else {
+                platformBill.setShopPayouts(BigDecimal.ZERO);
+                platformBill.setShopPayoutsRates(BigDecimal.ZERO);
+                platformBill.setShopPayoutsCount(0);
+            }
+
+            UserMoneyBalanceBO userMoneyBalance = userMoneyBalanceMap.get(goodsShop.getUserId());
+            if (ObjectUtil.isNotNull(userMoneyBalance)) {
+                platformBill.setShopBalance(userMoneyBalance.getBalance());
+            } else {
+                platformBill.setShopBalance(BigDecimal.ZERO);
+            }
+
+            PlatformBill preBill = platformBillMap.get(goodsShop.getUserId());
+            if (ObjectUtil.isNotNull(preBill)) {
+                platformBill.setStartMoney(preBill.getEndMoney());
+            } else {
+                platformBill.setStartMoney(BigDecimal.ZERO);
+            }
+
+            // 总收益等于完成订单收入
+            platformBill.setTotalIncome(platformBill.getRevenue());
+            // 期末金额等于总收益
+            platformBill.setEndMoney(platformBill.getRevenue());
+
+            return platformBill;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 统计BigDecimal类型数值
+     * @param bills 待统计数据
+     * @param mapper 待统计字段
+     * @return 统计结果
+     */
+    private static BigDecimal sum(List<PlatformBill> bills, Function<PlatformBill, BigDecimal> mapper) {
+        return bills.stream().map(mapper).reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
+    /**
+     * 统计Integer类型数值
+     * @param bills 待统计数据
+     * @param mapper 待统计字段
+     * @return 统计结果
+     */
+    private static int sumInt(List<PlatformBill> bills, ToIntFunction<PlatformBill> mapper) {
+        return bills.stream().mapToInt(mapper).sum();
+    }
 }

+ 40 - 26
src/main/java/com/sqx/scheduler/reconciliation/BillsScheduler.java

@@ -1,16 +1,14 @@
 package com.sqx.scheduler.reconciliation;
 
-import com.sqx.modules.coupon.service.TbCouponUserService;
 import com.sqx.modules.reconciliation.service.PlatformBillService;
-import com.sqx.scheduler.config.SchedulerLock;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.redisson.api.RLock;
-import org.redisson.api.RedissonClient;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
+import java.time.LocalDate;
+
 /**
  * 对账定时任务
  *
@@ -28,28 +26,44 @@ public class BillsScheduler {
      * 将所有超过失效时间的优惠券改为失效状态
      * 每填0点2分30秒执行一次
      */
+//     @Async
+//     @Scheduled(cron = "30 2 0 * * ?", zone = "Asia/Shanghai")
+// //    @Scheduled(cron = "30 * * * * ?", zone = "Asia/Shanghai")
+//     public void insertPlatformBill(){
+//         int errorCount = 0 ;
+//         log.info("开始统计对账数据");
+//         while (errorCount<3){
+//             try {
+//                 int count =platformBillService.insertPlatformBill();
+//                 if(count!=0){
+//                     break;
+//                 }
+//             } catch (Exception e) {
+//                 log.error("统计对账数据异常:{}", e.getMessage());
+//                 errorCount++;
+//                 try {
+//                     Thread.sleep(10000);
+//                 } catch (InterruptedException ex) {
+//                     throw new RuntimeException(ex);
+//                 }
+//             }
+//         }
+//         log.info("统计对账数据结束");
+//     }
+
+    /**
+     * 定时生成对账单
+     *    每天的2点30分、40分、50分执行一次
+     */
     @Async
-    @Scheduled(cron = "30 2 0 * * ?", zone = "Asia/Shanghai")
-//    @Scheduled(cron = "30 * * * * ?", zone = "Asia/Shanghai")
-    public void insertPlatformBill(){
-        int errorCount = 0 ;
-        log.info("开始统计对账数据");
-        while (errorCount<3){
-            try {
-                int count =platformBillService.insertPlatformBill();
-                if(count!=0){
-                    break;
-                }
-            } catch (Exception e) {
-                log.error("统计对账数据异常:{}", e.getMessage());
-                errorCount++;
-                try {
-                    Thread.sleep(10000);
-                } catch (InterruptedException ex) {
-                    throw new RuntimeException(ex);
-                }
-            }
-        }
-        log.info("统计对账数据结束");
+    @Scheduled(cron = "0 30,40,50 2 * * ?")
+    public void generatePlatformBill(){
+        log.info("开始统计对账数据...");
+        LocalDate date = LocalDate.now().minusDays(1);
+
+        // 统计对账数据,不覆盖已有数据
+        platformBillService.generatePlatformBill(date, false);
+
+        log.info("对账数据统计完成...");
     }
 }

+ 10 - 0
src/main/resources/mapper/errand/UserInfoMapper.xml

@@ -129,6 +129,16 @@
         select * from training_center where training_id = #{id}
     </select>
 
+    <select id="getAllRiderInfo" resultType="com.sqx.modules.app.entity.UserEntity">
+        SELECT
+            *
+        FROM
+            tb_user
+        WHERE
+            rider_open_id IS NOT NULL
+          AND check_certification = '1';
+    </select>
+
     <update id="updateNewUserFlagWm">
         update tb_user set new_user_flag_wm = 2 where user_id = #{userId}
     </update>

+ 97 - 0
src/main/resources/mapper/reconciliation/PlatformBillMapper.xml

@@ -292,4 +292,101 @@
         from platform_bill pb where day_id =#{dayId}
     </insert>
 
+    <!-- 按商家维度统计订单完成金额、订单完成数量、订单取消金额、订单取消数量 -->
+    <!-- 3待取餐/派送中 4已完成 6制作中 7商家待接单 5已取消、8商家拒绝接单 -->
+    <!-- 3,4,6,7状态下用户已经完成付款对账的时候视为已完成订单 5,8状态下表示订单已取消 -->
+    <select id="getOrderData" resultType="com.sqx.modules.reconciliation.model.OrderDataBO">
+        SELECT
+            shop_id,
+            IFNULL(SUM(pay_money), 0) AS pay_amount,  -- 当天用户支付总金额
+            SUM(IF(status IN (5, 8), pay_money, 0)) AS canceled_amount,     -- 已取消订单总金额
+            COUNT(IF(status IN (5, 8), 1, NULL)) AS canceled_count,  -- 已取消订单总数量
+            SUM(IF(status IN (3, 4, 6, 7), shop_income_money, 0)) AS shop_amount, -- 已完成订单商家总收入
+            COUNT(IF(status IN (3, 4, 6, 7), 1, NULL)) AS completed_count  -- 已完成订单总数量
+        FROM
+            tb_order
+        WHERE
+            is_pay = 1
+            AND pay_time BETWEEN #{startTime} AND #{endTime}
+        GROUP BY
+            shop_id;
+    </select>
+
+    <select id="getShopMoneyRecord" resultType="com.sqx.modules.reconciliation.model.ShopMoneyRecordBO">
+        SELECT
+            shop_id,
+            SUM(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(content, '平台服务费:', -1), ',',1), ':', -1))) AS platform_fee
+        FROM
+            user_money_details
+        WHERE
+            shop_id IS NOT NULL
+          AND type = 1
+          AND classify = 3
+          AND create_time BETWEEN #{startTime} AND #{endTime}
+        GROUP BY shop_id;
+    </select>
+
+    <select id="getCashOutRecord" resultType="com.sqx.modules.reconciliation.model.CashOutRecordBO">
+        SELECT
+            user_id,
+            IFNULL(SUM(money), 0) payouts, -- 提现金额
+            IFNULL(SUM(rate), 0) payouts_rates, -- 提现手续费
+            COUNT(id) payouts_count -- 提现次数
+        FROM
+            cash_out
+        WHERE
+            type = 1
+          AND state = 1 -- 提现成功
+          AND out_at BETWEEN #{startTime} AND #{endTime}
+          AND user_id IN
+            <foreach collection="userIds" item="userId" open="(" separator="," close=")">
+                #{userId}
+            </foreach>
+        GROUP BY user_id;
+    </select>
+
+    <select id="getUserMoneyBalance" resultType="com.sqx.modules.reconciliation.model.UserMoneyBalanceBO">
+        SELECT
+            user_id,
+            money balance
+        FROM
+            user_money
+        WHERE
+            user_id IN
+                <foreach collection="userIds" item="userId" open="(" separator="," close=")">
+                    #{userId}
+                </foreach>
+    </select>
+
+    <select id="getIndentOrderData" resultType="com.sqx.modules.reconciliation.model.IndentOrderDataBO">
+        SELECT
+            rider_user_id user_id,
+            SUM(rider_money) AS totalAmount,
+            COUNT(indent_id) AS orderCount
+        FROM
+            tb_indent
+        WHERE
+            finish_time BETWEEN #{startTime} AND #{endTime}
+          AND rider_user_id IS NOT NULL
+          AND indent_state = '6'
+        GROUP BY rider_user_id;
+    </select>
+
+    <select id="getSysGiftRecord" resultType="com.sqx.modules.reconciliation.model.SysGiftRecordBO">
+        SELECT
+            user_id,
+            SUM(IF(type = 1, money, 0)) - SUM(IF(type = 2, money, 0)) as amount
+        FROM
+            user_money_details
+        WHERE
+            state = 2
+          AND classify = 3
+          AND create_time BETWEEN #{startTime} AND #{endTime}
+          AND user_id IN
+                <foreach collection="userIds" item="userId" open="(" separator="," close=")">
+                    #{userId}
+                </foreach>
+          AND (title = '系统赠送骑手余额' or title = '系统扣除用户余额')
+        GROUP BY user_id;
+    </select>
 </mapper>

+ 29 - 0
src/test/java/PlatformBillTest.java

@@ -0,0 +1,29 @@
+import com.sqx.SqxApplication;
+import com.sqx.modules.reconciliation.service.PlatformBillService;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.time.LocalDate;
+
+/**
+ * @author : codingliang
+ * @date : 2024-09-10 16:24
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = SqxApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class PlatformBillTest {
+
+    @Resource
+    private PlatformBillService platformBillService;
+
+    @Test
+    public void test() {
+        LocalDate date = LocalDate.now().minusDays(4);
+        platformBillService.generatePlatformBill(date, true);
+    }
+}