2
0

feat: 余额计费

This commit is contained in:
caiyuchao
2025-01-07 10:30:41 +08:00
parent e8a0ad3356
commit 9b902bfd84
20 changed files with 589 additions and 26 deletions

View File

@@ -29,19 +29,21 @@ CREATE TABLE `u_account` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
`balance` decimal(18, 4) NULL DEFAULT NULL COMMENT '余额',
`balance_used` decimal(18, 4) NULL DEFAULT NULL COMMENT '余额已使用',
`package_id` bigint(20) NULL DEFAULT NULL COMMENT '套餐ID',
`start_time` datetime NULL DEFAULT NULL COMMENT '开始时间',
`end_time` datetime NULL DEFAULT NULL COMMENT '结束时间',
`traffic` bigint(20) NULL DEFAULT NULL COMMENT '流量',
`traffic_used` bigint(20) NULL DEFAULT NULL COMMENT '流量已使用',
`duration` bigint(20) NULL DEFAULT NULL COMMENT '时长',
`duration_used` bigint(20) NULL DEFAULT NULL COMMENT '时长已使用',
`client_num` int(11) NULL DEFAULT NULL COMMENT '在线设备数',
`client_num_used` int(11) NULL DEFAULT NULL COMMENT '在线设备数已使用',
`expired_time` datetime NULL DEFAULT NULL COMMENT '失效时间',
`package_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '套餐名称',
`period_num` int(11) NULL DEFAULT NULL COMMENT '有效期数',
`period_type` tinyint(4) NULL DEFAULT NULL COMMENT '有效期类型',
`price` decimal(18, 4) NULL DEFAULT NULL COMMENT '价格',
`traffic` bigint(20) NULL DEFAULT NULL COMMENT '流量',
`duration` bigint(20) NULL DEFAULT NULL COMMENT '时长',
`client_num` int(11) NULL DEFAULT NULL COMMENT '在线设备数',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`rate_limit_enable` tinyint(1) NULL DEFAULT 0 COMMENT '带宽是否限制',
`traffic_enable` tinyint(1) NULL DEFAULT 0 COMMENT '流量是否限制',
@@ -92,22 +94,37 @@ CREATE TABLE `u_balance` (
-- ----------------------------
DROP TABLE IF EXISTS `u_bill`;
CREATE TABLE `u_bill` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Bill ID',
`user_id` bigint(20) NULL DEFAULT NULL COMMENT 'User ID link to u_user',
`fee` double NULL DEFAULT NULL,
`billing_begin` datetime NULL DEFAULT NULL,
`billing_end` datetime NULL DEFAULT NULL,
`status` enum('unpaid','paid') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'unpaid',
`create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT 'create name ',
`create_time` datetime NULL DEFAULT NULL COMMENT 'create time',
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_user_id`(`user_id`) USING BTREE,
CONSTRAINT `u_bill_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `u_user` (`user_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户平台_用户信息表' ROW_FORMAT = DYNAMIC;
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
`cdr_history_id` bigint(20) NULL DEFAULT NULL COMMENT '话单记录ID',
`type` tinyint(4) NULL DEFAULT NULL COMMENT '类型',
`amount` decimal(18, 4) NULL DEFAULT NULL COMMENT '金额',
`status` tinyint(4) NULL DEFAULT NULL COMMENT '状态',
`del_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标志0存在 1删除',
`create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint(20) NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1876451063420497923 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户平台-账单表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of u_bill
-- Table structure for u_bill_rule
-- ----------------------------
DROP TABLE IF EXISTS `u_bill_rule`;
CREATE TABLE `u_bill_rule` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`price` decimal(18, 4) NULL DEFAULT NULL COMMENT '价格',
`traffic` bigint(20) NULL DEFAULT NULL COMMENT '流量',
`unit` tinyint(4) NULL DEFAULT NULL COMMENT '单位',
`enable` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用',
`del_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标志0存在 1删除',
`create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint(20) NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户平台-计费规则表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for u_cdr

View File

@@ -0,0 +1,69 @@
package org.wfc.user.controller;
import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wfc.common.core.web.controller.BaseController;
import org.wfc.common.core.web.domain.AjaxResult;
import org.wfc.common.core.web.page.TableDataInfo;
import org.wfc.user.domain.UBill;
import org.wfc.user.service.IUBillService;
import java.util.List;
/**
* <p>
* 用户平台-账单表 前端控制器
* </p>
*
* @author sys
* @since 2025-01-06
*/
@RestController
@RequestMapping("/user/uBill")
public class UBillController extends BaseController {
@Autowired
private IUBillService uBillService;
@GetMapping("/page")
public TableDataInfo page(UBill uBill) {
startPage();
List<UBill> list = uBillService.list();
return getDataTable(list);
}
@GetMapping("/list")
public AjaxResult list(UBill uBill) {
List<UBill> list = uBillService.list();
return success(list);
}
@GetMapping(value = "/{id}")
public AjaxResult getById(@PathVariable("id") Long id) {
return success(uBillService.getById(id));
}
@PostMapping
public AjaxResult add(@RequestBody UBill uBill) {
return toAjax(uBillService.save(uBill));
}
@PutMapping
public AjaxResult edit(@RequestBody UBill uBill) {
return toAjax(uBillService.updateById(uBill));
}
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(uBillService.removeByIds(CollUtil.newArrayList(ids)));
}
}

View File

@@ -0,0 +1,69 @@
package org.wfc.user.controller;
import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wfc.common.core.web.controller.BaseController;
import org.wfc.common.core.web.domain.AjaxResult;
import org.wfc.common.core.web.page.TableDataInfo;
import org.wfc.user.domain.UBillRule;
import org.wfc.user.service.IUBillRuleService;
import java.util.List;
/**
* <p>
* 用户平台-计费规则表 前端控制器
* </p>
*
* @author sys
* @since 2025-01-06
*/
@RestController
@RequestMapping("/user/uBillRule")
public class UBillRuleController extends BaseController {
@Autowired
private IUBillRuleService uBillRuleService;
@GetMapping("/page")
public TableDataInfo page(UBillRule uBillRule) {
startPage();
List<UBillRule> list = uBillRuleService.list();
return getDataTable(list);
}
@GetMapping("/list")
public AjaxResult list(UBillRule uBillRule) {
List<UBillRule> list = uBillRuleService.list();
return success(list);
}
@GetMapping(value = "/{id}")
public AjaxResult getById(@PathVariable("id") Long id) {
return success(uBillRuleService.getById(id));
}
@PostMapping
public AjaxResult add(@RequestBody UBillRule uBillRule) {
return toAjax(uBillRuleService.save(uBillRule));
}
@PutMapping
public AjaxResult edit(@RequestBody UBillRule uBillRule) {
return toAjax(uBillRuleService.updateById(uBillRule));
}
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(uBillRuleService.removeByIds(CollUtil.newArrayList(ids)));
}
}

View File

@@ -46,9 +46,15 @@ public class UAccount extends BaseData {
@Schema(description = "时长已使用")
private Long durationUsed;
@Schema(description = "失效时间")
private Date expiredTime;
@Schema(description = "在线设备数已使用")
private Integer clientNumUsed;
@Schema(description = "余额已使用")
private BigDecimal balanceUsed;
@Schema(description = "套餐名称")
private String packageName;

View File

@@ -0,0 +1,41 @@
package org.wfc.user.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import org.wfc.common.mybatis.domain.BaseData;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 用户平台-账单表
* </p>
*
* @author sys
* @since 2025-01-06
*/
@Getter
@Setter
@TableName("u_bill")
@Schema(name = "UBill", description = "用户平台-账单表")
public class UBill extends BaseData {
private static final long serialVersionUID = 1L;
@Schema(description = "用户ID")
private Long userId;
@Schema(description = "话单记录ID")
private Long cdrHistoryId;
@Schema(description = "类型")
private Integer type;
@Schema(description = "金额")
private BigDecimal amount;
@Schema(description = "状态")
private Integer status;
}

View File

@@ -0,0 +1,38 @@
package org.wfc.user.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import org.wfc.common.mybatis.domain.BaseData;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 用户平台-计费规则表
* </p>
*
* @author sys
* @since 2025-01-06
*/
@Getter
@Setter
@TableName("u_bill_rule")
@Schema(name = "UBillRule", description = "用户平台-计费规则表")
public class UBillRule extends BaseData {
private static final long serialVersionUID = 1L;
@Schema(description = "价格")
private BigDecimal price;
@Schema(description = "流量")
private Long traffic;
@Schema(description = "单位")
private Integer unit;
@Schema(description = "是否启用")
private Boolean enable;
}

View File

@@ -0,0 +1,37 @@
package org.wfc.user.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @description: cdr 最新记录vo
* @author: cyc
* @since: 2025-01-06
*/
@Data
public class UCdrLatestHistoryVo {
@Schema(description = "ID")
private Long id;
@Schema(description = "user ID")
private Long userId;
@Schema(description = "CDR ID")
private Long cdrId;
@Schema(description = "Downstream traffic (Byte)")
private Long trafficDown;
@Schema(description = "Upstream traffic (Byte)")
private Long trafficUp;
@Schema(description = "Start time")
private Long startTime;
@Schema(description = "End time")
private Long endTime;
@Schema(description = "Duration(s)")
private Long duration;
}

View File

@@ -0,0 +1,16 @@
package org.wfc.user.mapper;
import org.wfc.user.domain.UBill;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 用户平台-账单表 Mapper 接口
* </p>
*
* @author sys
* @since 2025-01-06
*/
public interface UBillMapper extends BaseMapper<UBill> {
}

View File

@@ -0,0 +1,16 @@
package org.wfc.user.mapper;
import org.wfc.user.domain.UBillRule;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 用户平台-计费规则表 Mapper 接口
* </p>
*
* @author sys
* @since 2025-01-06
*/
public interface UBillRuleMapper extends BaseMapper<UBillRule> {
}

View File

@@ -6,8 +6,10 @@ import org.wfc.user.domain.UCdr;
import org.wfc.user.domain.bo.UCdrClientBo;
import org.wfc.user.domain.vo.UCdrClientVo;
import org.wfc.user.domain.vo.UCdrHistoryUserVo;
import org.wfc.user.domain.vo.UCdrLatestHistoryVo;
import org.wfc.user.domain.vo.UCdrUserVo;
import java.util.Date;
import java.util.List;
/**
@@ -25,4 +27,8 @@ public interface UCdrMapper extends BaseMapper<UCdr> {
List<UCdrClientVo> getByClient(@Param("client") UCdrClientBo client);
List<UCdrHistoryUserVo> getHistoryByUser(@Param("userId") Long userId);
List<UCdrLatestHistoryVo> getLatestHistory(@Param("userIds") List<Long> userIds, @Param("endTime") Date endTime);
Long getCurrentTraffic(@Param("userId") Long userId);
}

View File

@@ -0,0 +1,16 @@
package org.wfc.user.service;
import org.wfc.user.domain.UBillRule;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 用户平台-计费规则表 服务类
* </p>
*
* @author sys
* @since 2025-01-06
*/
public interface IUBillRuleService extends IService<UBillRule> {
}

View File

@@ -0,0 +1,16 @@
package org.wfc.user.service;
import org.wfc.user.domain.UBill;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 用户平台-账单表 服务类
* </p>
*
* @author sys
* @since 2025-01-06
*/
public interface IUBillService extends IService<UBill> {
}

View File

@@ -3,6 +3,7 @@ package org.wfc.user.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -13,24 +14,31 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.wfc.common.core.domain.LoginUser;
import org.wfc.common.security.utils.SecurityUtils;
import org.wfc.omada.api.client.OmadaClientApi;
import org.wfc.user.api.IWifiApi;
import org.wfc.user.api.domain.bo.UClientBo;
import org.wfc.user.api.omada.domain.convert.OmadaConvert;
import org.wfc.user.api.omada.domain.dto.ClientRateLimitSettingDto;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UBill;
import org.wfc.user.domain.UBillRule;
import org.wfc.user.domain.UClient;
import org.wfc.user.domain.vo.UAccountDashboardVo;
import org.wfc.user.domain.vo.UCdrLatestHistoryVo;
import org.wfc.user.domain.vo.UCdrUserVo;
import org.wfc.user.mapper.UAccountMapper;
import org.wfc.user.mapper.UBillMapper;
import org.wfc.user.mapper.UBillRuleMapper;
import org.wfc.user.mapper.UCdrMapper;
import org.wfc.user.mapper.UClientMapper;
import org.wfc.user.service.IUAccountService;
import org.wfc.user.util.AccountUtil;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -46,7 +54,7 @@ import java.util.stream.Collectors;
public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> implements IUAccountService {
@Autowired
private UCdrMapper ucdrMapper;
private UCdrMapper cdrMapper;
@Autowired
private IWifiApi wifiApi;
@@ -55,7 +63,11 @@ public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> i
private UClientMapper clientMapper;
@Autowired
private OmadaClientApi omadaClientApi;
private UBillMapper billMapper;
@Autowired
private UBillRuleMapper billRuleMapper;
// 定时任务时间间隔
private static final int JOB_PERIOD = -30;
@@ -66,25 +78,118 @@ public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> i
Date current = new Date();
DateTime endTime = DateUtil.offsetSecond(current, JOB_PERIOD);
List<UAccount> accounts = this.list(Wrappers.<UAccount>lambdaQuery()
.le(UAccount::getStartTime, endTime).gt(UAccount::getEndTime, endTime)
.and(wrapper -> wrapper.isNotNull(UAccount::getBalance).gt(UAccount::getBalance, 0).or()
.le(UAccount::getStartTime, endTime).gt(UAccount::getEndTime, endTime))
.isNotNull(UAccount::getUserId));
List<UAccount> packageAccounts = accounts.stream().filter(account -> AccountUtil.isPackageValid(account, current))
.collect(Collectors.toList());
List<UAccount> balanceAccounts = accounts.stream().filter(account -> !AccountUtil.isPackageValid(account, current))
.collect(Collectors.toList());
// 根据使用流量扣费余额
List<Long> balanceUserIds = balanceAccounts.stream().map(UAccount::getUserId).collect(Collectors.toList());
List<Long> cancelUserIds = new ArrayList<>();
if (CollUtil.isNotEmpty(balanceUserIds)) {
List<UCdrLatestHistoryVo> latestHistoryList = cdrMapper.getLatestHistory(balanceUserIds, endTime);
List<UBillRule> billRules = billRuleMapper.selectList(Wrappers.<UBillRule>lambdaQuery().eq(UBillRule::getEnable, true));
Optional<UBillRule> billRuleOptional = billRules.stream().findFirst();
if (billRuleOptional.isPresent()) {
UBillRule billRule = billRuleOptional.get();
for (Long balanceUserId : balanceUserIds) {
Long currentTraffic = cdrMapper.getCurrentTraffic(balanceUserId);
if (ObjectUtil.isNull(currentTraffic)) {
continue;
}
BigDecimal traffic = BigDecimal.valueOf(currentTraffic).divide(BigDecimal.valueOf(1048576), 4, RoundingMode.HALF_UP);
UAccount account = this.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, balanceUserId), false);
account.setBalanceUsed(NumberUtil.mul(traffic, billRule.getPrice()));
if (ObjectUtil.isNull(account.getBalance())) {
account.setBalance(BigDecimal.ZERO);
}
if (account.getBalance().compareTo(account.getBalanceUsed()) <= 0) {
cancelUserIds.add(account.getUserId());
} else {
account.setBalance(BigDecimal.ZERO);
}
this.updateById(account);
}
for (UCdrLatestHistoryVo historyVo : latestHistoryList) {
UBill bill = new UBill();
bill.setUserId(historyVo.getUserId());
bill.setCdrHistoryId(historyVo.getCdrId());
BigDecimal total = NumberUtil.div(NumberUtil.add(historyVo.getTrafficDown(), historyVo.getTrafficUp()), 1048576);
bill.setAmount(NumberUtil.mul(total, billRule.getPrice()));
billMapper.insert(bill);
UAccount account = this.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, historyVo.getUserId()), false);
if (ObjectUtil.isNull(account) || (ObjectUtil.isNotNull(account.getExpiredTime())
&& account.getExpiredTime().getTime() >= historyVo.getEndTime())) {
continue;
}
if (ObjectUtil.isNull(account.getBalance())) {
account.setBalance(BigDecimal.ZERO);
}
if (account.getBalance().compareTo(bill.getAmount()) > 0) {
account.setBalance(account.getBalance().subtract(bill.getAmount()));
} else {
account.setBalance(BigDecimal.ZERO);
cancelUserIds.add(account.getUserId());
}
this.updateById(account);
}
}
}
// 更新账户已使用流量,已使用时长
for (UAccount account : accounts) {
for (UAccount account : packageAccounts) {
if (ObjectUtil.isNull(account.getUserId())) {
continue;
}
List<UCdrUserVo> statCdr = ucdrMapper.getByUser(account.getUserId(), account.getStartTime().getTime(), account.getEndTime().getTime());
List<UCdrUserVo> statCdr = cdrMapper.getByUser(account.getUserId(), account.getStartTime().getTime(), account.getEndTime().getTime());
statCdr.stream().findFirst().ifPresent(stat -> {
account.setTrafficUsed(stat.getTrafficUp() + stat.getTrafficDown());
account.setDurationUsed(stat.getDuration());
});
}
this.updateBatchById(accounts);
this.updateBatchById(packageAccounts);
// 取消授权
List<Long> userIds = accounts.stream().filter(account -> !AccountUtil.isValid(account, current))
List<Long> changeUserIds = packageAccounts.stream().filter(account -> !AccountUtil.isPackageValid(account, current) && AccountUtil.isBalanceValid(account))
.map(UAccount::getUserId)
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(changeUserIds)) {
List<UClient> clients = clientMapper.selectList(Wrappers.<UClient>lambdaQuery().isNotNull(UClient::getSiteId)
.in(UClient::getUserId, changeUserIds));
for (UClient client : clients) {
try {
wifiApi.reconnectClient(client.getSiteId(), client.getClientMac());
// 取消带宽限速
ClientRateLimitSettingDto clientRateLimitSetting = new ClientRateLimitSettingDto();
clientRateLimitSetting.setRateLimitEnable(false);
wifiApi.updateClientRateLimitSetting(client.getSiteId(), client.getClientMac(), clientRateLimitSetting);
} catch (Exception e) {
log.info("reconnect error: {}", e.getMessage());
}
}
ArrayList<UAccount> changeAccounts = new ArrayList<>();
Date expiredTime = new Date();
for (Long changeUserId : changeUserIds) {
UAccount changeAccount = new UAccount();
changeAccount.setId(changeUserId);
changeAccount.setExpiredTime(expiredTime);
}
this.updateBatchById(changeAccounts);
}
// 取消授权
List<Long> userIds = packageAccounts.stream().filter(account -> !AccountUtil.isValid(account, current))
.map(UAccount::getUserId)
.collect(Collectors.toList());
userIds.addAll(cancelUserIds);
if (CollUtil.isNotEmpty(userIds)) {
List<UClient> clients = clientMapper.selectList(Wrappers.<UClient>lambdaQuery().isNotNull(UClient::getSiteId)
@@ -140,6 +245,13 @@ public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> i
BeanUtils.copyProperties(account, dashboardVo);
dashboardVo.setId(loginUser.getUserid());
dashboardVo.setActivity(0L);
BigDecimal balanceUsed = Optional.of(account.getBalanceUsed()).orElse(BigDecimal.ZERO);
BigDecimal balance = Optional.of(dashboardVo.getBalance()).orElse(BigDecimal.ZERO);
if (balance.compareTo(balanceUsed) >= 0) {
dashboardVo.setBalance(BigDecimal.ZERO);
} else {
dashboardVo.setBalance(balance.subtract(balanceUsed));
}
}
return dashboardVo;
}

View File

@@ -0,0 +1,20 @@
package org.wfc.user.service.impl;
import org.wfc.user.domain.UBillRule;
import org.wfc.user.mapper.UBillRuleMapper;
import org.wfc.user.service.IUBillRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 用户平台-计费规则表 服务实现类
* </p>
*
* @author sys
* @since 2025-01-06
*/
@Service
public class UBillRuleServiceImpl extends ServiceImpl<UBillRuleMapper, UBillRule> implements IUBillRuleService {
}

View File

@@ -0,0 +1,20 @@
package org.wfc.user.service.impl;
import org.wfc.user.domain.UBill;
import org.wfc.user.mapper.UBillMapper;
import org.wfc.user.service.IUBillService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 用户平台-账单表 服务实现类
* </p>
*
* @author sys
* @since 2025-01-06
*/
@Service
public class UBillServiceImpl extends ServiceImpl<UBillMapper, UBill> implements IUBillService {
}

View File

@@ -72,6 +72,7 @@ public class UCdrServiceImpl extends ServiceImpl<UCdrMapper, UCdr> implements IU
@Autowired
private IUAccountService accountService;
@Override
public UCdrUserVo getByUser() {
LoginUser<Object> loginUser = SecurityUtils.getLoginUser();
@@ -142,6 +143,7 @@ public class UCdrServiceImpl extends ServiceImpl<UCdrMapper, UCdr> implements IU
.trafficDown(pastConn.getDownload())
.duration(pastConn.getDuration())
.build();
cdrHistoryService.save(uCdrHistory);
}
}

View File

@@ -1,8 +1,10 @@
package org.wfc.user.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import org.wfc.user.domain.UAccount;
import java.math.BigDecimal;
import java.util.Date;
/**
@@ -20,9 +22,22 @@ public class AccountUtil {
* @return boolean
*/
public static boolean isValid(UAccount account, Date current) {
// 过期/流量已用完/时长已用完应取消授权
return ((DateUtil.compare(account.getStartTime(), current) <= 0 && DateUtil.compare(account.getEndTime(), current) > 0)
&& (!account.getTrafficEnable() || account.getTrafficUsed() <= account.getTraffic())
&& (!account.getDurationEnable() || account.getDurationUsed() <= account.getDuration()))
|| (ObjectUtil.isNotNull(account.getBalance()) && account.getBalance().compareTo(BigDecimal.ZERO) > 0);
}
public static boolean isPackageValid(UAccount account, Date current) {
// 过期/流量已用完/时长已用完应取消授权
return (DateUtil.compare(account.getStartTime(), current) <= 0 && DateUtil.compare(account.getEndTime(), current) > 0)
&& (!account.getTrafficEnable() || account.getTrafficUsed() <= account.getTraffic())
&& (!account.getDurationEnable() || account.getDurationUsed() <= account.getDuration());
}
public static boolean isBalanceValid(UAccount account) {
// 过期/流量已用完/时长已用完应取消授权
return ObjectUtil.isNotNull(account.getBalance()) && account.getBalance().compareTo(BigDecimal.ZERO) > 0;
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.user.mapper.UBillMapper">
</mapper>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.user.mapper.UBillRuleMapper">
</mapper>

View File

@@ -133,4 +133,41 @@
ORDER BY
ch.start_time DESC
</select>
<select id="getLatestHistory" resultType="org.wfc.user.domain.vo.UCdrLatestHistoryVo">
SELECT
h.*,
c.user_id
FROM
u_cdr_history h
LEFT JOIN u_cdr c ON h.cdr_id = c.id
AND c.del_flag = 0
WHERE
h.del_flag = 0
<if test="userIds != null and userIds.size() > 0">
AND c.user_id in
<foreach collection="userIds" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
</if>
<if test="endTime != null">
AND h.create_time > #{endTime}
</if>
</select>
<select id="getCurrentTraffic" resultType="long">
SELECT
sum(
ifnull( c.traffic_down, 0 )) + sum(
ifnull( c.traffic_up, 0 )) traffic
FROM
u_cdr c
LEFT JOIN ( SELECT h.cdr_id, max( h.end_time ) end_time FROM u_cdr_history h WHERE h.del_flag = 0 GROUP BY h.cdr_id ) h ON c.id = h.cdr_id
WHERE
c.del_flag = 0
AND c.last_seen_time != ifnull( h.end_time, 0 )
AND c.user_id = #{userId}
GROUP BY
c.user_id
</select>
</mapper>