diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java index c06b24ca..08a8c775 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java @@ -23,6 +23,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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; @@ -31,6 +32,11 @@ import org.springblade.core.tool.utils.BeanUtil; import org.springblade.core.tool.utils.Func; import org.springblade.system.cache.DictBizCache; import org.springblade.system.pojo.entity.DictBiz; +import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveDTO; +import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveEntryDTO; +import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultItemVO; +import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO; +import org.springblade.thirdparty.bfi.service.IBfiService; import org.springblade.transport.mapper.FormalSettlementMapper; import org.springblade.transport.mapper.FormalSettlementPaymentMapper; import org.springblade.transport.mapper.BillLedgerMapper; @@ -71,6 +77,7 @@ import org.springblade.transport.service.IPaymentApplicationService; import org.springblade.transport.service.IFormalSettlementService; import org.springblade.transport.wrapper.PaymentApplicationWrapper; import org.springframework.stereotype.Service; +import org.springframework.beans.factory.annotation.Value; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; @@ -84,6 +91,7 @@ import java.util.Objects; import java.util.stream.Collectors; /** 付款申请服务实现。 @author Chill */ +@Slf4j @Service @RequiredArgsConstructor public class PaymentApplicationServiceImpl extends BaseServiceImpl @@ -93,6 +101,11 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl selectPage(IPage page, PaymentApplicationVO query) { @@ -307,15 +333,25 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpllambdaQuery().likeRight(PaymentApplication::getKingdeeBillNo, "FKD" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE))) + 1); - entity.setKingdeeBillNo(no); + String kingdeeBillId; + try { + kingdeeBillId = pushBfiPayApply(entity); + } catch (ServiceException exception) { + markSyncFailed(entity); + throw exception; + } catch (Exception exception) { + log.error("付款申请[{}]推送金蝶付款申请单异常", entity.getPaymentNo(), exception); + markSyncFailed(entity); + throw new ServiceException("推送金蝶付款申请失败:" + exception.getMessage()); + } + entity.setKingdeeBillNo(kingdeeBillId); entity.setKingdeeStatus("synced"); entity.setPaidAmount(money(entity.getAppliedAmount()).setScale(2, RoundingMode.HALF_UP)); mockPaymentRecords(entity); updateById(entity); syncPreSettlementAdvance(entity); syncFormalSettlementPayments(entity); - return no; + return kingdeeBillId; } @Override @@ -325,10 +361,106 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl distinctIds = ids.stream().filter(Objects::nonNull).distinct().toList(); if (distinctIds.isEmpty()) throw new ServiceException("请至少选择一条审批通过的付款申请"); List result = new ArrayList<>(); - for (Long id : distinctIds) result.add(syncKingdee(id)); + for (Long id : distinctIds) { + try { + result.add(syncKingdee(id)); + } catch (Exception exception) { + result.add("付款申请[" + id + "]同步失败:" + exception.getMessage()); + } + } return result; } + /** + * 推送金蝶付款申请单(A103-3 付款申请保存),返回金蝶单据id + * + * @param entity 付款申请实体 + * @return 金蝶付款申请单id + */ + private String pushBfiPayApply(PaymentApplication entity) { + if (Func.isBlank(bfiPayApplyOrgNumber)) throw new ServiceException("推送金蝶付款申请失败,请配置thirdParty.bfi.payApply.orgNumber"); + String applyDateText = (entity.getApplyDate() == null ? LocalDate.now() : entity.getApplyDate()).format(DateTimeFormatter.BASIC_ISO_DATE); + BigDecimal applyAmount = money(entity.getAppliedAmount()).setScale(2, RoundingMode.HALF_UP); + BfiPayApplySaveDTO param = new BfiPayApplySaveDTO(); + param.setAwrpSrcCode(entity.getPaymentNo()); + param.setAwrpSrcSys(bfiPayApplySrcSys); + param.setSettleorgNumber(bfiPayApplyOrgNumber); + param.setBilltypeNumber(bfiPayApplyBilltype); + param.setApplydate(applyDateText); + param.setApplyorgNumber(bfiPayApplyOrgNumber); + param.setPayorgNumber(bfiPayApplyOrgNumber); + param.setPurorgNumber(bfiPayApplyOrgNumber); + param.setApplycause(bfiApplyCause(entity.getPaymentType())); + param.setPaycurrencyNumber(bfiPayApplyCurrency); + param.setSettlecurrencyNumber(bfiPayApplyCurrency); + param.setAwrpSrcType(bfiPayApplySrcType); + param.setExratetableNumber(bfiPayApplyExratetable); + param.setExratedate(applyDateText); + param.setAwrpTextfield1(bfiPaymentMethodLabel(entity.getPaymentMethod())); + if (entity.getContractId() != null) { + param.setAwrpSrcBt(BFI_CONTRACT_SRC_BT); + param.setAwrpSrcConNo(entity.getContractNo()); + } + BfiPayApplySaveEntryDTO entry = new BfiPayApplySaveEntryDTO(); + entry.setEPaymenttypeNumber("settlement_payment".equals(entity.getPaymentType()) ? BFI_PAYMENT_TYPE_FORMAL : BFI_PAYMENT_TYPE_PREPAY); + entry.setEAsstacttype(BFI_SUPPLIER_ASSTACT_TYPE); + entry.setEAsstactNumber(bfiSupplierCode(entity)); + entry.setEAssacct(entity.getBankAccount()); + entry.setEBebankNumber(entity.getBankName()); + entry.setEPayamount(applyAmount); + entry.setEApplyamount(applyAmount); + entry.setEExpaydate(applyDateText); + entry.setProjectNumber(bfiProjectNumber(entity)); + entry.setAwrpEntryCode(entity.getPaymentNo() + "-1"); + entry.setERemark(entity.getRemark()); + param.setEntry(List.of(entry)); + BfiBillSaveResultVO saveResult = bfiService.savePrePayApply(param); + if (saveResult == null || Func.isEmpty(saveResult.getResult())) { + throw new ServiceException("推送金蝶付款申请失败,金蝶未返回单据结果"); + } + BfiBillSaveResultItemVO item = saveResult.getResult().get(0); + if (!Boolean.TRUE.equals(item.getBillStatus()) || item.getId() == null) { + String errorText = Func.isEmpty(item.getErrors()) ? "未知错误" : String.join(";", item.getErrors()); + throw new ServiceException("推送金蝶付款申请失败:" + errorText); + } + return String.valueOf(item.getId()); + } + + private void markSyncFailed(PaymentApplication entity) { + entity.setKingdeeStatus("failed"); + updateById(entity); + } + + private String bfiApplyCause(String paymentType) { + return switch (paymentType == null ? "" : paymentType) { + case "project_advance" -> "项目预付款申请"; + case "progress_advance" -> "进度预付款申请"; + case "settlement_payment" -> "结算付款申请"; + default -> "付款申请"; + }; + } + + private String bfiPaymentMethodLabel(String paymentMethod) { + if (Func.isEmpty(paymentMethod)) return null; + return DictBizCache.getList("pay_method").stream() + .filter(item -> paymentMethod.equals(item.getDictKey()) || paymentMethod.equals(item.getDictValue())) + .map(DictBiz::getDictValue).findFirst().orElse(paymentMethod); + } + + private String bfiSupplierCode(PaymentApplication entity) { + if (Func.isEmpty(entity.getPayeeName())) throw new ServiceException("推送金蝶付款申请失败,收款方不能为空"); + CustomerArchive customer = customerArchiveMapper.selectOne(Wrappers.lambdaQuery() + .and(wrapper -> wrapper.eq(CustomerArchive::getFullName, entity.getPayeeName()).or().eq(CustomerArchive::getShortName, entity.getPayeeName())) + .eq(CustomerArchive::getIsDeleted, 0).last("limit 1")); + return customer == null || Func.isEmpty(customer.getCustomerCode()) ? entity.getPayeeName() : customer.getCustomerCode(); + } + + private String bfiProjectNumber(PaymentApplication entity) { + if (entity.getProjectId() == null) return BFI_PROJECT_NUMBER_NONE; + ProjectApply project = projectApplyMapper.selectById(entity.getProjectId()); + return project == null || Func.isEmpty(project.getProjectCode()) ? BFI_PROJECT_NUMBER_NONE : project.getProjectCode(); + } + private void mockPaymentRecords(PaymentApplication entity) { recordMapper.delete(Wrappers.lambdaQuery() .eq(PaymentApplicationRecord::getPaymentApplicationId, entity.getId()));