Merge branch 'feature/payment-apply-bfi-sync' into feature/hcs-api-p0

# Conflicts:
#	blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java
#	blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java
#	blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java
#	blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java
#	blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java
#	blade-service/blade-transport/src/main/java/org/springblade/transport/task/CustomerKingdeeSyncTask.java
#	blade-service/blade-transport/src/main/java/org/springblade/transport/task/PaymentKingdeeResultTask.java
#	doc/nacos/blade.yaml
#	doc/nacos/third-party-api.yaml
This commit is contained in:
刘泉佳
2026-10-15 04:07:13 +08:00
556 changed files with 35208 additions and 6751 deletions
@@ -27,7 +27,12 @@ package org.springblade.thirdparty.bfi.config;
import feign.Request;
import feign.RequestInterceptor;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springblade.thirdparty.bfi.interceptor.BfiRequestInterceptor;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import java.util.concurrent.TimeUnit;
@@ -61,4 +66,9 @@ public class BfiFeignClientConfig {
public Request.Options options() {
return new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
}
@Bean
public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
@@ -84,6 +84,11 @@ public class BfiConstant {
*/
public static final long TOKEN_EXPIRE_BUFFER_MILLIS = 120_000L;
/**
* A801-5 黑名单查询页大小上限,取值范围[1, 2000]的正整数
*/
public static final int BLACKLIST_QUERY_PAGE_SIZE = 2000;
/**
* A303-5 开票申请发票查询 接口编码,固定值
*/
@@ -30,17 +30,18 @@ import org.springblade.thirdparty.bfi.config.BfiFeignClientConfig;
import org.springblade.thirdparty.bfi.constant.BfiConstant;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillSaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiBillLockDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiBlacklistQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimPushBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerSaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiExchangeRateQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplyOpenApiBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplySaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceAssignBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceDownloadDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoicePoolQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplyPushBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplyQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiExchangeRateQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiReceivedInvoiceQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiReceivedInvoiceSaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiTokenDTO;
@@ -48,7 +49,10 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiVerifyTokenDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiWithdrawTokenDTO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiApBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiArBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiAttachmentUploadVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillLockResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBlacklistVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiClaimAnnounceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiCustomerVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiExchangeRateVO;
@@ -58,18 +62,21 @@ import org.springblade.thirdparty.bfi.pojo.vo.BfiOpenApiResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiPayApplyVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiPayBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiReceivedInvoiceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiRecBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiReceivedInvoiceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiTokenVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiVerifyTokenVO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -106,6 +113,9 @@ public interface IBfiClient {
String CLAIM_BILL_PUSH_URL = "${thirdParty.bfi.claimBillPushUrl:/ierp/kapi/v2/awrp/cas/cas/cas_claimbill/claimbillPush}";
String INVOICE_POOL_QUERY_URL = "${thirdParty.bfi.invoicePoolQueryUrl:/ierp/kapi/v2/awrp/rim/rim_invoice/query}";
String INVOICE_DOWNLOAD_URL = "${thirdParty.bfi.invoiceDownloadUrl:/ierp/kapi/v2/awrp/bosext/attachment/download}";
String ATTACHMENT_UPLOAD_URL = "${thirdParty.bfi.attachmentUploadUrl:/ierp/kapi/v2/frame/attachment/uploadFile}";
String BLACKLIST_QUERY_URL = "${thirdParty.bfi.blacklistQueryUrl:/ierp/kapi/v2/awrp/bdm/bdm_blacklist_config/blacklistquery}";
String LOCK_BILL_URL = "${thirdParty.bfi.billLockUrl:/API_lockAction_Router}";
/**
* A100-1 获取令牌
@@ -144,6 +154,16 @@ public interface IBfiClient {
@GetMapping(FOREX_QUERY_URL)
BfiResultVO<BfiPageVO<BfiExchangeRateVO>> forexQuery(@RequestHeader(BfiConstant.HEADER_ACCESS_TOKEN) String accessToken, @SpringQueryMap BfiExchangeRateQueryDTO param);
/**
* A801-5 黑名单查询(分页,pageSize 取值范围[1, 2000]的正整数)
*
* @param accessToken 访问令牌,通过 getToken 获取
* @param param 请求参数
* @return 黑名单分页数据
*/
@GetMapping(BLACKLIST_QUERY_URL)
BfiResultVO<BfiPageVO<BfiBlacklistVO>> blacklistQuery(@RequestHeader(BfiConstant.HEADER_ACCESS_TOKEN) String accessToken, @SpringQueryMap BfiBlacklistQueryDTO param);
/**
* A103-1 付款申请保存(根据星瀚应付下推付款申请)
*
@@ -410,15 +430,21 @@ public interface IBfiClient {
/**
* A301-2 收款认领公告查询
*
* @param accessToken 访问令牌,通过 getToken 获取
* @param claimusers 参与认领用户名
* @param pageNo 页码,从1开始
* @param pageSize 页数
* @param accessToken 访问令牌,通过 getToken 获取
* @param claimusers 参与认领用户名
* @param billstatus 单据状态(0-未认领,1-已认领)
* @param modifytimeS 修改时间-开始时间,格式:yyyy-MM-dd
* @param modifytimeE 修改时间-结束时间,格式:yyyy-MM-dd
* @param pageNo 页码,从1开始
* @param pageSize 页数
* @return 收款认领公告分页数据
*/
@GetMapping(CLAIM_ANNOUNCE_QUERY_URL)
BfiResultVO<BfiPageVO<BfiClaimAnnounceVO>> claimAnnounceQuery(@RequestHeader(BfiConstant.HEADER_ACCESS_TOKEN) String accessToken,
@RequestParam("claimusers") String claimusers,
@RequestParam(value = "billstatus", required = false) String billstatus,
@RequestParam("modifytimeS") String modifytimeS,
@RequestParam("modifytimeE") String modifytimeE,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize);
@@ -451,4 +477,30 @@ public interface IBfiClient {
*/
@PostMapping(INVOICE_DOWNLOAD_URL)
Response invoiceDownload(@RequestHeader(BfiConstant.HEADER_ACCESS_TOKEN) String accessToken, @RequestBody BfiInvoiceDownloadDTO param);
/**
* A902 附件上传到指定单据(multipart/form-data)
*
* @param accessToken 访问令牌,通过 getToken 获取
* @param file 附件文件
* @param attachmentUploadFileArgs 上传参数 JSON 字符串:{"entityNumber":"ap_payapply","billPkId":2386455983883835392,"controlKey":"attachmentpanel"}
* @return 上传结果,data.path 即金蝶侧文件路径
*/
@PostMapping(value = ATTACHMENT_UPLOAD_URL, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
BfiResultVO<BfiAttachmentUploadVO> uploadAttachment(@RequestHeader(BfiConstant.HEADER_ACCESS_TOKEN) String accessToken,
@RequestPart("file") MultipartFile file,
@RequestPart("attachmentUploadFileArgs") String attachmentUploadFileArgs);
/**
* 单据锁定(lockBusiData):推送金蝶成功后 WLTMS 调用锁定目标单据;
* 接口 1对1:单次仅一个源单号(sourceBillNo)对一个金蝶单号(targetBillNo),
* 应答为 {updateCount, updateResultList} 裸结构(非 BfiResultVO 包装);
* 解锁结果由金蝶经 unLockNotifyBusiData 回调 WLTMS 通知(见 transport 侧公开端点)
*
* @param accessToken 访问令牌,通过 getToken 获取
* @param param 锁单参数
* @return 锁单处理结果
*/
@PostMapping(LOCK_BILL_URL)
BfiBillLockResultVO lockBusiData(@RequestHeader(BfiConstant.HEADER_ACCESS_TOKEN) String accessToken, @RequestBody BfiBillLockDTO param);
}
@@ -0,0 +1,90 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* of this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 业财融合(BFI)单据锁定/解锁通知参数(lockBusiData 与 unLockNotifyBusiData 出入参共用)。
* <p>lockBusiData:WLTMS 调金蝶,sourceSystem=WLTMS、targetSystem=XH、lockAction=LOCK;
* unLockNotifyBusiData:金蝶调 WLTMS,sourceSystem=XH、targetSystem=WLTMS、lockAction=UNLOCK,
* operationType=DELETE 时 WLTMS 侧需废除源单并还原关联数据。
* 传参约定:接口 1对1,单次仅一个源单号(sourceBillNo)对一个金蝶单号(targetBillNo),
* time/operator 按接口文档为选传字段(示例报文未携带),非空时才送</p>
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BfiBillLockDTO extends BfiBaseDTO {
@Serial
private static final long serialVersionUID = 1L;
/**
* 【必填】操作类型:LOCK-锁定,UNLOCK-解锁
*/
private String lockAction;
/**
* 【必填】源系统标识,即接口调用方:WLTMS / XH
*/
private String sourceSystem;
/**
* 【必填】目标系统标识,即接口目标接收方:WLTMS / XH
*/
private String targetSystem;
/**
* 【必填】来源操作类型:SAVE-单据新增,DELETE-单据删除
*/
private String operationType;
/**
* 【必填】源单据类型:调用方单据类型(WLTMS 自定义:SETTLEMENT/INVOICE_APPLY,金蝶固定:ApFin_other_BT_S 等)
*/
private String sourceBillType;
/**
* 【必填】源单据编号,与 targetBillNo 一对一
*/
private String sourceBillNo;
/**
* 【必填】目标单据类型:接收方单据类型(金蝶固定:ApFin_other_BT_S 等,WLTMS 自定义:SETTLEMENT 等)
*/
private String targetBillType;
/**
* 【必填】目标单据编号,与 sourceBillNo 一对一
*/
private String targetBillNo;
/**
* 操作时间,格式:yyyy-MM-dd HH:mm:ss(非空才送)
*/
private String time;
/**
* 操作人名字:推单用发起人,删除用操作人(非空才送)
*/
private String operator;
}
@@ -0,0 +1,69 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 业财融合(BFI)A801-5 黑名单查询参数
*
* @author Chill
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BfiBlacklistQueryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 使用状态[1:可用, 0:禁用]
*/
private String enable;
/**
* 企业税号,数组
*/
private List<String> number;
/**
* 企业名称,数组
*/
private List<String> name;
/**
* 【必填】页码,从1开始
*/
private Integer pageNo;
/**
* 【必填】页大小
*/
private Integer pageSize;
}
@@ -36,7 +36,7 @@ import java.io.Serializable;
* <p>
* 请求示例:
* <pre>{@code
* GET /ierp/kapi/v2/awrp/cas/cas_claimannounce/query?claimusers=苏浩晖&pageSize=10&pageNo=1
* GET /ierp/kapi/v2/awrp/cas/cas_claimannounce/query?claimusers=苏浩晖&billstatus=0&modifytimeS=2024-01-01&modifytimeE=2024-06-30&pageNo=1&pageSize=10
* }</pre>
*
* @author Chill
@@ -50,6 +50,18 @@ public class BfiClaimAnnounceQueryDTO implements Serializable {
* 【必填】参与认领用户名
*/
private String claimusers;
/**
* 单据状态(0-未认领,1-已认领)
*/
private String billstatus;
/**
* 【必填】修改时间-开始时间,格式:yyyy-MM-dd
*/
private String modifytimeS;
/**
* 【必填】修改时间-结束时间,格式:yyyy-MM-dd
*/
private String modifytimeE;
/**
* 【必填】页码,从1开始
*/
@@ -25,6 +25,7 @@
*/
package org.springblade.thirdparty.bfi.pojo.dto;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@@ -40,6 +41,9 @@ import java.math.BigDecimal;
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,
getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
public class BfiClaimPushEntryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@@ -61,7 +65,7 @@ public class BfiClaimPushEntryDTO implements Serializable {
/**
* 分录行号
*/
private Integer seq;
private Long seq;
/**
* 收款类型.编码
*/
@@ -307,4 +307,16 @@ public class BfiInvoiceApplySaveDTO implements Serializable {
*/
@JsonProperty("sim_original_bill_item")
private List<BfiInvoiceApplySaveEntryDTO> simOriginalBillItem;
/**
* 货物运输单据体(特殊票种 E04 货物运输时填写)
*/
private List<BfiInvoiceApplySaveFreightDTO> freights;
/**
* 旅客运输单据体(特殊票种 E09 旅客运输时填写)
*/
private List<BfiInvoiceApplySaveTravelerDTO> travelers;
/**
* 代收车船税单据体(特殊票种 E07 代收车船税时填写)
*/
private List<BfiInvoiceApplySaveVehicheVesselShipDTO> vehichevesselships;
}
@@ -0,0 +1,73 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 业财融合(BFI)A303-1 开票申请单新增 货物运输单据体(特殊票种 E04 货物运输时填写)
*
* @author Chill
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BfiInvoiceApplySaveFreightDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 星瀚内码
*/
private Long id;
/**
* 分录行号
*/
private Integer seq;
/**
* 运输工具种类[铁路运输:铁路运输, 公路运输:公路运输, 水路运输:水路运输, 航空运输:航空运输, 管道运输:管道运输, 其它运输工具:其它运输工具]
*/
private String transporttype;
/**
* 运输工具牌号
*/
private String licenseplate;
/**
* 运输货物名称
*/
private String transportgoods;
/**
* 起运地
*/
private String startplace;
/**
* 到达地
*/
private String endplace;
}
@@ -0,0 +1,88 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 业财融合(BFI)A303-1 开票申请单新增 旅客运输单据体(特殊票种 E09 旅客运输时填写)
*
* @author Chill
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BfiInvoiceApplySaveTravelerDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 星瀚内码
*/
private Long id;
/**
* 分录行号
*/
private Integer seq;
/**
* 出行人
*/
private String traveler;
/**
* 出行人证件类型
*/
private String travelercardtype;
/**
* 有效身份证件号
*/
private String travelercardno;
/**
* 出行日期,格式:yyyy-MM-dd
*/
private String traveldate;
/**
* 旅客出发地
*/
private String travelerstartplace;
/**
* 旅客到达地
*/
private String travelerendplace;
/**
* 交通工具类型[1:飞机, 2:火车, 3:长途汽车, 4:公共交通, 5:出租车, 6:汽车, 7:船舶, 9:其他]
*/
private String travelertransporttype;
/**
* 等级[公务舱:飞机-公务舱, 头等舱:飞机-头等舱, 经济舱:飞机-经济舱, 一等舱:船舶-一等舱, 二等舱:船舶-二等舱, 三等舱:船舶-三等舱, 一等座:火车-一等座, 二等座:火车-二等座, 软席(软座、软卧):火车-软席(软座、软卧), 硬席(硬座、硬卧):火车-硬席(硬座、硬卧)]
*/
private String travelerseatclass;
/**
* 等级(自定义文本)
*/
private String travelerseatclassstr;
}
@@ -0,0 +1,89 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 业财融合(BFI)A303-1 开票申请单新增 代收车船税单据体(特殊票种 E07 代收车船税时填写)
*
* @author Chill
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BfiInvoiceApplySaveVehicheVesselShipDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 星瀚内码
*/
private Long id;
/**
* 分录行号
*/
private Integer seq;
/**
* 保险单号
*/
private String policyno;
/**
* 车牌号/船舶登记号
*/
private String shipsno;
/**
* 税款所属期
*/
private String perioddate;
/**
* 车辆识别代码/车架号码
*/
private String vehiclecode;
/**
* 代收车船税金额
*/
private BigDecimal vehiclevesselamount;
/**
* 滞纳金金额
*/
private BigDecimal vehiclelateamount;
/**
* 金额合计
*/
private BigDecimal vehicletotalamount;
/**
* 税款所属期起,格式:yyyy-MM-dd
*/
private String periodstartdate;
/**
* 税款所属期止,格式:yyyy-MM-dd
*/
private String periodenddate;
}
@@ -0,0 +1,57 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.vo;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 业财融合(BFI)A902 附件上传返回数据
* <p>
* 响应示例:
* <pre>{@code
* {
* "data": {"path": "211e6ce5c9805c00"},
* "errorCode": "0",
* "status": true
* }
* }</pre>
*
* @author Chill
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class BfiAttachmentUploadVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 金蝶侧文件路径(附件面板回显/排查用)
*/
private String path;
}
@@ -0,0 +1,78 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* of this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 业财融合(BFI)单据锁定/解锁通知处理结果。
* <p>lockBusiData(金蝶返回)与 unLockNotifyBusiData(WLTMS 回调应答)同构:
* updateCount 为处理单据数,updateResultList 为逐单处理结果(1-成功,0-失败/未匹配),
* 批量传参时单据编号逗号拼接、结果列表与传参顺序对应</p>
*
* @author Chill
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BfiBillLockResultVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 处理单据数量
*/
private Integer updateCount;
/**
* 逐单处理结果:1-成功,0-失败/未匹配
*/
private List<Integer> updateResultList;
/**
* 组装成功应答
*
* @param count 处理单据数
* @return 应答结果
*/
public static BfiBillLockResultVO of(int count) {
BfiBillLockResultVO result = new BfiBillLockResultVO();
result.setUpdateCount(count);
result.setUpdateResultList(count > 0 ? List.of(1) : List.of(0));
return result;
}
/**
* 是否全部处理成功
*
* @return true-更新数量大于0
*/
public boolean isSuccess() {
return updateCount != null && updateCount > 0;
}
}
@@ -0,0 +1,108 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 业财融合(BFI)A801-5 黑名单查询返回结果
*
* @author Chill
*/
@Data
public class BfiBlacklistVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 企业税号
*/
private String number;
/**
* 企业名称
*/
private String name;
/**
* 数据状态[A:暂存, B:已提交, C:已审核]
*/
private String status;
/**
* 数据状态标题
*/
@JsonProperty("status_title")
private String statusTitle;
/**
* 使用状态[0:禁用, 1:可用]
*/
private String enable;
/**
* 使用状态标题
*/
@JsonProperty("enable_title")
private String enableTitle;
/**
* 创建时间
*/
private String createtime;
/**
* 修改时间
*/
private String modifytime;
/**
* 主数据内码
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long masterid;
/**
* 上报单位(部门)
*/
@JsonProperty("awrp_textfield1")
private String awrpTextfield1;
/**
* 失信类别[A:禁止交易类, B:风险警示类]
*/
private String awrpCombofield;
/**
* 失信类别标题
*/
@JsonProperty("awrp_combofield_title")
private String awrpCombofieldTitle;
/**
* 列入事由
*/
@JsonProperty("awrp_textareafield")
private String awrpTextareafield;
}
@@ -217,6 +217,14 @@ public class BfiInvoiceApplyOpenApiInvoiceVO implements Serializable {
* 发票图片URL
*/
private String invoiceImageUrl;
/**
* 数电PDF下载地址(发票云5.0.025版本返回)
*/
private String invoicePdfFileUrl;
/**
* 数电XML下载地址(发票云5.0.025版本返回)
*/
private String invoiceXmlFileUrl;
/**
* 开具状态
*/
@@ -518,10 +518,10 @@ public class BfiInvoicePoolVO implements Serializable {
@JsonProperty("taxXmlUrl")
private String taxXmlUrl;
/**
* 出行人列表,客运票
* 出行人列表,客运票;票易通多数场景返回字符串数组,部分数据源(如发票助手)返回对象数组,宽松承载防解析失败
*/
@JsonProperty("travelerList")
private List<String> travelerList;
private List<Object> travelerList;
/**
* 发票抬头
*/
@@ -30,6 +30,7 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiBillLockDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimAnnounceQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimPushDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerQueryDTO;
@@ -49,7 +50,9 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiReceivedInvoiceSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiRecBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiApBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiArBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiAttachmentUploadVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBlacklistVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiClaimAnnounceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiCustomerVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiExchangeRateVO;
@@ -123,6 +126,15 @@ public interface IBfiService {
*/
List<BfiExchangeRateVO> queryExchangeRate(LocalDate effectdate, LocalDate effectdateE);
/**
* A801-5 黑名单查询
*
* @param enable 使用状态[1:可用, 0:禁用]
* @param number 企业税号数组,按税号过滤时传
* @return 黑名单列表
*/
List<BfiBlacklistVO> queryBlacklist(String enable, List<String> number);
/**
* A103-1 付款申请保存(根据星瀚应付下推付款申请)
*
@@ -263,12 +275,10 @@ public interface IBfiService {
/**
* A301-2 收款认领公告查询
*
* @param claimusers 参与认领用户名
* @param pageNo 页码,从1开始
* @param pageSize 页数
* @param param 查询参数,claimusers/modifytimeS/modifytimeE 必填,页码从1开始
* @return 收款认领公告分页数据
*/
BfiPageVO<BfiClaimAnnounceVO> queryClaimAnnounce(String claimusers, Integer pageNo, Integer pageSize);
BfiPageVO<BfiClaimAnnounceVO> queryClaimAnnounce(BfiClaimAnnounceQueryDTO param);
/**
* A301-3 收款认领结果推送
@@ -293,4 +303,25 @@ public interface IBfiService {
* @return 文件流响应,调用方负责关闭
*/
Response downloadInvoice(String path);
/**
* A902 附件上传到指定单据
*
* @param entityNumber 星瀚单据标识(如 ap_payapply)
* @param billPkId 星瀚单据内码(保存/查询响应返回的 id)
* @param controlKey 附件面板标识,统一 attachmentpanel
* @param fileName 附件名称(含扩展名)
* @param fileContent 附件内容
* @return 上传结果,path 即金蝶侧文件路径
*/
BfiAttachmentUploadVO uploadAttachment(String entityNumber, String billPkId, String controlKey, String fileName, byte[] fileContent);
/**
* 单据锁定(lockBusiData):推送金蝶成功后锁定目标单据,接口 1对1(单次一个源单号对一个金蝶单号),
* 解锁结果由金蝶回调 unLockNotifyBusiData 通知
*
* @param param 锁单参数,操作类型固定 LOCK,源系统 WLTMS、目标系统 XH
* @return true-锁定成功(updateCount 大于 0)
*/
boolean lockBusiData(BfiBillLockDTO param);
}
@@ -31,6 +31,7 @@ import feign.Response;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.thirdparty.bfi.config.BfiProperties;
import org.springblade.thirdparty.bfi.constant.BfiConstant;
@@ -42,6 +43,9 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillSaveBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiBillLockDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiBlacklistQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimAnnounceQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimPushBodyDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimPushDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerQueryDTO;
@@ -73,7 +77,10 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiVerifyTokenDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiWithdrawTokenDTO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiApBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiArBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiAttachmentUploadVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillLockResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBlacklistVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiClaimAnnounceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiCustomerVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiExchangeRateVO;
@@ -91,6 +98,8 @@ import org.springblade.thirdparty.bfi.pojo.vo.BfiTokenVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiVerifyTokenVO;
import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.thirdparty.bfi.util.BfiUtil;
import org.springblade.thirdparty.bfi.util.InMemoryMultipartFile;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
@@ -215,6 +224,24 @@ public class BfiServiceImpl implements IBfiService {
return queryExchangeRate(effectdate.format(DATE_FORMATTER), effectdateE.format(DATE_FORMATTER));
}
@Override
public List<BfiBlacklistVO> queryBlacklist(String enable, List<String> number) {
if (StringUtil.isBlank(enable)) {
throw new BfiException("查询BFI黑名单失败,使用状态不能为空");
}
BfiBlacklistQueryDTO param = new BfiBlacklistQueryDTO();
param.setEnable(enable);
if (Func.isNotEmpty(number)) {
param.setNumber(number);
}
String accessToken = getAccessToken();
return BfiUtil.queryAllPages(pageNo -> {
param.setPageNo(pageNo);
param.setPageSize(BfiConstant.BLACKLIST_QUERY_PAGE_SIZE);
return commonCall("黑名单查询", () -> client.blacklistQuery(accessToken, param)).getData();
});
}
@Override
public BfiBillSaveResultVO pushPayApply(BfiPayApplyPushDTO param) {
if (param == null || StringUtil.isBlank(param.getAwrpSrcCode()) || StringUtil.isBlank(param.getAwrpSrcSys())) {
@@ -345,6 +372,33 @@ public class BfiServiceImpl implements IBfiService {
return result.getData();
}
@Override
public boolean lockBusiData(BfiBillLockDTO param) {
if (param == null || StringUtil.isBlank(param.getLockAction()) || StringUtil.isBlank(param.getSourceSystem())
|| StringUtil.isBlank(param.getTargetSystem()) || StringUtil.isBlank(param.getOperationType())
|| StringUtil.isBlank(param.getSourceBillType()) || StringUtil.isBlank(param.getSourceBillNo())
|| StringUtil.isBlank(param.getTargetBillType()) || StringUtil.isBlank(param.getTargetBillNo())) {
throw new BfiException("BFI单据锁定失败,操作类型/源目标系统/操作类型/单据类型与编号不能为空");
}
// 锁单应答为 {updateCount, updateResultList} 裸结构(非 BfiResultVO 包装),独立校验
try {
String accessToken = getAccessToken();
BfiBillLockResultVO result = client.lockBusiData(accessToken, param);
if (result != null && result.isSuccess()) {
return true;
}
log.error("调用BFI接口单据锁定异常响应参数:{}", JSONUtil.toJsonStr(result));
throw new BfiException("调用BFI接口单据锁定异常,应答缺少updateCount字段(金蝶侧可能返回了请求回显、未实际处理锁定) updateCount="
+ (result == null ? "无响应" : result.getUpdateCount()));
} catch (BfiException e) {
log.error("调用BFI接口单据锁定,BfiException异常", e);
throw e;
} catch (Exception e) {
log.error("调用BFI接口单据锁定异常", e);
throw new BfiException("调用BFI接口单据锁定异常", e);
}
}
@Override
public BfiPageVO<BfiArBillVO> queryArBill(BfiArBillQueryDTO param) {
if (param == null || param.getPageNo() == null || param.getPageSize() == null) {
@@ -470,15 +524,19 @@ public class BfiServiceImpl implements IBfiService {
}
@Override
public BfiPageVO<BfiClaimAnnounceVO> queryClaimAnnounce(String claimusers, Integer pageNo, Integer pageSize) {
if (StringUtil.isBlank(claimusers)) {
public BfiPageVO<BfiClaimAnnounceVO> queryClaimAnnounce(BfiClaimAnnounceQueryDTO param) {
if (param == null || StringUtil.isBlank(param.getClaimusers())) {
throw new BfiException("查询BFI收款认领公告失败,参与认领用户名不能为空");
}
if (pageNo == null || pageSize == null) {
if (StringUtil.isBlank(param.getModifytimeS()) || StringUtil.isBlank(param.getModifytimeE())) {
throw new BfiException("查询BFI收款认领公告失败,修改时间范围不能为空");
}
if (param.getPageNo() == null || param.getPageSize() == null) {
throw new BfiException("查询BFI收款认领公告失败,分页参数不能为空");
}
String accessToken = getAccessToken();
BfiResultVO<BfiPageVO<BfiClaimAnnounceVO>> result = commonCall("收款认领公告查询", () -> client.claimAnnounceQuery(accessToken, claimusers, pageNo, pageSize));
BfiResultVO<BfiPageVO<BfiClaimAnnounceVO>> result = commonCall("收款认领公告查询", () -> client.claimAnnounceQuery(accessToken,
param.getClaimusers(), param.getBillstatus(), param.getModifytimeS(), param.getModifytimeE(), param.getPageNo(), param.getPageSize()));
return result.getData();
}
@@ -533,12 +591,15 @@ public class BfiServiceImpl implements IBfiService {
BfiInvoiceDownloadDTO param = new BfiInvoiceDownloadDTO();
param.setPath(path);
String accessToken = getAccessToken();
long start = System.currentTimeMillis();
log.info("调用BFI接口 进项发票下载开始 path:{}", path);
try {
Response response = client.invoiceDownload(accessToken, param);
if (response == null || response.status() != 200) {
log.error("调用BFI接口 进项发票下载异常响应状态:{}", response == null ? "无响应" : response.status());
throw new BfiException("调用BFI接口进项发票下载异常,响应状态:" + (response == null ? "无响应" : response.status()));
}
log.info("调用BFI接口 进项发票下载结束 耗时:{}ms", System.currentTimeMillis() - start);
return response;
} catch (BfiException e) {
throw e;
@@ -548,6 +609,34 @@ public class BfiServiceImpl implements IBfiService {
}
}
@Override
public BfiAttachmentUploadVO uploadAttachment(String entityNumber, String billPkId, String controlKey, String fileName, byte[] fileContent) {
if (StringUtil.isBlank(entityNumber) || StringUtil.isBlank(billPkId)) {
throw new BfiException("上传BFI附件失败,entityNumber与billPkId不能为空");
}
if (StringUtil.isBlank(fileName) || fileContent == null || fileContent.length == 0) {
throw new BfiException("上传BFI附件失败,附件名称与内容不能为空");
}
String accessToken = getAccessToken();
// A902 参数原文 JSON:{"entityNumber":"ap_payapply","billPkId":2386455983883835392,"controlKey":"attachmentpanel"}
JSONObject args = new JSONObject();
args.set("entityNumber", entityNumber);
args.set("billPkId", billPkId);
args.set("controlKey", StringUtil.isBlank(controlKey) ? "attachmentpanel" : controlKey);
InMemoryMultipartFile file = new InMemoryMultipartFile("file", fileName, MediaType.APPLICATION_OCTET_STREAM_VALUE, fileContent);
long start = System.currentTimeMillis();
log.info("调用BFI接口 附件上传开始 entityNumber:{},billPkId:{},文件:{},大小:{}字节",
entityNumber, billPkId, fileName, fileContent.length);
BfiResultVO<BfiAttachmentUploadVO> result = commonCall("附件上传", () -> client.uploadAttachment(accessToken, file, args.toString()));
BfiAttachmentUploadVO uploadVO = result.getData();
if (uploadVO == null || StringUtil.isBlank(uploadVO.getPath())) {
log.error("调用BFI接口 附件上传返回数据为空:{}", JSONUtil.toJsonStr(result));
throw new BfiException("调用BFI接口附件上传异常,返回数据为空");
}
log.info("调用BFI接口 附件上传结束 耗时:{}ms,kingdeePath:{}", System.currentTimeMillis() - start, uploadVO.getPath());
return uploadVO;
}
/**
* 公共调用方法,统一校验响应结果
*
@@ -0,0 +1,101 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.thirdparty.bfi.util;
import org.springframework.lang.NonNull;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 内存字节数组版 MultipartFile:A902 附件上传经 Feign multipart 发送时使用,
* 文件内容已整体读入内存(单文件软限制 20MB,见 KingdeeAttachmentConstant)
*
* @author Chill
*/
public class InMemoryMultipartFile implements MultipartFile {
private final String name;
private final String originalFilename;
private final String contentType;
private final byte[] content;
public InMemoryMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
this.name = name;
this.originalFilename = originalFilename;
this.contentType = contentType;
this.content = content == null ? new byte[0] : content;
}
@Override
@NonNull
public String getName() {
return name;
}
@Override
public String getOriginalFilename() {
return originalFilename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return content.length == 0;
}
@Override
public long getSize() {
return content.length;
}
@Override
@NonNull
public byte[] getBytes() {
return content;
}
@Override
@NonNull
public InputStream getInputStream() {
return new ByteArrayInputStream(content);
}
@Override
public void transferTo(@NonNull File destination) throws IOException {
try (FileOutputStream outputStream = new FileOutputStream(destination)) {
outputStream.write(content);
}
}
}
@@ -46,11 +46,12 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiArBillSaveEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimAnnounceQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimPushDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiClaimPushEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerGroupEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerGroupEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplyOpenApiQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplyQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplySaveDTO;
@@ -60,10 +61,10 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceAssignItemDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceAssignRefDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoicePoolQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoicePoolQueryDataDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiRecBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiReceivedInvoiceQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiReceivedInvoiceSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiReceivedInvoiceSaveEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiRecBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiTokenDTO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiApBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiArBillVO;
@@ -74,31 +75,21 @@ import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoiceApplyVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoicePoolVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiOpenApiResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiReceivedInvoiceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiRecBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiReceivedInvoiceVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiTokenVO;
import org.springframework.data.redis.core.ValueOperations;
import org.springblade.thirdparty.bfi.service.impl.BfiServiceImpl;
import org.springframework.data.redis.core.ValueOperations;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
/**
* 业财融合(BFI)服务实现单元测试
@@ -480,16 +471,28 @@ class BfiServiceImplTest {
@Test
void queryClaimAnnounceShouldValidateParams() {
assertThrows(BfiException.class, () -> service.queryClaimAnnounce(null, 1, 10));
assertThrows(BfiException.class, () -> service.queryClaimAnnounce("张三", null, 10));
BfiClaimAnnounceQueryDTO nullParam = null;
assertThrows(BfiException.class, () -> service.queryClaimAnnounce(nullParam));
BfiClaimAnnounceQueryDTO noTimeRange = new BfiClaimAnnounceQueryDTO();
noTimeRange.setClaimusers("张三");
noTimeRange.setPageNo(1);
noTimeRange.setPageSize(10);
assertThrows(BfiException.class, () -> service.queryClaimAnnounce(noTimeRange));
}
@Test
void queryClaimAnnounceShouldReturnPage() {
mockAccessToken();
BfiPageVO<BfiClaimAnnounceVO> page = new BfiPageVO<>();
when(client.claimAnnounceQuery("token-1", "张三", 1, 10)).thenReturn(success(page));
assertEquals(page, service.queryClaimAnnounce("张三", 1, 10));
when(client.claimAnnounceQuery("token-1", "张三", null, "2026-01-01", "2026-06-30", 1, 10)).thenReturn(success(page));
BfiClaimAnnounceQueryDTO param = new BfiClaimAnnounceQueryDTO();
param.setClaimusers("张三");
param.setModifytimeS("2026-01-01");
param.setModifytimeE("2026-06-30");
param.setPageNo(1);
param.setPageSize(10);
assertEquals(page, service.queryClaimAnnounce(param));
}
@Test
@@ -17,9 +17,14 @@ public class MKProcessCreateDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 表单实例id,业务id
* 表单实例id(传给 MK;由后端生成,前端勿传)
*/
private String formInstanceId;
/**
* 业务主键,仅 ERP 内部使用,不传给 MK
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String bizId;
/**
* 标题
*/
@@ -50,4 +55,9 @@ public class MKProcessCreateDTO implements Serializable {
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String bizType;
/**
* 强制生成新表单实例(审核通过后再次提交),仅 ERP 内部使用,不传给 MK
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Boolean forceNewFormInstance;
}
@@ -323,10 +323,13 @@ public class MKServiceImpl implements IMKService {
return null;
}
String code = codeVO.getCode();
// 跳转域名使用 thirdParty.mk.baseUrl(loginUrl 在部分环境未配置会导致拼出相对路径 null/...)
AssertUtils.notBlank(properties.getBaseUrl(), "未配置 thirdParty.mk.baseUrl");
String mkBaseUrl = StringUtil.removeSuffix(properties.getBaseUrl().trim(), StringPool.SLASH);
// 审批页面地址
String approvalUrl = String.format(APPROVAL_URL_FORMAT, properties.getLoginUrl(), processInstanceId, processInstanceId);
String approvalUrl = String.format(APPROVAL_URL_FORMAT, mkBaseUrl, processInstanceId, processInstanceId);
// sso回调地址
return String.format(SSO_CALLBACK_URL_FORMAT, properties.getLoginUrl(), code, UrlUtil.encode(approvalUrl));
return String.format(SSO_CALLBACK_URL_FORMAT, mkBaseUrl, code, UrlUtil.encode(approvalUrl));
}
@Override
@@ -31,7 +31,35 @@ public class OAConvertConstant {
*/
public static final Long ROOT_PARENT_ID = 0L;
/**
* 同步人员时挂载的顶级组织名称
* OA 同步挂载的本地顶级组织主键(集团)
*/
public static final String ROOT_COMPANY_NAME = "桂物物流集团";
public static final Long OA_SYNC_ROOT_DEPT_ID = 135L;
/**
* OA 同步挂载的本地顶级组织默认名称(集团;已存在时不覆盖原名称,除非误写成外部组织)
*/
public static final String OA_SYNC_ROOT_DEPT_NAME = "桂物物流集团";
/**
* OA 同步挂载的本地顶级组织编码(集团)
*/
public static final String OA_SYNC_ROOT_DEPT_CODE = "GWWL";
/**
* 承运商等业务使用的外部组织顶级名称(与集团顶级并存)
*/
public static final String EXTERNAL_ORG_NAME = "外部组织";
/**
* 组织编码分段数字位数(不足补零)
*/
public static final int DEPT_CODE_SEGMENT_WIDTH = 3;
/**
* 历史人员同步创建的伪顶级编码,同步时需清理
*/
public static final String LEGACY_ROOT_DEPT_CODE = "OACROOT";
/**
* 历史人员同步创建的伪顶级名称(与集团同名时仅清理非 id=135 的记录)
*/
public static final String LEGACY_ROOT_DEPT_NAME = "桂物物流集团";
/**
* 同步人员时挂载的顶级组织名称(兼容旧引用)
*/
public static final String ROOT_COMPANY_NAME = OA_SYNC_ROOT_DEPT_NAME;
}