From 809b4eb63ad47d58dc65e991f6d9d0994989bad3 Mon Sep 17 00:00:00 2001
From: b2894lxlx <517289602@qq.com>
Date: Thu, 3 Sep 2026 22:40:19 +0800
Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=9F=BA=E7=A1=80=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E3=80=81=E8=BD=A6=E8=88=B9=E5=8A=A1=E3=80=81=E9=A1=B9?=
=?UTF-8?q?=E7=9B=AE=E3=80=81=E5=90=88=E5=90=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../system/pojo/entity/FeeItem.java | 6 +
.../transport/pojo/entity/ContractManage.java | 8 +-
.../system/excel/FeeItemExcel.java | 4 +
.../system/excel/FeeItemExportExcel.java | 4 +
.../excel/FeeItemImportFailureExcel.java | 4 +
.../system/mapper/FeeItemMapper.xml | 1 +
.../service/impl/FeeItemServiceImpl.java | 17 +-
.../controller/ContractManageController.java | 2 +-
.../impl/ContractManageServiceImpl.java | 203 +++++++++++++++++-
.../service/impl/ProjectApplyServiceImpl.java | 3 +
.../ReceivablePayableDetailServiceImpl.java | 34 +--
doc/sql/bladex/bladex.dameng.all.create.sql | 1 +
doc/sql/bladex/bladex.kingbase.all.create.sql | 1 +
doc/sql/bladex/bladex.mysql.all.create.sql | 1 +
doc/sql/bladex/bladex.oracle.all.create.sql | 1 +
doc/sql/bladex/bladex.postgres.all.create.sql | 1 +
.../bladex/bladex.sqlserver.all.create.sql | 1 +
doc/sql/bladex/bladex.yashan.all.create.sql | 1 +
..._manage_billing_plan_tax_rate_20260903.sql | 5 +
...act_manage_change_attachments_20260903.sql | 3 +
doc/sql/transport/blade_fee_item.sql | 1 +
.../blade_fee_item_tax_rate_20260903.sql | 5 +
.../blade_project_contract_management.sql | 3 +-
23 files changed, 279 insertions(+), 31 deletions(-)
create mode 100644 doc/sql/transport/blade_contract_manage_billing_plan_tax_rate_20260903.sql
create mode 100644 doc/sql/transport/blade_contract_manage_change_attachments_20260903.sql
create mode 100644 doc/sql/transport/blade_fee_item_tax_rate_20260903.sql
diff --git a/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/entity/FeeItem.java b/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/entity/FeeItem.java
index 8b8e68c..cd371d5 100644
--- a/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/entity/FeeItem.java
+++ b/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/entity/FeeItem.java
@@ -34,6 +34,7 @@ import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
+import java.math.BigDecimal;
/**
* 费用项实体类
@@ -64,6 +65,11 @@ public class FeeItem extends BaseEntity {
*/
@Schema(description = "费用项代码")
private String englishName;
+ /**
+ * 税率(百分比)
+ */
+ @Schema(description = "税率(百分比)")
+ private BigDecimal taxRate;
/**
* 备注
*/
diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ContractManage.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ContractManage.java
index 6b5755e..f703836 100644
--- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ContractManage.java
+++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ContractManage.java
@@ -150,7 +150,7 @@ public class ContractManage extends TenantEntity {
@Schema(description = "其它附件JSON")
private String attachmentsJson;
- @Schema(description = "计费方案JSON")
+ @Schema(description = "计费方案JSON(含规则税率)")
private String billingPlanJson;
@Schema(description = "结算生成规则JSON")
@@ -172,11 +172,17 @@ public class ContractManage extends TenantEntity {
private String changeRecordJson;
@Schema(description = "变更内容")
+ @TableField(updateStrategy = FieldStrategy.ALWAYS)
private String changeContent;
@Schema(description = "变更原因")
+ @TableField(updateStrategy = FieldStrategy.ALWAYS)
private String changeReason;
+ @Schema(description = "待审批变更附件JSON")
+ @TableField(updateStrategy = FieldStrategy.ALWAYS)
+ private String changeAttachmentsJson;
+
@Schema(description = "终止原因")
private String terminateReason;
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExcel.java
index a1a8cfc..3048164 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExcel.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExcel.java
@@ -34,6 +34,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
+import java.math.BigDecimal;
/**
* 费用项 Excel
@@ -60,6 +61,9 @@ public class FeeItemExcel implements Serializable {
@ExcelProperty("*费用项")
private String name;
+ @ExcelProperty("*税率")
+ private BigDecimal taxRate;
+
@ExcelIgnore
private String errorMessage;
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExportExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExportExcel.java
index a87a46b..aedffeb 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExportExcel.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemExportExcel.java
@@ -15,6 +15,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
+import java.math.BigDecimal;
import java.util.Date;
/**
@@ -40,6 +41,9 @@ public class FeeItemExportExcel implements Serializable {
@ExcelProperty("费用项")
private String name;
+ @ExcelProperty("税率")
+ private BigDecimal taxRate;
+
@ExcelProperty("备注")
private String remark;
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemImportFailureExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemImportFailureExcel.java
index d485b64..445bbd7 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemImportFailureExcel.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/FeeItemImportFailureExcel.java
@@ -33,6 +33,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
+import java.math.BigDecimal;
/**
* 费用项导入失败 Excel
@@ -56,6 +57,9 @@ public class FeeItemImportFailureExcel implements Serializable {
@ExcelProperty("*费用项")
private String name;
+ @ExcelProperty("*税率")
+ private BigDecimal taxRate;
+
@ExcelProperty("导入失败原因")
private String failureReason;
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/mapper/FeeItemMapper.xml b/blade-service/blade-system/src/main/java/org/springblade/system/mapper/FeeItemMapper.xml
index 698956a..b9bf3d9 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/mapper/FeeItemMapper.xml
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/mapper/FeeItemMapper.xml
@@ -16,6 +16,7 @@
+
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/FeeItemServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/FeeItemServiceImpl.java
index 86125e3..a3825a4 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/FeeItemServiceImpl.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/FeeItemServiceImpl.java
@@ -47,6 +47,7 @@ import org.springblade.system.service.IFeeItemService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -66,6 +67,8 @@ public class FeeItemServiceImpl extends BaseServiceImpl
private static final int NAME_MAX_LENGTH = 50;
private static final int ENGLISH_NAME_MAX_LENGTH = 100;
private static final int REMARK_MAX_LENGTH = 200;
+ private static final BigDecimal TAX_RATE_MIN = BigDecimal.ZERO;
+ private static final BigDecimal TAX_RATE_MAX = new BigDecimal("100");
@Override
public IPage selectFeeItemPage(IPage page, FeeItemVO feeItem) {
@@ -115,7 +118,7 @@ public class FeeItemServiceImpl extends BaseServiceImpl
save(feeItem);
} catch (Exception exception) {
String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败";
- failureList.add(toImportFailureExcel(excel, message));
+ failureList.add(toImportFailureExcel(excel, "第" + (index + 2) + "行:" + message));
}
}
return failureList;
@@ -156,6 +159,16 @@ public class FeeItemServiceImpl extends BaseServiceImpl
if (Func.isNotEmpty(feeItem.getEnglishName()) && feeItem.getEnglishName().length() > ENGLISH_NAME_MAX_LENGTH) {
throw new ServiceException("费用项代码不能超过100字");
}
+ BigDecimal taxRate = feeItem.getTaxRate();
+ if (taxRate == null) {
+ throw new ServiceException("税率不能为空");
+ }
+ if (taxRate.compareTo(TAX_RATE_MIN) < 0 || taxRate.compareTo(TAX_RATE_MAX) > 0) {
+ throw new ServiceException("税率必须在0到100之间");
+ }
+ if (taxRate.stripTrailingZeros().scale() > 2) {
+ throw new ServiceException("税率最多保留2位小数");
+ }
if (Func.isNotEmpty(feeItem.getRemark()) && feeItem.getRemark().length() > REMARK_MAX_LENGTH) {
throw new ServiceException("备注不能超过200个字");
}
@@ -192,6 +205,7 @@ public class FeeItemServiceImpl extends BaseServiceImpl
feeItem.setFeeCategory(resolveFeeCategory(excel.getFeeCategory()));
feeItem.setEnglishName(trimToNull(excel.getEnglishName()));
feeItem.setName(trimToEmpty(excel.getName()));
+ feeItem.setTaxRate(excel.getTaxRate());
feeItem.setStatus(STATUS_ENABLED);
return feeItem;
}
@@ -212,6 +226,7 @@ public class FeeItemServiceImpl extends BaseServiceImpl
failureExcel.setFeeCategory(excel.getFeeCategory());
failureExcel.setEnglishName(excel.getEnglishName());
failureExcel.setName(excel.getName());
+ failureExcel.setTaxRate(excel.getTaxRate());
failureExcel.setFailureReason(failureReason);
return failureExcel;
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/ContractManageController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/ContractManageController.java
index 412d674..92a11df 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/ContractManageController.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/ContractManageController.java
@@ -131,7 +131,7 @@ public class ContractManageController extends BladeController {
@ApiOperationSupport(order = 10)
@Operation(summary = "发起变更", description = "传入id、changeContent和changeReason")
public R startChange(@Parameter(description = "主键", required = true) @RequestParam Long id,
- @RequestParam String changeContent,
+ @RequestParam(required = false) String changeContent,
@RequestParam String changeReason) {
return R.status(contractManageService.startChange(id, changeContent, changeReason));
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java
index f572c84..1c37acb 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java
@@ -42,16 +42,18 @@ import org.springblade.transport.wrapper.ContractManageWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
-import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* 合同管理 服务实现类
@@ -72,6 +74,9 @@ public class ContractManageServiceImpl extends BaseServiceImpl selectContractManagePage(IPage page, ContractManageVO contractManage) {
@@ -93,7 +98,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl beforeData = buildContractChangeSnapshot(source);
source.setContractName(request.getContractName()); source.setPartyB(request.getPartyB());
source.setStartDate(request.getStartDate()); source.setEndDate(request.getEndDate()); source.setContractFormat(request.getContractFormat());
source.setSettlementMode(request.getSettlementMode()); source.setLegalSealFlag(request.getLegalSealFlag()); source.setCopyCount(request.getCopyCount());
@@ -237,8 +271,16 @@ public class ContractManageServiceImpl extends BaseServiceImpl afterData = buildContractChangeSnapshot(source);
+ retainChangedSnapshotFields(beforeData, afterData);
+ source.setApprovalStatus(STATUS_CHANGE_REVIEWING);
+ source.setChangeContent(TransportBusinessSupport.trimToNull(request.getChangeContent()));
+ source.setChangeReason(changeReason);
+ source.setCurrentNode("合同变更审批");
+ source.setCurrentProcessor("待处理");
+ appendChangeRecord(source, "合同信息变更", changeReason, STATUS_CHANGE_REVIEWING, "审核中", beforeData, afterData);
+ return updateById(source);
}
@Override
@@ -299,6 +341,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl plan) {
+ if (!(plan.get("rules") instanceof List> rules)) return;
+ for (int index = 0; index < rules.size(); index++) {
+ Object ruleValue = rules.get(index);
+ if (!(ruleValue instanceof Map, ?> rule)) continue;
+ Object value = rule.get("taxRate");
+ if (value == null || String.valueOf(value).isBlank()) {
+ throw new ServiceException("计费方案第" + (index + 1) + "行税率不能为空");
+ }
+ String taxRateText = String.valueOf(value).trim();
+ if (!taxRateText.matches("\\d+(\\.\\d{1,2})?")) {
+ throw new ServiceException("计费方案第" + (index + 1) + "行税率格式不正确");
+ }
+ BigDecimal taxRate;
+ try {
+ taxRate = new BigDecimal(taxRateText);
+ } catch (NumberFormatException exception) {
+ throw new ServiceException("计费方案第" + (index + 1) + "行税率格式不正确");
+ }
+ if (taxRate.compareTo(TAX_RATE_MIN) < 0 || taxRate.compareTo(TAX_RATE_MAX) > 0) {
+ throw new ServiceException("计费方案第" + (index + 1) + "行税率必须在0到100之间");
+ }
+ if (taxRate.stripTrailingZeros().scale() > 2) {
+ throw new ServiceException("计费方案第" + (index + 1) + "行税率最多保留2位小数");
+ }
+ }
+ }
+
private boolean hasConfiguredValue(Object value) {
if (value instanceof Collection> values) {
return values.stream().anyMatch(this::hasConfiguredValue);
@@ -597,6 +669,29 @@ public class ContractManageServiceImpl extends BaseServiceImpl beforeData, Map afterData) {
List