From 73c8f6665ebc2599296b5930f8f72c4e9ddb2c78 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Thu, 22 Oct 2026 12:56:48 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=AE=A2=E5=95=86=E6=A1=A3?= =?UTF-8?q?=E6=A1=88=E8=A1=A8=E5=8D=95=E9=87=8D=E6=9E=84=E5=B9=B6=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E5=AE=9E=E7=BC=B4=E8=B5=84=E6=9C=AC=E3=80=81=E8=90=A5?= =?UTF-8?q?=E4=B8=9A=E6=9C=9F=E9=99=90=E8=B5=B7=E6=97=A5=E4=B8=8E=E5=B7=B2?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=A2=9D=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../pojo/entity/CustomerArchive.java | 12 +++ .../mapper/CustomerArchiveMapper.xml | 6 ++ .../impl/CustomerArchiveServiceImpl.java | 53 +++++++++-- .../service/impl/CustomerBfiConverter.java | 92 +++++++++++++++---- doc/sql/transport/blade_customer_archive.sql | 7 +- ...r_archive_paid_in_used_credit_20261022.sql | 7 ++ 6 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 doc/sql/transport/blade_customer_archive_paid_in_used_credit_20261022.sql diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/CustomerArchive.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/CustomerArchive.java index 5ea8bec1..242d0f65 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/CustomerArchive.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/CustomerArchive.java @@ -115,6 +115,10 @@ public class CustomerArchive extends TenantEntity { @Schema(description = "营业期限类型") private String businessTermType; + @Schema(description = "营业期限开始日") + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private LocalDate businessStartDate; + @Schema(description = "营业期限截止日") @TableField(updateStrategy = FieldStrategy.ALWAYS) private LocalDate businessEndDate; @@ -123,6 +127,10 @@ public class CustomerArchive extends TenantEntity { @TableField(updateStrategy = FieldStrategy.ALWAYS) private BigDecimal registeredCapital; + @Schema(description = "实缴资本(万元)") + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private BigDecimal paidInCapital; + @Schema(description = "客商负责人") private String principal; @@ -140,6 +148,10 @@ public class CustomerArchive extends TenantEntity { @TableField(updateStrategy = FieldStrategy.ALWAYS) private BigDecimal applyCreditLimit; + @Schema(description = "已使用额度(万元),新建可录历史值,后续由收付款业务累加/减更新") + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private BigDecimal usedCreditLimit; + @Schema(description = "备注") private String remark; diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/CustomerArchiveMapper.xml b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/CustomerArchiveMapper.xml index e6d9996c..2c04f248 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/CustomerArchiveMapper.xml +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/CustomerArchiveMapper.xml @@ -33,13 +33,16 @@ + + + @@ -85,13 +88,16 @@ business_scope, network_freight_platform, business_term_type, + business_start_date, business_end_date, registered_capital, + paid_in_capital, principal, mnemonic_code, customer_level, max_credit_limit, apply_credit_limit, + used_credit_limit, remark, qualification_attachments, access_type, diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchiveServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchiveServiceImpl.java index a8444ebf..39d96798 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchiveServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchiveServiceImpl.java @@ -963,13 +963,16 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl() : customer.getContacts()); + syncContactPhoneFromContacts(customer); applyFixedOwnerDept(customer); customer.setAccessType(Func.isEmpty(customer.getAccessType()) ? ACCESS_TEMPORARY : customer.getAccessType()); customer.setApprovalStatus(Func.isEmpty(customer.getApprovalStatus()) ? APPROVAL_DRAFT : customer.getApprovalStatus()); @@ -977,12 +980,33 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl() : customer.getContacts()); customer.setReceiptAccounts(customer.getReceiptAccounts() == null ? new ArrayList<>() : customer.getReceiptAccounts()); customer.setInvoices(customer.getInvoices() == null ? new ArrayList<>() : customer.getInvoices()); customer.setScores(customer.getScores() == null ? new ArrayList<>() : customer.getScores()); } + /** + * 主表联系电话改由联系人维护:取第一条有效联系人手机号回填,兼容历史 NOT NULL 及金蝶同步字段。 + */ + private void syncContactPhoneFromContacts(CustomerArchiveVO customer) { + if (Func.isNotEmpty(customer.getContactPhone())) { + customer.setContactPhone(trimToEmpty(customer.getContactPhone())); + return; + } + List contacts = customer.getContacts(); + if (Func.isEmpty(contacts)) { + customer.setContactPhone(null); + return; + } + String phone = contacts.stream() + .map(CustomerContactVO::getContactPhone) + .filter(Func::isNotEmpty) + .map(String::trim) + .findFirst() + .orElse(null); + customer.setContactPhone(phone); + } + private void validateBase(CustomerArchiveVO customer) { if (Func.isEmpty(customer.getFullName())) { throw new ServiceException("客商全称不能为空"); @@ -1009,10 +1033,8 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl contacts = customer.getContacts() == null ? List.of() : customer.getContacts(); + boolean hasContact = contacts.stream() + .anyMatch(item -> Func.isNotEmpty(item.getContactName()) || Func.isNotEmpty(item.getContactPhone())); + if (!hasContact) { + throw new ServiceException("请至少维护一条联系人"); + } + } + private void validateCustomerType(String customerType) { List typeList = Func.toStrList(customerType.replace(",", ",")) .stream() @@ -2040,13 +2076,16 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl buildLinkmanEntries(CustomerArchiveVO customer) { + if (Func.isNotEmpty(customer.getContacts())) { + List entries = new ArrayList<>(); + boolean defaultAssigned = false; + for (CustomerContactVO contact : customer.getContacts()) { + if (Func.isBlank(contact.getContactName()) && Func.isBlank(contact.getContactPhone())) { + continue; + } + BfiCustomerLinkmanEntryDTO entry = new BfiCustomerLinkmanEntryDTO(); + entry.setContactperson(contact.getContactName()); + entry.setPhone(contact.getContactPhone()); + boolean isDefault = !defaultAssigned && (Objects.equals(contact.getIsDefault(), 1) + || Func.isNotBlank(contact.getContactName())); + entry.setIsdefaultLinkman(isDefault); + if (isDefault) { + defaultAssigned = true; + } + entries.add(entry); + } + if (!entries.isEmpty()) { + return entries; + } + } if (Func.isBlank(customer.getPrincipal())) { return List.of(); } BfiCustomerLinkmanEntryDTO entry = new BfiCustomerLinkmanEntryDTO(); - // 联系人:客商负责人 entry.setContactperson(customer.getPrincipal()); - // 电话:联系电话 - entry.setPhone(customer.getContactPhone()); - // 默认联系人 + entry.setPhone(this.resolveContactPhone(customer)); entry.setIsdefaultLinkman(Boolean.TRUE); return List.of(entry); } + private String resolveContactPhone(CustomerArchiveVO customer) { + if (Func.isNotBlank(customer.getContactPhone())) { + return customer.getContactPhone(); + } + if (Func.isEmpty(customer.getContacts())) { + return null; + } + return customer.getContacts().stream() + .map(CustomerContactVO::getContactPhone) + .filter(Func::isNotBlank) + .findFirst() + .orElse(null); + } + /** * 金蝶伙伴类型编码:客商性质(nature_of_client 字典)—— * 值为 dictKey(即伙伴类型编码,1~17)时直接使用; @@ -248,35 +285,50 @@ public class CustomerBfiConverter { } /** - * 经营范围多选编码 → 字典文本「、」拼接,字典缺失时回退原编码 + * 经营范围:长文本直传;兼容历史多选编码 → 字典文本「、」拼接。 * - * @param businessScope 逗号拼接的经营范围编码 + * @param businessScope 经营范围长文本或历史逗号拼接编码 * @return 金蝶经营范围文本 */ public String buildBusinessScopeText(String businessScope) { if (Func.isEmpty(businessScope)) { return ""; } + String text = businessScope.trim(); + // 长文本(含中文描述)直接推送,不再按字典拆分 + if (text.length() > 40 || text.contains(";") || text.contains("。") || text.contains("\n")) { + return text; + } List dictList = DictBizCache.getList("scope_of_business"); Map scopeNames = dictList == null ? Map.of() : dictList.stream() .collect(Collectors.toMap(DictBiz::getDictKey, DictBiz::getDictValue, (first, second) -> first)); - return Func.toStrList(businessScope.replace(",", ",")).stream() + return Func.toStrList(text.replace(",", ",")).stream() .map(code -> scopeNames.getOrDefault(code, code)) .collect(Collectors.joining("、")); } /** - * 营业期限:长期传「长期」;固定期限传「至 yyyy-MM-dd」(TMS 未采集起始日) + * 营业期限:长期传「长期」;固定期限传「yyyy-MM-dd 至 yyyy-MM-dd」或「至 yyyy-MM-dd」。 * - * @param businessTermType 营业期限类型 - * @param businessEndDate 营业期限截止日 + * @param businessTermType 营业期限类型 + * @param businessStartDate 营业期限开始日 + * @param businessEndDate 营业期限截止日 * @return 金蝶营业期限文本 */ - public String buildBusinessTerm(String businessTermType, LocalDate businessEndDate) { + public String buildBusinessTerm(String businessTermType, LocalDate businessStartDate, LocalDate businessEndDate) { if (CustomerBfiConstants.BUSINESS_TERM_LONG.equals(businessTermType)) { - return CustomerBfiConstants.BUSINESS_TERM_LONG; + if (businessStartDate == null) { + return CustomerBfiConstants.BUSINESS_TERM_LONG; + } + return businessStartDate + " 至 " + CustomerBfiConstants.BUSINESS_TERM_LONG; } - return businessEndDate == null ? "" : "至 " + businessEndDate; + if (businessStartDate != null && businessEndDate != null) { + return businessStartDate + " 至 " + businessEndDate; + } + if (businessEndDate != null) { + return "至 " + businessEndDate; + } + return businessStartDate == null ? "" : String.valueOf(businessStartDate); } } diff --git a/doc/sql/transport/blade_customer_archive.sql b/doc/sql/transport/blade_customer_archive.sql index d2a0ef83..58bf476a 100644 --- a/doc/sql/transport/blade_customer_archive.sql +++ b/doc/sql/transport/blade_customer_archive.sql @@ -18,21 +18,24 @@ CREATE TABLE `blade_customer_archive` ( `registered_region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址行政区划', `registered_detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址详细地址', `legal_person` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '法人/负责人', - `contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '联系电话', + `contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话', `dept_id` bigint NULL DEFAULT NULL COMMENT '所属组织ID', `dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属组织ID集合', `dept_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织', `invoice_tax_rate` decimal(6,2) NULL DEFAULT NULL COMMENT '开票税点', - `business_scope` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '经营范围', + `business_scope` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '经营范围', `network_freight_platform` tinyint NULL DEFAULT NULL COMMENT '网络货运平台:0否,1是', `business_term_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '营业期限类型', + `business_start_date` date NULL DEFAULT NULL COMMENT '营业期限开始日', `business_end_date` date NULL DEFAULT NULL COMMENT '营业期限截止日', `registered_capital` decimal(18,2) NULL DEFAULT NULL COMMENT '注册资金(万元)', + `paid_in_capital` decimal(18,2) NULL DEFAULT NULL COMMENT '实缴资本(万元)', `principal` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客商负责人', `mnemonic_code` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '助记码', `customer_level` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客户等级', `max_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '最大资金使用额度(万元)', `apply_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '申请总资金使用额度(万元)', + `used_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '已使用额度(万元)', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `qualification_attachments` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '客商材料JSON', `access_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'temporary' COMMENT '准入类型:temporary临时,formal正式', diff --git a/doc/sql/transport/blade_customer_archive_paid_in_used_credit_20261022.sql b/doc/sql/transport/blade_customer_archive_paid_in_used_credit_20261022.sql new file mode 100644 index 00000000..08557073 --- /dev/null +++ b/doc/sql/transport/blade_customer_archive_paid_in_used_credit_20261022.sql @@ -0,0 +1,7 @@ +-- 客商档案:实缴资本、营业期限开始日、已使用额度;经营范围加长;联系电话改为可空(改由联系人维护) +ALTER TABLE `blade_customer_archive` + ADD COLUMN `business_start_date` date NULL DEFAULT NULL COMMENT '营业期限开始日' AFTER `business_term_type`, + ADD COLUMN `paid_in_capital` decimal(18,2) NULL DEFAULT NULL COMMENT '实缴资本(万元)' AFTER `registered_capital`, + ADD COLUMN `used_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '已使用额度(万元)' AFTER `apply_credit_limit`, + MODIFY COLUMN `business_scope` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '经营范围', + MODIFY COLUMN `contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话';