调整 合同

This commit is contained in:
2026-09-14 15:00:40 +08:00
parent 940f0b9b9f
commit 70e44da789
10 changed files with 254 additions and 20 deletions
@@ -23,6 +23,7 @@
package org.springblade.transport.excel;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.format.NumberFormat;
import cn.idev.excel.annotation.write.style.ColumnWidth;
import cn.idev.excel.annotation.write.style.ContentRowHeight;
import cn.idev.excel.annotation.write.style.HeadRowHeight;
@@ -30,6 +31,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -77,6 +79,8 @@ public class ContractManageExcel implements Serializable {
private String contractStage;
@ExcelProperty("审核状态")
private String approvalStatus;
@ExcelProperty("归档状态")
private String archiveStatus;
@ExcelProperty("结算币种")
private String settlementCurrency;
@ExcelProperty("结算方式")
@@ -87,6 +91,15 @@ public class ContractManageExcel implements Serializable {
private Integer copyCount;
@ExcelProperty("回款账期(天)")
private Integer paymentDays;
@ExcelProperty("合同金额")
@NumberFormat("0.00")
private BigDecimal contractAmount;
@ExcelProperty("是否范本")
private Integer templateFlag;
@ExcelProperty("原件合同编号")
private String originalContractNo;
@ExcelProperty("是否电子章")
private Integer electronicSealFlag;
@ExcelProperty("当前节点")
private String currentNode;
@ExcelProperty("当前处理人")
@@ -71,9 +71,13 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private static final String STATUS_REVIEWING = "reviewing";
private static final String STATUS_REJECTED = "rejected";
private static final String STATUS_APPROVED = "approved";
private static final String STATUS_WITHDRAWN = "withdrawn";
private static final String STATUS_CHANGE_REVIEWING = "change_reviewing";
private static final String STATUS_CHANGE_APPROVED = "change_approved";
private static final String STATUS_CHANGE_REJECTED = "change_rejected";
private static final String ARCHIVE_STATUS_PENDING = "未归档";
private static final String ARCHIVE_STATUS_ARCHIVED = "已归档";
private static final String FILE_TYPE_SEAL_ARCHIVE = "双章归档文件";
private static final long TEMPORARY_VALIDITY_DAYS = 30L;
private static final BigDecimal TAX_RATE_MIN = BigDecimal.ZERO;
private static final BigDecimal TAX_RATE_MAX = BigDecimal.valueOf(100);
@@ -138,9 +142,10 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Transactional(rollbackFor = Exception.class)
public boolean toTemporary(Long id) {
ContractManage contractManage = loadEditable(id);
if (!Objects.equals(contractManage.getContractStage(), STAGE_DRAFT) || !Objects.equals(contractManage.getApprovalStatus(), STATUS_DRAFT)) {
throw new ServiceException("仅草稿合同允许临时合同");
if (!canResubmitTemporary(contractManage)) {
throw new ServiceException("仅草稿或已撤回/已驳回的临时合同允许提交临时合同审批");
}
validateTemporary(contractManage);
// 临时放开新增合同从草稿转临时合同时的组合重复校验。
// validateContractPartyCombinationUnique(contractManage);
contractManage.setContractStage(STAGE_TEMPORARY);
@@ -155,8 +160,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Transactional(rollbackFor = Exception.class)
public boolean submitFormal(Long id) {
ContractManage contractManage = loadExists(id);
if (!Objects.equals(contractManage.getContractStage(), STAGE_TEMPORARY) || !List.of(STATUS_REJECTED, STATUS_APPROVED, STATUS_DRAFT).contains(contractManage.getApprovalStatus())) {
throw new ServiceException("仅临时合同允许转正式合同");
if (!canResubmitFormal(contractManage)) {
throw new ServiceException("仅临时合同或已撤回/已驳回的正式合同允许提交正式合同审批");
}
validateFormal(contractManage);
// 临时放开新增合同从临时转正式合同时的组合重复校验。
@@ -186,6 +191,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setChangeContent(null);
contractManage.setChangeReason(null);
}
contractManage.setContractFileJson(markContractFilesApproved(contractManage.getContractFileJson()));
refreshArchiveStatusOnApprove(contractManage);
updateLatestReviewingChangeRecord(contractManage, contractManage.getApprovalStatus(), "审核通过");
return updateById(contractManage);
}
@@ -212,7 +219,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
public boolean withdraw(Long id) {
ContractManage contractManage = loadReviewing(id);
boolean changeReviewing = Objects.equals(contractManage.getApprovalStatus(), STATUS_CHANGE_REVIEWING);
contractManage.setApprovalStatus(changeReviewing ? STATUS_APPROVED : STATUS_DRAFT);
// 变更审批撤回回已通过;普通审批撤回为已撤回,便于再次编辑并重新提交。
contractManage.setApprovalStatus(changeReviewing ? STATUS_APPROVED : STATUS_WITHDRAWN);
contractManage.setCurrentNode("已撤回");
contractManage.setCurrentProcessor(AuthUtil.getUserName());
if (changeReviewing) {
@@ -268,7 +276,11 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
source.setSettlementMode(request.getSettlementMode()); source.setLegalSealFlag(request.getLegalSealFlag()); source.setCopyCount(request.getCopyCount());
source.setSettlementCurrency(TransportBusinessSupport.trimToNull(request.getSettlementCurrency())); source.setInvoiceCycle(request.getInvoiceCycle());
source.setPaymentDays(request.getPaymentDays()); source.setRemark(request.getRemark()); source.setBillingEnabled(request.getBillingEnabled()); source.setFeeGenerationMode(request.getFeeGenerationMode());
source.setContractAmount(request.getContractAmount()); source.setTemplateFlag(request.getTemplateFlag());
source.setOriginalContractNo(TransportBusinessSupport.trimToNull(request.getOriginalContractNo()));
source.setElectronicSealFlag(request.getElectronicSealFlag());
normalizeOptionalIntegerFields(source);
validateAdditionalFields(source);
source.setBillingPlanJson(request.getBillingPlanJson()); source.setSettlementRuleJson(request.getSettlementRuleJson()); source.setPreSettlementConfigJson(request.getPreSettlementConfigJson()); source.setFormalSettlementConfigJson(request.getFormalSettlementConfigJson()); source.setPaymentRatioJson(request.getPaymentRatioJson());
source.setContractFileJson(request.getContractFileJson()); source.setAttachmentsJson(request.getAttachmentsJson());
source.setChangeAttachmentsJson(TransportBusinessSupport.trimToNull(request.getChangeAttachmentsJson()));
@@ -291,8 +303,10 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|| !List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED).contains(source.getApprovalStatus())) {
throw new ServiceException("仅审批通过的正式合同允许上传附件");
}
source.setContractFileJson(TransportBusinessSupport.trimToNull(contractManage.getContractFileJson()));
String nextContractFileJson = mergeApprovedContractFiles(source.getContractFileJson(), contractManage.getContractFileJson());
source.setContractFileJson(nextContractFileJson);
source.setAttachmentsJson(TransportBusinessSupport.trimToNull(contractManage.getAttachmentsJson()));
refreshArchiveStatusOnApprove(source);
return updateById(source);
}
@@ -336,6 +350,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
target.setContractName(source.getContractName() + " - 副本");
target.setContractStage(STAGE_DRAFT);
target.setApprovalStatus(STATUS_DRAFT);
target.setArchiveStatus(ARCHIVE_STATUS_PENDING);
target.setCurrentNode(null);
target.setCurrentProcessor(null);
target.setApprovedTime(null);
@@ -396,6 +411,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
.eq(Func.isNotEmpty(contractManage.getContractCategory()), ContractManage::getContractCategory, contractManage.getContractCategory())
.eq(Func.isNotEmpty(contractManage.getSignType()), ContractManage::getSignType, contractManage.getSignType())
.eq(Func.isNotEmpty(contractManage.getApprovalStatus()), ContractManage::getApprovalStatus, contractManage.getApprovalStatus())
.eq(Func.isNotEmpty(contractManage.getArchiveStatus()), ContractManage::getArchiveStatus, contractManage.getArchiveStatus())
.eq(Func.isNotEmpty(contractManage.getContractStage()), ContractManage::getContractStage, contractManage.getContractStage())
.orderByDesc(ContractManage::getCreateTime);
applyEffectiveType(queryWrapper, contractManage.getEffectiveType());
@@ -463,6 +479,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setHandlerUserId(AuthUtil.getUserId());
contractManage.setHandlerUserName(AuthUtil.getUserName());
}
contractManage.setArchiveStatus(ARCHIVE_STATUS_PENDING);
} else {
ContractManage oldRecord = loadExists(contractManage.getId());
contractManage.setContractNo(oldRecord.getContractNo());
@@ -472,10 +489,99 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
}
contractManage.setHandlerUserId(oldRecord.getHandlerUserId());
contractManage.setHandlerUserName(oldRecord.getHandlerUserName());
// 归档状态仅由审核通过逻辑自动维护,保存时保留库中已有值。
contractManage.setArchiveStatus(Func.isEmpty(oldRecord.getArchiveStatus())
? ARCHIVE_STATUS_PENDING : oldRecord.getArchiveStatus());
}
if (Func.isEmpty(contractManage.getContractStage())) {
contractManage.setContractStage(STAGE_DRAFT);
}
if (Func.isEmpty(contractManage.getArchiveStatus())) {
contractManage.setArchiveStatus(ARCHIVE_STATUS_PENDING);
}
}
private void refreshArchiveStatusOnApprove(ContractManage contractManage) {
if (hasSealArchiveFile(contractManage.getContractFileJson())) {
contractManage.setArchiveStatus(ARCHIVE_STATUS_ARCHIVED);
} else if (Func.isEmpty(contractManage.getArchiveStatus())) {
contractManage.setArchiveStatus(ARCHIVE_STATUS_PENDING);
}
}
private boolean hasSealArchiveFile(String contractFileJson) {
return parseJsonArray(contractFileJson).stream().anyMatch(item -> {
if (!(item instanceof Map<?, ?> map)) {
return false;
}
Object fileType = map.get("fileType");
return fileType != null && FILE_TYPE_SEAL_ARCHIVE.equals(String.valueOf(fileType).trim());
});
}
@SuppressWarnings("unchecked")
private String markContractFilesApproved(String contractFileJson) {
List<Object> files = parseJsonArray(contractFileJson);
if (files.isEmpty()) {
return TransportBusinessSupport.trimToNull(contractFileJson);
}
List<Map<String, Object>> marked = new ArrayList<>();
for (Object item : files) {
if (item instanceof Map<?, ?> map) {
Map<String, Object> next = new LinkedHashMap<>((Map<String, Object>) map);
next.put("approved", true);
marked.add(next);
}
}
return marked.isEmpty() ? null : JsonUtil.toJson(marked);
}
@SuppressWarnings("unchecked")
private String mergeApprovedContractFiles(String originalJson, String requestJson) {
List<Object> originalFiles = parseJsonArray(originalJson);
List<Object> requestFiles = parseJsonArray(requestJson);
Map<String, Map<String, Object>> originalApproved = new LinkedHashMap<>();
for (Object item : originalFiles) {
if (!(item instanceof Map<?, ?> map)) {
continue;
}
Map<String, Object> file = new LinkedHashMap<>((Map<String, Object>) map);
if (isAttachmentApproved(file)) {
originalApproved.put(attachmentKey(file), file);
}
}
Set<String> requestKeys = new HashSet<>();
List<Map<String, Object>> merged = new ArrayList<>();
for (Object item : requestFiles) {
if (!(item instanceof Map<?, ?> map)) {
continue;
}
Map<String, Object> file = new LinkedHashMap<>((Map<String, Object>) map);
String key = attachmentKey(file);
requestKeys.add(key);
Map<String, Object> approvedOriginal = originalApproved.get(key);
if (approvedOriginal != null) {
// 已审核通过附件不允许改删,保留原记录。
merged.add(approvedOriginal);
continue;
}
file.put("approved", true);
merged.add(file);
}
for (Map.Entry<String, Map<String, Object>> entry : originalApproved.entrySet()) {
if (!requestKeys.contains(entry.getKey())) {
throw new ServiceException("已审核通过的合同文件不允许删除");
}
}
return merged.isEmpty() ? null : JsonUtil.toJson(merged);
}
private boolean isAttachmentApproved(Map<String, Object> file) {
Object approved = file.get("approved");
if (Boolean.TRUE.equals(approved) || Objects.equals(approved, 1) || Objects.equals(String.valueOf(approved), "1")) {
return true;
}
return Objects.equals(String.valueOf(file.get("approvalStatus")), STATUS_APPROVED);
}
private void prepare(ContractManage contractManage) {
@@ -490,6 +596,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setContractFormat(TransportBusinessSupport.trimToNull(contractManage.getContractFormat()));
contractManage.setRemark(TransportBusinessSupport.trimToNull(contractManage.getRemark()));
contractManage.setSettlementCurrency(TransportBusinessSupport.trimToNull(contractManage.getSettlementCurrency()));
contractManage.setOriginalContractNo(TransportBusinessSupport.trimToNull(contractManage.getOriginalContractNo()));
contractManage.setContractFileJson(TransportBusinessSupport.trimToNull(contractManage.getContractFileJson()));
contractManage.setAttachmentsJson(TransportBusinessSupport.trimToNull(contractManage.getAttachmentsJson()));
contractManage.setBillingPlanJson(TransportBusinessSupport.trimToNull(contractManage.getBillingPlanJson()));
@@ -498,6 +605,25 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setReconciliationJson(TransportBusinessSupport.trimToNull(contractManage.getReconciliationJson()));
contractManage.setChangeRecordJson(TransportBusinessSupport.trimToNull(contractManage.getChangeRecordJson()));
normalizeOptionalIntegerFields(contractManage);
validateAdditionalFields(contractManage);
}
private void validateAdditionalFields(ContractManage contractManage) {
BigDecimal contractAmount = contractManage.getContractAmount();
if (contractAmount != null && contractAmount.compareTo(BigDecimal.ZERO) < 0) {
throw new ServiceException("合同金额不能小于0");
}
if (contractAmount != null && contractAmount.scale() > 2) {
throw new ServiceException("合同金额最多保留2位小数");
}
validateFlag(contractManage.getTemplateFlag(), "是否范本");
validateFlag(contractManage.getElectronicSealFlag(), "是否电子章");
}
private void validateFlag(Integer value, String fieldName) {
if (value != null && value != 0 && value != 1) {
throw new ServiceException(fieldName + "只能选择是或否");
}
}
private void normalizeOptionalIntegerFields(ContractManage contractManage) {
@@ -515,11 +641,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private void validateDraft(ContractManage contractManage) {
TransportBusinessSupport.validateRequired(contractManage.getContractName(), "请输入合同名称");
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类别");
TransportBusinessSupport.validateRequired(contractManage.getSettlementCurrency(), "请选择结算币种");
validateContractNameUnique(contractManage);
TransportBusinessSupport.validateLength(contractManage.getRemark(), 2000, "备注不能超过2000字");
validateBillingPlans(contractManage.getBillingPlanJson());
validatePaymentRatios(contractManage.getPaymentRatioJson());
}
private void validateBillingPlans(String billingPlanJson) {
@@ -667,6 +790,12 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private void validateTemporary(ContractManage contractManage) {
TransportBusinessSupport.validateRequired(contractManage.getSignType(), "请选择签约类型");
TransportBusinessSupport.validateRequired(contractManage.getContractName(), "请输入合同名称");
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类型");
TransportBusinessSupport.validateRequired(contractManage.getProjectName(), "请选择所属项目");
TransportBusinessSupport.validateRequired(contractManage.getOrganizationName(), "请选择所属组织");
TransportBusinessSupport.validateRequired(contractManage.getPartyA(), "请选择甲方");
TransportBusinessSupport.validateRequired(contractManage.getPartyB(), "请选择乙方");
}
/**
@@ -693,6 +822,11 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
}
private void validateFormal(ContractManage contractManage) {
TransportBusinessSupport.validateRequired(contractManage.getSignType(), "请选择签约类型");
TransportBusinessSupport.validateRequired(contractManage.getContractName(), "请输入合同名称");
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类型");
TransportBusinessSupport.validateRequired(contractManage.getProjectName(), "请选择所属项目");
TransportBusinessSupport.validateRequired(contractManage.getOrganizationName(), "请选择所属组织");
TransportBusinessSupport.validateRequired(contractManage.getSettlementCurrency(), "请选择结算币种");
TransportBusinessSupport.validateRequired(contractManage.getPartyA(), "请输入甲方");
TransportBusinessSupport.validateRequired(contractManage.getPartyB(), "请输入乙方");
@@ -700,6 +834,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
TransportBusinessSupport.validateRequired(contractManage.getSignDate() == null ? null : contractManage.getSignDate().toString(), "请选择签订日期");
TransportBusinessSupport.validateDateRange(contractManage.getStartDate(), contractManage.getEndDate(), "合同期限开始日期不能晚于结束日期");
TransportBusinessSupport.validateLength(contractManage.getRemark(), 2000, "备注不能超过2000字");
validateBillingPlans(contractManage.getBillingPlanJson());
validatePaymentRatios(contractManage.getPaymentRatioJson());
}
private ContractManage loadExists(Long id) {
@@ -712,7 +848,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private ContractManage loadEditable(Long id) {
ContractManage contractManage = loadExists(id);
if (!Objects.equals(contractManage.getApprovalStatus(), STATUS_DRAFT)) {
if (!List.of(STATUS_DRAFT, STATUS_WITHDRAWN, STATUS_REJECTED).contains(contractManage.getApprovalStatus())) {
throw new ServiceException("当前状态不允许编辑");
}
if (!canOperateInCurrentScope(contractManage)) {
@@ -721,6 +857,26 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
return contractManage;
}
private boolean canResubmitTemporary(ContractManage contractManage) {
String stage = contractManage.getContractStage();
String status = contractManage.getApprovalStatus();
if (!List.of(STATUS_DRAFT, STATUS_WITHDRAWN, STATUS_REJECTED).contains(status)) {
return false;
}
return Objects.equals(stage, STAGE_DRAFT) || Objects.equals(stage, STAGE_TEMPORARY);
}
private boolean canResubmitFormal(ContractManage contractManage) {
String stage = contractManage.getContractStage();
String status = contractManage.getApprovalStatus();
if (Objects.equals(stage, STAGE_TEMPORARY)
&& List.of(STATUS_REJECTED, STATUS_APPROVED, STATUS_DRAFT, STATUS_WITHDRAWN).contains(status)) {
return true;
}
return Objects.equals(stage, STAGE_FORMAL)
&& List.of(STATUS_REJECTED, STATUS_DRAFT, STATUS_WITHDRAWN).contains(status);
}
private ContractManage loadReviewing(Long id) {
ContractManage contractManage = loadExists(id);
if (!List.of(STATUS_REVIEWING, STATUS_CHANGE_REVIEWING).contains(contractManage.getApprovalStatus())) {
@@ -774,6 +930,10 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
data.put("settlementCurrency", contractManage.getSettlementCurrency());
data.put("invoiceCycle", contractManage.getInvoiceCycle());
data.put("paymentDays", contractManage.getPaymentDays());
data.put("contractAmount", contractManage.getContractAmount());
data.put("templateFlag", contractManage.getTemplateFlag());
data.put("originalContractNo", contractManage.getOriginalContractNo());
data.put("electronicSealFlag", contractManage.getElectronicSealFlag());
data.put("remark", contractManage.getRemark());
data.put("feeGenerationMode", contractManage.getFeeGenerationMode());
data.put("billingPlanJson", contractManage.getBillingPlanJson());
@@ -361,6 +361,14 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
queryWrapper.eq(ProjectApply::getEffectiveType, EFFECTIVE_FORMAL)
.in(ProjectApply::getApprovalStatus, STATUS_APPROVED, "change_approved");
}
if (Boolean.TRUE.equals(projectApply.getContractSelectable())) {
// 正式审批通过项目 + 未作废的临时项目均可被合同选择
queryWrapper.and(wrapper -> wrapper
.nested(formal -> formal.eq(ProjectApply::getEffectiveType, EFFECTIVE_FORMAL)
.in(ProjectApply::getApprovalStatus, STATUS_APPROVED, "change_approved"))
.or(temporary -> temporary.eq(ProjectApply::getEffectiveType, EFFECTIVE_TEMPORARY)
.ne(ProjectApply::getApprovalStatus, STATUS_VOIDED)));
}
if (Func.isNotEmpty(projectApply.getFundUseRisk())) {
List<ProjectApplyVO> riskRecords = baseMapper.selectList(queryWrapper).stream()
.map(record -> ProjectApplyWrapper.build().entityVO(record))
@@ -102,7 +102,7 @@ public class ReceivablePayableDetailServiceImpl
private static final String SOURCE_MASTER_ORDER = "总单系统生成";
private static final String SOURCE_LOADING_ORDER = "配载单系统生成";
private static final String SOURCE_MANUAL_GENERATION = "手动生成";
private static final String SOURCE_MANUAL_GENERATION = "账单导入生成";
private static final String TRANSPORT_TYPE_SELF = "自运";
private static final String FEE_SOURCE_AUTO = "自动生成";
private static final String FEE_SOURCE_MANUAL = "手动录入";
@@ -900,7 +900,6 @@ public class ReceivablePayableDetailServiceImpl
if (!(conditionValue instanceof Map<?, ?> condition) || !hasConfiguredMatchCondition(condition)) return true;
return matchesLocation(condition, "origin", waybill.getDepartureAddressId(), waybill.getDepartureName(), waybill.getDepartureAddress())
&& matchesLocation(condition, "destination", waybill.getArrivalAddressId(), waybill.getArrivalName(), waybill.getArrivalAddress())
&& matchesCondition(condition.get("transportMode"), waybill.getTransportType())
&& matchesCargo(condition, waybill);
}
@@ -909,7 +908,6 @@ public class ReceivablePayableDetailServiceImpl
|| !isBlank(condition.get("originCode"))
|| !isBlank(condition.get("destination"))
|| !isBlank(condition.get("destinationCode"))
|| !isBlank(condition.get("transportMode"))
|| !isBlank(condition.get("cargoType"))
|| !isBlank(condition.get("cargoTypeCode"))
|| !isBlank(condition.get("cargoTypePath"))
@@ -1576,12 +1574,24 @@ public class ReceivablePayableDetailServiceImpl
if (ranges.isEmpty() || "固定单价".equals(type)) return base.multiply(unit).setScale(2, RoundingMode.HALF_UP);
if (intervalFlatPrice) return range(ranges, base).map(r -> decimal(r.get("unitPrice")).signum() == 0 ? unit : decimal(r.get("unitPrice"))).orElse(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
if (intervalUnitPrice) {
BigDecimal rangeBase = base;
return range(ranges, rangeBase).map(r -> {
BigDecimal minimum = decimal(r.get("minimumBillingWeight"));
if (minimum.signum() <= 0) minimum = decimal(rule.get("minimumBillingWeight"));
BigDecimal effectiveBase = applyMinimum(rangeBase, element, minimum, waybill);
return decimal(r.get("unitPrice")).multiply(effectiveBase);
List<Map<String, Object>> sortedRanges = ranges.stream()
.sorted(Comparator.comparing(item -> decimal(item.get("lowerLimit"))))
.toList();
return range(sortedRanges, base).map(matchedRange -> {
boolean firstTier = !sortedRanges.isEmpty() && matchedRange == sortedRanges.get(0);
BigDecimal effectiveBase = base;
if (firstTier) {
BigDecimal minimum = decimal(matchedRange.get("minimumBillingWeight"));
if (minimum.signum() <= 0) {
minimum = decimal(rule.get("minimumBillingWeight"));
}
effectiveBase = applyMinimum(base, element, minimum, waybill);
}
BigDecimal matchedUnitPrice = decimal(matchedRange.get("unitPrice"));
if (matchedUnitPrice.signum() == 0) {
matchedUnitPrice = unit;
}
return matchedUnitPrice.multiply(effectiveBase);
}).orElse(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
}
if ("阶梯单价".equals(type)) {
@@ -71,6 +71,7 @@ public class ContractManageWrapper extends BaseEntityWrapper<ContractManage, Con
case "draft" -> "草稿";
case "reviewing" -> "审批中";
case "rejected" -> "已驳回";
case "withdrawn" -> "已撤回";
case "approved" -> "审批通过";
case "change_reviewing" -> "变更审批中";
case "change_rejected" -> "变更驳回";