From 32fc1d98ac7b84947ab387ab51e5c173c2fb7d10 Mon Sep 17 00:00:00 2001 From: caiyuchao Date: Wed, 11 Jun 2025 17:45:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B4=A6=E5=8D=95=E5=92=8C=E5=8F=91?= =?UTF-8?q?=E7=A5=A8=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/upgrade/1.0.17/upgrade.sql | 8 + wfc-modules/wfc-user/pom.xml | 7 + .../wfc/user/controller/UEmailController.java | 49 +++- .../main/java/org/wfc/user/domain/UBill.java | 12 +- .../user/domain/bo/UInvoiceTemplateBo.java | 40 ++++ .../user/domain/constant/OrderTypeEnum.java | 4 +- .../user/domain/constant/PeriodTypeEnum.java | 8 +- .../org/wfc/user/service/IUBillService.java | 4 + .../user/service/impl/UBillServiceImpl.java | 221 ++++++++++++++++++ .../user/service/impl/UOrderServiceImpl.java | 5 + .../java/org/wfc/user/util/AccountUtil.java | 4 +- .../org/wfc/user/util/TrafficConverter.java | 106 +++++++++ 12 files changed, 454 insertions(+), 14 deletions(-) create mode 100644 sql/upgrade/1.0.17/upgrade.sql create mode 100644 wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/UInvoiceTemplateBo.java create mode 100644 wfc-modules/wfc-user/src/main/java/org/wfc/user/util/TrafficConverter.java diff --git a/sql/upgrade/1.0.17/upgrade.sql b/sql/upgrade/1.0.17/upgrade.sql new file mode 100644 index 0000000..38b5205 --- /dev/null +++ b/sql/upgrade/1.0.17/upgrade.sql @@ -0,0 +1,8 @@ +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +ALTER TABLE `wfc_user_db`.`u_bill` +ADD COLUMN `invoice_number` varchar(64) NULL COMMENT '发票编号' AFTER `status`, +ADD COLUMN `invoice_file` varchar(255) NULL COMMENT '发票文件' AFTER `invoice_number` + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/wfc-modules/wfc-user/pom.xml b/wfc-modules/wfc-user/pom.xml index fc32d53..f544f45 100644 --- a/wfc-modules/wfc-user/pom.xml +++ b/wfc-modules/wfc-user/pom.xml @@ -108,6 +108,13 @@ org.springframework.boot spring-boot-starter-thymeleaf + + + com.itextpdf + html2pdf + 6.2.0 + + diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java index b47b1c4..8f9d0a1 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UEmailController.java @@ -1,26 +1,34 @@ package org.wfc.user.controller; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; +import com.itextpdf.html2pdf.HtmlConverter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; import org.wfc.common.core.constant.Constants; import org.wfc.common.core.constant.GlobalConstants; import org.wfc.common.core.domain.R; import org.wfc.common.core.utils.MessageUtils; +import org.wfc.common.core.utils.file.MultipartFileUtil; import org.wfc.common.core.web.controller.BaseController; import org.wfc.common.mail.config.properties.MailProperties; -import org.wfc.common.mail.utils.MailUtils; import org.wfc.common.redis.service.RedisService; +import org.wfc.system.api.RemoteFileService; +import org.wfc.system.api.domain.SysFile; import javax.validation.constraints.NotBlank; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.concurrent.TimeUnit; /** @@ -38,6 +46,7 @@ public class UEmailController extends BaseController { private final MailProperties mailProperties; private final RedisService redisService; private final TemplateEngine templateEngine; + private final RemoteFileService remoteFileService; /** * 邮箱验证码 @@ -56,12 +65,46 @@ public class UEmailController extends BaseController { Context context = new Context(); context.setVariable("verificationCode", code); context.setVariable("expirationTime", Constants.MAIL_CAPTCHA_EXPIRATION); - String htmlStr = templateEngine.process("mail", context); + context.setVariable("username", "chason"); + context.setVariable("email", "707821112@qq.com"); + context.setVariable("invoiceNumber", "INV-2025-05-001"); + context.setVariable("invoiceDate", "2025-05-28"); + context.setVariable("hasDetails", "false"); + context.setVariable("itemName", "Network Traffic Fee"); + context.setVariable("qty", "1"); + context.setVariable("unitPrice", "$50"); + context.setVariable("total", "$50"); + context.setVariable("currency", "USD"); + context.setVariable("traffic", "200GB"); + context.setVariable("speedCap", "Upload 30 Mbps / Download 100 Mbps"); + context.setVariable("clientsNumber", "5"); + context.setVariable("billingCycle", "Monthly"); + + String htmlStr = templateEngine.process("invoice", context); + +// String basePath = System.getProperty("user.dir") + File.separator + "invoice.pdf"; + String basePath = "D:\\documents\\projects\\wanfi\\invoice"; + FileUtil.mkdir(basePath); + basePath = basePath + File.separator + "invoice.pdf"; + + File uploadFile = new File(basePath); +// HtmlConverter.convertToPdf(htmlStr, outputStream); + HtmlConverter.convertToPdf(htmlStr, Files.newOutputStream(Paths.get(basePath))); +// HtmlConverter.convertToPdf(htmlStr, Files.newOutputStream(Paths.get("D:\\projects\\pro\\be.wfc\\invoice.pdf"))); + + MultipartFile multipartFile = MultipartFileUtil.getMultipartFile(uploadFile); + R fileResult = remoteFileService.upload(multipartFile); + String url = fileResult.getData().getUrl(); + log.info("qr code file: {}", url); + + String subject = mailProperties.getSubject(); if (StrUtil.isBlank(subject)) { subject = "Your WANFI Verification Code"; } - MailUtils.sendHtml(email, subject, htmlStr); +// MailUtils.sendHtml(email, subject, htmlStr, uploadFile); + +// FileUtil.del(uploadFile); } catch (Exception e) { log.error("email verification code send failed => {}", e.getMessage()); return R.fail(e.getMessage()); diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/UBill.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/UBill.java index 6d02884..39998f1 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/UBill.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/UBill.java @@ -1,12 +1,12 @@ 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; +import org.wfc.common.mybatis.domain.BaseData; + +import java.math.BigDecimal; /** *

@@ -38,4 +38,10 @@ public class UBill extends BaseData { @Schema(description = "状态") private Integer status; + + @Schema(description = "发票编号") + private String invoiceNumber; + + @Schema(description = "发票文件") + private String invoiceFile; } diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/UInvoiceTemplateBo.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/UInvoiceTemplateBo.java new file mode 100644 index 0000000..c0be0b5 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/UInvoiceTemplateBo.java @@ -0,0 +1,40 @@ +package org.wfc.user.domain.bo; + +import lombok.Data; + +/** + * @description: 发票模板bo + * @author: cyc + * @since: 2025-06-06 + */ +@Data +public class UInvoiceTemplateBo { + + private String username; + + private String email; + + private String invoiceNumber; + + private String invoiceDate; + + private String itemName; + + private String qty; + + private String unitPrice; + + private String total; + + private String currency; + + private boolean hasDetails; + + private String traffic; + + private String speedCap; + + private String clientsNumber; + + private String billingCycle; +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderTypeEnum.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderTypeEnum.java index b043770..0dd59dc 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderTypeEnum.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderTypeEnum.java @@ -12,8 +12,8 @@ import lombok.Getter; @AllArgsConstructor public enum OrderTypeEnum { - PACKAGE(0, "套餐"), - RECHARGE(1, "充值"); + PACKAGE(0, "Package"), + RECHARGE(1, "Recharge"); private final Integer code; private final String desc; diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/PeriodTypeEnum.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/PeriodTypeEnum.java index b2b8319..ec0abc6 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/PeriodTypeEnum.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/PeriodTypeEnum.java @@ -12,10 +12,10 @@ import lombok.Getter; @AllArgsConstructor public enum PeriodTypeEnum { - HOUR(0, "小时"), - DAY(1, "天"), - MONTH(2, "月"), - YEAR(3, "年") + HOUR(0, "Hour"), + DAY(1, "Day"), + MONTH(2, "Month"), + YEAR(3, "Year") ; private final Integer code; diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUBillService.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUBillService.java index 6aacce3..e64483a 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUBillService.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUBillService.java @@ -2,7 +2,10 @@ package org.wfc.user.service; import com.baomidou.mybatisplus.extension.service.IService; import org.wfc.user.domain.UBill; +import org.wfc.user.domain.UOrder; import org.wfc.user.domain.vo.UBillUserVo; +import org.wfc.user.domain.vo.UInvoiceBillVo; +import org.wfc.user.domain.vo.UInvoiceGenVo; import java.util.List; @@ -20,4 +23,5 @@ public interface IUBillService extends IService { List getInvoiceByUser(); + UInvoiceGenVo genInvoice(UOrder order); } diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UBillServiceImpl.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UBillServiceImpl.java index 8c35169..9270f9a 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UBillServiceImpl.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UBillServiceImpl.java @@ -1,15 +1,62 @@ package org.wfc.user.service.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.itextpdf.html2pdf.ConverterProperties; +import com.itextpdf.html2pdf.HtmlConverter; +import com.itextpdf.layout.font.FontProvider; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; +import org.wfc.common.core.constant.CacheConstants; import org.wfc.common.core.domain.LoginUser; +import org.wfc.common.core.domain.R; +import org.wfc.common.core.exception.ServiceException; +import org.wfc.common.core.utils.file.MultipartFileUtil; +import org.wfc.common.mail.config.properties.MailProperties; +import org.wfc.common.mail.utils.MailUtils; +import org.wfc.common.mybatis.domain.BaseData; +import org.wfc.common.redis.service.RedisService; import org.wfc.common.security.utils.SecurityUtils; +import org.wfc.system.api.RemoteFileService; +import org.wfc.system.api.domain.SysFile; +import org.wfc.user.api.domain.UUser; +import org.wfc.user.domain.InvoiceBean; import org.wfc.user.domain.UBill; +import org.wfc.user.domain.UOrder; +import org.wfc.user.domain.UPackage; +import org.wfc.user.domain.URateLimit; +import org.wfc.user.domain.bo.UInvoiceTemplateBo; +import org.wfc.user.domain.constant.OrderTypeEnum; +import org.wfc.user.domain.constant.PeriodTypeEnum; import org.wfc.user.domain.vo.UBillUserVo; +import org.wfc.user.domain.vo.UInvoiceBillVo; +import org.wfc.user.domain.vo.UInvoiceGenVo; import org.wfc.user.mapper.UBillMapper; +import org.wfc.user.mapper.UPackageMapper; +import org.wfc.user.mapper.URateLimitMapper; +import org.wfc.user.mapper.UUserMapper; import org.wfc.user.service.IUBillService; +import org.wfc.user.util.TrafficConverter; +import java.io.File; +import java.io.IOException; +import java.math.RoundingMode; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; import java.util.List; +import java.util.Map; /** *

@@ -19,12 +66,186 @@ import java.util.List; * @author sys * @since 2025-01-06 */ +@Slf4j @Service +@RequiredArgsConstructor public class UBillServiceImpl extends ServiceImpl implements IUBillService { + private final MailProperties mailProperties; + private final TemplateEngine templateEngine; + private final RemoteFileService remoteFileService; + private final UUserMapper userMapper; + private final RedisService redisService; + private final UPackageMapper packageMapper; + private final URateLimitMapper urateLimitMapper; + private final InvoiceBean invoiceBean; + + public static final String PRE_INVOICE_NUMBER = "INV-"; + public static final String LAST_INVOICE_NUMBER = "-001"; + private static final String DEFAULT_SYS_PAY_CURRENCY_VALUE = "USD"; + private static final String DEFAULT_SYS_PAY_CURRENCY_SYMBOL_VALUE = "$"; + + @Override public List getBillByUser() { LoginUser loginUser = SecurityUtils.getLoginUser(); return this.baseMapper.getBillByUser(loginUser.getUserid()); } + + @Override + public List getInvoiceByUser() { + LoginUser loginUser = SecurityUtils.getLoginUser(); + return this.baseMapper.getInvoiceByUser(loginUser.getUserid()); + } + + @Override + public UInvoiceGenVo genInvoice(UOrder order) { + String url; + UInvoiceTemplateBo invoiceBo = new UInvoiceTemplateBo(); + if (order.getUserId() != null) { + UUser user = userMapper.selectUserById(order.getUserId()); + invoiceBo.setUsername(user.getUserName()); + invoiceBo.setEmail(user.getEmail()); + } + UBill bill = this.baseMapper.selectOne(Wrappers.lambdaQuery() + .isNotNull(UBill::getInvoiceNumber) + .orderByDesc(BaseData::getCreateTime).last("limit 1"), false); + + LocalDateTime dateTime = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String dateStr = dateTime.format(formatter); + String oldInvoiceNumber = StrUtil.EMPTY; + if (bill != null) { + oldInvoiceNumber = bill.getInvoiceNumber(); + } + invoiceBo.setInvoiceNumber(genInvoiceNumber(dateStr, oldInvoiceNumber)); + invoiceBo.setInvoiceDate(dateStr); + + Map cacheMap = redisService.getCacheMap(CacheConstants.SYS_PAY_CONFIG_KEY); + String currencySymbol = DEFAULT_SYS_PAY_CURRENCY_SYMBOL_VALUE; + String currency = DEFAULT_SYS_PAY_CURRENCY_VALUE; + if (CollUtil.isNotEmpty(cacheMap)) { + Object currencyObj = cacheMap.get(CacheConstants.SYS_PAY_CURRENCY_KEY); + if (currencyObj != null) { + currency = currencyObj.toString(); + } + invoiceBo.setCurrency(currency); + Object currencySymbolObj = cacheMap.get(CacheConstants.SYS_PAY_CURRENCY_SYMBOL_KEY); + if (currencySymbolObj != null) { + currencySymbol = currencySymbolObj.toString(); + } + } + + if (OrderTypeEnum.PACKAGE.getCode().equals(order.getType())) { + // 套餐 + invoiceBo.setHasDetails(true); + + UPackage uPackage = packageMapper.selectById(order.getPackageId()); + invoiceBo.setItemName(uPackage.getPackageName()); + invoiceBo.setTraffic(uPackage.getTrafficEnable() ? TrafficConverter.formatBytes(uPackage.getTraffic()) : "unlimited"); + invoiceBo.setClientsNumber(uPackage.getClientNumEnable() ? uPackage.getClientNum() + "" : "unlimited"); + PeriodTypeEnum periodTypeEnum = PeriodTypeEnum.getByCode(uPackage.getPeriodType()); + invoiceBo.setBillingCycle(uPackage.getPeriodNum() + " " + (periodTypeEnum == null ? "" : periodTypeEnum.getDesc())); + + + Boolean rateLimitEnable = uPackage.getRateLimitEnable(); + rateLimitEnable = ObjectUtil.isNotNull(uPackage.getRateLimitId()) ? rateLimitEnable : false; + String speedCap = ""; + if (rateLimitEnable) { + URateLimit rateLimit = urateLimitMapper.selectById(uPackage.getRateLimitId()); + if (rateLimit != null) { + String up = rateLimit.getUpLimitEnable() ? TrafficConverter.formatKbps(rateLimit.getUpLimit()) : "unlimited"; + String down = rateLimit.getDownLimitEnable() ? TrafficConverter.formatKbps(rateLimit.getDownLimit()) : "unlimited"; + speedCap = "Upload " + up + " / Download " + down; + } + } else { + speedCap = "unlimited"; + } + invoiceBo.setSpeedCap(speedCap); + + } else if (OrderTypeEnum.RECHARGE.getCode().equals(order.getType())) { + // 充值 + invoiceBo.setHasDetails(false); + invoiceBo.setItemName(OrderTypeEnum.RECHARGE.getDesc()); + } + invoiceBo.setUnitPrice(currencySymbol + order.getOrderAmount().setScale(2, RoundingMode.HALF_UP)); + invoiceBo.setTotal(currencySymbol + order.getOrderAmount().setScale(2, RoundingMode.HALF_UP)); + // 填充发票模版 + Context context = getContext(invoiceBo); + String htmlStr = templateEngine.process("invoice", context); + + String prefix = invoiceBean.getPath(); + String basePath = prefix + File.separator + "invoice"; + String fontsDir = prefix + File.separator + "fonts"; + FileUtil.mkdir(basePath); + basePath = basePath + File.separator + "invoice.pdf"; + + File uploadFile = new File(basePath); + + FontProvider fontProvider = new FontProvider(); + fontProvider.addDirectory(fontsDir); + + try { + HtmlConverter.convertToPdf(htmlStr, Files.newOutputStream(Paths.get(basePath)), new ConverterProperties().setFontProvider(fontProvider)); + } catch (IOException e) { + log.error("convert pdf failed: {}", e.getMessage()); + throw new ServiceException("convert pdf failed"); + } + + MultipartFile multipartFile = MultipartFileUtil.getMultipartFile(uploadFile); + R fileResult = remoteFileService.upload(multipartFile); + url = fileResult.getData().getUrl(); + log.info("invoice file addr: {}", url); + + try { + String subject = mailProperties.getSubject(); + if (StrUtil.isBlank(subject)) { + subject = "Your WANFI Verification Code"; + } + MailUtils.sendHtml(invoiceBo.getEmail(), subject, htmlStr, uploadFile); + + FileUtil.del(uploadFile); + } catch (Exception e) { + log.error("email invoice send failed => {}", e.getMessage()); + } + UInvoiceGenVo invoiceGenVo = new UInvoiceGenVo(); + invoiceGenVo.setInvoiceNumber(invoiceBo.getInvoiceNumber()); + invoiceGenVo.setInvoiceFile(url); + return invoiceGenVo; + } + + private static Context getContext(UInvoiceTemplateBo invoiceBo) { + Context context = new Context(); + context.setVariable("username", invoiceBo.getUsername()); + context.setVariable("email", invoiceBo.getEmail()); + context.setVariable("invoiceNumber", invoiceBo.getInvoiceNumber()); + context.setVariable("invoiceDate", invoiceBo.getInvoiceDate()); + context.setVariable("hasDetails", invoiceBo.isHasDetails() + ""); + context.setVariable("itemName", invoiceBo.getItemName()); + context.setVariable("qty", "1"); + context.setVariable("unitPrice", invoiceBo.getUnitPrice()); + context.setVariable("total", invoiceBo.getTotal()); + context.setVariable("currency", invoiceBo.getCurrency()); + context.setVariable("traffic", invoiceBo.getTraffic()); + context.setVariable("speedCap", invoiceBo.getSpeedCap()); + context.setVariable("clientsNumber", invoiceBo.getClientsNumber()); + context.setVariable("billingCycle", invoiceBo.getBillingCycle()); + return context; + } + + private String genInvoiceNumber(String dateStr, String oldInvoiceNumber) { + String dateSubStr = dateStr.substring(0, 7); + String invoiceNumber = PRE_INVOICE_NUMBER + dateSubStr + LAST_INVOICE_NUMBER; + if (oldInvoiceNumber.contains(dateSubStr)) { + List invStr = StrUtil.split(oldInvoiceNumber, "-"); + if (CollUtil.isNotEmpty(invStr)) { + String no = invStr.get(invStr.size() - 1); + int integer = NumberUtils.toInt(no); + String noStr = String.format("%0" + 3 + "d", integer + 1); + invoiceNumber = PRE_INVOICE_NUMBER + dateSubStr + "-" + noStr; + } + } + return invoiceNumber; + } + } diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java index 2c38ef2..2a4b30f 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java @@ -33,6 +33,7 @@ import org.wfc.user.mapper.UBillMapper; import org.wfc.user.mapper.UBillRuleMapper; import org.wfc.user.mapper.UOrderMapper; import org.wfc.user.service.IUAccountService; +import org.wfc.user.service.IUBillService; import org.wfc.user.service.IUClientService; import org.wfc.user.service.IUOrderService; import org.wfc.user.service.IUPackageService; @@ -76,6 +77,9 @@ public class UOrderServiceImpl extends ServiceImpl impleme @Autowired private UAccountPackageMapper accountPackageMapper; + @Autowired + private IUBillService billService; + @Autowired private IWifiApi wifiApi; @@ -108,6 +112,7 @@ public class UOrderServiceImpl extends ServiceImpl impleme billMapper.insert(bill); + // 保存或更新账户信息 UAccount account = accountService.getOne(Wrappers.lambdaQuery().eq(UAccount::getUserId, order.getUserId()), false); Long accountId = null; diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/AccountUtil.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/AccountUtil.java index 0d85731..267027f 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/AccountUtil.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/AccountUtil.java @@ -35,8 +35,8 @@ public class AccountUtil { 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()); + && (!account.getTrafficEnable() || account.getTrafficUsed() < account.getTraffic()) + && (!account.getDurationEnable() || account.getDurationUsed() < account.getDuration()); } public static boolean isBalanceValid(UAccount account) { diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/TrafficConverter.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/TrafficConverter.java new file mode 100644 index 0000000..f745f60 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/util/TrafficConverter.java @@ -0,0 +1,106 @@ +package org.wfc.user.util; + +import cn.hutool.core.convert.Convert; + +public class TrafficConverter { + + // 定义字节单位 + private static final String[] BYTE_UNITS = {"B", "KB", "MB", "GB", "TB"}; + + private static final String[] BPS_UNITS = {"Kbps", "Mbps", "Gbps"}; + + /** + * 将字节数转换为带单位的字符串 + * + * @param bytes 字节数 + * @return 带单位的字符串 + */ + public static String formatBytes(long bytes) { + if (bytes <= 0) { + return "0B"; + } + int unitIndex = 0; + double value = bytes; + while (value >= 1024 && unitIndex < BYTE_UNITS.length - 1) { + value /= 1024; + unitIndex++; + } + return String.format("%.0f%s", value, BYTE_UNITS[unitIndex]); + } + + /** + * 将kbps数转换为带单位的字符串 + * + * @param Kbps Kbps + * @return 带单位的字符串 + */ + public static String formatKbps(long Kbps) { + if (Kbps <= 0) { + return "0Kbps"; + } + int unitIndex = 0; + double value = Kbps; + while (value >= 1024 && unitIndex < BPS_UNITS.length - 1) { + value /= 1024; + unitIndex++; + } + return String.format("%.0f%s", value, BPS_UNITS[unitIndex]); + } + + /** + * 将带单位的字符串转换为字节数 + * + * @param byteStr 带单位的字符串 + * @return 字节数 + */ + public static long parseBytes(String byteStr) { + if (byteStr == null || byteStr.isEmpty()) { + throw new IllegalArgumentException("Byte string cannot be null or empty"); + } + + // 提取数字和单位 + String[] parts = byteStr.trim().split("\\s*"); + if (parts.length != 2) { + throw new IllegalArgumentException("Invalid byte string format: " + byteStr); + } + + long value = Convert.toLong(parts[0]); + String unit = parts[1].toUpperCase(); + + // 找到单位对应的指数 + int unitIndex = -1; + for (int i = 0; i < BYTE_UNITS.length; i++) { + if (BYTE_UNITS[i].equals(unit)) { + unitIndex = i; + break; + } + } + + if (unitIndex == -1) { + throw new IllegalArgumentException("Unknown byte unit: " + unit); + } + + // 计算字节数 + long result = value; + for (int i = 0; i < unitIndex; i++) { + result *= 1024; + } + + return result; + } + + public static void main(String[] args) { + // 测试字节单位转换 + long bytes = 123456789L; +// long bytes = 1073741824L; + String formatted = formatBytes(bytes); + System.out.println(formatted); // 输出: 117.74MB + + long kbps = 204800L; + formatted = formatKbps(kbps); + System.out.println(formatted); + +// long parsed = parseBytes("117.74MB"); +// System.out.println(parsed); // 输出: 123456789 + } +}