package com.ruoyi.system.ControllerUtil; import com.github.pagehelper.PageHelper; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.system.domain.*; import com.ruoyi.system.service.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; /** * 发票工具类 * * @author ruoyi * @date 2025-01-26 */ public class InvoiceUtil { private static final Logger logger = LoggerFactory.getLogger(InvoiceUtil.class); private static final IUsersInvoiceInfoService usersInvoiceInfoService = SpringUtils.getBean(IUsersInvoiceInfoService.class); private static final IOrderService orderService = SpringUtils.getBean(IOrderService.class); private static final IGoodsOrderService goodsOrderService = SpringUtils.getBean(IGoodsOrderService.class); private static final IUserMemberRechargeLogService userMemberRechargeLogService = SpringUtils.getBean(IUserMemberRechargeLogService.class); private static final IUsersService usersService = SpringUtils.getBean(IUsersService.class); /** * 获取用户发票中心数据 * * @param userId 用户ID * @param page 页码 * @param limit 每页数量 * @return 发票中心数据 */ public static Map getUserInvoiceCenter(Long userId, int page, int limit) { try { Map result = new HashMap<>(); // 1. 获取待开票订单列表 List> pendingInvoices = getPendingInvoiceOrders(userId, page, limit); // 2. 获取已开票列表 List> completedInvoices = getCompletedInvoices(userId, page, limit); // 3. 统计数据 Map statistics = getInvoiceStatistics(userId); result.put("pendingInvoices", pendingInvoices); result.put("completedInvoices", completedInvoices); result.put("statistics", statistics); return result; } catch (Exception e) { logger.error("获取用户发票中心数据失败", e); return null; } } /** * 获取待开票订单列表 * * @param userId 用户ID * @param page 页码 * @param limit 每页数量 * @return 待开票订单列表 */ public static List> getPendingInvoiceOrders(Long userId, int page, int limit) { try { List> pendingOrders = new ArrayList<>(); // 设置分页 PageHelper.startPage(page, limit); // 1. 查询服务订单(已完成且未开票) Order orderQuery = new Order(); orderQuery.setUid(userId); orderQuery.setStatus(4L); // 已完成状态 List serviceOrders = orderService.selectOrderList(orderQuery); for (Order order : serviceOrders) { // 检查是否已开票 if (!isOrderInvoiced(order.getOrderId())) { Map orderMap = new HashMap<>(); orderMap.put("orderId", order.getOrderId()); orderMap.put("orderType", "service"); // 服务订单 orderMap.put("orderTypeText", "服务订单"); orderMap.put("amount", order.getTotalPrice()); orderMap.put("title", "服务订单"+order.getTotalPrice()+"元" ); orderMap.put("createTime", order.getCreateTime()); orderMap.put("canInvoice", true); pendingOrders.add(orderMap); } } // 2. 查询商品订单(已完成且未开票) GoodsOrder goodsOrderQuery = new GoodsOrder(); goodsOrderQuery.setUid(userId); goodsOrderQuery.setStatus(4L); // 已完成状态 List goodsOrders = goodsOrderService.selectGoodsOrderList(goodsOrderQuery); for (GoodsOrder goodsOrder : goodsOrders) { // 检查是否已开票 if (!isOrderInvoiced(goodsOrder.getOrderId())) { Map orderMap = new HashMap<>(); orderMap.put("orderId", goodsOrder.getOrderId()); orderMap.put("orderType", "goods"); // 商品订单 orderMap.put("orderTypeText", "商品订单"); orderMap.put("amount", goodsOrder.getTotalPrice()); orderMap.put("title", "购买商品"+goodsOrder.getTotalPrice()+"元"); orderMap.put("createTime", goodsOrder.getCreateTime()); orderMap.put("canInvoice", true); pendingOrders.add(orderMap); } } // 3. 查询充值订单(已完成且未开票) UserMemberRechargeLog rechargeQuery = new UserMemberRechargeLog(); rechargeQuery.setUid(Math.toIntExact(userId)); rechargeQuery.setPaytype(1); // 已完成状态 List rechargeOrders = userMemberRechargeLogService.selectUserMemberRechargeLogList(rechargeQuery); for (UserMemberRechargeLog recharge : rechargeOrders) { // 检查是否已开票 if (!isOrderInvoiced(recharge.getOrderid())) { Map orderMap = new HashMap<>(); orderMap.put("orderId", recharge.getOrderid()); orderMap.put("orderType", "recharge"); // 充值订单 orderMap.put("orderTypeText", "充值订单"); orderMap.put("amount", recharge.getInmoney()); orderMap.put("title", "会员充值"+recharge.getInmoney()+"元"); orderMap.put("createTime", recharge.getCreatedAt()); orderMap.put("canInvoice", true); pendingOrders.add(orderMap); } } // // 按创建时间倒序排列 // pendingOrders.sort((a, b) -> { // Date timeA = (Date) a.get("createTime"); // Date timeB = (Date) b.get("createTime"); // return timeB.compareTo(timeA); // }); return pendingOrders; } catch (Exception e) { logger.error("获取待开票订单列表失败", e); return new ArrayList<>(); } } /** * 获取已开票列表 * * @param userId 用户ID * @param page 页码 * @param limit 每页数量 * @return 已开票列表 */ public static List> getCompletedInvoices(Long userId, int page, int limit) { try { // 设置分页 PageHelper.startPage(page, limit); UsersInvoiceInfo query = new UsersInvoiceInfo(); query.setUid(userId.intValue()); List invoiceList = usersInvoiceInfoService.selectUsersInvoiceInfoList(query); List> completedInvoices = new ArrayList<>(); for (UsersInvoiceInfo invoice : invoiceList) { Map invoiceMap = new HashMap<>(); invoiceMap.put("id", invoice.getId()); invoiceMap.put("orderId", invoice.getOrderid()); invoiceMap.put("invoiceTitle", invoice.getInvoiceTitle()); invoiceMap.put("amount", invoice.getInvoicemoney()); invoiceMap.put("invoiceText", invoice.getInvoicetext()); invoiceMap.put("status", invoice.getStatus()); invoiceMap.put("statusText", getInvoiceStatusText(invoice.getStatus())); invoiceMap.put("type", invoice.getType()); invoiceMap.put("typeText", getInvoiceTypeText(invoice.getType())); invoiceMap.put("category", invoice.getCategory()); invoiceMap.put("categoryText", invoice.getCategory() == 0 ? "个人" : "企业"); invoiceMap.put("createTime", invoice.getCreatedAt()); invoiceMap.put("hasFile", StringUtils.isNotEmpty(invoice.getFiledata())); invoiceMap.put("fileUrl", invoice.getFiledata()); completedInvoices.add(invoiceMap); } return completedInvoices; } catch (Exception e) { logger.error("获取已开票列表失败", e); return new ArrayList<>(); } } /** * 获取发票统计数据 * * @param userId 用户ID * @return 统计数据 */ public static Map getInvoiceStatistics(Long userId) { try { Map statistics = new HashMap<>(); // 待开票数量 List> pendingOrders = getPendingInvoiceOrders(userId, 1, 1000); int pendingCount = pendingOrders.size(); // 已开票数量 UsersInvoiceInfo query = new UsersInvoiceInfo(); query.setUid(userId.intValue()); List invoiceList = usersInvoiceInfoService.selectUsersInvoiceInfoList(query); int completedCount = invoiceList.size(); // 已开票总金额 BigDecimal totalAmount = invoiceList.stream() .filter(invoice -> invoice.getInvoicemoney() != null) .map(UsersInvoiceInfo::getInvoicemoney) .reduce(BigDecimal.ZERO, BigDecimal::add); statistics.put("pendingCount", pendingCount); statistics.put("completedCount", completedCount); statistics.put("totalAmount", totalAmount); return statistics; } catch (Exception e) { logger.error("获取发票统计数据失败", e); Map statistics = new HashMap<>(); statistics.put("pendingCount", 0); statistics.put("completedCount", 0); statistics.put("totalAmount", BigDecimal.ZERO); return statistics; } } /** * 批量开具发票 * * @param userId 用户ID * @param orderIds 订单ID数组 * @param invoiceData 发票数据 * @return 开票结果 */ public static AjaxResult createBatchInvoice(Long userId, List orderIds, Map invoiceData) { try { // 1. 参数验证 if (orderIds == null || orderIds.isEmpty()) { return AppletControllerUtil.appletWarning("请选择要开票的订单"); } // 2. 验证发票数据 String validateResult = validateInvoiceData(invoiceData); if (StringUtils.isNotEmpty(validateResult)) { return AppletControllerUtil.appletWarning(validateResult); } List successOrders = new ArrayList<>(); List failedOrders = new ArrayList<>(); BigDecimal totalAmount = BigDecimal.ZERO; List invoiceTexts = new ArrayList<>(); // 3. 逐个处理订单 for (String orderId : orderIds) { try { // 验证订单是否存在且属于当前用户 Map orderInfo = getOrderInfo(orderId, userId); if (orderInfo == null) { failedOrders.add(orderId + "(订单不存在或不属于当前用户)"); continue; } // 检查是否已开票 if (isOrderInvoiced(orderId)) { failedOrders.add(orderId + "(已开过发票)"); continue; } // 累计金额和开票内容 BigDecimal orderAmount = (BigDecimal) orderInfo.get("amount"); if (orderAmount != null) { totalAmount = totalAmount.add(orderAmount); } invoiceTexts.add((String) orderInfo.get("title")); successOrders.add(orderId); } catch (Exception e) { failedOrders.add(orderId + "(处理异常: " + e.getMessage() + ")"); } } // 4. 如果没有可开票的订单 if (successOrders.isEmpty()) { return AppletControllerUtil.appletWarning("没有可开票的订单:" + String.join(", ", failedOrders)); } // 5. 创建发票记录 UsersInvoiceInfo invoice = new UsersInvoiceInfo(); invoice.setUid(userId.intValue()); invoice.setOrderid(String.join(",", successOrders)); // 多个订单ID用逗号分隔 invoice.setInvoiceTitle((String) invoiceData.get("invoiceTitle")); invoice.setType((Integer) invoiceData.get("type")); invoice.setCategory((Integer) invoiceData.get("category")); invoice.setInvoicemoney(totalAmount); // 总金额 invoice.setInvoicetext(String.join("、", invoiceTexts)); // 开票内容合并 invoice.setStatus(1); // 待开票 invoice.setCreatedAt(new Date()); // 根据发票类别设置不同字段 if ((Integer) invoiceData.get("category") == 0) { // 个人发票 invoice.setEmail((String) invoiceData.get("email")); // 清空企业字段 invoice.setTaxNumber(null); invoice.setBankName(null); invoice.setBankAccount(null); invoice.setAddress(null); invoice.setPhone(null); invoice.setWechat(null); } else { // 企业发票 invoice.setTaxNumber((String) invoiceData.get("taxNumber")); invoice.setAddress((String) invoiceData.get("address")); invoice.setPhone((String) invoiceData.get("phone")); invoice.setBankName((String) invoiceData.get("bankName")); invoice.setBankAccount((String) invoiceData.get("bankAccount")); invoice.setEmail((String) invoiceData.get("email")); invoice.setWechat((String) invoiceData.get("wechat")); } // 6. 保存发票信息 int result = usersInvoiceInfoService.insertUsersInvoiceInfo(invoice); if (result > 0) { Map resultData = new HashMap<>(); resultData.put("successCount", successOrders.size()); resultData.put("successOrders", successOrders); resultData.put("totalAmount", totalAmount); resultData.put("invoiceId", invoice.getId()); if (!failedOrders.isEmpty()) { resultData.put("failedCount", failedOrders.size()); resultData.put("failedOrders", failedOrders); resultData.put("message", "发票申请提交成功,成功开票 " + successOrders.size() + " 个订单,失败 " + failedOrders.size() + " 个订单"); return AppletControllerUtil.appletSuccess(resultData); } else { resultData.put("message", "发票申请提交成功,共开票 " + successOrders.size() + " 个订单"); return AppletControllerUtil.appletSuccess(resultData); } } else { return AppletControllerUtil.appletWarning("发票申请提交失败"); } } catch (Exception e) { logger.error("批量开具发票失败", e); return AppletControllerUtil.appletError("批量开具发票失败:" + e.getMessage()); } } /** * 开具发票(单个订单,兼容旧接口) * * @param userId 用户ID * @param orderId 订单ID * @param invoiceData 发票数据 * @return 开票结果 */ public static AjaxResult createInvoice(Long userId, String orderId, Map invoiceData) { List orderIds = new ArrayList<>(); orderIds.add(orderId); return createBatchInvoice(userId, orderIds, invoiceData); } /** * 获取订单信息 * * @param orderId 订单ID * @param userId 用户ID * @return 订单信息 */ private static Map getOrderInfo(String orderId, Long userId) { try { // 1. 查询服务订单 Order serviceOrder = orderService.selectOrderByOrderId(orderId); if (serviceOrder != null && serviceOrder.getUid().equals(userId)) { Map orderInfo = new HashMap<>(); orderInfo.put("orderId", serviceOrder.getOrderId()); orderInfo.put("amount", serviceOrder.getTotalPrice()); orderInfo.put("title", serviceOrder.getOrderId()+ "服务订单"); orderInfo.put("type", "service"); return orderInfo; } // 2. 查询商品订单 GoodsOrder goodsOrder = goodsOrderService.selectGoodsOrderByorderId(orderId); if (goodsOrder != null && goodsOrder.getUid().equals(userId)) { Map orderInfo = new HashMap<>(); orderInfo.put("orderId", goodsOrder.getOrderId()); orderInfo.put("amount", goodsOrder.getTotalPrice()); orderInfo.put("title", "商品订单"); orderInfo.put("type", "goods"); return orderInfo; } // 3. 查询充值订单 UserMemberRechargeLog rechargeOrder = userMemberRechargeLogService.selectUserMemberRechargeLogByorderid(orderId); if (rechargeOrder != null && rechargeOrder.getUid().equals(userId)) { Map orderInfo = new HashMap<>(); orderInfo.put("orderId", rechargeOrder.getOrderid()); orderInfo.put("amount", rechargeOrder.getInmoney()); orderInfo.put("title", rechargeOrder.getReamk() != null ? rechargeOrder.getReamk() : "会员充值"); orderInfo.put("type", "recharge"); return orderInfo; } return null; } catch (Exception e) { logger.error("获取订单信息失败", e); return null; } } /** * 检查订单是否已开票 * * @param orderId 订单ID * @return 是否已开票 */ private static boolean isOrderInvoiced(String orderId) { try { // 查询所有发票记录 UsersInvoiceInfo query = new UsersInvoiceInfo(); List invoiceList = usersInvoiceInfoService.selectUsersInvoiceInfoList(query); // 检查订单ID是否在任何发票记录中 for (UsersInvoiceInfo invoice : invoiceList) { if (invoice.getOrderid() != null) { // 支持单个订单ID或多个订单ID(逗号分隔) String[] orderIds = invoice.getOrderid().split(","); for (String id : orderIds) { if (id.trim().equals(orderId)) { return true; } } } } return false; } catch (Exception e) { logger.error("检查订单开票状态失败", e); return false; } } /** * 验证发票数据 * * @param invoiceData 发票数据 * @return 验证结果,为空表示验证通过 */ private static String validateInvoiceData(Map invoiceData) { // 基础字段验证 if (invoiceData.get("invoiceTitle") == null || StringUtils.isEmpty(invoiceData.get("invoiceTitle").toString())) { return "发票抬头不能为空"; } if (invoiceData.get("type") == null) { return "发票类型不能为空"; } if (invoiceData.get("category") == null) { return "发票类别不能为空"; } Integer category = (Integer) invoiceData.get("category"); String invoiceTitle = invoiceData.get("invoiceTitle").toString(); // 个人发票验证 if (category == 0) { if (invoiceTitle.length() > 50) { return "个人发票抬头长度不能超过50个字符"; } // 检查是否填写了企业字段 // if (StringUtils.isNotEmpty((String) invoiceData.get("taxNumber"))) { // return "个人发票不能填写纳税人识别号"; // } // if (StringUtils.isNotEmpty((String) invoiceData.get("address"))) { // return "个人发票不能填写单位地址"; // } // if (StringUtils.isNotEmpty((String) invoiceData.get("phone"))) { // return "个人发票不能填写联系电话"; // } // if (StringUtils.isNotEmpty((String) invoiceData.get("wechat"))) { // return "个人发票不能填写微信号"; // } if (StringUtils.isEmpty((String) invoiceData.get("email"))) { return "邮箱不能为空"; } if (StringUtils.isEmpty((String) invoiceData.get("wechat"))) { return "微信号不能为空"; } } // 企业发票验证 else if (category == 1) { if (invoiceTitle.length() > 100) { return "企业发票抬头长度不能超过100个字符"; } // 必填字段验证 if (StringUtils.isEmpty((String) invoiceData.get("taxNumber"))) { return "企业发票的纳税人识别号不能为空"; } if (StringUtils.isEmpty((String) invoiceData.get("address"))) { return "企业发票的单位地址不能为空"; } if (StringUtils.isEmpty((String) invoiceData.get("phone"))) { return "企业发票的联系电话不能为空"; } if (StringUtils.isEmpty((String) invoiceData.get("bankName"))) { return "企业发票的开户银行不能为空"; } if (StringUtils.isEmpty((String) invoiceData.get("bankAccount"))) { return "企业发票的银行账号不能为空"; } // 格式验证 String taxNumber = (String) invoiceData.get("taxNumber"); if (!taxNumber.matches("^[A-Z0-9]{15,20}$")) { return "税号格式不正确"; } String phone = (String) invoiceData.get("phone"); if (!phone.matches("^1[3-9]\\d{9}$|^0\\d{2,3}-?\\d{7,8}$|^400-?\\d{3}-?\\d{4}$")) { return "联系电话格式不正确"; } if (StringUtils.isEmpty((String) invoiceData.get("email"))) { return "邮箱不能为空"; } if (StringUtils.isEmpty((String) invoiceData.get("wechat"))) { return "微信号不能为空"; } } return null; // 验证通过 } /** * 获取发票状态文本 * * @param status 状态值 * @return 状态文本 */ private static String getInvoiceStatusText(Integer status) { if (status == null) return "未知"; switch (status) { case 1: return "待开票"; case 2: return "已开票"; case 3: return "已完成"; default: return "未知"; } } /** * 获取发票类型文本 * * @param type 类型值 * @return 类型文本 */ private static String getInvoiceTypeText(Integer type) { if (type == null) return "未知"; switch (type) { case 1: return "增值税专用发票"; case 2: return "增值税普通发票"; case 3: return "电子发票"; default: return "未知"; } } /** * 获取用户发票信息列表(用于选择已保存的发票信息) * * @param userId 用户ID * @return 发票信息列表 */ public static List> getUserInvoiceInfoList(Long userId) { try { UsersInvoiceInfo query = new UsersInvoiceInfo(); query.setUid(userId.intValue()); List invoiceList = usersInvoiceInfoService.selectUsersInvoiceInfoList(query); // 去重,只保留不同的发票抬头 Map uniqueInvoices = new HashMap<>(); for (UsersInvoiceInfo invoice : invoiceList) { String key = invoice.getCategory() + "_" + invoice.getInvoiceTitle(); if (!uniqueInvoices.containsKey(key)) { uniqueInvoices.put(key, invoice); } } List> result = new ArrayList<>(); for (UsersInvoiceInfo invoice : uniqueInvoices.values()) { Map invoiceMap = new HashMap<>(); invoiceMap.put("id", invoice.getId()); invoiceMap.put("invoiceTitle", invoice.getInvoiceTitle()); invoiceMap.put("category", invoice.getCategory()); invoiceMap.put("categoryText", invoice.getCategory() == 0 ? "个人" : "企业"); invoiceMap.put("taxNumber", invoice.getTaxNumber()); invoiceMap.put("address", invoice.getAddress()); invoiceMap.put("phone", invoice.getPhone()); invoiceMap.put("bankName", invoice.getBankName()); invoiceMap.put("bankAccount", invoice.getBankAccount()); invoiceMap.put("email", invoice.getEmail()); invoiceMap.put("wechat", invoice.getWechat()); result.add(invoiceMap); } return result; } catch (Exception e) { logger.error("获取用户发票信息列表失败", e); return new ArrayList<>(); } } }