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 0fc97777..6890fa1b 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
@@ -158,4 +158,13 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "审核通过时间")
private LocalDateTime approvedTime;
+ @Schema(description = "金蝶协同状态:none未推送/exist金蝶已有/synced已推送/failed推送失败")
+ private String kingdeeStatus;
+
+ @Schema(description = "金蝶推送失败原因")
+ private String kingdeeFailReason;
+
+ @Schema(description = "金蝶推送时间")
+ private LocalDateTime kingdeeSyncTime;
+
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/CustomerBfiConstants.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/CustomerBfiConstants.java
new file mode 100644
index 00000000..6725a436
--- /dev/null
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/CustomerBfiConstants.java
@@ -0,0 +1,69 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.transport.constant;
+
+import java.util.Map;
+
+/**
+ * 客商档案金蝶(星瀚)协同常量
+ *
+ * @author Chill
+ */
+public class CustomerBfiConstants {
+
+ /**
+ * 推送金蝶固定值:业务职能全选(1销售,2结算,3付款,4收货)
+ */
+ public static final String BIZ_FUNCTION_ALL = "1,2,3,4";
+
+ /**
+ * 推送金蝶固定值:伙伴类型兜底编码(民营企业),客商性质未命中映射时使用
+ */
+ public static final String DEFAULT_PARTNER_TYPE = "6";
+
+ /**
+ * 营业期限类型:长期(TMS 表单文本)
+ */
+ public static final String BUSINESS_TERM_LONG = "长期";
+
+ /**
+ * 客商性质(nature_of_client 字典 dictKey)→ 金蝶伙伴类型编码
+ * 键名以数据库字典 nature_of_client 实际 dictKey 为准核对;未命中走 DEFAULT_PARTNER_TYPE
+ */
+ public static final Map NATURE_TYPE_MAPPING = Map.of(
+ "企业法人", "1",
+ "个人", "4",
+ "个体工商户", "5",
+ "民营企业", "6",
+ "国有企业", "8",
+ "政府事业单位", "9",
+ "其他", "12"
+ );
+
+ private CustomerBfiConstants() {
+ }
+
+}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/BfiCustomerController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/BfiCustomerController.java
new file mode 100644
index 00000000..5faea7c8
--- /dev/null
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/BfiCustomerController.java
@@ -0,0 +1,75 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.transport.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerQueryDTO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiCustomerVO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
+import org.springblade.thirdparty.bfi.service.IBfiService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 业财融合(BFI)客商查询控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/bfi")
+@Tag(name = "BFI客商", description = "业财融合客商查询接口")
+public class BfiCustomerController extends BladeController {
+
+ private final IBfiService bfiService;
+
+ @GetMapping("/customer/query-by-credit-code")
+ @Operation(summary = "按统一社会信用代码查询金蝶客商", description = "新增客商时查询金蝶是否已有该客商,已审核则回填工商信息")
+ public R queryByCreditCode(
+ @Parameter(description = "统一社会信用代码", required = true) @RequestParam String creditCode) {
+ if (StringUtil.isBlank(creditCode)) {
+ return R.fail("统一社会信用代码不能为空");
+ }
+ BfiCustomerQueryDTO param = new BfiCustomerQueryDTO();
+ param.setPageNo(1);
+ param.setPageSize(1);
+ param.setSocietycreditcode(List.of(creditCode.trim().toUpperCase()));
+ BfiPageVO page = bfiService.queryCustomer(param);
+ List rows = page == null ? null : page.getRows();
+ return R.data(rows == null || rows.isEmpty() ? null : rows.get(0));
+ }
+
+}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchiveController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchiveController.java
index 6b1a1266..3c44fd00 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchiveController.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchiveController.java
@@ -31,6 +31,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.mp.support.Condition;
@@ -60,6 +61,7 @@ import java.util.List;
*
* @author Chill
*/
+@Slf4j
@RestController
@AllArgsConstructor
@PreAuth(menu = "customer_archive")
@@ -133,13 +135,21 @@ public class CustomerArchiveController extends BladeController {
}
/**
- * 审核通过
+ * 审核通过(通过后自动推送金蝶,推送失败不影响审批结果)
*/
@PostMapping("/approve")
@ApiOperationSupport(order = 6)
@Operation(summary = "审核通过", description = "传入id")
public R approve(@Parameter(description = "主键", required = true) @RequestParam Long id) {
- return R.status(customerArchiveService.approve(id));
+ boolean result = customerArchiveService.approve(id);
+ if (result) {
+ try {
+ customerArchiveService.syncKingdee(id);
+ } catch (Exception exception) {
+ log.error("客商审批通过后推送金蝶异常,id={}", id, exception);
+ }
+ }
+ return R.status(result);
}
/**
@@ -173,6 +183,16 @@ public class CustomerArchiveController extends BladeController {
return R.status(customerArchiveService.removeDraft(ids));
}
+ /**
+ * 推送金蝶(审批通过后失败重推入口)
+ */
+ @PostMapping("/sync-kingdee")
+ @ApiOperationSupport(order = 12)
+ @Operation(summary = "推送金蝶", description = "传入id,仅审批通过的客商可推送,已推送/金蝶已有自动幂等跳过")
+ public R syncKingdee(@Parameter(description = "主键", required = true) @RequestParam Long id) {
+ return R.data(customerArchiveService.syncKingdee(id));
+ }
+
/**
* 评分明细模板
*/
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/CustomerArchiveExcel.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/CustomerArchiveExcel.java
index cc15e8b6..6c71a297 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/CustomerArchiveExcel.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/CustomerArchiveExcel.java
@@ -105,4 +105,7 @@ public class CustomerArchiveExcel implements Serializable {
@ExcelProperty("审核通过时间")
private LocalDateTime approvedTime;
+ @ExcelProperty("金蝶同步状态")
+ private String kingdeeStatusName;
+
}
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 d9df1358..2494a669 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
@@ -46,6 +46,9 @@
+
+
+
@@ -92,7 +95,10 @@
approval_status,
current_node,
current_processor,
- approved_time
+ approved_time,
+ kingdee_status,
+ kingdee_fail_reason,
+ kingdee_sync_time
FROM blade_customer_archive
WHERE is_deleted = 0
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ICustomerArchiveService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ICustomerArchiveService.java
index 73ddd1a1..09ea4d92 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ICustomerArchiveService.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ICustomerArchiveService.java
@@ -124,6 +124,14 @@ public interface ICustomerArchiveService extends BaseService {
*/
boolean removeDraft(String ids);
+ /**
+ * 推送金蝶(A902-1 复查 + A902-2 保存),幂等:已推送/金蝶已有直接返回
+ *
+ * @param id 主键
+ * @return 更新后的客商档案
+ */
+ CustomerArchive syncKingdee(Long id);
+
/**
* 基于启用评分量化表生成评分记录
*
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 7dde6cdc..7ce32739 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
@@ -29,12 +29,22 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.thirdparty.bfi.constant.BfiConstant;
+import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerQueryDTO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultErrorVO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultItemVO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiCustomerVO;
+import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
+import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.transport.excel.CustomerArchiveExcel;
import org.springblade.transport.mapper.CreditRatingStandardMapper;
import org.springblade.transport.mapper.CreditScoreCategoryMapper;
@@ -101,6 +111,7 @@ import java.util.stream.Collectors;
* @author Chill
*/
@Service
+@Slf4j
@RequiredArgsConstructor
public class CustomerArchiveServiceImpl extends BaseServiceImpl implements ICustomerArchiveService {
@@ -112,6 +123,10 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl selectCustomerArchivePage(IPage page, CustomerArchiveVO customer) {
@@ -268,6 +285,112 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl page = bfiService.queryCustomer(param);
+ List rows = page == null ? null : page.getRows();
+ return rows == null || rows.isEmpty() ? null : rows.get(0);
+ }
+
+ private BfiBillSaveResultItemVO firstSaveItem(BfiBillSaveResultVO result) {
+ if (result == null || result.getResult() == null || result.getResult().isEmpty()) {
+ return null;
+ }
+ return result.getResult().get(0);
+ }
+
+ private String buildSaveFailReason(BfiBillSaveResultVO result, BfiBillSaveResultItemVO item) {
+ if (item != null && Func.isNotEmpty(item.getErrors())) {
+ String messages = item.getErrors().stream()
+ .map(BfiBillSaveResultErrorVO::getRowMsg)
+ .filter(Func::isNotEmpty)
+ .flatMap(List::stream)
+ .collect(Collectors.joining(";"));
+ if (Func.isEmpty(messages)) {
+ messages = item.getErrors().stream()
+ .map(error -> String.valueOf(error.getEntityKey()))
+ .collect(Collectors.joining(";"));
+ }
+ return truncateText(messages);
+ }
+ if (result != null && Func.isNotEmpty(result.getFailCount())) {
+ return truncateText("金蝶返回失败数量:" + result.getFailCount());
+ }
+ return "金蝶返回结果为空";
+ }
+
+ private String truncateText(String text) {
+ if (text == null) {
+ return null;
+ }
+ return text.length() > 500 ? text.substring(0, 500) : text;
+ }
+
@Override
@Transactional(rollbackFor = Exception.class)
public boolean changeStatus(Long id, Integer status) {
@@ -343,6 +466,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl maxLength) {
throw new ServiceException(message);
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerBfiConverter.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerBfiConverter.java
new file mode 100644
index 00000000..941c96b2
--- /dev/null
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerBfiConverter.java
@@ -0,0 +1,147 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.transport.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.system.cache.DictBizCache;
+import org.springblade.system.pojo.entity.DictBiz;
+import org.springblade.thirdparty.bfi.constant.BfiConstant;
+import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerGroupEntryDTO;
+import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerSaveDTO;
+import org.springblade.transport.constant.CustomerBfiConstants;
+import org.springblade.transport.pojo.vo.CustomerArchiveVO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 客商档案金蝶(星瀚)报文转换器
+ *
+ * @author Chill
+ */
+@Component
+@RequiredArgsConstructor
+public class CustomerBfiConverter {
+
+ /**
+ * 数据来源系统编码,默认 WLTMS(运输TMS)
+ */
+ @Value("${thirdParty.bfi.customer.srcSys:WLTMS}")
+ private String srcSys;
+
+ /**
+ * 创建组织.编码,默认 WLTMS,需与财务确认
+ */
+ @Value("${thirdParty.bfi.customer.createOrg:WLTMS}")
+ private String createOrg;
+
+ /**
+ * 组装 A902-2 客户保存参数
+ *
+ * @param customer 客商档案
+ * @return 客户保存参数
+ */
+ public BfiCustomerSaveDTO buildSaveDTO(CustomerArchiveVO customer) {
+ BfiCustomerSaveDTO param = new BfiCustomerSaveDTO();
+ // 金蝶客户编码与 TMS 客商编号保持一致
+ param.setNumber(customer.getCustomerCode());
+ param.setStatus(BfiConstant.BILL_STATUS_SUBMITTED);
+ param.setName(customer.getFullName());
+ param.setSocietycreditcode(customer.getUnifiedCreditCode());
+ param.setTxRegisterNo(customer.getUnifiedCreditCode());
+ param.setArtificialperson(customer.getLegalPerson());
+ param.setType(resolvePartnerType(customer.getCustomerNature()));
+ param.setBizpartnerAddress(customer.getRegisteredAddress());
+ param.setBusinessscope(buildBusinessScopeText(customer.getBusinessScope()));
+ param.setBusinessterm(buildBusinessTerm(customer.getBusinessTermType(), customer.getBusinessEndDate()));
+ param.setBizpartnerPhone(customer.getContactPhone());
+ param.setFcusbeizhu(customer.getRemark());
+ param.setBizfunction(CustomerBfiConstants.BIZ_FUNCTION_ALL);
+ param.setAwrpDatasourcesys(srcSys);
+ param.setAwrpCusfortrade(BfiConstant.CUS_FOR_TRADE_YES);
+ param.setCreateorgNumber(createOrg);
+ BfiCustomerGroupEntryDTO groupEntry = new BfiCustomerGroupEntryDTO();
+ groupEntry.setStandardidNumber(BfiConstant.GROUP_STANDARD_BASIC);
+ groupEntry.setGroupidNumber(BfiConstant.CUSTOMER_GROUP_EXTERNAL);
+ param.setEntryGroupstandard(List.of(groupEntry));
+ return param;
+ }
+
+ /**
+ * 客商性质(字典 dictKey)→ 金蝶伙伴类型编码,未命中走兜底值
+ *
+ * @param customerNature 客商性质字典值
+ * @return 金蝶伙伴类型编码
+ */
+ public String resolvePartnerType(String customerNature) {
+ if (Func.isNotEmpty(customerNature)) {
+ String partnerType = CustomerBfiConstants.NATURE_TYPE_MAPPING.get(customerNature.trim());
+ if (StringUtil.isNotBlank(partnerType)) {
+ return partnerType;
+ }
+ }
+ return CustomerBfiConstants.DEFAULT_PARTNER_TYPE;
+ }
+
+ /**
+ * 经营范围多选编码 → 字典文本「、」拼接,字典缺失时回退原编码
+ *
+ * @param businessScope 逗号拼接的经营范围编码
+ * @return 金蝶经营范围文本
+ */
+ public String buildBusinessScopeText(String businessScope) {
+ if (Func.isEmpty(businessScope)) {
+ return "";
+ }
+ 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()
+ .map(code -> scopeNames.getOrDefault(code, code))
+ .collect(Collectors.joining("、"));
+ }
+
+ /**
+ * 营业期限:长期传「长期」;固定期限传「至 yyyy-MM-dd」(TMS 未采集起始日)
+ *
+ * @param businessTermType 营业期限类型
+ * @param businessEndDate 营业期限截止日
+ * @return 金蝶营业期限文本
+ */
+ public String buildBusinessTerm(String businessTermType, LocalDate businessEndDate) {
+ if (CustomerBfiConstants.BUSINESS_TERM_LONG.equals(businessTermType)) {
+ return CustomerBfiConstants.BUSINESS_TERM_LONG;
+ }
+ return businessEndDate == null ? "" : "至 " + businessEndDate;
+ }
+
+}
diff --git a/doc/sql/transport/blade_customer_archive_kingdee_20260917.sql b/doc/sql/transport/blade_customer_archive_kingdee_20260917.sql
new file mode 100644
index 00000000..1850aa03
--- /dev/null
+++ b/doc/sql/transport/blade_customer_archive_kingdee_20260917.sql
@@ -0,0 +1,16 @@
+-- 客商档案:金蝶(星瀚)协同字段
+-- kingdee_status:none未推送 / exist金蝶已有档案(A902-1查到已审核,跳过推送) / synced已推送成功 / failed推送失败或金蝶审核中
+-- 金蝶客户编码与 TMS 客商编号(customer_code)一致(A902-2 number 传入客商编号),无需单独存储
+
+ALTER TABLE `blade_customer_archive`
+ ADD COLUMN `kingdee_status` varchar(20) NOT NULL DEFAULT 'none' COMMENT '金蝶协同状态:none未推送/exist金蝶已有/synced已推送/failed推送失败' AFTER `approved_time`,
+ ADD COLUMN `kingdee_fail_reason` varchar(500) NULL DEFAULT NULL COMMENT '金蝶推送失败原因' AFTER `kingdee_status`,
+ ADD COLUMN `kingdee_sync_time` datetime NULL DEFAULT NULL COMMENT '金蝶推送时间' AFTER `kingdee_fail_reason`;
+
+CREATE INDEX idx_kingdee_status ON blade_customer_archive (kingdee_status);
+
+-- 列表「同步金蝶」按钮权限(审批通过后推送失败的重推入口;parent_id 通过菜单 code 关联,避免写死 id)
+INSERT INTO blade_menu (id, parent_id, code, name, alias, path, source, sort, category, action, is_open, component, remark, is_deleted)
+SELECT 2075431800000000001, m.id, 'customer_archive_sync', '同步金蝶', 'customer_archive_sync', '', '', 1, 2, 0, 1, '', '', 0
+FROM blade_menu m
+WHERE m.code = 'customer_archive' AND m.is_deleted = 0;