feat: A303-1 开票申请推送放开特殊票种E04并随单报送货物运输单据体
This commit is contained in:
+6
@@ -159,6 +159,12 @@ public final class KingdeeBfiConstant {
|
||||
/** A303-1 特殊票种货物运输判定关键字:命中商品名称或商品和服务分类简称即视为货物运输类。 */
|
||||
public static final List<String> BFI_INVOICE_FREIGHT_KEYWORDS = List.of("货物运输", "运费");
|
||||
|
||||
/** A303-1 货物运输单据体运输工具种类合法值:字典 transport_type 翻译名称命中则直送,否则兜底其它运输工具。 */
|
||||
public static final List<String> BFI_FREIGHT_TRANSPORT_TYPES = List.of("铁路运输", "公路运输", "水路运输", "航空运输", "管道运输", "其它运输工具");
|
||||
|
||||
/** A303-1 货物运输单据体运输工具种类兜底值。 */
|
||||
public static final String BFI_FREIGHT_TRANSPORT_TYPE_OTHER = "其它运输工具";
|
||||
|
||||
/** 金蝶同步状态:开票完成(A303-5 查到发票,终态,开票申请专用)。 */
|
||||
public static final String KINGDEE_STATUS_INVOICED = "invoiced";
|
||||
|
||||
|
||||
+80
-2
@@ -44,6 +44,7 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplyOpenApiQueryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplyQueryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplySaveDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplySaveEntryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiInvoiceApplySaveFreightDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoiceApplyOpenApiBillVO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoiceApplyOpenApiInvoiceVO;
|
||||
@@ -97,6 +98,7 @@ import org.springblade.transport.support.KingdeeArBillSyncSupport;
|
||||
import org.springblade.transport.support.KingdeeSyncLockSupport;
|
||||
import org.springblade.transport.support.KingdeeAttachmentSyncSupport;
|
||||
import org.springblade.transport.wrapper.InvoiceApplicationWrapper;
|
||||
import org.springblade.transport.wrapper.WaybillWrapper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -780,8 +782,18 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
|
||||
param.setTotalamount(sheetAmount);
|
||||
// 是否含税:金蝶要求统一按不含税口径送(联调反馈),固定 0 不含税
|
||||
param.setHsbz("0");
|
||||
// todo 特殊票种:金蝶要求映射(联调反馈)——本张发票商品行全部为货物运输(运费/货物运输)送 E04,其余(其他、非货物运输的运输类等)送 00 非特殊票种
|
||||
// param.setSpecialtype(this.specialTypeOf(items));
|
||||
// 特殊票种:金蝶要求映射(联调反馈)——本张发票商品行全部为货物运输(运费/货物运输)送 E04,其余(其他、非货物运输的运输类等)送 00 非特殊票种
|
||||
param.setSpecialtype(this.specialTypeOf(items));
|
||||
// 货物运输单据体:送 E04 时随单填报(车牌/起运地/到达地/货物名称取开票申请结算明细快照),数据为空不阻断推送
|
||||
if (KingdeeBfiConstant.BFI_INVOICE_SPECIAL_TYPE_FREIGHT.equals(param.getSpecialtype())) {
|
||||
List<BfiInvoiceApplySaveFreightDTO> freights = this.buildFreights(entity);
|
||||
if (Func.isNotEmpty(freights)) {
|
||||
param.setFreights(freights);
|
||||
} else {
|
||||
log.warn("金蝶开票申请推送:开票申请[{}]按货物运输特殊票种(E04)推送但无结算明细快照,货物运输单据体未填报",
|
||||
entity.getApplicationNo());
|
||||
}
|
||||
}
|
||||
// 【必填】客户.编码:受票方客商档案客商编码
|
||||
param.setCustomnameidNumber(customer.getCustomerCode());
|
||||
// 【必填】项目.项目编码(联调期临时传金蝶测试档案值 999)
|
||||
@@ -893,6 +905,72 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
|
||||
return KingdeeBfiConstant.BFI_INVOICE_FREIGHT_KEYWORDS.stream().anyMatch(goodsText::contains);
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装 A303-1 货物运输单据体(特殊票种 E04 随单报送)。
|
||||
* <p>
|
||||
* 金蝶数电货运发票要求随单报送运输工具信息,取数与组装规则:
|
||||
* <ul>
|
||||
* <li>数据来源:开票申请结算明细快照(blade_invoice_application_detail,制单时自正式结算明细快照,含车牌/线路/货物运输信息)</li>
|
||||
* <li>字段映射:vehicleNo→licenseplate(运输工具牌号)、departureAddress→startplace(起运地)、
|
||||
* arrivalAddress→endplace(到达地)、cargoName→transportgoods(运输货物名称)、
|
||||
* transportType→transporttype(运输工具种类,字典键翻译后映射,见 {@link #kingdeeTransportTypeOf(String)})</li>
|
||||
* <li>行归并:结算明细按车次成行,同一「车牌×起运地×到达地×货物×运输工具种类」的多笔明细只报送一条</li>
|
||||
* <li>空行剔除:牌号/起运地/到达地/货物名称均为空的明细行不报送(快照缺运输信息),避免金蝶侧空行报错</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param entity 开票申请
|
||||
* @return 货物运输单据体分录(无可用快照数据时返回空列表,由调用方决定是否告警)
|
||||
*/
|
||||
private List<BfiInvoiceApplySaveFreightDTO> buildFreights(InvoiceApplication entity) {
|
||||
List<InvoiceApplicationDetail> details = applicationDetailMapper.selectList(
|
||||
Wrappers.<InvoiceApplicationDetail>lambdaQuery()
|
||||
.eq(InvoiceApplicationDetail::getInvoiceApplicationId, entity.getId()));
|
||||
// 按运程归并键去重:结算明细按车次成行,同一运程多笔明细金蝶侧只需一条(LinkedHashMap 保持明细行序)
|
||||
Map<String, BfiInvoiceApplySaveFreightDTO> freightByKey = new LinkedHashMap<>();
|
||||
int emptyRowSkipCount = 0;
|
||||
for (InvoiceApplicationDetail detail : details) {
|
||||
BfiInvoiceApplySaveFreightDTO freight = new BfiInvoiceApplySaveFreightDTO();
|
||||
// 运输工具种类:字典 transport_type 键翻译后映射合法枚举,未命中兜底其它运输工具
|
||||
freight.setTransporttype(this.kingdeeTransportTypeOf(detail.getTransportType()));
|
||||
// 运输工具牌号/运输货物名称/起运地/到达地:结算明细快照直传
|
||||
freight.setLicenseplate(detail.getVehicleNo());
|
||||
freight.setTransportgoods(detail.getCargoName());
|
||||
freight.setStartplace(detail.getDepartureAddress());
|
||||
freight.setEndplace(detail.getArrivalAddress());
|
||||
// 全空明细行(快照缺运输信息)不报送,避免金蝶侧空行报错
|
||||
if (Func.isBlank(freight.getLicenseplate()) && Func.isBlank(freight.getStartplace())
|
||||
&& Func.isBlank(freight.getEndplace()) && Func.isBlank(freight.getTransportgoods())) {
|
||||
emptyRowSkipCount++;
|
||||
continue;
|
||||
}
|
||||
String dedupeKey = Func.toStr(freight.getLicenseplate()) + "|" + Func.toStr(freight.getStartplace())
|
||||
+ "|" + Func.toStr(freight.getEndplace()) + "|" + Func.toStr(freight.getTransportgoods())
|
||||
+ "|" + Func.toStr(freight.getTransporttype());
|
||||
freightByKey.putIfAbsent(dedupeKey, freight);
|
||||
}
|
||||
List<BfiInvoiceApplySaveFreightDTO> freights = new ArrayList<>(freightByKey.values());
|
||||
log.info("金蝶开票申请货物运输单据体组装:开票申请[{}],结算明细快照{}条,剔除空行{}条,去重归并后分录{}条",
|
||||
entity.getApplicationNo(), details.size(), emptyRowSkipCount, freights.size());
|
||||
freights.forEach(freight -> log.info("金蝶开票申请货物运输分录:开票申请[{}],运输工具种类[{}],牌号[{}],货物[{}],起运地[{}],到达地[{}]",
|
||||
entity.getApplicationNo(), freight.getTransporttype(), freight.getLicenseplate(),
|
||||
freight.getTransportgoods(), freight.getStartplace(), freight.getEndplace()));
|
||||
return freights;
|
||||
}
|
||||
|
||||
/**
|
||||
* 运输工具种类映射:结算明细快照存字典 transport_type 键,按业务/系统字典翻译为名称
|
||||
* (复用运单展示口径 {@link WaybillWrapper#transportTypeName(String)}),
|
||||
* 翻译名称命中 A303-1 合法枚举(铁路/公路/水路/航空/管道/其它运输工具)直送,否则兜底其它运输工具
|
||||
*
|
||||
* @param transportType 结算明细快照运输方式(字典键)
|
||||
* @return 金蝶运输工具种类
|
||||
*/
|
||||
private String kingdeeTransportTypeOf(String transportType) {
|
||||
String name = WaybillWrapper.transportTypeName(transportType);
|
||||
return KingdeeBfiConstant.BFI_FREIGHT_TRANSPORT_TYPES.contains(name)
|
||||
? name : KingdeeBfiConstant.BFI_FREIGHT_TRANSPORT_TYPE_OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String syncKingdeeInvoiceResult() {
|
||||
return kingdeeSyncLockSupport.runSingleFlight(INVOICE_RESULT_SYNC_LOCK_PREFIX, invoiceResultLockLeaseSeconds,
|
||||
|
||||
Reference in New Issue
Block a user