套餐、订单修改

This commit is contained in:
墨大叔 2024-10-11 14:48:27 +08:00
parent 1ae280ad0d
commit a1204272be
10 changed files with 145 additions and 100 deletions

View File

@ -50,14 +50,10 @@ public class ReceiveController {
@PostMapping(value = "/receive")
@Anonymous
public ResponseEntity<String> receive(@RequestBody String body){
log.info("receive方法接收到参数: body String --- {}", body);
ReceiveBody obj = IotUtil.resolveBody(body, false);
log.info("receive方法解析对象: body Object --- {}", JSON.toJSONString(obj));
if (obj != null){
if (IotUtil.checkSignature(obj, token)){
log.info("receive方法验证签名正确: content {}", JSON.toJSONString(obj));
Object msg = obj.getMsg();
log.info("receive方法-获取到消息体: msg--- {}", JSON.toJSONString(msg));
// 接收到msg
if (msg instanceof String) {
iotReceiveService.handleReceive(JSON.parseObject((String) msg, ReceiveMsg.class));

View File

@ -298,13 +298,10 @@ public interface DeviceService
*/
void pullDeviceInfo(Long deviceId);
/**
* 清空设备时长电量
*/
int clearTimeAndEle(DeviceVO device, boolean required);
/**
* 设备归零时长
* @param device 设备
* @param required 是否必须成功
*/
int resetTime(DeviceVO device, boolean required);
@ -353,4 +350,8 @@ public interface DeviceService
*/
DeviceVO selectByAnyMac(String mac);
/**
* 拉取最新设备数据
*/
void pullDeviceInfo(DeviceVO device);
}

View File

@ -438,21 +438,6 @@ public class DeviceServiceImpl implements DeviceService
pullDeviceInfo(Collections.singletonList(deviceId));
}
@Override
public int clearTimeAndEle(DeviceVO device, boolean required) {
if (device == null) {
return 0;
}
// 归零时长
int resetTime = this.resetTime(device, required);
// 归零剩余电量
int resetEle = this.resetEle(device, required);
return 1;
}
@Override
public int resetTime(DeviceVO device, boolean required) {
LocalDateTime now = LocalDateTime.now();
@ -645,6 +630,11 @@ public class DeviceServiceImpl implements DeviceService
return deviceMapper.selectByAnyMac(mac);
}
@Override
public void pullDeviceInfo(DeviceVO device) {
this.pullDeviceInfoList(Collections.singletonList(device));
}
@Override
public boolean addTime(Long deviceId, long seconds, boolean withIot) {

View File

@ -211,16 +211,19 @@ public class SuitValidatorImpl extends BaseValidator implements SuitValidator {
}
// 一次性充值的套餐价格不允许低于最低服务费
BigDecimal minService = sysConfigService.getBigDecimal(ConfigKey.RECHARGE_MIN_SERVICE);
if (SuitFeeType.singleList().contains(feeType)) {
ServiceUtil.assertion(vo.getPrice() == null, "价格不允许为空");
BigDecimal minService = sysConfigService.getBigDecimal(ConfigKey.RECHARGE_MIN_SERVICE);
if (vo.getPrice().compareTo(minService) < 0) {
throw new ServiceException("价格不允许低于" + minService + "");
}
ServiceUtil.assertion(vo.getPrice().compareTo(minService) < 0, "价格不允许低于" + minService + "");
}
// 判断押金是否设置
if (SuitFeeMode.SMART.getMode().equals(feeMode)) {
ServiceUtil.assertion(vo.getDeposit() == null, "押金不允许为空");
ServiceUtil.assertion(vo.getDeposit().compareTo(minService) < 0, "押金不允许低于" + minService + "");
// 若为智能计时智能按量则押金不允许低于价格且必须为价格的整数倍
if (SuitFeeMode.SMART.getMode().equals(feeMode)) {
ServiceUtil.assertion(vo.getDeposit() == null, "押金不允许为空");
if (SuitFeeType.singleList().contains(feeType)) {
ServiceUtil.assertion(vo.getDeposit().compareTo(vo.getPrice()) < 0, "押金不允许低于价格");
// 取模判断余数

View File

@ -61,7 +61,6 @@ public class RechargeDTO {
private BigDecimal suitPrice;
@ApiModelProperty("套餐押金")
@NotNull(message = "套餐押金不允许为空")
@Min(value = 0, message = "套餐押金不允许小于0")
private BigDecimal suitDeposit;

View File

@ -66,26 +66,6 @@ public class TransactionBillVO extends TransactionBill implements IotDevice {
@ApiModelProperty("总用电量(度)/时长(秒)")
private BigDecimal totalUse;
/**
* 获取套餐时长
*/
public long toSecondSuitTime() {
SuitTimeUnit unit = SuitTimeUnit.getByValue(this.getSuitTimeUnit());
if (unit == null) {
unit = SuitTimeUnit.MINUTE;
}
long time = this.getSuitTime() == null ? 0 : this.getSuitTime();
// 计算周期数
int round = 1;
// 若为智能模式则计算出押金最大支持多少次向上取整
if (SuitFeeMode.SMART.getMode().equals(this.getSuitFeeMode())) {
round = this.getSuitDeposit().divide(this.getSuitPrice(), 0, RoundingMode.UP).intValue();
}
return time * unit.getConversion() * round;
}
@Override
public String iotMac1() {
return getDeviceMac();

View File

@ -4,6 +4,8 @@ import com.ruoyi.ss.transactionBill.domain.bo.*;
import com.ruoyi.ss.transactionBill.domain.dto.*;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import java.math.BigDecimal;
/**
* @author wjh
* 2024/7/28
@ -28,4 +30,22 @@ public interface TransactionBillConverter {
RechargePayDepositBO toRechargePayDepositBO(PayDepositDTO dto);
EndUseBO toEndUseBO(EndUseDTO dto);
/**
* 获取充值的电量
*
* @param bill 订单
*/
BigDecimal toRechargeEle(TransactionBillVO bill);
/**
* 获取充值的时长
*/
long toRechargeSeconds(TransactionBillVO bill);
/**
* 获取订单套餐时长的秒数
*/
long toSecondSuitTime(TransactionBillVO bill);
}

View File

@ -15,6 +15,8 @@ import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.store.domain.StoreVo;
import com.ruoyi.ss.store.service.StoreService;
import com.ruoyi.ss.suit.domain.SuitVO;
import com.ruoyi.ss.suit.domain.enums.SuitFeeMode;
import com.ruoyi.ss.suit.domain.enums.SuitTimeUnit;
import com.ruoyi.ss.suit.service.SuitAssembler;
import com.ruoyi.ss.suit.service.SuitService;
import com.ruoyi.ss.transactionBill.domain.bo.*;
@ -27,6 +29,8 @@ import com.ruoyi.system.service.ISysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
/**
@ -191,4 +195,42 @@ public class TransactionBillConverterImpl implements TransactionBillConverter {
}
return bo;
}
@Override
public BigDecimal toRechargeEle(TransactionBillVO bill) {
if (bill == null) {
return BigDecimal.ZERO;
}
// 计算周期数
long round = this.calcRound(bill);
return BigDecimal.valueOf(bill.getSuitTime() * round);
}
@Override
public long toRechargeSeconds(TransactionBillVO bill) {
long round = this.calcRound(bill);
return this.toSecondSuitTime(bill) * round;
}
@Override
public long toSecondSuitTime(TransactionBillVO bill) {
SuitTimeUnit unit = SuitTimeUnit.getByValue(bill.getSuitTimeUnit());
if (unit == null) {
unit = SuitTimeUnit.MINUTE;
}
long time = bill.getSuitTime() == null ? 0 : bill.getSuitTime();
return time * unit.getConversion();
}
/**
* 计算周期数
*/
private long calcRound(TransactionBillVO bill) {
int round = 1;
// 若为智能模式则计算出押金最大支持多少次向上取整
if (SuitFeeMode.SMART.getMode().equals(bill.getSuitFeeMode())) {
round = bill.getSuitDeposit().divide(bill.getSuitPrice(), 0, RoundingMode.UP).intValue();
}
return round;
}
}

View File

@ -868,15 +868,15 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
try {
if (SuitFeeType.TIME.getType().equals(bill.getSuitFeeType())) {
// 设备充值时长
return deviceService.addTime(bill.getDeviceId(), bill.toSecondSuitTime(), true);
return deviceService.addTime(bill.getDeviceId(), transactionBillConverter.toRechargeSeconds(bill), true);
} else if (SuitFeeType.COUNT.getType().equals(bill.getSuitFeeType())) {
// 若设备剩余时长为负数则补偿设备时长
BigDecimal openTime = BigDecimal.valueOf(bill.getSuitTime());
// 若设备剩余电量为负数则补偿设备电量
BigDecimal ele = transactionBillConverter.toRechargeEle(bill);
if (device.getSurplusEle() != null && device.getSurplusEle().compareTo(BigDecimal.ZERO) < 0) {
openTime = openTime.add(device.getSurplusEle().abs());
ele = ele.add(device.getSurplusEle().abs());
}
// 设备充值电量
CommandResponse res = iotService.addEle(device, openTime);
CommandResponse res = iotService.addEle(device, ele);
ServiceUtil.assertion(res == null, "设备充值失败,返回数据为空");
ServiceUtil.assertion(!res.isSuccess(), "设备充值失败:" + res.getMsg());
return true;
@ -927,13 +927,13 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
// 充值时长
if (SuitFeeType.TIME.getType().equals(bill.getSuitFeeType())) {
// 计算开始使用的时间
LocalDateTime endTime = startTime.plusSeconds(bill.toSecondSuitTime());
LocalDateTime endTime = startTime.plusSeconds(transactionBillConverter.toRechargeSeconds(bill));
data.setSuitEndTime(endTime);
data.setSuitExpireTime(endTime);
}
// 充值电量
else if (SuitFeeType.COUNT.getType().equals(bill.getSuitFeeType())) {
data.setSuitEndEle(device.getTotalElectriQuantity().add(BigDecimal.valueOf(bill.getSuitTime())));
data.setSuitEndEle(device.getTotalElectriQuantity().add(transactionBillConverter.toRechargeEle(bill)));
}
return transactionBillMapper.updateSmTransactionBill(data);
}
@ -1169,8 +1169,11 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
// 尝试设备清零时长电量
if (withDevice) {
int clear = deviceService.clearTimeAndEle(device, false);
ServiceUtil.assertion(clear != 1, "设备归零失败");
if (SuitFeeType.TIME.getType().equals(order.getSuitFeeType())) {
deviceService.resetTime(device, true);
} else if (SuitFeeType.COUNT.getType().equals(order.getSuitFeeType())) {
deviceService.resetEle(device, true);
}
}
return update;
@ -1199,29 +1202,27 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
TransactionBillVO bill = selectSmTransactionBillByBillId(billId);
ServiceUtil.assertion(bill == null, "计算金额出错,订单不存在");
// 计量收费则获取最新的设备信息
if(SuitFeeType.COUNT.getType().equals(bill.getSuitFeeType()) || SuitFeeType.TIMING_COUNT.getType().equals(bill.getSuitFeeType())) {
DeviceVO device = deviceService.selectById(bill.getDeviceId());
deviceService.pullDeviceInfo(device);
totalEle = this.calcTotalEle(device, totalEle);
}
BigDecimal totalAmount = BigDecimal.ZERO;
// 智能计费
if (SuitFeeMode.SMART.getMode().equals(bill.getSuitFeeMode())) {
if (SuitFeeType.timingList().contains(bill.getSuitFeeType())) {
// 分时段计费
totalAmount = this.calcTimingAmount(bill, endTime, totalEle);
return this.calcTimingAmount(bill, endTime, totalEle);
} else {
// 非分时段计费
BigDecimal refundAmount = this.calcRefundAmount(bill, endTime, totalEle);
totalAmount = bill.getMoney().subtract(refundAmount);
return this.calcSmartAmount(bill, endTime, totalEle);
}
}
// 非智能计费
else {
totalAmount = bill.getMoney();
return bill.getMoney();
}
return totalAmount;
}
@Override
@ -1295,26 +1296,38 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
return EndUseVO.toResult(result, true, null);
}
/**
* 计算退款金额
*/
private BigDecimal calcRefundAmount(TransactionBillVO order, LocalDateTime endTime, BigDecimal totalEle) {
BigDecimal refund = BigDecimal.ZERO;
BigDecimal refund = order.getMoney().subtract(this.calcSmartAmount(order, endTime, totalEle));
// 退款金额不允许大于订单金额
if (refund.compareTo(order.getMoney()) > 0) {
return order.getMoney();
}
// 退款金额不允许小于0
if (refund.compareTo(BigDecimal.ZERO) < 0) {
return BigDecimal.ZERO;
}
return refund;
}
/**
* 计算智能收费实际使用金额
*/
private BigDecimal calcSmartAmount(TransactionBillVO order, LocalDateTime endTime, BigDecimal totalEle) {
// 智能收费时长计费
if (SuitFeeType.TIME.getType().equals(order.getSuitFeeType())) {
refund = this.calcTimeRefund(order, endTime);
return this.calcSmartTimeAmount(order, endTime);
}
// 智能收费计量收费
else if (SuitFeeType.COUNT.getType().equals(order.getSuitFeeType())) {
refund = this.calcCountRefund(order, totalEle);
return this.calcSmartCountAmount(order, totalEle);
}
else {
throw new ServiceException("不支持的智能收费方式");
}
// 退款金额不允许大于订单金额
if (refund.compareTo(order.getMoney()) > 0) {
refund = order.getMoney();
}
return refund;
}
@Override
@ -1325,40 +1338,39 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
return this.selectSmTransactionBillList(query);
}
// 计算智能计量收费需要退款的金额
private BigDecimal calcCountRefund(TransactionBillVO order, BigDecimal totalEle) {
// 计算智能计量使用金额
private BigDecimal calcSmartCountAmount(TransactionBillVO order, BigDecimal totalEle) {
BigDecimal startEle = order.getSuitStartEle();
BigDecimal usedEle = totalEle.subtract(startEle); // 已使用的电量
BigDecimal suitTotalEle = BigDecimal.valueOf(order.getSuitTime()); // 套餐总电量
BigDecimal suitTotalEle = transactionBillConverter.toRechargeEle(order); // 套餐总电量
// 计算总使用的周期数不满足一个周期也算一个周期
BigDecimal totalRound = usedEle.divide(suitTotalEle, 0, RoundingMode.UP);
// 退款金额 = 订单金额 - 使用周期数 * 单价
return order.getMoney()
.subtract(
totalRound.multiply(order.getSuitPrice())
);
if (totalRound.compareTo(BigDecimal.ZERO) <= 0 ) {
totalRound = BigDecimal.ONE;
}
// 使用金额 = 使用周期数 * 单价
return totalRound.multiply(order.getSuitPrice());
}
// 计算智能时长收费需要退款的金额
private BigDecimal calcTimeRefund(TransactionBillVO order, LocalDateTime endTime) {
// 计算智能时长使用金额
private BigDecimal calcSmartTimeAmount(TransactionBillVO order, LocalDateTime endTime) {
LocalDateTime startTime = order.getSuitStartTime();
Duration between = Duration.between(startTime, endTime);
SuitTimeUnit unit = SuitTimeUnit.getByValue(order.getSuitTimeUnit());
ServiceUtil.assertion(unit == null, "订单套餐单位无效");
long totalSeconds = unit.getConversion() * order.getSuitTime(); // 总时长
// 计算总使用的周期数不满足一个周期也算一个周期
long totalRound = totalSeconds / order.getSuitTime() + (totalSeconds % order.getSuitTime() != 0 ? 1 : 0);
long totalSeconds = between.getSeconds(); // 总使用时长
long secondSuitTime = transactionBillConverter.toSecondSuitTime(order);
long totalRound = totalSeconds / secondSuitTime + (totalSeconds % secondSuitTime != 0 ? 1 : 0);
if (totalRound <= 0) {
totalRound = 1;
}
// 退款金额 = 订单金额 - 使用周期数 * 单价
return order.getMoney()
.subtract(
BigDecimal.valueOf(totalRound).multiply(order.getSuitPrice())
);
// 使用金额 = 使用周期数 * 单价
return BigDecimal.valueOf(totalRound).multiply(order.getSuitPrice());
}
// 计算分时段计量金额
@ -1616,7 +1628,7 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
ServiceUtil.assertion(updateInfo != 1, "更新套餐使用信息失败");
// 修改剩余时间失败
boolean addTime = deviceService.addTime(bill.getDeviceId(), bill.toSecondSuitTime(), false);
boolean addTime = deviceService.addTime(bill.getDeviceId(), transactionBillConverter.toRechargeSeconds(bill), false);
ServiceUtil.assertion(!addTime, "修改剩余时间失败");
return result;
@ -1643,7 +1655,7 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
SmUserVo user = userService.selectSmUserByUserId(bill.getUserId());
// 根据订单套餐类型记录
if (SuitFeeType.TIME.getType().equals(bill.getSuitFeeType())) {
recordTimeService.insertRecordTime(recordTimeConverter.toRecordTime(device, bill.toSecondSuitTime(), reason, user, RecordTimeType.TIME.getType()));
recordTimeService.insertRecordTime(recordTimeConverter.toRecordTime(device, transactionBillConverter.toRechargeSeconds(bill), reason, user, RecordTimeType.TIME.getType()));
} else if (SuitFeeType.COUNT.getType().equals(bill.getSuitFeeType())) {
recordTimeService.insertRecordTime(recordTimeConverter.toRecordTime(device, bill.getSuitTime(), reason, user, RecordTimeType.ELE.getType()));
}

View File

@ -127,8 +127,10 @@ public class TransactionBillValidatorImpl extends BaseValidator implements Trans
if (suit.getPrice().compareTo(dto.getSuitPrice()) != 0) {
return error("当前套餐价格已发生变化,请重新下单");
}
if (suit.getDeposit().compareTo(dto.getSuitDeposit()) != 0) {
return error("当前套餐押金已发生变化,请重新下单");
if (SuitFeeMode.SMART.getMode().equals(suit.getFeeMode())) {
if (suit.getDeposit().compareTo(dto.getSuitDeposit()) != 0) {
return error("当前套餐押金已发生变化,请重新下单");
}
}
if (!suit.getFeeMode().equals(dto.getSuitFeeMode())) {
return error("当前套餐收费模式发生变化,请重新下单");