From 62d4326103dd25ed226c739094a5f93edfb54817 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=A2=A8=E5=A4=A7=E5=8F=94?= <494979559@qq.com>
Date: Mon, 5 Aug 2024 17:55:44 +0800
Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=A7=9F=E6=9C=9F=EF=BC=88?=
 =?UTF-8?q?=E6=9C=AA=E6=B5=8B=E8=AF=95=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/ruoyi/ss/device/domain/Device.java    |  4 ++
 .../ruoyi/ss/device/mapper/DeviceMapper.java  |  5 ++
 .../ruoyi/ss/device/mapper/DeviceMapper.xml   | 14 +++++
 .../ss/device/service/DeviceService.java      |  9 +++
 .../service/impl/DeviceServiceImpl.java       |  6 ++
 .../service/ReceiveBillService.java           | 12 ++--
 .../service/impl/ReceiveBillServiceImpl.java  | 61 +++++++++++++------
 .../domain/vo/UserRechargeServiceVO.java      | 28 +++++++++
 .../impl/TransactionBillServiceImpl.java      | 56 +++++++++--------
 9 files changed, 143 insertions(+), 52 deletions(-)
 create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/vo/UserRechargeServiceVO.java

diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/domain/Device.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/domain/Device.java
index 1fbd6164..98daed9a 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/domain/Device.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/domain/Device.java
@@ -184,4 +184,8 @@ public class Device extends BaseEntity
     @Excel(name = "超出起步时长价格", readConverterExp = "元=")
     @ApiModelProperty("超出起步时长价格")
     private BigDecimal overPrice;
+
+    @ApiModelProperty("设备租期到期时间")
+    @JsonView(JsonViewProfile.AppMch.class)
+    private LocalDateTime rentTime;
 }
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java
index 3eb0f68a..f3cd7c2a 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java
@@ -180,4 +180,9 @@ public interface DeviceMapper
      * 更新服务费
      */
     int updateServiceRate(DeviceVO data);
+
+    /**
+     * 续费时长
+     */
+    int renewalRentTime(@Param("deviceId") Long deviceId, @Param("seconds") long seconds);
 }
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml
index d1b1b3a6..eb21db6d 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml
@@ -99,6 +99,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             sd.over_time,
             sd.over_unit,
             sd.over_price,
+            sd.rent_time,
             sm.model_name as model,
             sm.picture as picture,
             sm.tags as  model_tags,
@@ -259,6 +260,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="overTime != null">over_time,</if>
             <if test="overUnit != null">over_unit,</if>
             <if test="overPrice != null">over_price,</if>
+            <if test="rentTime != null">rent_time,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="storeId != null">#{storeId},</if>
@@ -296,6 +298,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="overTime != null">#{overTime},</if>
             <if test="overUnit != null">#{overUnit},</if>
             <if test="overPrice != null">#{overPrice},</if>
+            <if test="rentTime != null">#{rentTime},</if>
          </trim>
     </insert>
 
@@ -354,6 +357,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="overTime != null">over_time = #{overTime},</if>
             <if test="overUnit != null">over_unit = #{overUnit},</if>
             <if test="overPrice != null">over_price = #{overPrice},</if>
+            <if test="rentTime != null">rent_time = #{rentTime},</if>
         </trim>
         where device_id = #{deviceId}
     </update>
@@ -457,6 +461,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where device_id = #{deviceId}
     </update>
 
+    <update id="renewalRentTime">
+        update sm_device
+        set rent_time = if(
+                now() > rent_time,
+                date_add(now(), interval #{seconds} second),
+                date_add(rent_time, interval #{seconds} second)
+            )
+        where device_id = #{deviceId}
+    </update>
+
     <delete id="deleteSmDeviceByDeviceId" parameterType="Long">
         delete from sm_device where device_id = #{deviceId}
     </delete>
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java
index e1e3eda4..4798638e 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java
@@ -12,6 +12,7 @@ import com.ruoyi.ss.device.domain.vo.DeviceVO;
 import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 
 /**
@@ -267,4 +268,12 @@ public interface DeviceService
      * 更新服务费
      */
     int updateServiceRate(DeviceVO data);
+
+    /**
+     * 续费时长
+     * @param deviceId 设备ID
+     * @param time 时长
+     * @param timeUnit 时长单位
+     */
+    int renewalRentTime(Long deviceId, int time, TimeUnit timeUnit);
 }
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java
index 488b1c2d..a321facb 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java
@@ -393,6 +393,12 @@ public class DeviceServiceImpl implements DeviceService
         return deviceMapper.updateServiceRate(data);
     }
 
