diff --git a/cf-framework/cf-common/src/main/java/com/cf/imes/framework/common/util/Assert/AssertUtils.java b/cf-framework/cf-common/src/main/java/com/cf/imes/framework/common/util/Assert/AssertUtils.java index c90069d9c..25e0d3b30 100644 --- a/cf-framework/cf-common/src/main/java/com/cf/imes/framework/common/util/Assert/AssertUtils.java +++ b/cf-framework/cf-common/src/main/java/com/cf/imes/framework/common/util/Assert/AssertUtils.java @@ -90,4 +90,16 @@ public class AssertUtils { throw exception(errorCode); } } + + public static void isFalse(boolean expression, ErrorCode errorCode) { + if (!expression) { + throw exception(errorCode); + } + } + + public static void isTrue(boolean expression, ErrorCode errorCode) { + if (expression) { + throw exception(errorCode); + } + } } diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index a1aeac755..ea45b7021 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -446,6 +446,8 @@ public class ErrorCodeConstants { public static final ErrorCode PRODUCTS_NOT_NOLIST = new ErrorCode(1_002_043_033, "当前产品未上架"); public static final ErrorCode ORG_PRODUCT_PURCHASE_LOCK_ERROR = new ErrorCode(1_002_043_034, "组织下存在购买中的产品操作,请稍后再试"); public static final ErrorCode INVOICE_TITLE_ENTERPRISE_TAXNUMBER_EMPTY_ERROR = new ErrorCode(1_002_043_035, "企业统一信用代码不能为空"); + public static final ErrorCode INVOICE_AMOUNT_ZERO_ERROR = new ErrorCode(1_002_043_036, "可开票金额为,请检查购买记录"); + public static final ErrorCode INVOICE_APPLY_UNINVOICEABLE_EXIST = new ErrorCode(1_002_043_036, "当前提交记录中存在不可开票记录,请刷新列表后重新选择提交"); //=========== 支付相关 1-002-048-000 ============ public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道"); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/organ/OrganApiImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/organ/OrganApiImpl.java index 8ef5b9981..8832008a0 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/organ/OrganApiImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/api/organ/OrganApiImpl.java @@ -63,12 +63,15 @@ public class OrganApiImpl implements OrganApi { // 当前产品购买记录有效期是否超过当前时间 boolean productMatch = false; if (ObjectUtil.isNotNull(previouPurchaseRecord)) { - productMatch = previouPurchaseRecord.getEndTime().isAfter(LocalDate.now()); + LocalDate endTime = previouPurchaseRecord.getEndTime(); + productMatch = endTime.isAfter(LocalDate.now()) || endTime.isEqual(LocalDate.now()); } // 延期记录中是否有超过当前时间的记录 boolean delayMatch = false; if (CollUtil.isNotEmpty(delayRespVOList)) { - delayMatch = delayRespVOList.stream().anyMatch(item -> item.getDelayTime().isAfter(LocalDate.now())); + delayMatch = delayRespVOList.stream() + .anyMatch(item -> item.getDelayTime().isAfter(LocalDate.now()) + || item.getDelayTime().isEqual(LocalDate.now())); } // 产品过期且没有有效的延期记录时,提示产品已过期 if (!productMatch && !delayMatch) { diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsReqVO.java index 00603013a..69e648a79 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsReqVO.java @@ -13,7 +13,7 @@ import java.util.List; public class InvoiceRecordsReqVO { @Schema(description = "购买记录ID") - @Size(max = 300, message = "单次开票选择记录不能超过100条") + @Size(max = 100, message = "单次开票选择记录不能超过100条") @NotEmpty private List purchaseRecordId; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsRespVO.java index 4f9320685..5d1ff9145 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsRespVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/invoice/vo/InvoiceRecordsRespVO.java @@ -47,6 +47,8 @@ public class InvoiceRecordsRespVO { @Schema(description = "发票附件保存路径") private String invoiceAttachmentPath; + @Schema(description = "发票附件名称") + private String invoiceAttachmentName; @Schema(description = "开票人") private String invoicePerson; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/invoice/InvoiceRecordsMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/invoice/InvoiceRecordsMapper.java index 0a15bf0da..0bdbd9134 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/invoice/InvoiceRecordsMapper.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/invoice/InvoiceRecordsMapper.java @@ -16,15 +16,15 @@ public interface InvoiceRecordsMapper extends BaseMapperX { default PageResult selectInvoiceRecordsPage(InvoiceDetailsPageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eq(InvoiceRecordsDO::getDeleted,false) - .eqIfPresent(InvoiceRecordsDO::getOrganId,pageReqVO.getOrganId()) - .likeIfPresent(InvoiceRecordsDO::getInvoiceNo,pageReqVO.getInvoiceNo()) - .eqIfPresent(InvoiceRecordsDO::getStatus,pageReqVO.getStatus()) - .likeIfPresent(InvoiceRecordsDO::getCreator,pageReqVO.getCreator()) - .likeIfPresent(InvoiceRecordsDO::getInvoicePerson,pageReqVO.getInvoicePerson()) - .betweenIfPresent(InvoiceRecordsDO::getInvoiceAmount,pageReqVO.getInvoiceAmount()) - .betweenIfPresent(InvoiceRecordsDO::getCreateTime,pageReqVO.getCreateTime()) - .betweenIfPresent(InvoiceRecordsDO::getInvoiceTime,pageReqVO.getInvoiceTime()) + .eq(InvoiceRecordsDO::getDeleted, false) + .eqIfPresent(InvoiceRecordsDO::getOrganId, pageReqVO.getOrganId()) + .likeIfPresent(InvoiceRecordsDO::getInvoiceNo, pageReqVO.getInvoiceNo()) + .eqIfPresent(InvoiceRecordsDO::getStatus, pageReqVO.getStatus()) + .likeIfPresent(InvoiceRecordsDO::getCreator, pageReqVO.getCreator()) + .likeIfPresent(InvoiceRecordsDO::getInvoicePerson, pageReqVO.getInvoicePerson()) + .betweenIfPresent(InvoiceRecordsDO::getInvoiceAmount, pageReqVO.getInvoiceAmount()) + .betweenIfPresent(InvoiceRecordsDO::getCreateTime, pageReqVO.getCreateTime()) + .betweenIfPresent(InvoiceRecordsDO::getInvoiceTime, pageReqVO.getInvoiceTime()) .orderByDesc(InvoiceRecordsDO::getId)); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/invoice/InvoiceServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/invoice/InvoiceServiceImpl.java index a6a64b4ab..82837a205 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/invoice/InvoiceServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/invoice/InvoiceServiceImpl.java @@ -1,11 +1,14 @@ package com.cf.imes.module.system.service.funds.invoice; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.util.Assert.AssertUtils; @@ -47,15 +50,20 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Optional; +import static cn.hutool.core.date.DatePattern.NORM_DATE_FORMATTER; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.framework.common.util.json.JsonUtils.parseObject; import static com.cf.imes.framework.common.util.json.JsonUtils.toJsonString; import static com.cf.imes.framework.common.util.json.JsonUtils.unzipString; import static com.cf.imes.framework.common.util.json.JsonUtils.zipString; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.INVOICE_AMOUNT_ZERO_ERROR; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.INVOICE_APPLY_UNINVOICEABLE_EXIST; import static com.cf.imes.module.system.enums.ErrorCodeConstants.INVOICE_NO_EXIST; import static com.cf.imes.module.system.enums.ErrorCodeConstants.INVOICE_TITLE_ENTERPRISE_TAXNUMBER_EMPTY_ERROR; import static com.cf.imes.module.system.enums.ErrorCodeConstants.INVOICE_TITLE_NOT_EXISTS_ERROR; @@ -165,12 +173,13 @@ public class InvoiceServiceImpl implements InvoiceService { * @param id * @param organId */ - private void validTitleOrg(Long id, Long organId) { + private InvoiceTitleInfoDO validTitleOrg(Long id, Long organId) { InvoiceTitleInfoDO titleInfoDO = invoiceTitleInfoMapper.selectById(id); // 抬头不存在 AssertUtils.notEmpty(titleInfoDO, INVOICE_TITLE_NOT_EXISTS_ERROR); // 抬头组织不匹配 AssertUtils.notEquals(titleInfoDO.getOrganId(), organId, INVOICE_TITLE_NOT_EXISTS_ERROR); + return titleInfoDO; } @Override @@ -217,8 +226,15 @@ public class InvoiceServiceImpl implements InvoiceService { AssertUtils.notEmpty(invoiceTitleInfoDO, INVOICE_TITLE_NOT_EXISTS_ERROR); + // 检查关联记录的购买记录,不能有已开票的 + List purchaseRecordDOS = purchaseRecordMapper.selectByIds(purchaseRecordId); + boolean uninvoicableExist = purchaseRecordDOS.stream().filter(p -> !InvoiceStatusEnum.INVOICABLE.getCode().equals(p.getIsInvocing())).findAny().isPresent(); + AssertUtils.isTrue(uninvoicableExist, INVOICE_APPLY_UNINVOICEABLE_EXIST); + // 查询可开票金额 BigDecimal invoicableAmount = purchaseRecordMapper.getInvoicableAmount(organId, purchaseRecordId); + // 可开票金额不能为0 + AssertUtils.isTrue(ObjectUtils.isNull(invoicableAmount) || invoicableAmount.compareTo(BigDecimal.ZERO) == 0, INVOICE_AMOUNT_ZERO_ERROR); // 更新购买记录表的发票状态 int update = purchaseRecordMapper.update(new LambdaUpdateWrapper() @@ -256,7 +272,7 @@ public class InvoiceServiceImpl implements InvoiceService { PageResult pageResult = invoiceRecordsMapper.selectInvoiceRecordsPage(pageReqVO); List resultList = pageResult.getList(); - if(CollUtil.isEmpty(resultList)){ + if (CollUtil.isEmpty(resultList)) { return new PageResult<>(); } List recordsRespVOS = BeanUtils.toBean(resultList, InvoiceRecordsRespVO.class); @@ -266,7 +282,7 @@ public class InvoiceServiceImpl implements InvoiceService { @Override public InvoiceDetailsRespVO getInvoiceRecordDetail(Long recordId) { InvoiceRecordsDO invoiceRecordsDO = invoiceRecordsMapper.selectById(recordId); - AssertUtils.notEmpty(invoiceRecordsDO,INVOICE_NO_EXIST); + AssertUtils.notEmpty(invoiceRecordsDO, INVOICE_NO_EXIST); // 记录中的购买记录id数组转list String purchaseIds = Optional.ofNullable(invoiceRecordsDO.getPurchaseIds()).orElse("[]"); @@ -321,6 +337,9 @@ public class InvoiceServiceImpl implements InvoiceService { List purchaseIdList = JSON.parseArray(purchaseIds).toJavaList(Long.class).stream().distinct().toList(); List purchaseRecordDOS = validatePurchaseRecordExists(purchaseIdList); + // 获取对应组织的抬头信息 + InvoiceTitleInfoDO invoiceTitleInfoDO = validTitleOrg(invoiceRecordsDO.getInvoiceTitleId(), invoiceRecordsDO.getOrganId()); + if (reqVO.isAgree()) { // 同意开票 // 更新发票申请记录状态 @@ -333,11 +352,13 @@ public class InvoiceServiceImpl implements InvoiceService { if (ObjectUtil.isNull(file) || file.isEmpty()) { throw new ServiceException(ORG_INVOICE_AGREE_FILE_NULL_ERROR); } - String originalFilename = file.getOriginalFilename(); - String filePath = fileApi.createFile(IoUtil.readBytes(file.getInputStream()), originalFilename); + LocalDateTime now = LocalDateTime.now(); + String invoiceFileName = invoiceTitleInfoDO.getInvoiceTitle() + "-" + LocalDateTimeUtil.format(now, NORM_DATE_FORMATTER) + invoiceRecordsDO.getInvoiceAmount() + getFileExtension(file.getOriginalFilename()); + String filePath = fileApi.createFile(IoUtil.readBytes(file.getInputStream()), invoiceFileName); invoiceRecordsDO.setInvoiceAttachmentPath(filePath); - invoiceRecordsDO.setInvoiceAttachmentName(originalFilename); + invoiceRecordsDO.setInvoiceAttachmentName(invoiceFileName); invoiceRecordsDO.setInvoiceNo(reqVO.getInvoiceNo()); + invoiceRecordsDO.setInvoiceTime(now); } else { // 拒绝开票 // 更新发票申请记录状态 @@ -359,6 +380,27 @@ public class InvoiceServiceImpl implements InvoiceService { purchaseRecordMapper.updateBatch(purchaseRecordDOS); } + /** + * 截取文件类型 + * + * @param fileName + * @return + */ + public static String getFileExtension(String fileName) { + if (StrUtil.isEmpty(fileName)) { + return ""; // 或者返回 null,看你需求 + } + + int lastDotIndex = fileName.lastIndexOf('.'); + if (lastDotIndex < 0 || lastDotIndex == fileName.length() - 1) { + // 没有点号,或者点号在最后一位(例如 "file.") + return ""; + } + + // 截取后缀部分并转小写 + return "." + fileName.substring(lastDotIndex + 1).toLowerCase(Locale.ROOT); + } + /** * 校验发票申请记录 * diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayProductProcessor.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayProductProcessor.java index 7200f4904..b339f4739 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayProductProcessor.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayProductProcessor.java @@ -268,7 +268,7 @@ public class PayProductProcessor { .originalAmount(originalPrice) .monthAverageAmount(monthAverageAmount) .accountBalanceSpent(price) - .isInvocing(InvoiceStatusEnum.INVOICABLE.getCode()) + .isInvocing(null) .initial(initialized) .status(PurchaseRecordStatusEnum.ACTIVE.getStatus()) .build(); @@ -412,6 +412,8 @@ public class PayProductProcessor { purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId()); } + // 是否只用了赠送金 + boolean justPayGift = true; // 先用赠送金 if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) { usedGift = remaining.min(gift); @@ -424,6 +426,7 @@ public class PayProductProcessor { usedBalance = remaining.min(balance); remaining = remaining.subtract(usedBalance); purchaseRecordDO.setAccountBalanceSpent(usedBalance); + justPayGift = false; } // 剩下走第三方 @@ -449,6 +452,11 @@ public class PayProductProcessor { .giftAmount(newGift) .build(); + // 如果只用赠送金那么不可开票 + if (justPayGift) { + purchaseRecordDO.setIsInvocing(null); + } + // 更新余额 organAmountDO.setAmount(newAmounta); organAmountDO.setGiftAmount(newGift); @@ -570,7 +578,9 @@ public class PayProductProcessor { purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId()); } - // 先用余额 + // 是否只用赠送金 + boolean justPayGift = true; + // 先用赠送金 if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) { usedGift = remaining.min(gift); remaining = remaining.subtract(usedGift); @@ -605,6 +615,12 @@ public class PayProductProcessor { purchaseRecordDO.setWechatSpent(remaining); } purchaseRecordDO.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus()); + justPayGift = false; + } + + // 如果只用赠送金那么不可开票 + if (justPayGift) { + purchaseRecordDO.setIsInvocing(null); } // 更新余额 @@ -651,6 +667,8 @@ public class PayProductProcessor { purchaseRecordDO.setPreviousId(previousPurchaseRecord.getId()); } + // 是否只用了赠送金 + boolean justPayGift = true; // 先用赠送金 if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) { usedGift = remaining.min(gift); @@ -663,6 +681,7 @@ public class PayProductProcessor { usedBalance = remaining.min(balance); remaining = remaining.subtract(usedBalance); purchaseRecordDO.setAccountBalanceSpent(usedBalance); + justPayGift = false; } // 新增收支明细 @@ -694,6 +713,12 @@ public class PayProductProcessor { purchaseRecordDO.setWechatSpent(remaining); } purchaseRecordDO.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus()); + justPayGift = false; + } + + // 如果只用赠送金那么不可开票 + if (justPayGift) { + purchaseRecordDO.setIsInvocing(null); } // 更新余额