调整配载、总单
This commit is contained in:
+2
-2
@@ -77,8 +77,8 @@ public interface IReceivablePayableDetailService extends BaseService<ReceivableP
|
|||||||
/** 完成运单后按合同系统计费模式自动生成应收、应付明细。 */
|
/** 完成运单后按合同系统计费模式自动生成应收、应付明细。 */
|
||||||
void generateForCompletedWaybills(List<Long> waybillIds);
|
void generateForCompletedWaybills(List<Long> waybillIds);
|
||||||
|
|
||||||
/** 完成配载单后按其记录的承运商合同自动生成应付明细。 */
|
/** 完成配载单后按其记录的承运商合同汇总生成一条应付明细。 */
|
||||||
void generateForCompletedLoading(List<Long> waybillIds, Long carrierContractId);
|
void generateForCompletedLoading(List<Long> waybillIds, Long carrierContractId, String loadingNo);
|
||||||
|
|
||||||
/** 关闭总单调度后生成总单客户合同应收,并按所属运单记录的承运商合同生成应付。 */
|
/** 关闭总单调度后生成总单客户合同应收,并按所属运单记录的承运商合同生成应付。 */
|
||||||
void generateForClosedMasterOrder(MasterOrder masterOrder);
|
void generateForClosedMasterOrder(MasterOrder masterOrder);
|
||||||
|
|||||||
+2
-2
@@ -300,7 +300,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
syncAssociatedWaybills(loadingManage, STATUS_COMPLETED, new ArrayList<>());
|
syncAssociatedWaybills(loadingManage, STATUS_COMPLETED, new ArrayList<>());
|
||||||
if (result) {
|
if (result) {
|
||||||
receivablePayableDetailService.generateForCompletedLoading(
|
receivablePayableDetailService.generateForCompletedLoading(
|
||||||
associatedWaybillIds, loadingManage.getCarrierContractId());
|
associatedWaybillIds, loadingManage.getCarrierContractId(), loadingManage.getLoadingNo());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -338,7 +338,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
boolean result = updateById(loadingManage);
|
boolean result = updateById(loadingManage);
|
||||||
if (result) {
|
if (result) {
|
||||||
receivablePayableDetailService.generateForCompletedLoading(
|
receivablePayableDetailService.generateForCompletedLoading(
|
||||||
waybillIdList, loadingManage.getCarrierContractId());
|
waybillIdList, loadingManage.getCarrierContractId(), loadingManage.getLoadingNo());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+137
-8
@@ -101,6 +101,7 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
implements IReceivablePayableDetailService {
|
implements IReceivablePayableDetailService {
|
||||||
|
|
||||||
private static final String SOURCE_MASTER_ORDER = "总单系统生成";
|
private static final String SOURCE_MASTER_ORDER = "总单系统生成";
|
||||||
|
private static final String SOURCE_LOADING_ORDER = "配载单系统生成";
|
||||||
|
|
||||||
private final ReceivablePayableCargoFeeMapper cargoFeeMapper;
|
private final ReceivablePayableCargoFeeMapper cargoFeeMapper;
|
||||||
private final ReceivablePayableChangeRecordMapper changeRecordMapper;
|
private final ReceivablePayableChangeRecordMapper changeRecordMapper;
|
||||||
@@ -546,15 +547,28 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW,
|
@Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW,
|
||||||
rollbackFor = Exception.class)
|
rollbackFor = Exception.class)
|
||||||
public void generateForCompletedLoading(List<Long> waybillIds, Long carrierContractId) {
|
public void generateForCompletedLoading(List<Long> waybillIds, Long carrierContractId, String loadingNo) {
|
||||||
|
if (Func.isEmpty(loadingNo)) {
|
||||||
|
throw new ServiceException("配载单号不能为空");
|
||||||
|
}
|
||||||
ContractManage carrierContract = carrierContractId == null
|
ContractManage carrierContract = carrierContractId == null
|
||||||
? null : contractManageService.getById(carrierContractId);
|
? null : contractManageService.getById(carrierContractId);
|
||||||
if (carrierContractId != null && (carrierContract == null
|
if (carrierContractId != null && (carrierContract == null
|
||||||
|| !"承运商合同".equals(carrierContract.getContractCategory()))) {
|
|| !"承运商合同".equals(carrierContract.getContractCategory()))) {
|
||||||
throw new ServiceException("配载单记录的承运商合同不存在或合同类别不正确");
|
throw new ServiceException("配载单记录的承运商合同不存在或合同类别不正确");
|
||||||
}
|
}
|
||||||
generateAutomaticWaybillDetails(loadWaybills(waybillIds), true,
|
List<Waybill> waybills = loadWaybills(waybillIds);
|
||||||
waybill -> carrierContract, AuthUtil.getUserId(), new Date());
|
if (waybills.isEmpty()) return;
|
||||||
|
Long currentUserId = AuthUtil.getUserId();
|
||||||
|
Date generateTime = new Date();
|
||||||
|
generateAutomaticWaybillDetails(waybills, true, waybill -> null, currentUserId, generateTime);
|
||||||
|
generateAutomaticDetail(carrierContract, "payable",
|
||||||
|
() -> existsByLoading(loadingNo, "payable"), waybills,
|
||||||
|
(fees, unitPrice) -> {
|
||||||
|
normalizeWaybillFeeLines(fees);
|
||||||
|
return buildLoadingDetail(loadingNo, carrierContract, waybills, fees, unitPrice);
|
||||||
|
},
|
||||||
|
false, currentUserId, generateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Waybill> loadWaybills(List<Long> waybillIds) {
|
private List<Waybill> loadWaybills(List<Long> waybillIds) {
|
||||||
@@ -679,13 +693,23 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
Map<Long, ContractManage> carrierContracts = contractManageService.listByIds(waybills.stream()
|
Map<Long, ContractManage> carrierContracts = contractManageService.listByIds(waybills.stream()
|
||||||
.map(Waybill::getCarrierContractId).distinct().toList()).stream()
|
.map(Waybill::getCarrierContractId).distinct().toList()).stream()
|
||||||
.collect(Collectors.toMap(ContractManage::getId, contract -> contract));
|
.collect(Collectors.toMap(ContractManage::getId, contract -> contract));
|
||||||
generateAutomaticWaybillDetails(waybills, false, waybill -> {
|
Map<Long, List<Waybill>> carrierWaybills = waybills.stream().collect(Collectors.groupingBy(
|
||||||
ContractManage carrierContract = carrierContracts.get(waybill.getCarrierContractId());
|
Waybill::getCarrierContractId, LinkedHashMap::new, Collectors.toList()));
|
||||||
|
for (Map.Entry<Long, List<Waybill>> entry : carrierWaybills.entrySet()) {
|
||||||
|
ContractManage carrierContract = carrierContracts.get(entry.getKey());
|
||||||
if (carrierContract == null || !"承运商合同".equals(carrierContract.getContractCategory())) {
|
if (carrierContract == null || !"承运商合同".equals(carrierContract.getContractCategory())) {
|
||||||
throw new ServiceException("运单【" + waybill.getWaybillNo() + "】记录的承运商合同不存在或合同类别不正确");
|
throw new ServiceException("总单【" + masterOrder.getMasterNo() + "】记录的承运商合同不存在或合同类别不正确");
|
||||||
|
}
|
||||||
|
List<Waybill> currentCarrierWaybills = entry.getValue();
|
||||||
|
generateAutomaticDetail(carrierContract, "payable",
|
||||||
|
() -> existsByMasterOrderContract(masterOrder.getMasterNo(), "payable", carrierContract.getId()),
|
||||||
|
currentCarrierWaybills,
|
||||||
|
(fees, unitPrice) -> {
|
||||||
|
normalizeWaybillFeeLines(fees);
|
||||||
|
return buildMasterOrderPayableDetail(masterOrder, carrierContract,
|
||||||
|
currentCarrierWaybills, fees, unitPrice);
|
||||||
|
}, false, currentUserId, generateTime);
|
||||||
}
|
}
|
||||||
return carrierContract;
|
|
||||||
}, currentUserId, generateTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAutomaticContract(ContractManage contract, String settlementType) {
|
private boolean isAutomaticContract(ContractManage contract, String settlementType) {
|
||||||
@@ -972,6 +996,46 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReceivablePayableDetail buildLoadingDetail(String loadingNo, ContractManage contract,
|
||||||
|
List<Waybill> waybills,
|
||||||
|
List<ReceivablePayableCargoFee> fees, BigDecimal unitPrice) {
|
||||||
|
Waybill firstWaybill = waybills.get(0);
|
||||||
|
ReceivablePayableDetail detail = buildDetail(firstWaybill, contract, "payable", fees, unitPrice);
|
||||||
|
detail.setSourceType(SOURCE_LOADING_ORDER);
|
||||||
|
detail.setWaybillId(null);
|
||||||
|
detail.setWaybillNo(loadingNo);
|
||||||
|
detail.setCargoName(joinWaybillField(waybills, Waybill::getCargoName));
|
||||||
|
detail.setCargoType(joinWaybillField(waybills, Waybill::getCargoType));
|
||||||
|
detail.setTransportQuantity(waybills.stream().map(Waybill::getQuantity)
|
||||||
|
.filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
|
||||||
|
detail.setQuantityUnit(commonWaybillValue(waybills, Waybill::getQuantityUnit));
|
||||||
|
detail.setBatchNo(commonWaybillValue(waybills, Waybill::getBatchNo));
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReceivablePayableDetail buildMasterOrderPayableDetail(MasterOrder masterOrder,
|
||||||
|
ContractManage contract, List<Waybill> waybills,
|
||||||
|
List<ReceivablePayableCargoFee> fees, BigDecimal unitPrice) {
|
||||||
|
ReceivablePayableDetail detail = buildLoadingDetail(
|
||||||
|
masterOrder.getMasterNo(), contract, waybills, fees, unitPrice);
|
||||||
|
detail.setSourceType(SOURCE_MASTER_ORDER);
|
||||||
|
detail.setTransportType(masterOrder.getTransportOrganizationType());
|
||||||
|
detail.setRemark(masterOrder.getRemark());
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joinWaybillField(List<Waybill> waybills,
|
||||||
|
java.util.function.Function<Waybill, String> getter) {
|
||||||
|
return waybills.stream().map(getter).filter(Func::isNotEmpty).distinct()
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String commonWaybillValue(List<Waybill> waybills,
|
||||||
|
java.util.function.Function<Waybill, String> getter) {
|
||||||
|
List<String> values = waybills.stream().map(getter).filter(Func::isNotEmpty).distinct().toList();
|
||||||
|
return values.size() == 1 ? values.get(0) : "";
|
||||||
|
}
|
||||||
|
|
||||||
private List<Waybill> masterOrderGoods(MasterOrder masterOrder) {
|
private List<Waybill> masterOrderGoods(MasterOrder masterOrder) {
|
||||||
List<Waybill> result = new ArrayList<>();
|
List<Waybill> result = new ArrayList<>();
|
||||||
for (Map<String, Object> goods : parseList(masterOrder.getGoodsJson())) {
|
for (Map<String, Object> goods : parseList(masterOrder.getGoodsJson())) {
|
||||||
@@ -1013,6 +1077,12 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void normalizeWaybillFeeLines(List<ReceivablePayableCargoFee> fees) {
|
||||||
|
for (int index = 0; index < fees.size(); index++) {
|
||||||
|
fees.get(index).setLineNo(String.format("%04d", index + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String joinMasterGoodsField(List<Waybill> masterGoods,
|
private String joinMasterGoodsField(List<Waybill> masterGoods,
|
||||||
java.util.function.Function<Waybill, String> getter) {
|
java.util.function.Function<Waybill, String> getter) {
|
||||||
return masterGoods.stream().map(getter).filter(Func::isNotEmpty).distinct()
|
return masterGoods.stream().map(getter).filter(Func::isNotEmpty).distinct()
|
||||||
@@ -1616,7 +1686,15 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
|
|
||||||
private void rebuildDetailFee(ReceivablePayableDetail detail, String billingPlanId) {
|
private void rebuildDetailFee(ReceivablePayableDetail detail, String billingPlanId) {
|
||||||
if (SOURCE_MASTER_ORDER.equals(detail.getSourceType())) {
|
if (SOURCE_MASTER_ORDER.equals(detail.getSourceType())) {
|
||||||
|
if ("payable".equals(detail.getSettlementType())) {
|
||||||
|
rebuildAggregatedWaybillDetailFee(detail, billingPlanId, "总单关联运单不存在");
|
||||||
|
} else {
|
||||||
rebuildMasterOrderDetailFee(detail, billingPlanId);
|
rebuildMasterOrderDetailFee(detail, billingPlanId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SOURCE_LOADING_ORDER.equals(detail.getSourceType())) {
|
||||||
|
rebuildAggregatedWaybillDetailFee(detail, billingPlanId, "配载单关联运单不存在");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Waybill waybill = waybillService.getById(detail.getWaybillId());
|
Waybill waybill = waybillService.getById(detail.getWaybillId());
|
||||||
@@ -1669,6 +1747,40 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
updateById(detail);
|
updateById(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void rebuildAggregatedWaybillDetailFee(ReceivablePayableDetail detail, String billingPlanId,
|
||||||
|
String missingMessage) {
|
||||||
|
List<Long> waybillIds = cargoFeeMapper.selectList(Wrappers.<ReceivablePayableCargoFee>lambdaQuery()
|
||||||
|
.select(ReceivablePayableCargoFee::getWaybillId)
|
||||||
|
.eq(ReceivablePayableCargoFee::getDetailId, detail.getId())
|
||||||
|
.eq(ReceivablePayableCargoFee::getIsDeleted, 0)
|
||||||
|
.isNotNull(ReceivablePayableCargoFee::getWaybillId))
|
||||||
|
.stream().map(ReceivablePayableCargoFee::getWaybillId).distinct().toList();
|
||||||
|
List<Waybill> waybills = loadWaybills(waybillIds);
|
||||||
|
if (waybills.isEmpty()) {
|
||||||
|
throw new ServiceException(missingMessage);
|
||||||
|
}
|
||||||
|
ContractManage contract = contractManageService.getById(detail.getContractId());
|
||||||
|
List<ReceivablePayableCargoFee> fees = waybills.stream()
|
||||||
|
.flatMap(waybill -> calculatedFees(waybill, contract, billingPlanId).stream()).toList();
|
||||||
|
normalizeWaybillFeeLines(fees);
|
||||||
|
cargoFeeMapper.delete(Wrappers.<ReceivablePayableCargoFee>lambdaQuery()
|
||||||
|
.eq(ReceivablePayableCargoFee::getDetailId, detail.getId()));
|
||||||
|
fees.forEach(fee -> {
|
||||||
|
fee.setDetailId(detail.getId());
|
||||||
|
cargoFeeMapper.insert(fee);
|
||||||
|
});
|
||||||
|
BigDecimal freight = fees.stream().map(fee -> money(fee.getFreightAmount()))
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
BigDecimal total = fees.stream().map(ReceivablePayableCargoFee::getAfterAmount)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
detail.setFreightAmount(freight);
|
||||||
|
detail.setOtherFeeAmount(total.subtract(freight));
|
||||||
|
detail.setTotalAmount(total);
|
||||||
|
detail.setUnitPrice(resolveContractUnitPrice(fees));
|
||||||
|
detail.setFeeItemsJson(aggregateFeeItemsJson(fees));
|
||||||
|
updateById(detail);
|
||||||
|
}
|
||||||
|
|
||||||
private void closeDetails(List<Long> ids, String settlementType) {
|
private void closeDetails(List<Long> ids, String settlementType) {
|
||||||
if (Func.isEmpty(ids)) {
|
if (Func.isEmpty(ids)) {
|
||||||
throw new ServiceException("请选择需要关闭的明细");
|
throw new ServiceException("请选择需要关闭的明细");
|
||||||
@@ -1766,6 +1878,23 @@ public class ReceivablePayableDetailServiceImpl
|
|||||||
.eq(ReceivablePayableDetail::getIsDeleted, 0)) > 0;
|
.eq(ReceivablePayableDetail::getIsDeleted, 0)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean existsByMasterOrderContract(String masterNo, String settlementType, Long contractId) {
|
||||||
|
return count(Wrappers.<ReceivablePayableDetail>lambdaQuery()
|
||||||
|
.eq(ReceivablePayableDetail::getSourceType, SOURCE_MASTER_ORDER)
|
||||||
|
.eq(ReceivablePayableDetail::getWaybillNo, masterNo)
|
||||||
|
.eq(ReceivablePayableDetail::getSettlementType, settlementType)
|
||||||
|
.eq(ReceivablePayableDetail::getContractId, contractId)
|
||||||
|
.eq(ReceivablePayableDetail::getIsDeleted, 0)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean existsByLoading(String loadingNo, String settlementType) {
|
||||||
|
return count(Wrappers.<ReceivablePayableDetail>lambdaQuery()
|
||||||
|
.eq(ReceivablePayableDetail::getSourceType, SOURCE_LOADING_ORDER)
|
||||||
|
.eq(ReceivablePayableDetail::getWaybillNo, loadingNo)
|
||||||
|
.eq(ReceivablePayableDetail::getSettlementType, settlementType)
|
||||||
|
.eq(ReceivablePayableDetail::getIsDeleted, 0)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
private String settlementType(String value) {
|
private String settlementType(String value) {
|
||||||
if (Func.isEmpty(value)) return "receivable";
|
if (Func.isEmpty(value)) return "receivable";
|
||||||
if (!List.of("receivable", "payable").contains(value)) {
|
if (!List.of("receivable", "payable").contains(value)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user