✨ 开票合计反算、配载承运商乙方交集与临时合同结算校验
开票按合计金额/税率反算不含税单价(6位小数);配载按子单客户合同甲方匹配后取承运商乙方交集;临时合同过期不可结算,并修正合同变更编号唯一校验。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+1
-1
@@ -76,7 +76,7 @@ public class InvoiceApplicationLine extends TenantEntity {
|
||||
*/
|
||||
private BigDecimal quantity;
|
||||
/**
|
||||
* 不含税单价
|
||||
* 不含税单价(由合计金额反算,保留 6 位小数)
|
||||
*/
|
||||
private BigDecimal unitPriceNoTax;
|
||||
/**
|
||||
|
||||
+4
@@ -87,4 +87,8 @@ public class WaybillVO extends Waybill {
|
||||
@Schema(description = "运单主键集合")
|
||||
private List<Long> ids;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "承运商合同名称")
|
||||
private String carrierContractName;
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -56,9 +56,11 @@ public class LoadingManageController extends BladeController {
|
||||
|
||||
@GetMapping("/carrier-contracts")
|
||||
@ApiOperationSupport(order = 13)
|
||||
@Operation(summary = "可选承运商合同", description = "查询已审核生效的承运商合同")
|
||||
public R<List<LoadingCarrierContractVO>> carrierContracts(@RequestParam List<Long> projectIds) {
|
||||
return R.data(loadingManageService.carrierContracts(projectIds));
|
||||
@Operation(summary = "可选承运商合同", description = "查询已审核生效的承运商合同;传入 waybillIds 时按子运单客户合同甲方匹配后对乙方取交集")
|
||||
public R<List<LoadingCarrierContractVO>> carrierContracts(
|
||||
@RequestParam List<Long> projectIds,
|
||||
@RequestParam(required = false) List<Long> waybillIds) {
|
||||
return R.data(loadingManageService.carrierContracts(projectIds, waybillIds));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
|
||||
+15
@@ -72,4 +72,19 @@ public interface IContractManageService extends BaseService<ContractManage> {
|
||||
*/
|
||||
String nextContractNo(Long organizationId);
|
||||
|
||||
/**
|
||||
* 合同是否可用于生成结算单:已审批、未终止,且临时合同仍在临时效力期内。
|
||||
*
|
||||
* @param contract 合同
|
||||
* @return true=可用
|
||||
*/
|
||||
boolean isUsableForSettlement(ContractManage contract);
|
||||
|
||||
/**
|
||||
* 校验合同可用于生成结算单,不满足时抛出业务异常。
|
||||
*
|
||||
* @param contract 合同
|
||||
*/
|
||||
void assertUsableForSettlement(ContractManage contract);
|
||||
|
||||
}
|
||||
|
||||
+6
-1
@@ -26,7 +26,12 @@ public interface ILoadingManageService extends BaseService<LoadingManage> {
|
||||
|
||||
LoadingManageVO detail(Long id);
|
||||
|
||||
List<LoadingCarrierContractVO> carrierContracts(List<Long> projectIds);
|
||||
/**
|
||||
* 查询项目下已审核生效的承运商合同。
|
||||
* <p>
|
||||
* 传入 waybillIds 时,按各子运单客户合同甲方匹配可用承运商合同,再对乙方名称取交集后返回。
|
||||
*/
|
||||
List<LoadingCarrierContractVO> carrierContracts(List<Long> projectIds, List<Long> waybillIds);
|
||||
|
||||
boolean saveDraft(LoadingManage loadingManage);
|
||||
|
||||
|
||||
+48
-2
@@ -592,7 +592,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存合同编号。新增未填写时按部门规则生成,已填写或编辑时保留手工编号并校验唯一。
|
||||
* 保存合同编号。新增未填写时按部门规则生成,已填写或编辑/变更时保留手工编号并校验唯一。
|
||||
* 编号相对当前记录未变化时跳过唯一校验,避免合同变更原编号提交误报「合同编号已存在」。
|
||||
*/
|
||||
private void applyContractNo(ContractManage contractManage, String contractNo, boolean generateWhenEmpty) {
|
||||
String normalizedContractNo = TransportBusinessSupport.trimToNull(contractNo);
|
||||
@@ -603,8 +604,12 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
normalizedContractNo = nextContractNo(contractManage.getOrganizationId());
|
||||
}
|
||||
TransportBusinessSupport.validateLength(normalizedContractNo, 100, "合同编号不能超过100字");
|
||||
String currentContractNo = TransportBusinessSupport.trimToNull(contractManage.getContractNo());
|
||||
if (Objects.equals(normalizedContractNo, currentContractNo) && Func.isNotEmpty(contractManage.getId())) {
|
||||
contractManage.setContractNo(normalizedContractNo);
|
||||
return;
|
||||
}
|
||||
Long duplicatedCount = count(Wrappers.<ContractManage>lambdaQuery()
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.eq(ContractManage::getContractNo, normalizedContractNo)
|
||||
.ne(Func.isNotEmpty(contractManage.getId()), ContractManage::getId, contractManage.getId()));
|
||||
if (duplicatedCount != null && duplicatedCount > 0) {
|
||||
@@ -613,6 +618,47 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
contractManage.setContractNo(normalizedContractNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsableForSettlement(ContractManage contract) {
|
||||
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)) {
|
||||
return false;
|
||||
}
|
||||
if (!List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED).contains(contract.getApprovalStatus())) {
|
||||
return false;
|
||||
}
|
||||
if (Objects.equals(contract.getContractStage(), STAGE_TERMINATED)) {
|
||||
return false;
|
||||
}
|
||||
return !isTemporaryContractExpired(contract);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertUsableForSettlement(ContractManage contract) {
|
||||
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)) {
|
||||
throw new ServiceException("合同不存在");
|
||||
}
|
||||
if (!List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED).contains(contract.getApprovalStatus())) {
|
||||
throw new ServiceException("合同未审核完成,不可生成结算单");
|
||||
}
|
||||
if (Objects.equals(contract.getContractStage(), STAGE_TERMINATED)) {
|
||||
throw new ServiceException("合同已终止,不可生成结算单");
|
||||
}
|
||||
if (isTemporaryContractExpired(contract)) {
|
||||
throw new ServiceException("临时合同已过期,不可生成结算单");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时合同是否已过临时效力止日(不含当天仍有效)。
|
||||
*/
|
||||
private boolean isTemporaryContractExpired(ContractManage contract) {
|
||||
if (contract == null || !Objects.equals(contract.getContractStage(), STAGE_TEMPORARY)) {
|
||||
return false;
|
||||
}
|
||||
LocalDate temporaryEndDate = contract.getTemporaryEndDate();
|
||||
return temporaryEndDate != null && temporaryEndDate.isBefore(LocalDate.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String nextContractNo(Long organizationId) {
|
||||
if (Func.isEmpty(organizationId)) {
|
||||
|
||||
+1
-5
@@ -548,11 +548,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
}
|
||||
PreSettlement first = sources.isEmpty() ? null : sources.get(0);
|
||||
ContractManage contract = contractManageService.getById(contractId);
|
||||
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)) throw new ServiceException("合同不存在");
|
||||
if (!List.of("approved", "change_approved").contains(contract.getApprovalStatus())
|
||||
|| "terminated".equals(contract.getContractStage())) {
|
||||
throw new ServiceException("合同未审核完成,不可转正式结算单");
|
||||
}
|
||||
contractManageService.assertUsableForSettlement(contract);
|
||||
if (creating || restoring) {
|
||||
if (Func.isEmpty(settlement.getFormalSettlementNo())) settlement.setFormalSettlementNo(nextNo(settlementType));
|
||||
settlement.setApprovalStatus(TransportBusiConstant.DRAFT);
|
||||
|
||||
+21
-5
@@ -1423,14 +1423,30 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
|
||||
required(line.getGoodsCategory(), "商品和服务分类");
|
||||
required(line.getGoodsName(), "货物或服务简称");
|
||||
BigDecimal quantity = nonNegative(line.getQuantity(), "数量");
|
||||
BigDecimal unitPriceNoTax = nonNegative(line.getUnitPriceNoTax(), "不含税单价")
|
||||
if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("数量必须大于0");
|
||||
}
|
||||
BigDecimal totalAmount = nonNegative(line.getTotalAmount(), "合计金额")
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
if (totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("合计金额必须大于0");
|
||||
}
|
||||
BigDecimal taxRate = nonNegative(line.getTaxRate(), "税率");
|
||||
if (taxRate.compareTo(BigDecimal.valueOf(100)) > 0) {
|
||||
throw new ServiceException("税率必须在0-100之间");
|
||||
}
|
||||
// 合计金额 = 数量 × 不含税单价 × (1 + 税率)
|
||||
// 不含税单价 = 合计金额 / 数量 / (1 + 税率),保留 6 位小数
|
||||
BigDecimal rateFactor = BigDecimal.ONE.add(
|
||||
taxRate.divide(BigDecimal.valueOf(100), 8, RoundingMode.HALF_UP));
|
||||
BigDecimal unitPriceNoTax = totalAmount
|
||||
.divide(quantity, 10, RoundingMode.HALF_UP)
|
||||
.divide(rateFactor, 6, RoundingMode.HALF_UP);
|
||||
BigDecimal amountNoTax = quantity.multiply(unitPriceNoTax)
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal taxRate = nonNegative(line.getTaxRate(), "税率");
|
||||
if (taxRate.compareTo(BigDecimal.valueOf(100)) > 0) throw new ServiceException("税率必须在0-100之间");
|
||||
BigDecimal taxAmount = calculateTax(amountNoTax, taxRate);
|
||||
BigDecimal totalAmount = amountNoTax.add(taxAmount).setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal taxAmount = totalAmount.subtract(amountNoTax)
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
line.setUnitPriceNoTax(unitPriceNoTax);
|
||||
line.setAmountNoTax(amountNoTax);
|
||||
line.setTaxAmount(taxAmount);
|
||||
line.setTotalAmount(totalAmount);
|
||||
|
||||
+99
-2
@@ -107,11 +107,22 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LoadingCarrierContractVO> carrierContracts(List<Long> projectIds) {
|
||||
public List<LoadingCarrierContractVO> carrierContracts(List<Long> projectIds, List<Long> waybillIds) {
|
||||
if (Func.isEmpty(projectIds)) {
|
||||
return List.of();
|
||||
}
|
||||
return availableCarrierContracts(projectIds).stream().map(contract -> {
|
||||
List<ContractManage> contracts = availableCarrierContracts(projectIds);
|
||||
if (Func.isNotEmpty(waybillIds)) {
|
||||
List<Waybill> waybills = loadWaybills(waybillIds);
|
||||
Set<String> allowedPartyBs = intersectCarrierPartyBs(waybills, contracts);
|
||||
if (allowedPartyBs.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
contracts = contracts.stream()
|
||||
.filter(contract -> allowedPartyBs.contains(normalizePartyName(contract.getPartyB())))
|
||||
.toList();
|
||||
}
|
||||
return contracts.stream().map(contract -> {
|
||||
LoadingCarrierContractVO option = new LoadingCarrierContractVO();
|
||||
option.setId(contract.getId());
|
||||
option.setContractName(contract.getContractName());
|
||||
@@ -862,6 +873,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
}
|
||||
}
|
||||
validateSameProject(waybills);
|
||||
validateCompatibleCarrierPartyB(waybills);
|
||||
return waybills;
|
||||
}
|
||||
|
||||
@@ -894,6 +906,20 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同一配载单子运单除同项目外,还必须存在共同的承运商合同乙方(按客户合同甲方匹配后取交集)。
|
||||
*/
|
||||
private void validateCompatibleCarrierPartyB(List<Waybill> waybills) {
|
||||
if (Func.isEmpty(waybills) || waybills.size() < 2) {
|
||||
return;
|
||||
}
|
||||
List<ContractManage> contracts = availableCarrierContracts(projectIdsOf(waybills));
|
||||
Set<String> allowedPartyBs = intersectCarrierPartyBs(waybills, contracts);
|
||||
if (allowedPartyBs.isEmpty()) {
|
||||
throw new ServiceException("所选运单在同一项目下没有共同的承运商合同乙方,不能配载到同一配载单");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCarrierContract(LoadingManage loadingManage, boolean required) {
|
||||
validateCarrierContract(loadingManage, required, null);
|
||||
}
|
||||
@@ -931,6 +957,18 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
? "所选承运商合同不属于本项目"
|
||||
: "所选承运商合同不属于运单" + waybillNos + "的项目");
|
||||
}
|
||||
if (Func.isNotEmpty(childWaybills)) {
|
||||
List<ContractManage> projectContracts = availableCarrierContracts(projectIdsOf(childWaybills));
|
||||
Set<String> allowedPartyBs = intersectCarrierPartyBs(childWaybills, projectContracts);
|
||||
String partyB = normalizePartyName(carrierContract.getPartyB());
|
||||
if (Func.isNotEmpty(allowedPartyBs) && !allowedPartyBs.contains(partyB)) {
|
||||
throw new ServiceException("所选承运商合同乙方与子运单可共同承运的乙方不一致,可选:"
|
||||
+ String.join("、", allowedPartyBs));
|
||||
}
|
||||
if (allowedPartyBs.isEmpty()) {
|
||||
throw new ServiceException("所选运单在同一项目下没有共同的承运商合同乙方,不能配载到同一配载单");
|
||||
}
|
||||
}
|
||||
loadingManage.setCarrierName(carrierContract.getPartyB());
|
||||
}
|
||||
|
||||
@@ -969,6 +1007,65 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
.orderByDesc(ContractManage::getCreateTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* 各子运单按「客户合同甲方 = 承运商合同甲方」匹配可用承运商合同,再对乙方名称取交集。
|
||||
* 例:子单1可选 A/B/C,子单2可选 B,则交集为 B。
|
||||
*/
|
||||
private Set<String> intersectCarrierPartyBs(List<Waybill> waybills, List<ContractManage> projectContracts) {
|
||||
Set<String> intersection = null;
|
||||
Map<Long, String> customerPartyAMap = loadCustomerContractPartyAMap(waybills);
|
||||
for (Waybill waybill : waybills) {
|
||||
Set<String> available = availableCarrierPartyBs(waybill, projectContracts, customerPartyAMap);
|
||||
if (intersection == null) {
|
||||
intersection = new LinkedHashSet<>(available);
|
||||
} else {
|
||||
intersection.retainAll(available);
|
||||
}
|
||||
if (intersection.isEmpty()) {
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
return intersection == null ? Set.of() : intersection;
|
||||
}
|
||||
|
||||
private Set<String> availableCarrierPartyBs(Waybill waybill, List<ContractManage> projectContracts,
|
||||
Map<Long, String> customerPartyAMap) {
|
||||
if (waybill == null || Func.isEmpty(projectContracts)) {
|
||||
return Set.of();
|
||||
}
|
||||
String partyA = customerPartyAMap.get(waybill.getContractId());
|
||||
return projectContracts.stream()
|
||||
.filter(contract -> Objects.equals(contract.getProjectId(), waybill.getProjectId()))
|
||||
.filter(contract -> Func.isEmpty(partyA) || Objects.equals(normalizePartyName(contract.getPartyA()), partyA))
|
||||
.map(ContractManage::getPartyB)
|
||||
.map(this::normalizePartyName)
|
||||
.filter(Func::isNotEmpty)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
private Map<Long, String> loadCustomerContractPartyAMap(List<Waybill> waybills) {
|
||||
List<Long> contractIds = waybills.stream()
|
||||
.map(Waybill::getContractId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (Func.isEmpty(contractIds)) {
|
||||
return Map.of();
|
||||
}
|
||||
return contractManageService.list(Wrappers.<ContractManage>lambdaQuery()
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.in(ContractManage::getId, contractIds))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(ContractManage::getId,
|
||||
contract -> normalizePartyName(contract.getPartyA()),
|
||||
(left, right) -> left,
|
||||
LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private String normalizePartyName(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按主键取一张可用的承运商合同。
|
||||
* <p>
|
||||
|
||||
+4
-3
@@ -1318,14 +1318,15 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
|| !List.of("客户合同", "承运商合同").contains(contract.getContractCategory())) {
|
||||
throw new ServiceException("仅允许选择审批完成且未作废的合同");
|
||||
}
|
||||
if (!contractManageService.isUsableForSettlement(contract)) {
|
||||
throw new ServiceException("临时合同已过期,不可生成结算单");
|
||||
}
|
||||
validateContractRelations(contract);
|
||||
return contract;
|
||||
}
|
||||
|
||||
private boolean isAvailableContract(ContractManage contract) {
|
||||
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)
|
||||
|| !List.of("approved", "change_approved").contains(contract.getApprovalStatus())
|
||||
|| "terminated".equals(contract.getContractStage()) || contract.getProjectId() == null
|
||||
if (!contractManageService.isUsableForSettlement(contract) || contract.getProjectId() == null
|
||||
|| !List.of("客户合同", "承运商合同").contains(contract.getContractCategory())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+11
-11
@@ -847,20 +847,20 @@ public class ReceivablePayableDetailServiceImpl
|
||||
|
||||
private List<Long> settlementContractIds() {
|
||||
return contractManageService.list(Wrappers.<ContractManage>lambdaQuery()
|
||||
.select(ContractManage::getId)
|
||||
.select(ContractManage::getId, ContractManage::getContractStage, ContractManage::getTemporaryEndDate,
|
||||
ContractManage::getApprovalStatus, ContractManage::getIsDeleted)
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.in(ContractManage::getApprovalStatus, "approved", "change_approved")
|
||||
.ne(ContractManage::getContractStage, "terminated"))
|
||||
.stream().map(ContractManage::getId).toList();
|
||||
.stream()
|
||||
.filter(contractManageService::isUsableForSettlement)
|
||||
.map(ContractManage::getId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private void validateSettlementContract(Long contractId) {
|
||||
ContractManage contract = contractId == null ? null : contractManageService.getById(contractId);
|
||||
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)
|
||||
|| !List.of("approved", "change_approved").contains(contract.getApprovalStatus())
|
||||
|| "terminated".equals(contract.getContractStage())) {
|
||||
throw new ServiceException("合同未审核完成,不可转预结算单或正式结算单");
|
||||
}
|
||||
contractManageService.assertUsableForSettlement(contract);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -935,9 +935,7 @@ public class ReceivablePayableDetailServiceImpl
|
||||
return List.of();
|
||||
}
|
||||
ContractManage contract = contractManageService.getById(contractId);
|
||||
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)) {
|
||||
throw new ServiceException("合同不存在");
|
||||
}
|
||||
contractManageService.assertUsableForSettlement(contract);
|
||||
String targetSettlementType = settlementType(settlementType);
|
||||
Long currentUserId = AuthUtil.getUserId();
|
||||
Date generateTime = new Date();
|
||||
@@ -3253,8 +3251,10 @@ public class ReceivablePayableDetailServiceImpl
|
||||
if (Func.isEmpty(request.getBillingPlanId())) {
|
||||
throw new ServiceException("请选择计费方案");
|
||||
}
|
||||
ContractManage contract = contractManageService.getById(request.getContractId());
|
||||
contractManageService.assertUsableForSettlement(contract);
|
||||
String targetSettlementType = settlementType(request.getSettlementType());
|
||||
validateContractSettlementType(contractManageService.getById(request.getContractId()), targetSettlementType);
|
||||
validateContractSettlementType(contract, targetSettlementType);
|
||||
if (requireWaybill && Func.isEmpty(request.getWaybillIds())) {
|
||||
throw new ServiceException("请选择需要生成费用的运单");
|
||||
}
|
||||
|
||||
+3
@@ -1079,6 +1079,9 @@ public class SettlementImportBatchServiceImpl
|
||||
|| "terminated".equals(contract.getContractStage())) {
|
||||
throw new ServiceException(label + "未审核完成或已终止");
|
||||
}
|
||||
if (!contractManageService.isUsableForSettlement(contract)) {
|
||||
throw new ServiceException(label + "为临时合同且已过期,不可生成结算单");
|
||||
}
|
||||
return contract;
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -128,6 +128,10 @@ public class SettlementRuleAutoGenerateServiceImpl implements ISettlementRuleAut
|
||||
}
|
||||
|
||||
private int[] generateContract(ContractManage contract, LocalDate today) {
|
||||
if (!contractManageService.isUsableForSettlement(contract)) {
|
||||
log.warn("合同[{}]不可用于结算(未审批、已终止或临时合同已过期),跳过自动生成", contract.getContractNo());
|
||||
return new int[]{0, 0};
|
||||
}
|
||||
String settlementType = contractSettlementType(contract);
|
||||
if (settlementType == null || contract.getProjectId() == null || contract.getOrganizationId() == null) {
|
||||
log.warn("合同[{}]缺少结算类型、项目或所属组织,跳过自动生成", contract.getContractNo());
|
||||
|
||||
+25
@@ -141,6 +141,7 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
entityPage.getRecords().forEach(this::syncDriverAcceptState);
|
||||
IPage<WaybillVO> result = WaybillWrapper.build().pageVO(entityPage);
|
||||
fillMileageMaintainable(result.getRecords());
|
||||
fillCarrierContractName(result.getRecords());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -148,6 +149,7 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
public WaybillVO detail(Long id) {
|
||||
WaybillVO result = WaybillWrapper.build().entityVO(syncDriverAcceptState(loadEditable(id, false)));
|
||||
fillCustomerNameFromContract(result);
|
||||
fillCarrierContractName(List.of(result));
|
||||
fillMileageMaintainable(List.of(result));
|
||||
return result;
|
||||
}
|
||||
@@ -1206,6 +1208,29 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
}
|
||||
}
|
||||
|
||||
private void fillCarrierContractName(List<WaybillVO> waybills) {
|
||||
if (Func.isEmpty(waybills)) {
|
||||
return;
|
||||
}
|
||||
List<Long> contractIds = waybills.stream()
|
||||
.map(Waybill::getCarrierContractId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (Func.isEmpty(contractIds)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, String> nameMap = contractManageService.listByIds(contractIds).stream()
|
||||
.filter(contract -> contract != null && Objects.equals(contract.getIsDeleted(), 0))
|
||||
.collect(Collectors.toMap(ContractManage::getId, ContractManage::getContractName, (left, right) -> left));
|
||||
waybills.forEach(waybill -> {
|
||||
if (waybill.getCarrierContractId() == null) {
|
||||
return;
|
||||
}
|
||||
waybill.setCarrierContractName(nameMap.get(waybill.getCarrierContractId()));
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isCustomerContract(ContractManage contract) {
|
||||
return contract != null && "客户合同".equals(contract.getContractCategory());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
-- 开票申请明细:不含税单价按合计金额反算后保留 6 位小数
|
||||
SET @schema_name = DATABASE();
|
||||
SET @has_unit_price_column = (
|
||||
SELECT COUNT(1)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @schema_name
|
||||
AND table_name = 'blade_invoice_application_line'
|
||||
AND column_name = 'unit_price_no_tax'
|
||||
);
|
||||
SET @alter_unit_price_sql = IF(
|
||||
@has_unit_price_column > 0,
|
||||
'ALTER TABLE `blade_invoice_application_line` MODIFY COLUMN `unit_price_no_tax` decimal(18,6) DEFAULT NULL COMMENT ''不含税单价''',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @alter_unit_price_sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
Reference in New Issue
Block a user