diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java index dc80865..0b77935 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java @@ -20,12 +20,15 @@ public class ContractLaunchPartyDto implements Serializable { /** 关联合同主表 ID */ private Long contractId; - /** 角色编码(A:甲方/我方, B:乙方/相对方, C:丙方 等) */ + /** 角色编码(OUR:我方主体, OPPOSITE:相对方) */ private String roleCode; - /** 角色名称(甲方/乙方/丙方) */ + /** 角色名称(我方/相对方) */ private String roleName; + /** 主体编码(前端传值,当前不单独落库,用于拼接 signingSubjectCode/c_weNames) */ + private String subjectCode; + /** 排序号 */ private Integer sortOrder; diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java index 92eb9db..5bdcf4a 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java @@ -217,13 +217,25 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { throw new ServiceException("当前状态不允许提交法务"); } SysUserEntity currentUser = adminSecurityManage.getUser(); + boolean singleAgreement = isSingleAgreement(contract); contract.setStatus(ContractLaunchConstants.STATUS_REVIEWING); contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_PENDING); - contract.setApproveMessage("已提交法务,等待审批"); + contract.setApproveMessage(singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批"); contract.setUpdateBy(currentUser.getUsername()); contract.setUpdateTime(LocalDateTime.now()); contractLaunchMapper.updateContract(contract); + if (singleAgreement) { + Map approvalPayload = new LinkedHashMap<>(); + approvalPayload.put("approvalType", "internal"); + approvalPayload.put("isSingleAgreement", contract.getIsSingleAgreement()); + approvalPayload.put("contractSysId", contract.getContractSysId()); + approvalPayload.put("contractName", contract.getContractName()); + approvalPayload.put("partyList", contract.getPartyList()); + insertLog(id, ContractLaunchConstants.ACTION_SUBMIT, "提交内部审批", ContractLaunchConstants.ACTION_STATUS_PENDING, "单方协议已提交内部审批,未推送法务", approvalPayload, currentUser); + return getDetail(id); + } + Map settlementPayload = buildSettlementPushPayload(contract); log.info("结算参数 JSON:{}", JsonUtils.toJson(settlementPayload)); insertLog(id, ContractLaunchConstants.ACTION_SUBMIT, "提交法务", ContractLaunchConstants.ACTION_STATUS_PENDING, "合同已提交法务接口,当前先保留 mock 流程", settlementPayload, currentUser); @@ -256,21 +268,24 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { throw new ServiceException("仅审批中的合同可模拟通过"); } SysUserEntity currentUser = adminSecurityManage.getUser(); + boolean singleAgreement = isSingleAgreement(contract); contract.setStatus(ContractLaunchConstants.STATUS_PENDING_SIGN); contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_APPROVED); contract.setApproveMessage(approveDto == null || approveDto.getApproveMessage() == null || approveDto.getApproveMessage().isBlank() - ? "法务审批通过(测试按钮模拟)" + ? (singleAgreement ? "内部审批通过(测试按钮模拟)" : "法务审批通过(测试按钮模拟)") : approveDto.getApproveMessage()); - contract.setLawContractCode(approveDto == null || approveDto.getLawContractCode() == null || approveDto.getLawContractCode().isBlank() - ? "LAW-" + ContractLaunchCodeUtils.buildContractCode(contract.getContractTypeCode()) - : approveDto.getLawContractCode()); - contract.setLawContractId(approveDto == null || approveDto.getLawContractId() == null || approveDto.getLawContractId().isBlank() - ? "LAWID-" + id - : approveDto.getLawContractId()); + if (!singleAgreement) { + contract.setLawContractCode(approveDto == null || approveDto.getLawContractCode() == null || approveDto.getLawContractCode().isBlank() + ? "LAW-" + ContractLaunchCodeUtils.buildContractCode(contract.getContractTypeCode()) + : approveDto.getLawContractCode()); + contract.setLawContractId(approveDto == null || approveDto.getLawContractId() == null || approveDto.getLawContractId().isBlank() + ? "LAWID-" + id + : approveDto.getLawContractId()); + } contract.setUpdateBy(currentUser.getUsername()); contract.setUpdateTime(LocalDateTime.now()); contractLaunchMapper.updateContract(contract); - insertLog(id, ContractLaunchConstants.ACTION_APPROVE, "模拟审批通过", ContractLaunchConstants.ACTION_STATUS_SUCCESS, contract.getApproveMessage(), approveDto, currentUser); + insertLog(id, ContractLaunchConstants.ACTION_APPROVE, singleAgreement ? "模拟内部审批通过" : "模拟审批通过", ContractLaunchConstants.ACTION_STATUS_SUCCESS, contract.getApproveMessage(), approveDto, currentUser); return getDetail(id); } @@ -288,15 +303,16 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { throw new ServiceException("仅审批中的合同可模拟驳回"); } SysUserEntity currentUser = adminSecurityManage.getUser(); + boolean singleAgreement = isSingleAgreement(contract); contract.setStatus(ContractLaunchConstants.STATUS_REJECTED); contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_REJECTED); contract.setApproveMessage(approveDto == null || approveDto.getApproveMessage() == null || approveDto.getApproveMessage().isBlank() - ? "法务审批驳回(测试按钮模拟)" + ? (singleAgreement ? "内部审批驳回(测试按钮模拟)" : "法务审批驳回(测试按钮模拟)") : approveDto.getApproveMessage()); contract.setUpdateBy(currentUser.getUsername()); contract.setUpdateTime(LocalDateTime.now()); contractLaunchMapper.updateContract(contract); - insertLog(id, ContractLaunchConstants.ACTION_REJECT, "模拟审批驳回", ContractLaunchConstants.ACTION_STATUS_SUCCESS, contract.getApproveMessage(), approveDto, currentUser); + insertLog(id, ContractLaunchConstants.ACTION_REJECT, singleAgreement ? "模拟内部审批驳回" : "模拟审批驳回", ContractLaunchConstants.ACTION_STATUS_SUCCESS, contract.getApproveMessage(), approveDto, currentUser); return getDetail(id); } @@ -810,6 +826,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { list.forEach(item -> { item.setPartyList(new ArrayList<>(partyMap.getOrDefault(item.getId(), Collections.emptyList()))); + enrichOurPartySubjectCodes(item); List contractFiles = new ArrayList<>(fileMap.getOrDefault(item.getId(), Collections.emptyList())); item.setFileList(contractFiles); item.setPerformancePlans(new ArrayList<>(planMap.getOrDefault(item.getId(), Collections.emptyList()))); @@ -823,7 +840,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { item.setLogList(new ArrayList<>(logMap.getOrDefault(item.getId(), Collections.emptyList()))); item.setCounterpartySummary( item.getPartyList().stream() - .filter(party -> !"A".equalsIgnoreCase(party.getRoleCode())) + .filter(this::isOppositeParty) .map(ContractLaunchPartyDto::getCompanyName) .filter(name -> name != null && !name.isBlank()) .collect(Collectors.joining(";")) @@ -831,6 +848,33 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { }); } + private void enrichOurPartySubjectCodes(ContractLaunchDto contract) { + if (contract == null || contract.getPartyList() == null || contract.getPartyList().isEmpty()) { + return; + } + List subjectCodes = String.valueOf(contract.getSigningSubjectCode() == null ? "" : contract.getSigningSubjectCode()) + .split(",").length == 0 ? List.of() : java.util.Arrays.stream(String.valueOf(contract.getSigningSubjectCode() == null ? "" : contract.getSigningSubjectCode()).split(",")) + .map(String::trim) + .filter(item -> !item.isBlank()) + .collect(Collectors.toList()); + int ourIndex = 0; + for (ContractLaunchPartyDto party : contract.getPartyList()) { + if (!isOurParty(party)) { + continue; + } + if (party.getSubjectCode() != null && !party.getSubjectCode().isBlank()) { + ourIndex++; + continue; + } + if (subjectCodes.size() == 1) { + party.setSubjectCode(subjectCodes.get(0)); + } else if (ourIndex < subjectCodes.size()) { + party.setSubjectCode(subjectCodes.get(ourIndex)); + } + ourIndex++; + } + } + /** 保存子表数据(合同方/文件/履行计划,插入前生成主键 ID) */ private void saveChildren(ContractLaunchDto contract, String operator) { if (contract.getPartyList() != null) { @@ -967,6 +1011,77 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { if (contract.getPerformancePlans() == null) { contract.setPerformancePlans(new ArrayList<>()); } + normalizePartyList(contract); + contract.setSigningSubjectCode(resolveSigningSubjectCodes(contract)); + } + + private void normalizePartyList(ContractLaunchDto contract) { + if (contract == null || contract.getPartyList() == null) { + return; + } + List normalized = contract.getPartyList().stream() + .filter(Objects::nonNull) + .filter(item -> item.getCompanyName() != null && !item.getCompanyName().isBlank()) + .peek(item -> { + String roleCode = trim(item.getRoleCode()); + if (roleCode == null || roleCode.isBlank()) { + roleCode = "OPPOSITE"; + } + item.setRoleCode(roleCode.toUpperCase()); + if (isOurParty(item)) { + item.setRoleName("我方"); + } else if (isOppositeParty(item)) { + item.setRoleName("相对方"); + } + item.setSubjectCode(trim(item.getSubjectCode())); + item.setCompanyName(trim(item.getCompanyName())); + item.setCreditCode(trim(item.getCreditCode())); + item.setOppositeId(trim(item.getOppositeId())); + item.setContactName(trim(item.getContactName())); + item.setContactPhone(trim(item.getContactPhone())); + item.setContactEmail(trim(item.getContactEmail())); + item.setRegisteredAddress(trim(item.getRegisteredAddress())); + item.setContactAddress(trim(item.getContactAddress())); + item.setLegalRepresentative(trim(item.getLegalRepresentative())); + item.setBankName(trim(item.getBankName())); + item.setBankAccount(trim(item.getBankAccount())); + }) + .collect(Collectors.toList()); + contract.setPartyList(normalized); + } + + private boolean isOurParty(ContractLaunchPartyDto party) { + return party != null && "OUR".equalsIgnoreCase(trim(party.getRoleCode())); + } + + private boolean isOppositeParty(ContractLaunchPartyDto party) { + return party != null && "OPPOSITE".equalsIgnoreCase(trim(party.getRoleCode())); + } + + private boolean isSingleAgreement(ContractLaunchDto contract) { + String value = contract == null ? null : trim(contract.getIsSingleAgreement()); + return "1".equals(value) || "Y".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value); + } + + private String resolveSigningSubjectCodes(ContractLaunchDto contract) { + if (contract == null) { + return null; + } + List subjectCodes = contract.getPartyList() == null ? List.of() : contract.getPartyList().stream() + .filter(this::isOurParty) + .map(ContractLaunchPartyDto::getSubjectCode) + .filter(Objects::nonNull) + .map(String::trim) + .filter(item -> !item.isBlank()) + .distinct() + .collect(Collectors.toList()); + if (!subjectCodes.isEmpty()) { + return String.join(",", subjectCodes); + } + if (contract.getSigningSubjectCode() != null && !contract.getSigningSubjectCode().isBlank()) { + return trim(contract.getSigningSubjectCode()); + } + return trim(contract.getOrgId()); } /** 校验草稿必填项 */ @@ -1013,12 +1128,26 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { if ("2".equals(contract.getValuationMode()) && contract.getEstimatedAmount() == null) { throw new ServiceException("预估总价合同必须填写预估金额"); } - boolean hasPartyA = contract.getPartyList().stream().anyMatch(item -> "A".equalsIgnoreCase(item.getRoleCode())); - boolean hasCounterparty = contract.getPartyList().stream().anyMatch(item -> !"A".equalsIgnoreCase(item.getRoleCode())); - if (!hasPartyA) { + boolean hasOurParty = contract.getPartyList().stream().anyMatch(this::isOurParty); + boolean hasCounterparty = contract.getPartyList().stream().anyMatch(this::isOppositeParty); + if (!hasOurParty) { throw new ServiceException("必须维护我方信息"); } - if (!hasCounterparty) { + String currentOrgId = trim(adminSecurityManage.getUser() == null || adminSecurityManage.getUser().getSysOrgEntity() == null + ? null + : adminSecurityManage.getUser().getSysOrgEntity().getId()); + if (currentOrgId != null && !currentOrgId.isBlank()) { + boolean containsCurrentOrg = contract.getPartyList().stream() + .filter(this::isOurParty) + .map(ContractLaunchPartyDto::getSubjectCode) + .filter(Objects::nonNull) + .map(String::trim) + .anyMatch(currentOrgId::equals); + if (!containsCurrentOrg) { + throw new ServiceException("我方主体中必须包含当前登录主体"); + } + } + if (!isSingleAgreement(contract) && !hasCounterparty) { throw new ServiceException("至少维护一个相对方"); } if (Integer.valueOf(1).equals(contract.getIsOpenBidding()) @@ -1109,10 +1238,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { payload.put("paymentDirection", contract.getPaymentDirection()); payload.put("contractTypeCode", contract.getContractTypeCode()); payload.put("bodySummary", contract.getBodySummary()); - payload.put("signingSubjectCode", - contract.getSigningSubjectCode() == null || contract.getSigningSubjectCode().isBlank() - ? contract.getOrgId() - : contract.getSigningSubjectCode()); + payload.put("signingSubjectCode", resolveSigningSubjectCodes(contract)); payload.put("executorAccount", contract.getExecutorAccount()); payload.put("contractPeriod", contract.getContractPeriodType()); payload.put("contractAmount", contract.getContractAmount()); @@ -1130,7 +1256,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { payload.put("yfkAmount", contract.getYfkAmount()); payload.put("bzjAmount", contract.getBzjAmount()); payload.put("contractOpposites", contract.getPartyList().stream() - .filter(item -> !"A".equalsIgnoreCase(item.getRoleCode())) + .filter(this::isOppositeParty) .map(item -> { Map map = new LinkedHashMap<>(); map.put("oppCharacter", "2".equals(item.getOppositeCharacter()) ? "ZZR" : "QY"); @@ -1163,12 +1289,9 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { Map payload = new LinkedHashMap<>(); payload.put("c_name", contract.getContractName()); payload.put("c_code", contract.getLawContractCode() == null || contract.getLawContractCode().isBlank() ? contract.getContractCode() : contract.getLawContractCode()); - // TODO: c_weNames 传机构编码,当前用 signingSubjectCode(签约主体编码),若为空则用 orgId - payload.put("c_weNames", contract.getSigningSubjectCode() != null && !contract.getSigningSubjectCode().isBlank() - ? contract.getSigningSubjectCode() - : contract.getOrgId()); + payload.put("c_weNames", resolveSigningSubjectCodes(contract)); payload.put("c_oppositeNames", contract.getPartyList().stream() - .filter(item -> !"A".equalsIgnoreCase(item.getRoleCode())) + .filter(this::isOppositeParty) .map(item -> item.getOppositeId() != null && !item.getOppositeId().isBlank() ? item.getOppositeId() : item.getPartnerId() == null ? null : String.valueOf(item.getPartnerId())) diff --git a/src/main/resources/mapper/partner/PartnerManageMapper.xml b/src/main/resources/mapper/partner/PartnerManageMapper.xml index 1da342c..2fa6e54 100644 --- a/src/main/resources/mapper/partner/PartnerManageMapper.xml +++ b/src/main/resources/mapper/partner/PartnerManageMapper.xml @@ -22,6 +22,7 @@ + @@ -68,7 +69,7 @@ select CUSTOMER_SYSID, CUSTOMER_REGNO, CUSTOMER_NO, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_ADDRESS, OFFICEPHONE, CUSTOMER_BANK, CUSTOMER_BANKACCOUNT, CUSTOMER_REGADDR, - EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, + EMAIL_ADDRESS, ORG_ID, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY, COUNTRY_NAME, LEGAL_PERSON_NAME, CERTIFICATE_TYPE, CERTIFICATE_NUM, TIN_CODE, REGISTERED_CAPITAL, REG_CAPITAL, OPPOSITE_CODE, OPPOSITE_STATUS, IS_SGAT, IS_JTN,