✨ 新增业务部门配置并按平台公司生成合同号与金蝶部门码
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+4
-3
@@ -188,10 +188,11 @@ public class ContractManageController extends BladeController {
|
||||
|
||||
@GetMapping("/next-contract-no")
|
||||
@ApiOperationSupport(order = 16)
|
||||
@Operation(summary = "预览下一合同编号", description = "按合同负责部门编码前缀+年份+三位流水预览")
|
||||
@Operation(summary = "预览下一合同编号", description = "按平台公司+业务部门配置的前缀+年份+三位流水预览")
|
||||
public R<String> nextContractNo(
|
||||
@Parameter(description = "合同负责部门ID", required = true) @RequestParam Long organizationId) {
|
||||
return R.data(contractManageService.nextContractNo(organizationId));
|
||||
@Parameter(description = "合同负责部门ID", required = true) @RequestParam Long organizationId,
|
||||
@Parameter(description = "平台公司ID", required = true) @RequestParam Long platformCompanyId) {
|
||||
return R.data(contractManageService.nextContractNo(organizationId, platformCompanyId));
|
||||
}
|
||||
|
||||
@GetMapping("/export-contract-manage")
|
||||
|
||||
+4
-3
@@ -75,12 +75,13 @@ public interface IContractManageService extends BaseService<ContractManage> {
|
||||
List<ContractManageExcel> exportContractManage(ContractManageVO contractManage, String ids);
|
||||
|
||||
/**
|
||||
* 预览下一合同编号(按合同负责部门前缀 + 年份 + 三位流水)
|
||||
* 预览下一合同编号(按平台公司 + 业务部门配置的前缀 + 年份 + 三位流水)
|
||||
*
|
||||
* @param organizationId 合同负责部门ID
|
||||
* @param organizationId 合同负责部门(业务部门)ID
|
||||
* @param platformCompanyId 平台公司ID
|
||||
* @return 预览编号
|
||||
*/
|
||||
String nextContractNo(Long organizationId);
|
||||
String nextContractNo(Long organizationId, Long platformCompanyId);
|
||||
|
||||
/**
|
||||
* 合同是否可用于生成结算单:已审批、未终止,且临时合同仍在临时效力期内。
|
||||
|
||||
+31
-13
@@ -36,6 +36,7 @@ import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.system.pojo.entity.BusinessDeptConfig;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springblade.transport.excel.ContractManageExcel;
|
||||
@@ -736,6 +737,10 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
contractManage.setOrganizationId(oldRecord.getOrganizationId());
|
||||
contractManage.setOrganizationName(oldRecord.getOrganizationName());
|
||||
}
|
||||
if (Func.isEmpty(contractManage.getPlatformCompanyId())) {
|
||||
contractManage.setPlatformCompanyId(oldRecord.getPlatformCompanyId());
|
||||
contractManage.setPlatformCompanyName(oldRecord.getPlatformCompanyName());
|
||||
}
|
||||
contractManage.setHandlerUserId(oldRecord.getHandlerUserId());
|
||||
contractManage.setHandlerUserName(oldRecord.getHandlerUserName());
|
||||
// 归档状态仅由审核通过逻辑自动维护,保存时保留库中已有值。
|
||||
@@ -760,7 +765,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
if (!generateWhenEmpty) {
|
||||
throw new ServiceException("请输入合同编号");
|
||||
}
|
||||
normalizedContractNo = nextContractNo(contractManage.getOrganizationId());
|
||||
normalizedContractNo = nextContractNo(contractManage.getOrganizationId(), contractManage.getPlatformCompanyId());
|
||||
}
|
||||
TransportBusinessSupport.validateLength(normalizedContractNo, 100, "合同编号不能超过100字");
|
||||
String currentContractNo = TransportBusinessSupport.trimToNull(contractManage.getContractNo());
|
||||
@@ -819,30 +824,39 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String nextContractNo(Long organizationId) {
|
||||
public synchronized String nextContractNo(Long organizationId, Long platformCompanyId) {
|
||||
if (Func.isEmpty(organizationId)) {
|
||||
throw new ServiceException("请选择合同负责部门");
|
||||
}
|
||||
if (Func.isEmpty(platformCompanyId)) {
|
||||
throw new ServiceException("请选择平台公司");
|
||||
}
|
||||
Dept dept = SysCache.getDept(organizationId);
|
||||
if (dept == null) {
|
||||
throw new ServiceException("合同负责部门不存在");
|
||||
}
|
||||
String prefix = TransportBusinessSupport.trimToNull(dept.getContractCodePrefix());
|
||||
Dept platformCompany = SysCache.getDept(platformCompanyId);
|
||||
if (platformCompany == null) {
|
||||
throw new ServiceException("平台公司不存在");
|
||||
}
|
||||
BusinessDeptConfig config = SysCache.getBusinessDeptConfig(platformCompanyId, organizationId);
|
||||
String prefix = config == null ? null : TransportBusinessSupport.trimToNull(config.getContractCodePrefix());
|
||||
if (Func.isEmpty(prefix)) {
|
||||
throw new ServiceException("请先在组织机构中配置该部门的合同编码前缀");
|
||||
throw new ServiceException("部门合同前缀未配置,无法自动生成,请手动输入合同编号");
|
||||
}
|
||||
int year = LocalDate.now().getYear();
|
||||
String head = prefix + "(" + year + ")";
|
||||
// 按前缀+年份扫描已占用流水号;系统已有相同流水号则跳过
|
||||
List<ContractManage> latestList = list(Wrappers.<ContractManage>lambdaQuery()
|
||||
.select(ContractManage::getContractNo)
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.eq(ContractManage::getOrganizationId, organizationId)
|
||||
.likeRight(ContractManage::getContractNo, head)
|
||||
.orderByDesc(ContractManage::getContractNo)
|
||||
.last("LIMIT 50"));
|
||||
.last("LIMIT 200"));
|
||||
Pattern pattern = Pattern.compile("^" + Pattern.quote(prefix) + "(" + year + ")(\\d{3})号$");
|
||||
// 当年尚无匹配编号时,从组织配置的初始流水号起编;否则在已有最大流水号上加1
|
||||
int next = resolveContractInitialSerial(dept);
|
||||
int initialSerial = resolveContractInitialSerial(config);
|
||||
int maxUsed = 0;
|
||||
boolean hasMatched = false;
|
||||
for (ContractManage item : latestList) {
|
||||
String contractNo = TransportBusinessSupport.trimToNull(item.getContractNo());
|
||||
if (Func.isEmpty(contractNo)) {
|
||||
@@ -852,22 +866,24 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
next = Integer.parseInt(matcher.group(1)) + 1;
|
||||
break;
|
||||
hasMatched = true;
|
||||
maxUsed = Math.max(maxUsed, Integer.parseInt(matcher.group(1)));
|
||||
}
|
||||
// 从初始流水号起编;若系统已有相同或更大流水号则跳到 maxUsed+1
|
||||
int next = hasMatched ? Math.max(initialSerial, maxUsed + 1) : initialSerial;
|
||||
if (next > 999) {
|
||||
throw new ServiceException("当前部门本年合同流水号已达上限999");
|
||||
}
|
||||
return head + String.format("%03d", next) + "号";
|
||||
}
|
||||
|
||||
private int resolveContractInitialSerial(Dept dept) {
|
||||
Integer serial = dept.getContractInitialSerial();
|
||||
private int resolveContractInitialSerial(BusinessDeptConfig config) {
|
||||
Integer serial = config == null ? null : config.getInitialSerial();
|
||||
if (serial == null || serial < 1) {
|
||||
return 1;
|
||||
}
|
||||
if (serial > 999) {
|
||||
throw new ServiceException("组织机构中配置的合同初始流水号不能超过999");
|
||||
throw new ServiceException("业务部门配置的合同初始流水号不能超过999");
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
@@ -1163,6 +1179,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类型");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getProjectName(), "请选择所属项目");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getOrganizationName(), "请选择合同负责部门");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getPlatformCompanyName(), "请选择平台公司");
|
||||
ContractPartySupport.validateRequiredParties(contractManage, true);
|
||||
ContractPartySupport.validateBillingPlanBindings(contractManage);
|
||||
validateContractAmountRequired(contractManage);
|
||||
@@ -1197,6 +1214,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类型");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getProjectName(), "请选择所属项目");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getOrganizationName(), "请选择合同负责部门");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getPlatformCompanyName(), "请选择平台公司");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getSettlementCurrency(), "请选择结算币种");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getPartyA(), "请输入甲方");
|
||||
TransportBusinessSupport.validateRequired(contractManage.getPartyB(), "请输入乙方");
|
||||
|
||||
+11
-5
@@ -818,10 +818,16 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
|
||||
}
|
||||
if (Func.isBlank(entity.getDepartmentEmails())) throw new ServiceException("推送金蝶开票申请失败:部门邮箱(发票推送邮箱)不能为空");
|
||||
if (Func.isBlank(entity.getTaxpayerNo())) throw new ServiceException("推送金蝶开票申请失败:购方纳税人识别号不能为空");
|
||||
// 金蝶组织编码:项目业务部门反查唯一平台公司 → 平台公司金蝶组织编码;申请部门编码:项目业务部门自身金蝶编码(与付款申请单部门.编码同源,共用上下文缓存)
|
||||
// 金蝶组织/申请部门:按首张关联结算单合同的平台公司 + 业务部门配置取数
|
||||
KingdeeSyncContext kingdeeContext = KingdeeSyncContext.empty();
|
||||
String kingdeeOrgNumber = kingdeeApBillSyncSupport.kingdeeOrgNumber(entity.getProjectId(), kingdeeContext);
|
||||
String kingdeeDeptNumber = kingdeeApBillSyncSupport.kingdeeDeptNumber(entity.getProjectId(), kingdeeContext);
|
||||
FormalSettlement firstSettlement = formalSettlementMapper.selectById(relations.get(0).getFormalSettlementId());
|
||||
if (firstSettlement == null || Objects.equals(firstSettlement.getIsDeleted(), 1)) {
|
||||
throw new ServiceException("推送金蝶开票申请失败:正式结算单["
|
||||
+ Func.toStr(relations.get(0).getFormalSettlementNo()) + "]不存在");
|
||||
}
|
||||
ContractManage contract = kingdeeApBillSyncSupport.requireContract(firstSettlement.getContractId(), kingdeeContext);
|
||||
String kingdeeOrgNumber = kingdeeApBillSyncSupport.bfiOrgNumber(contract, kingdeeContext);
|
||||
String kingdeeDeptNumber = kingdeeApBillSyncSupport.kingdeeDeptNumber(contract, entity.getProjectId(), kingdeeContext);
|
||||
CustomerArchive customer = entity.getReceiverCustomerId() == null ? null : customerArchiveMapper.selectById(entity.getReceiverCustomerId());
|
||||
if (customer == null || Func.isBlank(customer.getCustomerCode())) {
|
||||
throw new ServiceException("推送金蝶开票申请失败:受票方客户未在客商档案中维护客商编码,请补充后重试");
|
||||
@@ -909,9 +915,9 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
|
||||
String firstArSrcCode, BigDecimal sheetAmount, List<BfiInvoiceApplySaveEntryDTO> items) {
|
||||
BfiInvoiceApplySaveDTO param = new BfiInvoiceApplySaveDTO();
|
||||
// ==================== 以下为【必填】字段(BfiInvoiceApplySaveDTO 标注),非必填字段先注释保留 ====================
|
||||
// 【必填】组织.编码:项目业务部门反查唯一平台公司 → 平台公司金蝶组织编码
|
||||
// 【必填】组织.编码:合同平台公司金蝶组织编码
|
||||
param.setOrgidNumber(orgNumber);
|
||||
// 【必填】申请部门.编码:项目业务部门金蝶编码(与付款申请单 awrp_department_number 同源)
|
||||
// 【必填】申请部门.编码:合同平台公司下业务部门配置的金蝶部门代码
|
||||
param.setAwrpOrgfieldNumber(deptNumber);
|
||||
// 【必填】业务单据编号(候选键):单张发票候选 billno(多张发票时开票申请单号-张次序号)
|
||||
param.setBillno(billNo);
|
||||
|
||||
+2
-2
@@ -1254,8 +1254,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
param.setAwrpSrcSys(bfiProperties.getSrcSys());
|
||||
// 结算组织.编码
|
||||
param.setSettleorgNumber(orgNumber);
|
||||
// 部门.编码:项目业务部门自身的金蝶编码(结算/申请/付款组织仍传上溯平台公司编码)
|
||||
param.setAwrpDepartmentNumber(kingdeeApBillSyncSupport.kingdeeDeptNumber(contract.getProjectId(), context));
|
||||
// 部门.编码:合同平台公司下业务部门配置的金蝶部门代码
|
||||
param.setAwrpDepartmentNumber(kingdeeApBillSyncSupport.kingdeeDeptNumber(contract, contract.getProjectId(), context));
|
||||
// 【必填】单据类型.编码
|
||||
param.setBilltypeNumber(bfiProperties.getPayApply().getBilltype());
|
||||
// 【必填】申请日期:yyyy-MM-dd HH:mm:ss(各接口统一格式)
|
||||
|
||||
+44
-9
@@ -282,8 +282,8 @@ public class KingdeeApBillSyncSupport {
|
||||
param.setCurrencyNumber(currency);
|
||||
// 【必填】付款组织.编码
|
||||
param.setPayorgNumber(orgNumber);
|
||||
// 部门.编码:项目业务部门自身的金蝶编码(结算/付款组织仍传上溯平台公司编码,口径与付款申请 A103-3 一致)
|
||||
param.setDepartmentNumber(this.kingdeeDeptNumber(contract.getProjectId(), context));
|
||||
// 部门.编码:合同平台公司下业务部门配置的金蝶部门代码
|
||||
param.setDepartmentNumber(this.kingdeeDeptNumber(contract, contract.getProjectId(), context));
|
||||
// 采购组织.编码(非必传)
|
||||
// param.setPurorgNumber(orgNumber);
|
||||
// 【必填】款项性质.编码
|
||||
@@ -962,6 +962,20 @@ public class KingdeeApBillSyncSupport {
|
||||
* @return 组织编码
|
||||
*/
|
||||
public String bfiOrgNumber(ContractManage contract, KingdeeSyncContext context) {
|
||||
if (contract == null) {
|
||||
throw new ServiceException("推送金蝶失败,合同不存在,无法确定金蝶组织编码");
|
||||
}
|
||||
// 优先取合同平台公司金蝶代码;未维护时回退项目业务部门上溯
|
||||
if (contract.getPlatformCompanyId() != null) {
|
||||
Dept platformCompany = SysCache.getDept(contract.getPlatformCompanyId());
|
||||
if (platformCompany == null) {
|
||||
throw new ServiceException("推送金蝶失败,合同平台公司不存在,无法确定金蝶组织编码");
|
||||
}
|
||||
if (Func.isBlank(platformCompany.getKingdeeDeptCode())) {
|
||||
throw new ServiceException("推送金蝶失败,平台公司[" + platformCompany.getDeptName() + "]未维护金蝶组织编码,请检查部门数据");
|
||||
}
|
||||
return platformCompany.getKingdeeDeptCode();
|
||||
}
|
||||
if (contract.getProjectId() == null) {
|
||||
throw new ServiceException("推送金蝶失败,合同[" + Func.toStr(contract.getContractNo()) + "]未关联项目,无法确定金蝶组织编码");
|
||||
}
|
||||
@@ -993,20 +1007,41 @@ public class KingdeeApBillSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 金蝶部门编码:项目业务部门自身的金蝶编码(blade_dept.kingdee_dept_code,不上溯平台公司),
|
||||
* 用于付款申请单 awrp_department_number(部门.编码);项目未关联/未维护业务部门/业务部门未维护金蝶编码时拦截
|
||||
* 金蝶部门编码:必须取「业务部门配置」中合同平台公司 + 业务部门的金蝶部门代码;
|
||||
* 未配置时拦截推送
|
||||
*
|
||||
* @param projectId 项目id
|
||||
* @param context 金蝶同步上下文(缓存载体)
|
||||
* @return 部门编码
|
||||
*/
|
||||
public String kingdeeDeptNumber(Long projectId, KingdeeSyncContext context) {
|
||||
ProjectApply project = this.requireOrgProject(projectId, context);
|
||||
Dept dept = SysCache.getDept(project.getBusinessDeptId());
|
||||
if (dept == null || Func.isBlank(dept.getKingdeeDeptCode())) {
|
||||
throw new ServiceException("推送金蝶失败,项目业务部门[" + Func.toStr(project.getBusinessDeptName()) + "]未维护金蝶编码,请检查部门数据");
|
||||
return kingdeeDeptNumber(null, projectId, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 金蝶部门编码:按合同平台公司下业务部门配置的金蝶部门代码推送
|
||||
*
|
||||
* @param contract 合同(优先取其平台公司、合同负责部门)
|
||||
* @param projectId 项目id(合同未带业务部门时回退项目业务部门)
|
||||
* @param context 金蝶同步上下文(缓存载体)
|
||||
* @return 部门编码
|
||||
*/
|
||||
public String kingdeeDeptNumber(ContractManage contract, Long projectId, KingdeeSyncContext context) {
|
||||
Long platformCompanyId = contract == null ? null : contract.getPlatformCompanyId();
|
||||
Long businessDeptId = contract == null ? null : contract.getOrganizationId();
|
||||
if (businessDeptId == null && projectId != null) {
|
||||
ProjectApply project = this.requireOrgProject(projectId, context);
|
||||
businessDeptId = project.getBusinessDeptId();
|
||||
}
|
||||
return dept.getKingdeeDeptCode();
|
||||
if (platformCompanyId == null || businessDeptId == null) {
|
||||
throw new ServiceException("业务部门对应的金蝶组织代码未配置,单据无法推送,请联系管理员处理。");
|
||||
}
|
||||
org.springblade.system.pojo.entity.BusinessDeptConfig config =
|
||||
SysCache.getBusinessDeptConfig(platformCompanyId, businessDeptId);
|
||||
if (config == null || Func.isBlank(config.getKingdeeDeptCode())) {
|
||||
throw new ServiceException("业务部门对应的金蝶组织代码未配置,单据无法推送,请联系管理员处理。");
|
||||
}
|
||||
return config.getKingdeeDeptCode().trim();
|
||||
}
|
||||
|
||||
/** 金蝶组织/部门编码共用校验:项目存在且已维护业务部门 */
|
||||
|
||||
+2
-2
@@ -218,8 +218,8 @@ public class KingdeeArBillSyncSupport {
|
||||
param.setOrgNumber(orgNumber);
|
||||
// 收款组织.编码:同结算组织
|
||||
param.setRecorgNumber(orgNumber);
|
||||
// 部门.编码:项目业务部门自身的金蝶编码(结算/收款组织仍传上溯平台公司编码,口径与付款申请/应付单一致)
|
||||
param.setDepartmentNumber(kingdeeApBillSyncSupport.kingdeeDeptNumber(contract.getProjectId(), context));
|
||||
// 部门.编码:合同平台公司下业务部门配置的金蝶部门代码
|
||||
param.setDepartmentNumber(kingdeeApBillSyncSupport.kingdeeDeptNumber(contract, contract.getProjectId(), context));
|
||||
// 【必填】单据日期
|
||||
param.setBizdate(billDateText);
|
||||
// 【必填】往来类型:统一固定客户(KingdeeApBillSyncSupport#bfiAsstactType,与应付单/付款申请同口径)
|
||||
|
||||
+3
-1
@@ -185,7 +185,9 @@ public class KingdeeReceivedInvoiceSyncSupport {
|
||||
param.setPaymenttype(BfiConstant.PAY_MODE_CASH);
|
||||
// 【必填】往来类型:统一固定客户(KingdeeApBillSyncSupport#bfiAsstactType,与应付单/付款申请同口径)
|
||||
param.setAsstacttype(kingdeeApBillSyncSupport.bfiAsstactType(contract));
|
||||
// 【必填】结算组织.编码:合同关联项目业务部门反查平台公司(与应付单同源)
|
||||
// 部门金蝶代码校验:收票单主表无部门字段,推送前仍按合同平台公司下业务部门配置校验
|
||||
kingdeeApBillSyncSupport.kingdeeDeptNumber(contract, contract.getProjectId(), context);
|
||||
// 【必填】结算组织.编码:合同平台公司金蝶组织编码(与应付单同源)
|
||||
param.setOrgNumber(kingdeeApBillSyncSupport.bfiOrgNumber(contract, context));
|
||||
// 【必填】结算币别:合同结算币种
|
||||
param.setCurrencyNumber(kingdeeApBillSyncSupport.bfiCurrency(contract));
|
||||
|
||||
Reference in New Issue
Block a user