+    @Override
+    public int renewalRentTime(Long deviceId, int time, TimeUnit timeUnit) {
+        long seconds = timeUnit.toSeconds(time);
+        return deviceMapper.renewalRentTime(deviceId, seconds);
+    }
+
 
     @Override
     public boolean addTime(Long deviceId, long seconds, boolean withIot) {
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/ReceiveBillService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/ReceiveBillService.java
index ec05768f..c5a6cced 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/ReceiveBillService.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/ReceiveBillService.java
@@ -1,14 +1,12 @@
 package com.ruoyi.ss.receiveBill.service;
 
 import java.math.BigDecimal;
-import java.time.LocalDateTime;
 import java.util.List;
 
-import com.ruoyi.ss.device.domain.vo.DeviceVO;
 import com.ruoyi.ss.receiveBill.domain.ReceiveBill;
 import com.ruoyi.ss.receiveBill.domain.ReceiveBillVO;
 import com.ruoyi.ss.receiveBill.domain.ReceiveBillQuery;
-import com.ruoyi.ss.user.domain.SmUserVo;
+import com.ruoyi.ss.transactionBill.domain.bo.RechargeBO;
 
 /**
  * 应收账单Service接口
@@ -69,12 +67,10 @@ public interface ReceiveBillService
     /**
      * 月费商户出账
      *
-     * @param user     用户ID
-     * @param device
-     * @param billTime 出账日期
-     * @param amount
+     * @param bo     充值BO
+     * @param amount 收取的金额
      */
-    int genBillByMonthAndPay(SmUserVo user, DeviceVO device, LocalDateTime billTime, BigDecimal amount);
+    int genBillByMonthAndPay(RechargeBO bo, BigDecimal amount);
 
     /**
      * 查询数量
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/impl/ReceiveBillServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/impl/ReceiveBillServiceImpl.java
index 3aa85b2e..69613030 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/impl/ReceiveBillServiceImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/receiveBill/service/impl/ReceiveBillServiceImpl.java
@@ -3,13 +3,16 @@ package com.ruoyi.ss.receiveBill.service.impl;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.ServiceUtil;
 import com.ruoyi.ss.device.domain.vo.DeviceVO;
+import com.ruoyi.ss.device.service.DeviceService;
 import com.ruoyi.ss.receiveBill.domain.enums.ReceiveBillStatus;
 import com.ruoyi.ss.receiveBill.domain.enums.ReceiveBillType;
-import com.ruoyi.ss.transactionBill.service.impl.TransactionBillServiceImpl;
+import com.ruoyi.ss.transactionBill.domain.TransactionBill;
+import com.ruoyi.ss.transactionBill.domain.bo.RechargeBO;
 import com.ruoyi.ss.user.domain.SmUserVo;
 import com.ruoyi.ss.user.service.ISmUserService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -35,8 +38,10 @@ public class ReceiveBillServiceImpl implements ReceiveBillService
 
     @Autowired
     private ISmUserService userService;
+
     @Autowired
-    private TransactionBillServiceImpl transactionBillService;
+    private DeviceService deviceService;
+
     @Autowired
     private TransactionTemplate transactionTemplate;
 
@@ -114,26 +119,37 @@ public class ReceiveBillServiceImpl implements ReceiveBillService
     }
 
     @Override
-    public int genBillByMonthAndPay(SmUserVo user, DeviceVO device, LocalDateTime billTime, BigDecimal amount) {
-        ServiceUtil.assertion(user == null || user.getUserId() == null, "用户不存在");
+    public int genBillByMonthAndPay(RechargeBO bo, BigDecimal amount) {
+        SmUserVo mch = bo.getMch();
+        DeviceVO device = bo.getDevice();
+        TransactionBill order = bo.getOrder();
+        LocalDateTime billTime = LocalDateTime.now();
+        ServiceUtil.assertion(mch == null || mch.getUserId() == null, "用户不存在");
         ServiceUtil.assertion(device == null || device.getDeviceId() == null, "设备不存在");
-        ServiceUtil.assertion(billTime == null, "请指定一个月份");
 
-        // 查询指定月份是否已出账
-        ReceiveBillQuery query = new ReceiveBillQuery();
-        query.setBillYear(billTime.getYear());
-        query.setBillMonth(billTime.getMonthValue());
-        query.setType(ReceiveBillType.MONTH.getType());
-        query.setUserId(user.getUserId());
-        query.setDeviceId(device.getDeviceId());
-        int count = this.selectCount(query);
-        if ( count > 0) {
-            return count;
+        // 设备未过期,则不生成账单
+        if (device.getRentTime() != null && device.getRentTime().isAfter(LocalDateTime.now())) {
+            return 1;
         }
 
-        // 若未出账则生成账单
+        // 查询指定月份是否已出账,已出账则不生成账单
+//        ReceiveBillQuery query = new ReceiveBillQuery();
+//        query.setBillYear(billTime.getYear());
+//        query.setBillMonth(billTime.getMonthValue());
+//        query.setType(ReceiveBillType.MONTH.getType());
+//        query.setUserId(mch.getUserId());
+//        query.setDeviceId(device.getDeviceId());
+//        int count = this.selectCount(query);
+//        if ( count > 0) {
+//            return count;
+//        }
+
+        // 判断商户余额 + 订单金额是否足够账单金额
+        ServiceUtil.assertion(mch.getBalance().add(order.getArrivalAmount()).compareTo(amount) < 0, "设备到期,商家余额不足,请联系商家处理");
+
+        // 生成账单
         ReceiveBill bill = new ReceiveBill();
-        bill.setUserId(user.getUserId());
+        bill.setUserId(mch.getUserId());
         bill.setDeviceId(device.getDeviceId());
         bill.setType(ReceiveBillType.MONTH.getType());
         bill.setStatus(ReceiveBillStatus.PAID.getStatus());
@@ -143,11 +159,18 @@ public class ReceiveBillServiceImpl implements ReceiveBillService
         bill.setReceivedAmount(amount);
         Integer result = transactionTemplate.execute(status -> {
             // 用户余额扣减
-            int subtract = userService.subtractBalance(user.getUserId(), amount, false, bill.getDescription());
+            int subtract = userService.subtractBalance(mch.getUserId(), amount, true, bill.getDescription());
             ServiceUtil.assertion(subtract != 1, "扣减商户余额失败");
 
             // 插入账单
-            return this.insertReceiveBill(bill);
+            int insert = this.insertReceiveBill(bill);
+            ServiceUtil.assertion(insert != 1, "新增账单失败");
+
+            // 设备续费30天
+            int renewal = deviceService.renewalRentTime(device.getDeviceId(), 30, TimeUnit.DAYS);
+            ServiceUtil.assertion(renewal != 1, "设备续费失败");
+
+            return insert;
         });
 
         return result == null ? 0 : result;
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/vo/UserRechargeServiceVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/vo/UserRechargeServiceVO.java
new file mode 100644
index 00000000..10413dd9
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/vo/UserRechargeServiceVO.java
@@ -0,0 +1,28 @@
+package com.ruoyi.ss.transactionBill.domain.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 用户充值手续费
+ * @author wjh
+ * 2024/8/5
+ */
+@Data
+public class UserRechargeServiceVO {
+
+    // 类型
+    private String serviceType;
+
+    // 手续费
+    private BigDecimal serviceRate;
+
+    public UserRechargeServiceVO() {
+    }
+
+    public UserRechargeServiceVO(String serviceType, BigDecimal serviceRate) {
+        this.serviceType = serviceType;
+        this.serviceRate = serviceRate;
+    }
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java
index 11a47c0d..e56a601d 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java
@@ -27,6 +27,7 @@ import com.ruoyi.ss.transactionBill.domain.TransactionBill;
 import com.ruoyi.ss.transactionBill.domain.TransactionBillQuery;
 import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
 import com.ruoyi.ss.transactionBill.domain.bo.RechargeBO;
+import com.ruoyi.ss.transactionBill.domain.vo.UserRechargeServiceVO;
 import com.ruoyi.ss.transactionBill.domain.vo.UserWithdrawServiceVO;
 import com.ruoyi.ss.transactionBill.domain.bo.WithdrawBO;
 import com.ruoyi.ss.transactionBill.domain.dto.BillRefundDTO;
@@ -45,7 +46,6 @@ import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.task.bill.BillDelayedManager;
 import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
 import com.wechat.pay.java.service.payments.model.Transaction;
-import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -242,35 +242,23 @@ public class TransactionBillServiceImpl implements TransactionBillService {
     }
 
     // 处理充值服务费
-    private void handleRechargeService(TransactionBill order, ChannelVO channel, SmUserVo mch, DeviceVO device) {
+    private void handleRechargeService(RechargeBO bo) {
+        TransactionBill order = bo.getOrder();
+        ChannelVO channel = bo.getChannel();
+        SmUserVo mch = bo.getMch();
+        DeviceVO device = bo.getDevice();
         ServiceUtil.assertion(mch == null, "商户不存在,不允许下单");
         ServiceUtil.assertion(device == null, "设备不存在,不允许下单");
 
-        String serviceType = null;  // 服务费类型
-        BigDecimal serviceRate = null;   // 服务费
-
-        // 优先级: 设备 > 商户 > 渠道
-        if (device.getServiceRate() != null && StringUtils.hasText(device.getServiceType())) {
-            serviceType = device.getServiceType();
-            serviceRate = device.getServiceRate();
-        }
-        // 商户
-        else if (mch.getServiceRate() != null && StringUtils.hasText(mch.getServiceType())) {
-            serviceType = mch.getServiceType();
-            serviceRate = mch.getServiceRate();
-        }
-        // 渠道
-        else {
-            ServiceUtil.assertion(channel == null, "支付渠道不存在");
-            ServiceUtil.assertion(channel.getServiceRate() == null, "支付渠道服务费未配置,请联系管理员");
-            ServiceUtil.assertion(StringUtils.isBlank(channel.getServiceType()), "支付渠道服务费收取方式未配置,请联系管理员");
-            serviceType = channel.getServiceType();
-            serviceRate = channel.getServiceRate();
-        }
+        // 获取商户的服务费配置
+        UserRechargeServiceVO userRechargeService = this.getUserRechargeService(channel, mch, device);
+        String serviceType = userRechargeService.getServiceType();  // 服务费类型
+        BigDecimal serviceRate = userRechargeService.getServiceRate();   // 服务费
 
+        // 根据服务费类型进行对应操作
         // 月费
         if (ServiceType.MONTH.getType().equals(serviceType)) {
-            int count = receiveBillService.genBillByMonthAndPay(mch, device, LocalDateTime.now(), serviceRate);
+            int count = receiveBillService.genBillByMonthAndPay(bo, serviceRate);
             ServiceUtil.assertion(count == 0, "商户出账失败,请刷新后重试");
             // 服务费 = 0
             order.setServiceCharge(BigDecimal.ZERO);
@@ -290,6 +278,24 @@ public class TransactionBillServiceImpl implements TransactionBillService {
 
     }
 
+    private UserRechargeServiceVO getUserRechargeService(ChannelVO channel, SmUserVo mch, DeviceVO device) {
+        // 优先级: 设备 > 商户 > 渠道
+        if (device.getServiceRate() != null && StringUtils.hasText(device.getServiceType())) {
+            return new UserRechargeServiceVO(device.getServiceType(), device.getServiceRate());
+        }
+        // 商户
+        else if (mch.getServiceRate() != null && StringUtils.hasText(mch.getServiceType())) {
+            return new UserRechargeServiceVO(mch.getServiceType(), mch.getServiceRate());
+        }
+        // 渠道
+        else {
+            ServiceUtil.assertion(channel == null, "支付渠道不存在");
+            ServiceUtil.assertion(channel.getServiceRate() == null, "支付渠道服务费未配置,请联系管理员");
+            ServiceUtil.assertion(StringUtils.isBlank(channel.getServiceType()), "支付渠道服务费收取方式未配置,请联系管理员");
+            return new UserRechargeServiceVO(channel.getServiceType(),  channel.getServiceRate());
+        }
+    }
+
     // 转换为订单所需的数据
     private TransactionBill parseToOrder(RechargeBO bo) {
         // 校验
@@ -332,7 +338,7 @@ public class TransactionBillServiceImpl implements TransactionBillService {
         // 渠道费用计算
         order.setChannelCost(channel.getCostRate().multiply(order.getMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
         // 充值服务费处理
-        this.handleRechargeService(order, channel, mch, device);
+        this.handleRechargeService(bo);
         // 支付过期时间
         long expireTime = TimeUnit.MILLISECONDS.convert(Constants.BILL_UNPAID_TIMEOUT, Constants.BILL_UNPAID_TIMEUNIT) + System.currentTimeMillis();
         order.setExpireTime(new Date(expireTime));