:fix: 修复客商审核通过推送金蝶失败被吞异常且失败状态未落库的问题
This commit is contained in:
+12
-8
@@ -136,21 +136,25 @@ public class CustomerArchiveController extends BladeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 审核通过(通过后自动推送金蝶,推送失败不影响审批结果)
|
* 审核通过(通过后自动推送金蝶,推送失败不影响审批结果,失败原因以警告文案返回)
|
||||||
*/
|
*/
|
||||||
@PostMapping("/approve")
|
@PostMapping("/approve")
|
||||||
@ApiOperationSupport(order = 6)
|
@ApiOperationSupport(order = 6)
|
||||||
@Operation(summary = "审核通过", description = "传入id")
|
@Operation(summary = "审核通过", description = "传入id")
|
||||||
public R approve(@Parameter(description = "主键", required = true) @RequestParam Long id) {
|
public R approve(@Parameter(description = "主键", required = true) @RequestParam Long id) {
|
||||||
boolean result = customerArchiveService.approve(id);
|
boolean result = customerArchiveService.approve(id);
|
||||||
if (result) {
|
if (!result) {
|
||||||
try {
|
return R.status(false);
|
||||||
customerArchiveService.syncKingdee(id);
|
}
|
||||||
} catch (Exception exception) {
|
try {
|
||||||
log.error("客商审批通过后推送金蝶异常,id={}", id, exception);
|
customerArchiveService.syncKingdee(id);
|
||||||
}
|
return R.success("审核通过");
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("客商审批通过后推送金蝶异常,id={}", id, exception);
|
||||||
|
String reason = exception.getMessage() == null ? "金蝶接口调用异常" : exception.getMessage();
|
||||||
|
// 与结算/付款/开票审批口径一致:审批已生效,推送失败原因以 data=false 警告文案返回
|
||||||
|
return R.data(Boolean.FALSE, "审核通过,但推送金蝶失败:" + reason);
|
||||||
}
|
}
|
||||||
return R.status(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+8
@@ -196,6 +196,14 @@ public interface ICustomerArchiveService extends BaseService<CustomerArchive> {
|
|||||||
*/
|
*/
|
||||||
CustomerArchive syncKingdee(Long id);
|
CustomerArchive syncKingdee(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送失败状态落库(独立事务):推送主事务已回滚,失败状态与原因单独落库供页面展示与手动重推
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
* @param reason 失败原因
|
||||||
|
*/
|
||||||
|
void markKingdeeSyncFailed(Long id, String reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时同步金蝶客商数据:待推送客商自动推送 + 已同步客商使用状态回写
|
* 定时同步金蝶客商数据:待推送客商自动推送 + 已同步客商使用状态回写
|
||||||
*
|
*
|
||||||
|
|||||||
+52
-4
@@ -34,6 +34,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
|
import org.springblade.core.tool.utils.SpringUtil;
|
||||||
import org.springblade.transport.mk.MkProcessNodeHelper;
|
import org.springblade.transport.mk.MkProcessNodeHelper;
|
||||||
import org.springblade.transport.support.TransportBusinessSupport;
|
import org.springblade.transport.support.TransportBusinessSupport;
|
||||||
import org.springblade.core.tenant.annotation.TenantIgnore;
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
@@ -96,6 +97,7 @@ import org.springblade.transport.pojo.vo.CustomerReceiptAccountVO;
|
|||||||
import org.springblade.transport.service.ICustomerArchiveService;
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
import org.springblade.transport.support.KingdeeSyncLockSupport;
|
import org.springblade.transport.support.KingdeeSyncLockSupport;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -528,14 +530,52 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
updateById(after);
|
updateById(after);
|
||||||
return after;
|
return after;
|
||||||
}
|
}
|
||||||
pushCustomerToKingdee(id, customer, after, detail(id));
|
try {
|
||||||
|
pushCustomerToKingdee(id, customer, after, detail(id));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
// 推送事务已回滚,此处独立事务落"推送失败"状态与原因,供页面展示与手动重推(与结算/付款/开票口径一致)
|
||||||
|
self().markKingdeeSyncFailed(id, exception.getMessage());
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
updateById(after);
|
updateById(after);
|
||||||
return after;
|
return after;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 自代理:跨方法调用确保事务注解生效(失败状态独立事务) */
|
||||||
|
private ICustomerArchiveService self() {
|
||||||
|
return SpringUtil.getBean(ICustomerArchiveService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||||
|
public void markKingdeeSyncFailed(Long id, String reason) {
|
||||||
|
if (id == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String failReason = truncateText(Func.toStrWithEmpty(reason, "金蝶接口调用异常"));
|
||||||
|
CustomerArchive before = getById(id);
|
||||||
|
// 条件更新:仅审批通过且未推送/推送失败的客商落失败状态,已推送/金蝶已有自动跳过保持原状态
|
||||||
|
int updated = baseMapper.update(null, Wrappers.<CustomerArchive>lambdaUpdate()
|
||||||
|
.eq(CustomerArchive::getId, id)
|
||||||
|
.eq(CustomerArchive::getApprovalStatus, APPROVAL_APPROVED)
|
||||||
|
.and(wrapper -> wrapper.isNull(CustomerArchive::getKingdeeStatus)
|
||||||
|
.or()
|
||||||
|
.notIn(CustomerArchive::getKingdeeStatus, List.of(KINGDEE_STATUS_SYNCED, KINGDEE_STATUS_EXIST)))
|
||||||
|
.set(CustomerArchive::getKingdeeStatus, KINGDEE_STATUS_FAILED)
|
||||||
|
.set(CustomerArchive::getKingdeeFailReason, failReason));
|
||||||
|
if (updated > 0 && before != null) {
|
||||||
|
// 变更记录留档(推送主事务已回滚,此处独立事务落状态与记录)
|
||||||
|
CustomerArchive after = copyCustomer(before);
|
||||||
|
after.setKingdeeStatus(KINGDEE_STATUS_FAILED);
|
||||||
|
after.setKingdeeFailReason(failReason);
|
||||||
|
addChangeRecord(id, "推送金蝶失败:" + failReason, before, after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组装 A902-2 报文推送金蝶并回写协同状态;detail 由调用方准备,
|
* 组装 A902-2 报文推送金蝶并回写协同状态;detail 由调用方准备,
|
||||||
* 定时同步批量组装报文数据,避免逐条 detail 查询的 N+1 问题
|
* 定时同步批量组装报文数据,避免逐条 detail 查询的 N+1 问题;
|
||||||
|
* 推送失败先落 failed 状态与变更记录,再抛出异常由调用方提示前端(与结算/付款/开票口径一致)
|
||||||
*/
|
*/
|
||||||
private void pushCustomerToKingdee(Long id, CustomerArchive customer, CustomerArchive after, CustomerArchiveVO detail) {
|
private void pushCustomerToKingdee(Long id, CustomerArchive customer, CustomerArchive after, CustomerArchiveVO detail) {
|
||||||
try {
|
try {
|
||||||
@@ -549,12 +589,18 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
after.setKingdeeStatus(KINGDEE_STATUS_FAILED);
|
after.setKingdeeStatus(KINGDEE_STATUS_FAILED);
|
||||||
after.setKingdeeFailReason(buildSaveFailReason(result, item));
|
after.setKingdeeFailReason(buildSaveFailReason(result, item));
|
||||||
addChangeRecord(id, "推送金蝶失败:" + after.getKingdeeFailReason(), customer, after);
|
addChangeRecord(id, "推送金蝶失败:" + after.getKingdeeFailReason(), customer, after);
|
||||||
|
throw new ServiceException("推送金蝶失败:" + after.getKingdeeFailReason());
|
||||||
}
|
}
|
||||||
|
} catch (ServiceException exception) {
|
||||||
|
throw exception;
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.error("客商推送金蝶失败,id={},unifiedCreditCode={}", id, customer.getUnifiedCreditCode(), exception);
|
log.error("客商推送金蝶失败,id={},unifiedCreditCode={}", id, customer.getUnifiedCreditCode(), exception);
|
||||||
after.setKingdeeStatus(KINGDEE_STATUS_FAILED);
|
after.setKingdeeStatus(KINGDEE_STATUS_FAILED);
|
||||||
after.setKingdeeFailReason(truncateText(exception.getMessage() == null ? "金蝶接口调用异常" : exception.getMessage()));
|
after.setKingdeeFailReason(truncateText(exception.getMessage() == null ? "金蝶接口调用异常" : exception.getMessage()));
|
||||||
addChangeRecord(id, "推送金蝶失败:" + after.getKingdeeFailReason(), customer, after);
|
addChangeRecord(id, "推送金蝶失败:" + after.getKingdeeFailReason(), customer, after);
|
||||||
|
throw exception instanceof RuntimeException runtimeException
|
||||||
|
? runtimeException
|
||||||
|
: new ServiceException("推送金蝶失败:" + after.getKingdeeFailReason());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -715,11 +761,11 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
.map(CustomerArchive::getId)
|
.map(CustomerArchive::getId)
|
||||||
.toList());
|
.toList());
|
||||||
for (CustomerArchive customer : pushList) {
|
for (CustomerArchive customer : pushList) {
|
||||||
|
CustomerArchive after = copyCustomer(customer);
|
||||||
|
after.setKingdeeSyncTime(LocalDateTime.now());
|
||||||
try {
|
try {
|
||||||
CustomerArchiveVO detail = buildSyncArchiveVO(customer,
|
CustomerArchiveVO detail = buildSyncArchiveVO(customer,
|
||||||
receiptAccountsMap.getOrDefault(customer.getId(), new ArrayList<>()));
|
receiptAccountsMap.getOrDefault(customer.getId(), new ArrayList<>()));
|
||||||
CustomerArchive after = copyCustomer(customer);
|
|
||||||
after.setKingdeeSyncTime(LocalDateTime.now());
|
|
||||||
pushCustomerToKingdee(customer.getId(), customer, after, detail);
|
pushCustomerToKingdee(customer.getId(), customer, after, detail);
|
||||||
updateList.add(after);
|
updateList.add(after);
|
||||||
if (Objects.equals(after.getKingdeeStatus(), KINGDEE_STATUS_SYNCED)) {
|
if (Objects.equals(after.getKingdeeStatus(), KINGDEE_STATUS_SYNCED)) {
|
||||||
@@ -735,6 +781,8 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
pushFailed++;
|
pushFailed++;
|
||||||
log.error("定时同步金蝶客商推送异常,id={},unifiedCreditCode={}",
|
log.error("定时同步金蝶客商推送异常,id={},unifiedCreditCode={}",
|
||||||
customer.getId(), customer.getUnifiedCreditCode(), exception);
|
customer.getId(), customer.getUnifiedCreditCode(), exception);
|
||||||
|
// 失败状态与原因已在推送方法内回填 after,落库供页面展示与重推
|
||||||
|
updateList.add(after);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ②③ 共用:对已推送(synced)/金蝶已有(exist)客商按信用代码批量复查金蝶档案(审核状态 + 使用状态),仅调用一次 A902-1
|
// ②③ 共用:对已推送(synced)/金蝶已有(exist)客商按信用代码批量复查金蝶档案(审核状态 + 使用状态),仅调用一次 A902-1
|
||||||
|
|||||||
Reference in New Issue
Block a user