From ed1df8462c6b431b934def092937ac410c92ce10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E5=A4=A7=E5=8F=94?= <494979559@qq.com> Date: Fri, 13 Sep 2024 15:09:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ruoyi/common/constant/Constants.java | 4 + .../common/core/domain/entity/SmUser.java | 3 + .../common/core/redis/enums/RedisLockKey.java | 3 +- .../java/com/ruoyi/common/enums/UserType.java | 5 +- .../com/ruoyi/common/utils/ServiceUtil.java | 5 + .../ruoyi/common/domain/vo/CommonCountVO.java | 18 + .../ruoyi/common/domain/vo/CommonSumVO.java | 18 + .../iot/service/IotReceiveServiceImpl.java | 76 ++-- .../com/ruoyi/iot/service/IotService.java | 18 + .../com/ruoyi/iot/service/IotServiceImpl.java | 33 ++ .../java/com/ruoyi/ss/bonus/domain/Bonus.java | 94 +++++ .../ss/bonus/domain/BonusProvideQuery.java | 30 ++ .../com/ruoyi/ss/bonus/domain/BonusQuery.java | 37 ++ .../com/ruoyi/ss/bonus/domain/BonusVO.java | 11 + .../bonus/domain/enums/BonusArrivalType.java | 65 ++++ .../ss/bonus/domain/enums/BonusStatus.java | 20 ++ .../bonus/domain/vo/BonusDailyAmountVO.java | 18 + .../bonus/domain/vo/BonusMonthAmountVO.java | 21 ++ .../ss/bonus/domain/vo/ProvideBonusVO.java | 22 ++ .../ruoyi/ss/bonus/mapper/BonusMapper.java | 113 ++++++ .../com/ruoyi/ss/bonus/mapper/BonusMapper.xml | 336 ++++++++++++++++++ .../ss/bonus/service/BonusConverter.java | 32 ++ .../ruoyi/ss/bonus/service/BonusService.java | 120 +++++++ .../service/impl/BonusConverterImpl.java | 168 +++++++++ .../bonus/service/impl/BonusServiceImpl.java | 269 ++++++++++++++ .../com/ruoyi/ss/device/domain/Device.java | 3 + .../ss/device/service/DeviceService.java | 12 + .../service/impl/DeviceServiceImpl.java | 14 + .../transactionBill/domain/bo/RechargeBO.java | 6 + .../service/TransactionBillService.java | 8 + .../service/impl/RechargeDepositAfterPay.java | 2 +- .../impl/TransactionBillServiceImpl.java | 31 +- .../com/ruoyi/ss/user/domain/SmUserVo.java | 4 + .../com/ruoyi/ss/user/mapper/SmUserMapper.xml | 1 + .../ruoyi/ss/user/service/ISmUserService.java | 2 +- .../user/service/impl/SmUserServiceImpl.java | 4 +- 36 files changed, 1585 insertions(+), 41 deletions(-) create mode 100644 smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonCountVO.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonSumVO.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/Bonus.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusProvideQuery.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusQuery.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusVO.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusArrivalType.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusStatus.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusDailyAmountVO.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusMonthAmountVO.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/ProvideBonusVO.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.xml create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusConverter.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusService.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusConverterImpl.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusServiceImpl.java diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/Constants.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/Constants.java index 8dd0232e..bba5e6bb 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -220,4 +220,8 @@ public class Constants * 设备已绑定 */ public static final int DEVICE_BINDED = 2; + /** + * 根部门 + */ + public static final long ROOT_DEPT = 100L; } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/domain/entity/SmUser.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/domain/entity/SmUser.java index d0759f0e..828cccde 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/domain/entity/SmUser.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/domain/entity/SmUser.java @@ -166,4 +166,7 @@ public class SmUser extends BaseEntity @ApiModelProperty("是否已经实名认证") @JsonView(JsonViewProfile.App.class) private Boolean isReal; + + @ApiModelProperty("用户类型") + private String type; } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/enums/RedisLockKey.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/enums/RedisLockKey.java index c4d8b34d..d066e802 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/enums/RedisLockKey.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/enums/RedisLockKey.java @@ -22,7 +22,8 @@ public enum RedisLockKey { ADD_TIME_BILL("add_time_bill", "创建时长订单"), PAY_BILL("pay_bill", "支付订单"), PREPAY_DEPOSIT("prepay_deposit", "支付押金"), - ADD_RECHARGE_ORDER("add_recharge_order", "创建充值订单"); + ADD_RECHARGE_ORDER("add_recharge_order", "创建充值订单"), + RECOVER_DEVICE_BALANCE("recover_device_balance", "恢复设备余额"); private final String key; diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/enums/UserType.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/enums/UserType.java index 3db456f2..c9da6755 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/enums/UserType.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/enums/UserType.java @@ -15,8 +15,9 @@ import java.util.Objects; @AllArgsConstructor public enum UserType { - TENANT("00", "租户"), - LANDLORD("01", "商户"); + USER("1", "普通用户"), + MCH("2", "商户"), + AGENT("3", "代理商"); private final String type; private final String name; diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/ServiceUtil.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/ServiceUtil.java index 2b44cfcb..0abefae4 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/ServiceUtil.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/ServiceUtil.java @@ -43,4 +43,9 @@ public class ServiceUtil { throw new ServiceException(result.getMsg(), result.getCode()); } } + public static void assertion(boolean flag, String format, Object ...args) { + if (flag) { + throw new ServiceException(String.format(format, args), 500); + } + } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonCountVO.java b/smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonCountVO.java new file mode 100644 index 00000000..de62f43c --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonCountVO.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.domain.vo; + +import lombok.Data; + +/** + * @author wjh + * 2024/8/23 + */ +@Data +public class CommonCountVO { + + // 键 + private T key; + + // 数量 + private Integer count; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonSumVO.java b/smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonSumVO.java new file mode 100644 index 00000000..9e77e8c8 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/common/domain/vo/CommonSumVO.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.domain.vo; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author wjh + * 2024/8/23 + */ +@Data +public class CommonSumVO { + + private T key; + + private BigDecimal sum; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotReceiveServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotReceiveServiceImpl.java index 8610e5d5..ac067414 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotReceiveServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotReceiveServiceImpl.java @@ -1,10 +1,14 @@ package com.ruoyi.iot.service; +import com.ruoyi.common.core.redis.RedisLock; +import com.ruoyi.common.core.redis.enums.RedisLockKey; import com.ruoyi.common.utils.NumberUtils; +import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.collection.CollectionUtils; import com.ruoyi.iot.constants.ReceiveConstants; import com.ruoyi.iot.domain.IotDeviceDetail; import com.ruoyi.iot.domain.ReceiveMsg; +import com.ruoyi.iot.domain.response.CommandResponse; import com.ruoyi.iot.enums.ReceiveStatus; import com.ruoyi.iot.enums.ReceiveType; import com.ruoyi.ss.device.domain.Device; @@ -21,9 +25,11 @@ import com.ruoyi.ss.transactionBill.service.TransactionBillService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.support.TransactionTemplate; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.LocalDateTime; import java.util.List; /** @@ -46,6 +52,12 @@ public class IotReceiveServiceImpl implements IotReceiveService{ @Autowired private IotService iotService; + @Autowired + private RedisLock redisLock; + + @Autowired + private TransactionTemplate transactionTemplate; + @Override public void handleReceive(ReceiveMsg msg) { if (msg == null) { @@ -65,43 +77,51 @@ public class IotReceiveServiceImpl implements IotReceiveService{ // 恢复设备的余额 private void recoverBalance(ReceiveMsg msg) { - // 查询设备 - DeviceVO device = deviceService.selectByMac(msg.getDevName()); - if (device == null) { + String lockKey = msg.getDevName(); + if (!redisLock.lock(RedisLockKey.RECOVER_DEVICE_BALANCE, lockKey)){ return; } + try { + // 查询设备 + DeviceVO device = deviceService.selectByMac(msg.getDevName()); + if (device == null) { + return; + } - // 查询未结束的订单 - TransactionBillQuery query = new TransactionBillQuery(); - query.setDeviceId(device.getDeviceId()); - query.setIsFinished(false); - query.setStatus(TransactionBillStatus.SUCCESS.getStatus()); - query.setSuitFeeTypes(SuitFeeType.singleList()); - List billList = transactionBillService.selectSmTransactionBillList(query); + // 判断上次恢复余额的时间和本次恢复余额的时间是否相同,若相同则视为重复推送,则忽略 + if (device.getLastRecoverTime() != null && msg.getAt().equals(device.getLastRecoverTime())) { + return; + } - if (CollectionUtils.isNotEmptyElement(billList)) { - // 拼接剩余时长(秒)/电量(度) - transactionAssembler.assembleSuitSurplus(billList); + // 待恢复的时长(秒) + LocalDateTime expireTime = device.getExpireTime(); - long seconds = 0; // 待恢复的时长(秒) - BigDecimal ele = BigDecimal.ZERO; // 待恢复的电量(度) + // 待恢复的电量(度) + BigDecimal ele = BigDecimal.ZERO; - for (TransactionBillVO bill : billList) { - if (bill.getSuitSurplus().compareTo(BigDecimal.ZERO) > 0) { - if (SuitFeeType.rechargeTimeList().contains(bill.getSuitFeeType())) { - seconds += bill.getSuitSurplus().longValue(); - } else if (SuitFeeType.rechargeCountList().contains(bill.getSuitFeeType())) { - ele = ele.add(bill.getSuitSurplus()); + // 若有需要恢复余额的设备,则进行操作 + if (expireTime != null || ele.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal finalEle = ele; + transactionTemplate.execute(status -> { + // 记录上次恢复余额的时间 + int update = deviceService.updateLastRecoverTime(device.getDeviceId(), msg.getAt()); + ServiceUtil.assertion(update != 1, "更新设备信息失败"); + + log.info("设备:{} 恢复余额,过期时间:{},剩余电量:{}", device.getMac(), expireTime, finalEle); + if (expireTime != null ) { + int setTime = deviceService.setTime(device, expireTime, true, 3); + ServiceUtil.assertion(setTime != 1, "恢复设备时长失败"); + } + if (finalEle.compareTo(BigDecimal.ZERO) > 0) { + CommandResponse res = iotService.trySetEle(device.getMac(), finalEle, device.getModelProductId(), 3); + ServiceUtil.assertion(!res.isSuccess(), "设备电量恢复失败:%s", res.getMsg()); } - } - } - if (seconds > 0) { - iotService.setTime(device.getMac(), seconds, device.getModelProductId()); - } - if (ele.compareTo(BigDecimal.ZERO) > 0) { - iotService.setEle(device.getMac(), ele, device.getModelProductId()); + return update; + }); } + } finally { + redisLock.unlock(RedisLockKey.RECOVER_DEVICE_BALANCE, lockKey); } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java index 7f21b83a..8db21a92 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java +++ b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java @@ -146,4 +146,22 @@ public interface IotService { * 直接设置设备电量(度) */ CommandResponse setEle(String deviceName, BigDecimal ele, String productId); + + /** + * 尝试设置设备剩余时长 + * @param mac MAC + * @param seconds 时长 + * @param productId 产品ID + * @param tryCount 尝试次数 + */ + CommandResponse trySetTime(String mac, long seconds, String productId, int tryCount); + /** + * 尝试设置设备剩余时长 + * @param mac MAC + * @param ele 电量(度) + * @param productId 产品ID + * @param tryCount 尝试次数 + */ + CommandResponse trySetEle(String mac, BigDecimal ele, String productId, int tryCount); + } diff --git a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotServiceImpl.java index f8e8d0f1..86f6ecba 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotServiceImpl.java @@ -283,4 +283,37 @@ public class IotServiceImpl implements IotService { return JSON.parseObject(result, CommandResponse.class); } + @Override + public CommandResponse trySetTime(String mac, long seconds, String productId, int tryCount) { + CommandResponse res = this.setTime(mac, seconds, productId); + if (!res.isSuccess()) { + if (tryCount > 0) { + try { + Thread.sleep(1000); + return trySetTime(mac, seconds, productId, --tryCount); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + return res; + } + + @Override + public CommandResponse trySetEle(String mac, BigDecimal ele, String productId, int tryCount) { + CommandResponse res = this.setEle(mac, ele, productId); + if (!res.isSuccess()) { + if (tryCount > 0) { + try { + Thread.sleep(1000); + return trySetEle(mac, ele, productId, --tryCount); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + return res; + } + + } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/Bonus.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/Bonus.java new file mode 100644 index 00000000..7b19f4f9 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/Bonus.java @@ -0,0 +1,94 @@ +package com.ruoyi.ss.bonus.domain; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonView; +import com.ruoyi.common.core.domain.JsonViewProfile; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 分成明细对象 ss_bonus + * + * @author ruoyi + * @date 2024-08-20 + */ +@Data +public class Bonus extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + private Long id; + + @Excel(name = "订单ID") + @ApiModelProperty("订单ID") + @JsonView(JsonViewProfile.AppMch.class) + private Long billId; + + @Excel(name = "订单编号") + @ApiModelProperty("订单编号") + @JsonView(JsonViewProfile.AppMch.class) + private String billNo; + + @Excel(name = "状态") + @ApiModelProperty("状态") + @JsonView(JsonViewProfile.AppMch.class) + private String status; + + @Excel(name = "收款方ID") + @ApiModelProperty("收款方ID") + @JsonView(JsonViewProfile.AppMch.class) + private Long arrivalId; + + @Excel(name = "收款方名称") + @ApiModelProperty("收款方名称") + @JsonView(JsonViewProfile.AppMch.class) + private String arrivalName; + + @Excel(name = "收款方类型") + @ApiModelProperty("收款方类型") + @JsonView(JsonViewProfile.AppMch.class) + private String arrivalType; + + @Excel(name = "分成比例") + @ApiModelProperty("分成比例") + @JsonView(JsonViewProfile.AppMch.class) + private BigDecimal point; + + @Excel(name = "分成金额") + @ApiModelProperty("分成金额") + @JsonView(JsonViewProfile.AppMch.class) + private BigDecimal amount; + + @Excel(name = "退款金额") + @ApiModelProperty("退款金额") + @JsonView(JsonViewProfile.AppMch.class) + private BigDecimal refundAmount; + + @Excel(name = "收款方祖级列表") + @ApiModelProperty("收款方祖级列表") + private String ancestors; + + @Excel(name = "收款方部门") + @ApiModelProperty("收款方部门") + private Long deptId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "实际分成时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("实际分成时间") + @JsonView(JsonViewProfile.AppMch.class) + private LocalDateTime payTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "预计分成时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("预计分成时间") + @JsonView(JsonViewProfile.AppMch.class) + private LocalDateTime prePayTime; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusProvideQuery.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusProvideQuery.java new file mode 100644 index 00000000..e10a5cdf --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusProvideQuery.java @@ -0,0 +1,30 @@ +package com.ruoyi.ss.bonus.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import nonapi.io.github.classgraph.utils.LogNode; + +import java.util.List; + +/** + * @author wjh + * 2024/8/23 + */ +@Data +public class BonusProvideQuery { + + @ApiModelProperty("到账方ID") + private Long arrivalId; + + @ApiModelProperty("到账方类型") + private List arrivalTypes; + + @ApiModelProperty("提供者ID列表") + private List providerIds; + + @ApiModelProperty("提供者类型") + private List providerTypes; + + @ApiModelProperty("分成状态") + private String status; +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusQuery.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusQuery.java new file mode 100644 index 00000000..6398fce2 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusQuery.java @@ -0,0 +1,37 @@ +package com.ruoyi.ss.bonus.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; +import java.util.List; + +/** + * @author wjh + * 2024/8/20 + */ +@Data +public class BonusQuery extends BonusVO { + + @ApiModelProperty("订单ID列表") + private List billIds; + + @ApiModelProperty("分成方ID列表") + private List arrivalIds; + + @ApiModelProperty("分成方类型列表") + private List arrivalTypes; + + @ApiModelProperty("支付时间:年") + private Integer payTimeYear; + + @ApiModelProperty("支付日期(起始)") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate payDateStart; + + @ApiModelProperty("支付日期(结束)") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate payDateEnd; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusVO.java new file mode 100644 index 00000000..2e177534 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/BonusVO.java @@ -0,0 +1,11 @@ +package com.ruoyi.ss.bonus.domain; + +import lombok.Data; + +/** + * @author wjh + * 2024/8/20 + */ +@Data +public class BonusVO extends Bonus { +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusArrivalType.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusArrivalType.java new file mode 100644 index 00000000..09fc20fa --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusArrivalType.java @@ -0,0 +1,65 @@ +package com.ruoyi.ss.bonus.domain.enums; + +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.common.enums.UserType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author wjh + * 2024/8/21 + */ +@Getter +@AllArgsConstructor +public enum BonusArrivalType { + + PLATFORM("1", "平台"), + AGENT("2", "代理商"), + MCH("3", "商户"); + + private final String type; + private final String msg; + + public static BonusArrivalType parseByUserType(String type) { + if (UserType.MCH.equalsType(type)) { + return MCH; + } + if (UserType.AGENT.equalsType(type)) { + return AGENT; + } + return null; + } + + public static BonusArrivalType parseByDept(SysDept dept) { + if (dept == null) { + return null; + } + if (Constants.ROOT_DEPT == dept.getDeptId()) { + return PLATFORM; + } + return null; + } + + public static List asList(BonusArrivalType ...types) { + return Arrays.stream(types).map(BonusArrivalType::getType).collect(Collectors.toList()); + } + + /** + * 用户表 + */ + public static List userList() { + return asList(AGENT, MCH); + } + + /** + * 部门表 + */ + public static List deptList() { + return asList(PLATFORM); + } +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusStatus.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusStatus.java new file mode 100644 index 00000000..96d8fd61 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/enums/BonusStatus.java @@ -0,0 +1,20 @@ +package com.ruoyi.ss.bonus.domain.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author wjh + * 2024/8/21 + */ +@Getter +@AllArgsConstructor +public enum BonusStatus { + + UN_DIVIDEND("1", "未分成"), + DIVIDEND("2", "已分成"); + + private final String status; + private final String msg; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusDailyAmountVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusDailyAmountVO.java new file mode 100644 index 00000000..e767dde5 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusDailyAmountVO.java @@ -0,0 +1,18 @@ +package com.ruoyi.ss.bonus.domain.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * @author wjh + * 2024/8/30 + */ +@Data +public class BonusDailyAmountVO { + + private LocalDate key; + + private BigDecimal sum; +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusMonthAmountVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusMonthAmountVO.java new file mode 100644 index 00000000..c44853a5 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/BonusMonthAmountVO.java @@ -0,0 +1,21 @@ +package com.ruoyi.ss.bonus.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author wjh + * 2024/8/28 + */ +@Data +public class BonusMonthAmountVO { + + @ApiModelProperty("月份") + private Integer month; + + @ApiModelProperty("金额") + private BigDecimal amount; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/ProvideBonusVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/ProvideBonusVO.java new file mode 100644 index 00000000..19bd0450 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/domain/vo/ProvideBonusVO.java @@ -0,0 +1,22 @@ +package com.ruoyi.ss.bonus.domain.vo; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author wjh + * 2024/8/23 + */ +@Data +public class ProvideBonusVO { + + // 提供者ID + private Long providerId; + + // 到账人ID + private Long arrivalId; + + // 到账金额 + private BigDecimal arrivalAmount; +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.java new file mode 100644 index 00000000..edeb9b14 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.java @@ -0,0 +1,113 @@ +package com.ruoyi.ss.bonus.mapper; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import com.ruoyi.common.domain.vo.CommonCountVO; +import com.ruoyi.common.domain.vo.CommonSumVO; +import com.ruoyi.ss.bonus.domain.Bonus; +import com.ruoyi.ss.bonus.domain.BonusProvideQuery; +import com.ruoyi.ss.bonus.domain.BonusVO; +import com.ruoyi.ss.bonus.domain.BonusQuery; +import com.ruoyi.ss.bonus.domain.vo.BonusDailyAmountVO; +import com.ruoyi.ss.bonus.domain.vo.BonusMonthAmountVO; +import com.ruoyi.ss.bonus.domain.vo.ProvideBonusVO; +import org.apache.ibatis.annotations.Param; + +/** + * 分成明细Mapper接口 + * + * @author ruoyi + * @date 2024-08-20 + */ +public interface BonusMapper +{ + /** + * 查询分成明细 + * + * @param id 分成明细主键 + * @return 分成明细 + */ + public BonusVO selectBonusById(Long id); + + /** + * 查询分成明细列表 + * + * @param query 分成明细 + * @return 分成明细集合 + */ + public List selectBonusList(@Param("query")BonusQuery query); + + /** + * 新增分成明细 + * + * @param bonus 分成明细 + * @return 结果 + */ + public int insertBonus(Bonus bonus); + + /** + * 修改分成明细 + * + * @param bonus 分成明细 + * @return 结果 + */ + public int updateBonus(@Param("data") Bonus bonus); + + /** + * 删除分成明细 + * + * @param id 分成明细主键 + * @return 结果 + */ + public int deleteBonusById(Long id); + + /** + * 批量删除分成明细 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteBonusByIds(Long[] ids); + + /** + * 批量插入 + */ + int batchInsert(@Param("list") List bonusList); + + /** + * 批量更新分成金额 + */ + int batchUpdateAmount(@Param("list") List list); + + /** + * 根据到账方统计 + */ + List> selectCountByArrival(@Param("query") BonusQuery query); + + /** + * 根据到账方统计金额 + */ + List> selectBillAmountByArrival(@Param("query") BonusQuery query); + + /** + * 查询提供分成 + */ + List selectProvideBonus(@Param("query") BonusProvideQuery query); + + /** + * 增加退款金额 + */ + int addRefundAmount(@Param("id") Long id, @Param("amount") BigDecimal amount); + + /** + * 按月查询 + */ + List selectMonthAmount(@Param("query") BonusQuery query); + + /** + * 按日查询 + */ + List selectDailyAmount(@Param("query") BonusQuery query); +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.xml new file mode 100644 index 00000000..710e5892 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/mapper/BonusMapper.xml @@ -0,0 +1,336 @@ + + + + + + + + select + sb.id, + sb.bill_id, + sb.bill_no, + sb.status, + sb.arrival_id, + sb.arrival_name, + sb.arrival_type, + sb.point, + sb.amount, + sb.refund_amount, + sb.ancestors, + sb.create_time, + sb.pay_time, + sb.dept_id, + sb.pre_pay_time + + + + + from ss_bonus sb + left join sys_dept sd on sd.dept_id = sb.dept_id + + + + and sb.id = #{query.id} + and sb.bill_id = #{query.billId} + and sb.dept_id = #{query.deptId} + and sb.bill_no like concat('%', #{query.billNo}, '%') + and sb.status = #{query.status} + and sb.arrival_id = #{query.arrivalId} + and sb.arrival_type = #{query.arrivalType} + and sb.arrival_name like concat('%', #{query.arrivalName}, '%') + and year(sb.pay_time) = #{query.payTimeYear} + and date(sb.pay_time) >= #{query.payDateStart} + and date(sb.pay_time) <= #{query.payDateEnd} + + and sb.bill_id in + + #{item} + + + + and sb.arrival_type in + + #{item} + + + + and sb.arrival_id in + + #{item} + + + ${query.params.dataScope} + ${@com.ruoyi.common.utils.DataScopeUtil@dataScopeDept("sd", query.needScope)} + + + + + + + + + + + + + + + + + + + + + + + + + + insert into ss_bonus + + bill_id, + bill_no, + `status`, + arrival_id, + arrival_name, + arrival_type, + `point`, + amount, + refund_amount, + ancestors, + create_time, + pay_time, + dept_id, + pre_pay_time, + + + #{billId}, + #{billNo}, + #{status}, + #{arrivalId}, + #{arrivalName}, + #{arrivalType}, + #{point}, + #{amount}, + #{refundAmount}, + #{ancestors}, + #{createTime}, + #{payTime}, + #{deptId}, + #{prePayTime}, + + + + + insert into ss_bonus( + bill_id, + bill_no, + status, + arrival_id, + arrival_name, + arrival_type, + point, + amount, + refund_amount, + ancestors, + create_time, + pay_time, + dept_id, + pre_pay_time + ) + values + + + #{i.billId}, + default, + #{i.billNo}, + default, + #{i.status}, + default, + #{i.arrivalId}, + default, + #{i.arrivalName}, + default, + #{i.arrivalType}, + default, + #{i.point}, + default, + #{i.amount}, + default, + #{i.refundAmount}, + default, + #{i.ancestors}, + default, + #{i.createTime}, + default, + #{i.payTime}, + default, + #{i.deptId}, + default, + #{i.prePayTime}, + default, + + + + + + update ss_bonus + set refund_amount = refund_amount + #{amount} + where id = #{id} and amount >= refund_amount + #{amount} + + + + update ss_bonus + + + + where id = #{data.id} + + + + update ss_bonus + + + + + WHEN #{item.id} THEN #{item.amount} + + + WHEN #{item.id} THEN amount + + + + + + + WHEN #{item.id} THEN #{item.status} + + + WHEN #{item.id} THEN `status` + + + + + + + WHEN #{item.id} THEN #{item.payTime} + + + WHEN #{item.id} THEN `pay_time` + + + + + where id in + + #{item.id} + + and `status` = '1' + + + + bill_id = #{data.billId}, + bill_no = #{data.billNo}, + `status` = #{data.status}, + arrival_id = #{data.arrivalId}, + arrival_name = #{data.arrivalName}, + arrival_type = #{data.arrivalType}, + `point` = #{data.point}, + amount = #{data.amount}, + refund_amount = #{data.refundAmount}, + ancestors = #{data.ancestors}, + create_time = #{data.createTime}, + pay_time = #{data.payTime}, + dept_id = #{data.deptId}, + pre_pay_time = #{data.prePayTime}, + + + + delete from ss_bonus where id = #{id} + + + + delete from ss_bonus where id in + + #{id} + + + diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusConverter.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusConverter.java new file mode 100644 index 00000000..122127ee --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusConverter.java @@ -0,0 +1,32 @@ +package com.ruoyi.ss.bonus.service; + +import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.ss.bonus.domain.Bonus; +import com.ruoyi.ss.device.domain.vo.DeviceVO; +import com.ruoyi.ss.transactionBill.domain.bo.RechargeBO; +import com.ruoyi.ss.user.domain.SmUserVo; + +import java.util.List; + +/** + * @author wjh + * 2024/8/20 + */ +public interface BonusConverter { + + /** + * 订单转为分成明细 + */ + List toPo(RechargeBO bo); + + /** + * 生成分成列表 + * + * @param mch + * @param agent + * @param platform + * @param device + * @return + */ + List genBonusList(SmUserVo mch, SmUserVo agent, SysDept platform, DeviceVO device); +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusService.java new file mode 100644 index 00000000..cf8f5a7b --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/BonusService.java @@ -0,0 +1,120 @@ +package com.ruoyi.ss.bonus.service; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import com.ruoyi.common.domain.vo.CommonCountVO; +import com.ruoyi.common.domain.vo.CommonSumVO; +import com.ruoyi.ss.bonus.domain.Bonus; +import com.ruoyi.ss.bonus.domain.BonusProvideQuery; +import com.ruoyi.ss.bonus.domain.BonusVO; +import com.ruoyi.ss.bonus.domain.BonusQuery; +import com.ruoyi.ss.bonus.domain.vo.BonusDailyAmountVO; +import com.ruoyi.ss.bonus.domain.vo.BonusMonthAmountVO; +import com.ruoyi.ss.bonus.domain.vo.ProvideBonusVO; + +/** + * 分成明细Service接口 + * + * @author ruoyi + * @date 2024-08-20 + */ +public interface BonusService +{ + /** + * 查询分成明细 + * + * @param id 分成明细主键 + * @return 分成明细 + */ + public BonusVO selectBonusById(Long id); + + /** + * 查询分成明细列表 + * + * @param bonus 分成明细 + * @return 分成明细集合 + */ + public List selectBonusList(BonusQuery bonus); + + /** + * 新增分成明细 + * + * @param bonus 分成明细 + * @return 结果 + */ + public int insertBonus(Bonus bonus); + + /** + * 修改分成明细 + * + * @param bonus 分成明细 + * @return 结果 + */ + public int updateBonus(Bonus bonus); + + /** + * 批量删除分成明细 + * + * @param ids 需要删除的分成明细主键集合 + * @return 结果 + */ + public int deleteBonusByIds(Long[] ids); + + /** + * 删除分成明细信息 + * + * @param id 分成明细主键 + * @return 结果 + */ + public int deleteBonusById(Long id); + + /** + * 批量新增 + */ + int batchInsert(List bonusList); + + /** + * 处理分成支付 + * @param bonusList 分成列表 + * @param money 总金额 + * @return 处理数量 + */ + int payBonus(List bonusList, BigDecimal money); + + /** + * 根据到账方统计 + */ + List> selectCountByArrival(BonusQuery query); + + /** + * 根据到账方统计订单金额 + */ + List> selectBillAmountByArrival(BonusQuery query); + + /** + * 查询提供分成 + */ + List selectProvideBonus(BonusProvideQuery query); + + /** + * 增加已退款金额 + */ + int addRefundAmount(Long id, BigDecimal amount); + + /** + * 数据隔离过滤 + */ + List filterBonusScope(List bonusList); + + /** + * 按月查询分成金额 + */ + List selectMonthAmount(BonusQuery query); + + /** + * 按日查询分成 + */ + List selectDailyAmount(BonusQuery query); +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusConverterImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusConverterImpl.java new file mode 100644 index 00000000..8ce358c1 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusConverterImpl.java @@ -0,0 +1,168 @@ +package com.ruoyi.ss.bonus.service.impl; + +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.ss.bonus.domain.Bonus; +import com.ruoyi.ss.bonus.domain.enums.BonusArrivalType; +import com.ruoyi.ss.bonus.domain.enums.BonusStatus; +import com.ruoyi.ss.bonus.service.BonusConverter; +import com.ruoyi.ss.device.domain.vo.DeviceVO; +import com.ruoyi.ss.store.service.StoreService; +import com.ruoyi.ss.transactionBill.domain.TransactionBill; +import com.ruoyi.ss.transactionBill.domain.bo.RechargeBO; +import com.ruoyi.ss.transactionBill.service.TransactionBillService; +import com.ruoyi.ss.user.domain.SmUserVo; +import com.ruoyi.ss.user.service.ISmUserService; +import com.ruoyi.system.service.ISysDeptService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; + +/** + * @author wjh + * 2024/8/20 + */ +@Service +public class BonusConverterImpl implements BonusConverter { + + @Autowired + private ISmUserService userService; + + @Autowired + private StoreService storeService; + + @Autowired + private ISysDeptService deptService; + + @Autowired + private TransactionBillService transactionBillService; + + /** + * 订单转为分成明细 + * + * @param bo + */ + @Override + public List toPo(RechargeBO bo) { + if (bo == null) { + return Collections.emptyList(); + } + + TransactionBill bill = bo.getOrder(); + if (bill == null) { + return null; + } + + List result = bo.getBonusList(); + for (Bonus bonus : result) { + bonus.setBillId(bill.getBillId()); + bonus.setBillNo(bill.getBillNo()); + } + + return result; + } + + @Override + public List genBonusList(SmUserVo mch, SmUserVo agent, SysDept platform, DeviceVO device) { + List result = new ArrayList<>(); + + BigDecimal point = BigDecimal.valueOf(100); + + // TODO 平台收取服务费 + + // TODO 代理商收取服务费 + + // TODO 剩余的给商户 + +// +// // 根据设备的投资人、经营场所获取各自的分成比例 +// result.add(this.toPo(store, storeInvestor, mch)); +// result.add(this.toPo(mch, mch.getPoint())); +// BigDecimal lastPoint = mch.getPoint().add(storeInvestor.getPoint()); // 上一次的分成比例 +// +// // 投资人上级 +// if (StringUtils.hasText(mch.getAncestors()) && CollectionUtils.isNotEmpty(agent)) { +// List collect = Arrays.stream(mch.getAncestors().split(",")).map(Long::valueOf).collect(Collectors.toList()); +// for (int i = collect.size() - 1; i >= 0; i --) { +// Long id = collect.get(i); +// SmUserVo investorAncestor = agent.stream().filter(item -> item.getUserId().equals(id)).findFirst().orElse(null); +// if (investorAncestor != null) { +// result.add(this.toPo(investorAncestor, investorAncestor.getPoint().subtract(lastPoint))); +// lastPoint = investorAncestor.getPoint(); +// } +// } +// } +// +// // 直属部门 +// result.add(this.toPo(platform, platform.getPoint().subtract(lastPoint))); +// lastPoint = platform.getPoint(); +// +// // 直属部门的祖级列表 +// if (StringUtils.hasText(platform.getAncestors()) && CollectionUtils.isNotEmpty(investorDeptList)) { +// List collect = Arrays.stream(platform.getAncestors().split(",")).map(Long::valueOf).collect(Collectors.toList()); +// for (int i = collect.size() - 1; i >= 0; i --) { +// Long id = collect.get(i); +// SysDept d = investorDeptList.stream().filter(item -> item.getDeptId().equals(id)).findFirst().orElse(null); +// if (d != null) { +// result.add(this.toPo(d, d.getPoint().subtract(lastPoint))); +// lastPoint = d.getPoint(); +// } +// } +// } + + // 校验分成比例 +// ServiceUtil.assertion(lastPoint.compareTo(BigDecimal.valueOf(100)) != 0, "分成计算失败:最终分成比例不等于100"); +// BigDecimal total = BigDecimal.ZERO; +// BigDecimal decimal100 = BigDecimal.valueOf(100); +// for (Bonus bonus : result) { +// ServiceUtil.assertion(bonus.getPoint().compareTo(BigDecimal.ZERO) < 0, "分成计算失败:分成比例小于0"); +// ServiceUtil.assertion(bonus.getPoint().compareTo(decimal100) > 0, "分成计算失败:分成比例大于100"); +// total = total.add(bonus.getPoint()); +// } +// ServiceUtil.assertion(total.compareTo(decimal100) > 0, "分成计算失败:分成比例总和大于100"); + + return result; + } + + private Bonus toPo(SysDept dept, BigDecimal point) { + if (dept == null) { + return null; + } + + Bonus po = new Bonus(); + po.setStatus(BonusStatus.UN_DIVIDEND.getStatus()); + po.setArrivalId(dept.getDeptId()); + po.setArrivalName(dept.getDeptName()); + BonusArrivalType arrivalType = BonusArrivalType.parseByDept(dept); + if (arrivalType != null) { + po.setArrivalType(arrivalType.getType()); + } + po.setPoint(point); + po.setAncestors(dept.getAncestors()); + po.setDeptId(dept.getDeptId()); + + return po; + } + + private Bonus toPo(SmUserVo user, BigDecimal point, DeviceVO device) { + if (user == null || point == null) { + return null; + } + + Bonus po = new Bonus(); + po.setStatus(BonusStatus.UN_DIVIDEND.getStatus()); + po.setArrivalId(user.getUserId()); + po.setArrivalName(user.getRealOrUserName()); + BonusArrivalType arrivalType = BonusArrivalType.parseByUserType(user.getType()); + if (arrivalType != null) { + po.setArrivalType(arrivalType.getType()); + } + po.setPoint(point); +// po.setAncestors(Arrays.asList(device.getAgentId(), device.getUserId())); + po.setDeptId(Constants.ROOT_DEPT); + + return po; + } +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusServiceImpl.java new file mode 100644 index 00000000..d25279e3 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/bonus/service/impl/BonusServiceImpl.java @@ -0,0 +1,269 @@ +package com.ruoyi.ss.bonus.service.impl; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.domain.vo.CommonCountVO; +import com.ruoyi.common.domain.vo.CommonSumVO; +import com.ruoyi.common.enums.LoginType; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.collection.CollectionUtils; +import com.ruoyi.ss.bonus.domain.BonusProvideQuery; +import com.ruoyi.ss.bonus.domain.enums.BonusArrivalType; +import com.ruoyi.ss.bonus.domain.enums.BonusStatus; +import com.ruoyi.ss.bonus.domain.vo.BonusDailyAmountVO; +import com.ruoyi.ss.bonus.domain.vo.BonusMonthAmountVO; +import com.ruoyi.ss.bonus.domain.vo.ProvideBonusVO; +import com.ruoyi.ss.recordBalance.domain.enums.RecordBalanceBstType; +import com.ruoyi.ss.store.service.StoreService; +import com.ruoyi.ss.user.service.ISmUserService; +import com.ruoyi.system.service.ISysDeptService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.ss.bonus.mapper.BonusMapper; +import com.ruoyi.ss.bonus.domain.Bonus; +import com.ruoyi.ss.bonus.domain.BonusVO; +import com.ruoyi.ss.bonus.domain.BonusQuery; +import com.ruoyi.ss.bonus.service.BonusService; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * 分成明细Service业务层处理 + * + * @author ruoyi + * @date 2024-08-20 + */ +@Service +public class BonusServiceImpl implements BonusService +{ + @Autowired + private BonusMapper bonusMapper; + + @Autowired + private TransactionTemplate transactionTemplate; + + @Autowired + private ISmUserService userService; + + @Autowired + private ISysDeptService deptService; + + @Autowired + private StoreService storeService; + + /** + * 查询分成明细 + * + * @param id 分成明细主键 + * @return 分成明细 + */ + @Override + public BonusVO selectBonusById(Long id) + { + return bonusMapper.selectBonusById(id); + } + + /** + * 查询分成明细列表 + * + * @param bonus 分成明细 + * @return 分成明细 + */ + @Override + public List selectBonusList(BonusQuery bonus) + { + return bonusMapper.selectBonusList(bonus); + } + + /** + * 新增分成明细 + * + * @param bonus 分成明细 + * @return 结果 + */ + @Override + public int insertBonus(Bonus bonus) + { + this.buildBeforeCreate(bonus); + return bonusMapper.insertBonus(bonus); + } + + // 补全新增前的数据 + private void buildBeforeCreate(Bonus bonus) { + bonus.setCreateTime(DateUtils.getNowDate()); + } + + /** + * 修改分成明细 + * + * @param bonus 分成明细 + * @return 结果 + */ + @Override + public int updateBonus(Bonus bonus) + { + return bonusMapper.updateBonus(bonus); + } + + /** + * 批量删除分成明细 + * + * @param ids 需要删除的分成明细主键 + * @return 结果 + */ + @Override + public int deleteBonusByIds(Long[] ids) + { + return bonusMapper.deleteBonusByIds(ids); + } + + /** + * 删除分成明细信息 + * + * @param id 分成明细主键 + * @return 结果 + */ + @Override + public int deleteBonusById(Long id) + { + return bonusMapper.deleteBonusById(id); + } + + @Override + public int batchInsert(List bonusList) { + if (CollectionUtils.isEmptyElement(bonusList)) { + return 0; + } + for (Bonus bonus : bonusList) { + this.buildBeforeCreate(bonus); + } + return bonusMapper.batchInsert(bonusList); + } + + @Override + public int payBonus(List bonusList, BigDecimal money) { + if (CollectionUtils.isEmptyElement(bonusList)) { + return 0; + } + + BigDecimal decimal100 = new BigDecimal(100); + BigDecimal dividedAmount = BigDecimal.ZERO; // 已分配金额 + LocalDateTime now = LocalDateTime.now(); + + // 循环遍历,构造分成金额 + for (BonusVO bonus : bonusList) { + BigDecimal amount = money.multiply(bonus.getPoint()).divide(decimal100, 2, RoundingMode.HALF_UP); + bonus.setAmount(amount); + bonus.setStatus(BonusStatus.DIVIDEND.getStatus()); + bonus.setPayTime(now); + dividedAmount = dividedAmount.add(amount); + } + // 平台吃掉误差 + BonusVO platform = bonusList.stream().filter(bonus -> bonus.getArrivalType().equals(BonusArrivalType.PLATFORM.getType())).findFirst().orElse(null); + ServiceUtil.assertion(platform == null, "平台不存在"); + if (dividedAmount.compareTo(money) != 0) { + BigDecimal subtract = money.subtract(dividedAmount); // 误差值 + platform.setAmount(platform.getAmount().add(subtract)); + } + + Integer result = transactionTemplate.execute(status -> { + + // 循环遍历,添加金额到账户上 + for (BonusVO bonus : bonusList) { + int add = 0; + // 根据类型,添加金额 + if (BonusArrivalType.userList().contains(bonus.getArrivalType())) { + add = userService.addBalance(bonus.getArrivalId(), bonus.getAmount(), String.format("订单分成:%s", bonus.getBillNo()), RecordBalanceBstType.RECHARGE, bonus.getBillId()); + } else if (BonusArrivalType.deptList().contains(bonus.getArrivalType())) { +// add = deptService.addBalance(bonus.getArrivalId(), bonus.getAmount(), String.format("订单分成:%s", bonus.getBillNo()), RecordBalanceBstType.RECHARGE, bonus.getBillId()); + } + ServiceUtil.assertion(add != 1, "增加账户金额失败"); + } + + // 批量更新分成金额 + int updateAmount = this.batchUpdateAmount(bonusList); + ServiceUtil.assertion(updateAmount != bonusList.size(), "更新分成金额失败"); + + return updateAmount; + }); + + return result == null ? 0 : result; + } + + @Override + public List> selectCountByArrival(BonusQuery query) { + return bonusMapper.selectCountByArrival(query); + } + + @Override + public List> selectBillAmountByArrival(BonusQuery query) { + return bonusMapper.selectBillAmountByArrival(query); + } + + @Override + public List selectProvideBonus(BonusProvideQuery query) { + return bonusMapper.selectProvideBonus(query); + } + + @Override + public int addRefundAmount(Long id, BigDecimal amount) { + if (id == null) { + return 0; + } + ServiceUtil.assertion(amount.compareTo(BigDecimal.ZERO) < 0, "退款金额必须大于0"); + return bonusMapper.addRefundAmount(id, amount); + } + + @Override + public List filterBonusScope(List bonusList) { + LoginUser loginUser = SecurityUtils.getLoginUser(); + Long userId = loginUser.getUserId(); + Long deptId = loginUser.getDeptId(); + return bonusList.stream().filter(bonus -> { + // 前台用户过滤 + if (LoginType.FRONT.equals(loginUser.getLoginType())) { + return BonusArrivalType.userList().contains(bonus.getArrivalType()) && ( + Arrays.asList(bonus.getAncestors().split(",")).contains(userId.toString()) + || bonus.getArrivalId().equals(userId) + ); + } + // 后台用户过滤 + else if (LoginType.ADMIN.equals(loginUser.getLoginType())) { + if (BonusArrivalType.userList().contains(bonus.getArrivalType())) { + return true; + } + if (BonusArrivalType.deptList().contains(bonus.getArrivalType())) { + return Arrays.asList(bonus.getAncestors().split(",")).contains(deptId.toString()) + || bonus.getArrivalId().equals(deptId); + } + } + return false; + }).collect(Collectors.toList()); + } + + @Override + public List selectMonthAmount(BonusQuery query) { + return bonusMapper.selectMonthAmount(query); + } + + @Override + public List selectDailyAmount(BonusQuery query) { + return bonusMapper.selectDailyAmount(query); + } + + private int batchUpdateAmount(List list) { + if (CollectionUtils.isEmptyElement(list)) { + return 0; + } + return bonusMapper.batchUpdateAmount(list); + } +} 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 ed2c4889..3782bdf5 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 @@ -199,4 +199,7 @@ public class Device extends BaseEntity @ApiModelProperty("剩余电量(度)") @JsonView(JsonViewProfile.App.class) private BigDecimal surplusEle; + + @ApiModelProperty("上次恢复余额的时间戳") + private Long lastRecoverTime; } 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 7860ce28..e006813d 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 @@ -10,6 +10,7 @@ import com.ruoyi.ss.device.domain.enums.DevicePowerStatus; import com.ruoyi.ss.device.domain.vo.DeviceVO; import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -307,4 +308,15 @@ public interface DeviceService */ int resetEleWithBill(Long deviceId); + int updateLastRecoverTime(Long deviceId, Long lastRecoverTime); + + /** + * 设置时间 + * @param device 设备 + * @param expireTime 过期时间 + * @param withIot 是否操作设备 + * @param tryCount 尝试次数 + */ + int setTime(DeviceVO device, LocalDateTime expireTime, boolean withIot, int tryCount); + } 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 a479ed94..7e0c1c64 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 @@ -540,6 +540,20 @@ public class DeviceServiceImpl implements DeviceService return result == null ? 0 : result; } + @Override + public int updateLastRecoverTime(Long deviceId, Long lastRecoverTime) { + Device data = new Device(); + data.setDeviceId(deviceId); + data.setLastRecoverTime(lastRecoverTime); + return deviceMapper.updateSmDevice(data); + } + + // TODO + @Override + public int setTime(DeviceVO device, LocalDateTime expireTime, boolean withIot, int tryCount) { + return 0; + } + @Override public boolean addTime(Long deviceId, long seconds, boolean withIot) { diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/bo/RechargeBO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/bo/RechargeBO.java index cc5caaed..788687e2 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/bo/RechargeBO.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/bo/RechargeBO.java @@ -1,5 +1,6 @@ package com.ruoyi.ss.transactionBill.domain.bo; +import com.ruoyi.ss.bonus.domain.Bonus; import com.ruoyi.ss.channel.domain.ChannelVO; import com.ruoyi.ss.device.domain.vo.DeviceVO; import com.ruoyi.ss.store.domain.StoreVo; @@ -9,6 +10,8 @@ import com.ruoyi.ss.transactionBill.domain.dto.RechargeDTO; import com.ruoyi.ss.user.domain.SmUserVo; import lombok.Data; +import java.util.List; + /** * 设备充值BO * @author wjh @@ -38,4 +41,7 @@ public class RechargeBO { // 店铺 private StoreVo store; + // 分成详情 + private List bonusList; + } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/TransactionBillService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/TransactionBillService.java index 3ad015e0..9de8aae9 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/TransactionBillService.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/TransactionBillService.java @@ -1,5 +1,6 @@ package com.ruoyi.ss.transactionBill.service; +import com.ruoyi.ss.channel.domain.ChannelVO; import com.ruoyi.ss.dashboard.vo.BillCountVo; import com.ruoyi.ss.device.domain.vo.DeviceVO; import com.ruoyi.ss.payBill.domain.vo.DoPayVO; @@ -12,7 +13,9 @@ import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO; import com.ruoyi.ss.transactionBill.domain.dto.BillRefundDTO; import com.ruoyi.ss.transactionBill.domain.dto.WithdrawApprovalDTO; import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillStatus; +import com.ruoyi.ss.transactionBill.domain.vo.UserRechargeServiceVO; import com.ruoyi.ss.transactionBill.domain.vo.UserWithdrawServiceVO; +import com.ruoyi.ss.user.domain.SmUserVo; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -293,4 +296,9 @@ public interface TransactionBillService * 开启/关闭订单设备 */ int switchDevice(TransactionBillVO bill, boolean open); + + /** + * 获取商户的充值手续费 + */ + UserRechargeServiceVO getMchRechargeService(ChannelVO channel, SmUserVo mch, DeviceVO device); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/RechargeDepositAfterPay.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/RechargeDepositAfterPay.java index 378e4358..7070bcef 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/RechargeDepositAfterPay.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/RechargeDepositAfterPay.java @@ -62,7 +62,7 @@ public class RechargeDepositAfterPay implements AfterPay { query.setBillId(bill.getBillId()); query.setStatus(TransactionBillStatus.UNPAID_DEPOSIT.getStatus()); int update = transactionBillService.updateByQuery(data, query); - ServiceUtil.assertion(update != 1, "修改订单信息失败,状态已经发生改变"); + ServiceUtil.assertion(update != 1, "修改订单信息失败,状态已经发生改变:%s", bill.getBillNo()); try { iotService.open(device.getMac(), device.getModelProductId()); 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 3f75ed0a..d0227b34 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 @@ -272,7 +272,7 @@ public class TransactionBillServiceImpl implements TransactionBillService, After private void handleRechargeService(RechargePayBO bo) { TransactionBillVO order = bo.getOrder(); // 获取商户的服务费配置 - UserRechargeServiceVO userRechargeService = this.getUserRechargeService(bo.getChannel(), bo.getMch(), bo.getDevice()); + UserRechargeServiceVO userRechargeService = this.getMchRechargeService(bo.getChannel(), bo.getMch(), bo.getDevice()); String serviceType = userRechargeService.getServiceType(); // 服务费类型 BigDecimal serviceRate = userRechargeService.getServiceRate(); // 服务费 @@ -313,7 +313,8 @@ public class TransactionBillServiceImpl implements TransactionBillService, After } - private UserRechargeServiceVO getUserRechargeService(ChannelVO channel, SmUserVo mch, DeviceVO device) { + @Override + public UserRechargeServiceVO getMchRechargeService(ChannelVO channel, SmUserVo mch, DeviceVO device) { // 优先级: 设备 > 商户 > 渠道 if (device.getServiceRate() != null && StringUtils.hasText(device.getServiceType())) { return new UserRechargeServiceVO(device.getServiceType(), device.getServiceRate()); @@ -973,14 +974,14 @@ public class TransactionBillServiceImpl implements TransactionBillService, After data.setSuitEndEle(totalEle); TransactionBillQuery query = new TransactionBillQuery(); query.setBillId(order.getBillId()); - + query.setStatus(TransactionBillStatus.SUCCESS.getStatus()); if (SuitFeeType.TIME.getType().equals(order.getSuitFeeType())) { query.setStartSuitEndTime(endTime); // 计时的话,需要结束时间在这之后的订单 } else if (SuitFeeType.COUNT.getType().equals(order.getSuitFeeType())) { query.setStartSuitEndEle(totalEle); // 计量的话,需要结束电量比这个大的订单 } int update = this.updateByQuery(data, query); - ServiceUtil.assertion(update != 1, "修改订单信息失败"); + ServiceUtil.assertion(update != 1, "修改订单信息失败,请重试:%s", order.getBillNo()); // 若金额 > 0.01 则申请退款 if (BigDecimal.valueOf(0.01).compareTo(refundAmount) < 0) { @@ -1069,13 +1070,14 @@ public class TransactionBillServiceImpl implements TransactionBillService, After data.setSuitEndEle(totalEle); TransactionBillQuery query = new TransactionBillQuery(); query.setBillId(order.getBillId()); + query.setStatus(TransactionBillStatus.SUCCESS.getStatus()); if (SuitFeeType.TIME.getType().equals(order.getSuitFeeType())) { query.setStartSuitEndTime(endTime); // 计时的话,需要结束时间在这之后的订单 } else if (SuitFeeType.COUNT.getType().equals(order.getSuitFeeType())) { query.setStartSuitEndEle(totalEle); // 计量的话,需要结束电量比这个大的订单 } int update = this.updateByQuery(data, query); - ServiceUtil.assertion(update != 1, "修改订单信息失败"); + ServiceUtil.assertion(update != 1, "修改订单信息失败,请重试:%s", order.getBillNo()); return update; }); @@ -1439,7 +1441,7 @@ public class TransactionBillServiceImpl implements TransactionBillService, After billQuery.setBillId(dto.getBillId()); billQuery.setStatus(TransactionBillStatus.SUCCESS.getStatus()); int updateBill = this.updateByQuery(data, billQuery); - ServiceUtil.assertion(updateBill != 1, "修改订单状态失败"); + ServiceUtil.assertion(updateBill != 1, "退款时修改订单状态失败,订单状态已发生改变,请刷新后重试"); // 商户余额按照比例扣减 // 按比例计算退款金额 @@ -1600,10 +1602,25 @@ public class TransactionBillServiceImpl implements TransactionBillService, After ServiceUtil.assertion(StringUtils.isBlank(device.getMac()), "设备MAC为空,请联系管理员处理"); if (open) { - return iotService.open(device.getMac(), device.getModelProductId()) ? 1 : 0; + if (SuitFeeType.timingList().contains(bill.getSuitFeeType())) { + return iotService.open(device.getMac(), device.getModelProductId()) ? 1 : 0; + } else { + // 计算设备剩余时长 + LocalDateTime expireTime = device.getExpireTime(); + if (expireTime == null) { + return 0; + } + Duration between = Duration.between(LocalDateTime.now(), expireTime); + if (between.getSeconds() > 0) { + CommandResponse res = iotService.setTime(device.getMac(), between.getSeconds(), device.getModelProductId()); + return res.isSuccess() ? 1 : 0; + } + } } else { return iotService.close(device.getMac(), device.getModelProductId()) ? 1 : 0; } + + return 0; } @Override diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/SmUserVo.java b/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/SmUserVo.java index 1804ae4e..411eaa16 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/SmUserVo.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/SmUserVo.java @@ -39,4 +39,8 @@ public class SmUserVo extends SmUser { @ApiModelProperty("商户店铺数量") @JsonView(JsonViewProfile.App.class) private Integer storeCount; + + @ApiModelProperty("实名或用户名") + private String realOrUserName; + } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/mapper/SmUserMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/user/mapper/SmUserMapper.xml index c695ddd5..aa8b9a05 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/user/mapper/SmUserMapper.xml +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/mapper/SmUserMapper.xml @@ -45,6 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" su.real_id_card, su.real_phone, su.is_real, + if(su.is_real, su.real_name, su.user_name) as real_or_user_name, (select sum(stb.money) from sm_transaction_bill stb where stb.user_id = su.user_id and stb.type = '1' and stb.status = '2') as recharge_amount, (select sum(stb.arrival_amount) from sm_transaction_bill stb where stb.user_id = su.user_id and stb.type = '2' and stb.status = '14') as with_drawl_amount, (select sum(stb.arrival_amount) from sm_transaction_bill stb where stb.mch_id = su.user_id and stb.type = '1' and stb.status = '2') as total_income diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/ISmUserService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/ISmUserService.java index 1169ee92..64277137 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/ISmUserService.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/ISmUserService.java @@ -109,7 +109,7 @@ public interface ISmUserService * @param bstType * @param bstId */ - void addBalance(Long userId, BigDecimal amount, String reason, RecordBalanceBstType bstType, Long bstId); + int addBalance(Long userId, BigDecimal amount, String reason, RecordBalanceBstType bstType, Long bstId); /** * 减少余额 diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java index 0df818ec..dbd1aca3 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java @@ -128,7 +128,7 @@ public class SmUserServiceImpl implements ISmUserService @Override @Transactional - public void addBalance(Long userId, BigDecimal amount, String reason, RecordBalanceBstType bstType, Long bstId) { + public int addBalance(Long userId, BigDecimal amount, String reason, RecordBalanceBstType bstType, Long bstId) { ServiceUtil.assertion(BigDecimal.ZERO.compareTo(amount) > 0, "增加的金额需要大于0"); // 查询用户 @@ -141,6 +141,8 @@ public class SmUserServiceImpl implements ISmUserService // 余额变动记录 int record = recordBalanceService.record(userId, user.getBalance(), amount, reason, bstType, bstId); ServiceUtil.assertion(record != 1, "用户余额变动记录失败"); + + return updateCount; } @Override