diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/PreSettlementSaveRequest.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/PreSettlementSaveRequest.java index d892003..dbe0667 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/PreSettlementSaveRequest.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/PreSettlementSaveRequest.java @@ -95,6 +95,9 @@ public class PreSettlementSaveRequest implements Serializable { @Schema(description = "调整金额") private BigDecimal adjustAmount; + @Schema(description = "原金额") + private BigDecimal originalAmount; + @Schema(description = "备注") private String remark; diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java index a403af8..9e329b3 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java @@ -134,7 +134,7 @@ public class CurrencyServiceImpl extends BaseServiceImpl impleme this.save(region); } } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + excel.setErrorMessage(exception.getMessage()); errorList.add(excel); } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CommonCargoServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CommonCargoServiceImpl.java index 75b51b4..91fbbcc 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CommonCargoServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CommonCargoServiceImpl.java @@ -162,7 +162,7 @@ public class CommonCargoServiceImpl extends BaseServiceImpl plan) { + if (!(plan.get("rules") instanceof List rules)) return; + for (Object ruleValue : rules) { + if (!(ruleValue instanceof Map rule) + || !(rule.get("matchCondition") instanceof Map condition)) continue; + boolean cargoNameConfigured = hasConfiguredValue(condition.get("cargoNames")) + || hasConfiguredValue(condition.get("cargoName")); + boolean cargoTypeConfigured = hasConfiguredValue(condition.get("cargoType")) + || hasConfiguredValue(condition.get("cargoTypeCode")) + || hasConfiguredValue(condition.get("cargoTypePath")); + if (cargoNameConfigured && !cargoTypeConfigured) { + throw new ServiceException("设置货物名称匹配条件前请先选择货物类型"); + } + } + } + + private boolean hasConfiguredValue(Object value) { + if (value instanceof Collection values) { + return values.stream().anyMatch(this::hasConfiguredValue); + } + return value != null && !String.valueOf(value).trim().isEmpty(); + } + private boolean isDefaultBillingPlan(Map plan) { Object value = plan.get("defaultPlan"); return Boolean.TRUE.equals(value) || "true".equalsIgnoreCase(String.valueOf(value)) || "1".equals(String.valueOf(value)); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java index 635d4a2..19f1b8e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java @@ -142,7 +142,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl> settlementCandidates(String keyword) { List settlements = formalSettlementMapper.selectList(Wrappers.lambdaQuery() - .eq(FormalSettlement::getSettlementType, "receivable") + .eq(FormalSettlement::getSettlementType, "payable") .eq(FormalSettlement::getApprovalStatus, APPROVED) .eq(FormalSettlement::getStatus, 1) .and(Func.isNotEmpty(keyword), wrapper -> wrapper.like(FormalSettlement::getFormalSettlementNo, keyword) @@ -418,8 +418,8 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl requestRows) { if (requestRows == null) return; - Map generatedFeeTypeMap = contractFeeTypeMap(loadExisting(settlementId).getContractId()); Map> allowedManualFees = new LinkedHashMap<>(); if (requestRows.stream().anyMatch(row -> Integer.valueOf(1).equals(row.getManualFlag()))) { for (Map option : feeOptions()) { @@ -901,7 +900,11 @@ public class PreSettlementServiceImpl extends BaseServiceImpl manualRows = existingMap.values().stream() .filter(row -> Integer.valueOf(1).equals(row.getManualFlag())).toList(); + List existingGeneratedRows = existingMap.values().stream() + .filter(row -> !Integer.valueOf(1).equals(row.getManualFlag())).toList(); + List availableGeneratedRows = new ArrayList<>(existingGeneratedRows); Set retainedManualIds = new LinkedHashSet<>(); + Set retainedGeneratedIds = new LinkedHashSet<>(); for (PreSettlementSaveRequest.SummaryFee requestRow : requestRows) { if (Integer.valueOf(1).equals(requestRow.getManualFlag())) { String feeType = requiredText(requestRow.getFeeType(), "费用类型"); @@ -939,18 +942,26 @@ public class PreSettlementServiceImpl extends BaseServiceImpl !Integer.valueOf(1).equals(item.getManualFlag())) + row = availableGeneratedRows.stream() .filter(item -> Objects.equals(item.getFeeType(), feeType) && Objects.equals(item.getFeeItem(), feeItem)) .findFirst().orElse(null); } - if (row == null || Integer.valueOf(1).equals(row.getManualFlag())) { - throw new ServiceException("存在无效的结算合计行"); + if (row != null) availableGeneratedRows.remove(row); + if (row == null) { + row = new PreSettlementSummaryFee(); + row.setPreSettlementId(settlementId); + row.setManualFlag(0); } + row.setFeeType(feeType); + row.setFeeItem(feeItem); + row.setOriginalAmount(requestRow.getOriginalAmount() == null + ? money(row.getOriginalAmount()) : money(requestRow.getOriginalAmount())); BigDecimal before = money(row.getAdjustAmount()); row.setAdjustAmount(money(requestRow.getAdjustAmount())); row.setSettlementAmount(money(row.getOriginalAmount()).add(row.getAdjustAmount())); @@ -958,7 +969,8 @@ public class PreSettlementServiceImpl extends BaseServiceImpl condition) { @@ -814,7 +814,10 @@ public class ReceivablePayableDetailServiceImpl || !isBlank(condition.get("destinationCode")) || !isBlank(condition.get("transportMode")) || !isBlank(condition.get("cargoType")) - || !isBlank(condition.get("cargoTypeCode")); + || !isBlank(condition.get("cargoTypeCode")) + || !isBlank(condition.get("cargoTypePath")) + || !isBlank(condition.get("cargoNames")) + || !isBlank(condition.get("cargoName")); } private boolean matchesLocation(Map condition, String location, Long addressId, String addressName, @@ -831,14 +834,98 @@ public class ReceivablePayableDetailServiceImpl || matchesCondition(expectedName, detailAddress); } - private boolean matchesCargoType(Map condition, Waybill waybill) { - Object expectedName = condition.get("cargoType"); - Object expectedCode = condition.get("cargoTypeCode"); - if (!isBlank(expectedName)) return matchesCondition(expectedName, waybill.getCargoType()); - if (!isBlank(expectedCode)) return matchesCondition(expectedCode, waybill.getCargoType()); + private boolean matchesCargo(Map condition, Waybill waybill) { + Object expectedTypeName = condition.get("cargoType"); + Object expectedTypeCode = condition.get("cargoTypeCode"); + Object expectedTypePath = condition.get("cargoTypePath"); + Object expectedCargoNames = !isBlank(condition.get("cargoNames")) + ? condition.get("cargoNames") : condition.get("cargoName"); + boolean cargoTypeConfigured = !isBlank(expectedTypeName) + || !isBlank(expectedTypeCode) || !isBlank(expectedTypePath); + if (!cargoTypeConfigured && isBlank(expectedCargoNames)) return true; + List> goods = parseCargoTypeGoods(waybill.getGoodsJson()); + if (goods.isEmpty()) { + return (!cargoTypeConfigured || matchesCondition(expectedTypeName, waybill.getCargoType())) + && (isBlank(expectedCargoNames) + || matchesCargoName(expectedCargoNames, waybill.getCargoName())); + } + return goods.stream().anyMatch(item -> + (!cargoTypeConfigured || matchesCargoType(expectedTypeName, expectedTypeCode, + expectedTypePath, item, waybill.getCargoType())) + && (isBlank(expectedCargoNames) || matchesCargoName(expectedCargoNames, + stringValue(item, "cargoName", waybill.getCargoName())))); + } + + private List> parseCargoTypeGoods(String goodsJson) { + List> goods = parseList(goodsJson); + if (!goods.isEmpty()) return goods; + if (Func.isEmpty(goodsJson)) return List.of(); + try { + Object parsed = JsonUtil.parse(goodsJson, Object.class); + if (parsed instanceof Map source) return List.of(stringMap(source)); + } catch (Exception ignored) { + // 兼容历史货物 JSON 异常数据,后续回退使用运单货物类型名称匹配。 + } + return List.of(); + } + + private boolean matchesCargoName(Object expectedNames, String actualName) { + String actual = String.valueOf(actualName == null ? "" : actualName).trim(); + if (actual.isEmpty()) return false; + if (expectedNames instanceof Collection values) { + return values.stream().anyMatch(value -> matchesCargoName(value, actual)); + } + return Objects.equals(String.valueOf(expectedNames).trim(), actual); + } + + private boolean matchesCargoType(Object expectedName, Object expectedCode, Object expectedPath, + Map goods, String fallbackName) { + Object actualPath = goods.get("cargoTypePath"); + if (matchesCargoTypePath(expectedPath, actualPath)) return true; + String actualCode = firstNotBlank( + goods.get("cargoTypeCode"), + goods.get("secondCargoTypeCode"), + goods.get("firstCargoTypeCode")); + if (!isBlank(expectedCode) && Func.isNotEmpty(actualCode)) { + String expectedCodeText = String.valueOf(expectedCode).trim(); + if (expectedCodeText.equals(actualCode)) return true; + if (isFirstLevelCargoType(expectedPath, expectedCodeText) + && actualCode.startsWith(expectedCodeText)) return true; + } + if (isBlank(expectedName)) return false; + return matchesCondition(expectedName, stringValue(goods, "cargoType", fallbackName)) + || matchesCondition(expectedName, stringValue(goods, "secondCargoTypeName", "")) + || matchesCondition(expectedName, stringValue(goods, "firstCargoTypeName", "")); + } + + private boolean matchesCargoTypePath(Object expectedPath, Object actualPath) { + if (!(expectedPath instanceof Collection expectedValues) + || !(actualPath instanceof Collection actualValues) + || expectedValues.isEmpty() || actualValues.size() < expectedValues.size()) { + return false; + } + List expected = expectedValues.stream().map(String::valueOf).toList(); + List actual = actualValues.stream().map(String::valueOf).toList(); + for (int index = 0; index < expected.size(); index++) { + if (!Objects.equals(expected.get(index), actual.get(index))) return false; + } return true; } + private boolean isFirstLevelCargoType(Object expectedPath, String expectedCode) { + if (expectedPath instanceof Collection values && !values.isEmpty()) { + return values.size() == 1; + } + return expectedCode.matches("\\d{2}"); + } + + private String firstNotBlank(Object... values) { + for (Object value : values) { + if (!isBlank(value)) return String.valueOf(value).trim(); + } + return ""; + } + private String resolveRegionCode(Long addressId) { if (addressId == null) return ""; try { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ShippingTemplateServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ShippingTemplateServiceImpl.java index be33891..63b386b 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ShippingTemplateServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ShippingTemplateServiceImpl.java @@ -184,7 +184,7 @@ public class ShippingTemplateServiceImpl extends BaseServiceImpl 200) throw new ServiceException("备注不能超过200个字符"); } catch (Exception e) { - item.setErrorMessage("第" + (index + 2) + "行:" + e.getMessage()); + item.setErrorMessage(e.getMessage()); failures.add(item); } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportPlanServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportPlanServiceImpl.java index 2843a48..5deb1a5 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportPlanServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportPlanServiceImpl.java @@ -190,7 +190,7 @@ public class TransportPlanServiceImpl extends BaseServiceImpl waybill.setCarrierJson(buildImportCarrierJson(waybill)); submit(waybill); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + excel.setErrorMessage(exception.getMessage()); errorList.add(excel); } }