调整 合同
This commit is contained in:
+21
-1
@@ -31,6 +31,7 @@ import lombok.EqualsAndHashCode;
|
||||
import org.springblade.core.tenant.mp.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -123,12 +124,31 @@ public class ContractManage extends TenantEntity {
|
||||
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
|
||||
private Integer paymentDays;
|
||||
|
||||
@Schema(description = "合同金额")
|
||||
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
|
||||
private BigDecimal contractAmount;
|
||||
|
||||
@Schema(description = "是否范本")
|
||||
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
|
||||
private Integer templateFlag;
|
||||
|
||||
@Schema(description = "原件合同编号")
|
||||
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String originalContractNo;
|
||||
|
||||
@Schema(description = "是否电子章")
|
||||
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
|
||||
private Integer electronicSealFlag;
|
||||
|
||||
@Schema(description = "合同阶段")
|
||||
private String contractStage;
|
||||
|
||||
@Schema(description = "审核状态")
|
||||
private String approvalStatus;
|
||||
|
||||
@Schema(description = "归档状态:未归档/已归档")
|
||||
private String archiveStatus;
|
||||
|
||||
@Schema(description = "当前节点")
|
||||
private String currentNode;
|
||||
|
||||
@@ -141,7 +161,7 @@ public class ContractManage extends TenantEntity {
|
||||
@Schema(description = "计费信息开关")
|
||||
private Integer billingEnabled;
|
||||
|
||||
@Schema(description = "费用生成模式:system系统生成,manual手动生成")
|
||||
@Schema(description = "费用生成模式:system系统生成,manual账单导入生成")
|
||||
private String feeGenerationMode;
|
||||
|
||||
@Schema(description = "合同主文件JSON")
|
||||
|
||||
+4
@@ -80,6 +80,10 @@ public class ProjectApplyVO extends ProjectApply {
|
||||
@Schema(description = "是否仅查询可用于临时额度申请的项目")
|
||||
private Boolean temporaryCreditLimitSelectable;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "是否仅查询可用于合同选择的项目(含临时项目与正式审批通过项目)")
|
||||
private Boolean contractSelectable;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "资金使用风险等级:high、medium、none")
|
||||
private String fundUseRisk;
|
||||
|
||||
+13
@@ -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("当前处理人")
|
||||
|
||||
+170
-10
@@ -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());
|
||||
|
||||
+8
@@ -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))
|
||||
|
||||
+19
-9
@@ -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)) {
|
||||
|
||||
+1
@@ -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" -> "变更驳回";
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 合同管理新增归档状态:默认未归档;审核通过且合同文件含双章归档文件时自动置为已归档
|
||||
ALTER TABLE `blade_contract_manage`
|
||||
ADD COLUMN `archive_status` varchar(50) DEFAULT '未归档' COMMENT '归档状态:未归档/已归档' AFTER `approval_status`;
|
||||
|
||||
UPDATE `blade_contract_manage`
|
||||
SET `archive_status` = '未归档'
|
||||
WHERE `archive_status` IS NULL OR `archive_status` = '';
|
||||
@@ -0,0 +1,6 @@
|
||||
-- 合同管理新增合同金额、范本、原件编号及电子章字段
|
||||
ALTER TABLE `blade_contract_manage`
|
||||
ADD COLUMN `contract_amount` decimal(18,2) DEFAULT NULL COMMENT '合同金额' AFTER `payment_days`,
|
||||
ADD COLUMN `template_flag` int(11) DEFAULT '0' COMMENT '是否范本' AFTER `contract_amount`,
|
||||
ADD COLUMN `original_contract_no` varchar(100) DEFAULT NULL COMMENT '原件合同编号' AFTER `template_flag`,
|
||||
ADD COLUMN `electronic_seal_flag` int(11) DEFAULT '0' COMMENT '是否电子章' AFTER `original_contract_no`;
|
||||
@@ -139,8 +139,13 @@ CREATE TABLE `blade_contract_manage` (
|
||||
`settlement_currency` varchar(50) DEFAULT NULL COMMENT '结算币种',
|
||||
`invoice_cycle` int(11) DEFAULT NULL COMMENT '开票周期(天)',
|
||||
`payment_days` int(11) DEFAULT NULL COMMENT '回款账期(天)',
|
||||
`contract_amount` decimal(18,2) DEFAULT NULL COMMENT '合同金额',
|
||||
`template_flag` int(11) DEFAULT '0' COMMENT '是否范本',
|
||||
`original_contract_no` varchar(100) DEFAULT NULL COMMENT '原件合同编号',
|
||||
`electronic_seal_flag` int(11) DEFAULT '0' COMMENT '是否电子章',
|
||||
`contract_stage` varchar(50) DEFAULT NULL COMMENT '合同阶段',
|
||||
`approval_status` varchar(50) DEFAULT NULL COMMENT '审核状态',
|
||||
`archive_status` varchar(50) DEFAULT '未归档' COMMENT '归档状态:未归档/已归档',
|
||||
`current_node` varchar(100) DEFAULT NULL COMMENT '当前节点',
|
||||
`current_processor` varchar(100) DEFAULT NULL COMMENT '当前处理人',
|
||||
`approved_time` datetime DEFAULT NULL COMMENT '审核通过时间',
|
||||
|
||||
Reference in New Issue
Block a user