From 12996eb7392818a7f4e043f809489c48205dae57 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Mon, 31 Aug 2026 10:38:14 +0800 Subject: [PATCH] fix bug --- .../pojo/dto/FormalSettlementSaveRequest.java | 9 + .../dto/SettlementAdjustmentSaveRequest.java | 1 + .../pojo/dto/WaybillMileageRequest.java | 56 ++++++ .../entity/ReceivablePayableCargoFee.java | 5 +- .../transport/pojo/entity/Waybill.java | 3 + .../transport/pojo/vo/WaybillVO.java | 4 + .../SettlementAdjustmentController.java | 3 + .../controller/WaybillController.java | 18 +- .../IReceivablePayableDetailService.java | 4 + .../transport/service/IWaybillService.java | 2 + .../impl/FormalSettlementServiceImpl.java | 147 ++++++++++++++- .../impl/InvoiceApplicationServiceImpl.java | 2 +- .../impl/InvoiceReceiptServiceImpl.java | 2 +- .../ReceivablePayableDetailServiceImpl.java | 138 +++++++++++--- .../impl/SettlementAdjustmentServiceImpl.java | 169 ++++++++++++++---- .../service/impl/WaybillServiceImpl.java | 54 +++++- ...yable_cargo_fee_billing_rules_20260830.sql | 28 +++ ...ade_receivable_payable_detail_20260812.sql | 3 +- .../blade_settlement_adjustment_20260818.sql | 6 +- ...ent_adjustment_draft_nullable_20260831.sql | 5 + ...tlement_adjustment_manual_fee_20260830.sql | 5 + doc/sql/transport/blade_tms_business.sql | 2 + .../blade_waybill_mileage_remark_20260831.sql | 8 + 23 files changed, 602 insertions(+), 72 deletions(-) create mode 100644 blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillMileageRequest.java create mode 100644 doc/sql/transport/blade_receivable_payable_cargo_fee_billing_rules_20260830.sql create mode 100644 doc/sql/transport/blade_settlement_adjustment_draft_nullable_20260831.sql create mode 100644 doc/sql/transport/blade_settlement_adjustment_manual_fee_20260830.sql create mode 100644 doc/sql/transport/blade_waybill_mileage_remark_20260831.sql diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementSaveRequest.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementSaveRequest.java index 7e5c842..03210df 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementSaveRequest.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/FormalSettlementSaveRequest.java @@ -24,6 +24,7 @@ public class FormalSettlementSaveRequest implements Serializable { private String settlementType; private List sourcePreSettlementIds; private List sourceDetailIds; + private List detailAdjustments; private LocalDate exchangeRateDate; private BigDecimal exchangeRate; private String attachmentsJson; @@ -31,6 +32,14 @@ public class FormalSettlementSaveRequest implements Serializable { private List summaryFees; private List invoices; + @Data + public static class DetailAdjustment implements Serializable { + @Serial private static final long serialVersionUID = 1L; + private Long sourcePreSettlementDetailId; + private Long sourceDetailId; + private BigDecimal adjustAmount; + } + @Data public static class SummaryFee implements Serializable { @Serial private static final long serialVersionUID = 1L; diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/SettlementAdjustmentSaveRequest.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/SettlementAdjustmentSaveRequest.java index 9aa016c..1b3d27e 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/SettlementAdjustmentSaveRequest.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/SettlementAdjustmentSaveRequest.java @@ -22,6 +22,7 @@ public class SettlementAdjustmentSaveRequest implements Serializable { private Long formalSettlementDetailFeeId; private String feeType; private String feeItem; + private BigDecimal originalAmountTax; private BigDecimal adjustmentAmountTax; private BigDecimal adjustmentAmountNoTax; private String remark; diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillMileageRequest.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillMileageRequest.java new file mode 100644 index 0000000..fc78b14 --- /dev/null +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillMileageRequest.java @@ -0,0 +1,56 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *

+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.transport.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 运单里程维护请求 + * + * @author Chill + */ +@Data +@Schema(description = "运单里程维护请求") +public class WaybillMileageRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "运单ID") + private Long id; + + @Schema(description = "里程(公里)") + private BigDecimal mileage; + + @Schema(description = "里程维护备注") + private String mileageRemark; + +} diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ReceivablePayableCargoFee.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ReceivablePayableCargoFee.java index a812b0c..8c6acb2 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ReceivablePayableCargoFee.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/ReceivablePayableCargoFee.java @@ -54,7 +54,7 @@ public class ReceivablePayableCargoFee extends TenantEntity { @Schema(description = "行号") private String lineNo; - @Schema(description = "来源:自动生成/手工录入") + @Schema(description = "来源:自动生成/手动录入") private String dataSource; @Schema(description = "货物名称") @@ -75,6 +75,9 @@ public class ReceivablePayableCargoFee extends TenantEntity { @Schema(description = "计费类型") private String billingType; + @Schema(description = "命中计费规则JSON") + private String billingRulesJson; + @Schema(description = "运输量") private BigDecimal transportQuantity; diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/Waybill.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/Waybill.java index e712ce0..aaa207b 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/Waybill.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/Waybill.java @@ -163,6 +163,9 @@ public class Waybill extends TenantEntity { @Schema(description = "里程") private BigDecimal mileage; + @Schema(description = "里程维护备注") + private String mileageRemark; + @Schema(description = "预计发货日期") private LocalDate estimatedStartTime; diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/WaybillVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/WaybillVO.java index 590c804..915d715 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/WaybillVO.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/WaybillVO.java @@ -51,6 +51,10 @@ public class WaybillVO extends Waybill { @Schema(description = "是否只读") private Boolean readonly; + @TableField(exist = false) + @Schema(description = "是否允许维护里程") + private Boolean mileageMaintainable; + @TableField(exist = false) @Schema(description = "创建人姓名") private String createUserName; diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/SettlementAdjustmentController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/SettlementAdjustmentController.java index 497ed40..a846941 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/SettlementAdjustmentController.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/SettlementAdjustmentController.java @@ -11,6 +11,7 @@ import org.springblade.transport.pojo.dto.SettlementAdjustmentSaveRequest; import org.springblade.transport.pojo.dto.SettlementAdjustmentStatusRequest; import org.springblade.transport.pojo.entity.SettlementAdjustment; import org.springblade.transport.pojo.vo.SettlementAdjustmentVO; +import org.springblade.transport.service.IPreSettlementService; import org.springblade.transport.service.ISettlementAdjustmentService; import org.springframework.web.bind.annotation.*; @@ -23,10 +24,12 @@ import java.util.Map; @RequestMapping("/settlement-adjustment") public class SettlementAdjustmentController extends BladeController { private final ISettlementAdjustmentService service; + private final IPreSettlementService preSettlementService; @GetMapping("/list") public R> list(SettlementAdjustmentVO query, Query page) { return R.data(service.selectPage(Condition.getPage(page), query)); } @GetMapping("/detail") public R detail(@RequestParam Long id) { return R.data(service.detail(id)); } @GetMapping("/candidate-formal-settlements") public R>> candidates(@RequestParam(required = false) String keyword) { return R.data(service.candidateFormalSettlements(keyword)); } @GetMapping("/formal-details") public R>> formalDetails(@RequestParam Long formalSettlementId) { return R.data(service.formalDetails(formalSettlementId)); } + @GetMapping("/fee-options") public R>> feeOptions() { return R.data(preSettlementService.feeOptions()); } @PostMapping("/save") public R save(@RequestBody SettlementAdjustmentSaveRequest request) { return R.data(service.saveDraft(request)); } @PostMapping("/remove") public R remove(@RequestParam Long id) { service.removeDraft(id); return R.success("删除成功"); } @PostMapping("/submit") public R submit(@RequestBody SettlementAdjustmentStatusRequest request) { service.submit(request); return R.success("提交成功"); } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/WaybillController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/WaybillController.java index c9c8773..a21f338 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/WaybillController.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/WaybillController.java @@ -54,6 +54,7 @@ import org.springblade.transport.pojo.vo.BusinessRemoveResultVO; import org.springblade.transport.pojo.vo.LoadingManageVO; import org.springblade.transport.pojo.vo.WaybillImportBatchVO; import org.springblade.transport.pojo.vo.WaybillVO; +import org.springblade.transport.pojo.dto.WaybillMileageRequest; import org.springblade.transport.service.IContractManageService; import org.springblade.transport.service.ICustomerArchiveService; import org.springblade.transport.service.IProjectApplyService; @@ -235,36 +236,43 @@ public class WaybillController extends BladeController { return R.status(waybillService.changeRoute(waybill)); } - @PostMapping("/cancel") + @PostMapping("/maintain-mileage") @ApiOperationSupport(order = 17) + @Operation(summary = "维护里程", description = "仅已完成且未生成结算单的运单允许维护") + public R maintainMileage(@RequestBody WaybillMileageRequest request) { + return R.status(waybillService.maintainMileage(request)); + } + + @PostMapping("/cancel") + @ApiOperationSupport(order = 18) @Operation(summary = "取消", description = "传入id") public R cancel(@Parameter(description = "主键", required = true) @RequestParam Long id) { return R.status(waybillService.cancel(id)); } @PostMapping("/reassign") - @ApiOperationSupport(order = 18) + @ApiOperationSupport(order = 19) @Operation(summary = "重新派单", description = "传入id") public R reassign(@Parameter(description = "主键", required = true) @RequestParam Long id) { return R.status(waybillService.reassign(id)); } @PostMapping("/complete") - @ApiOperationSupport(order = 19) + @ApiOperationSupport(order = 20) @Operation(summary = "完成", description = "传入id") public R complete(@Parameter(description = "主键", required = true) @RequestParam Long id) { return R.status(waybillService.complete(id)); } @PostMapping("/batch-complete") - @ApiOperationSupport(order = 20) + @ApiOperationSupport(order = 21) @Operation(summary = "批量完成", description = "传入ids") public R batchComplete(@Parameter(description = "主键集合", required = true) @RequestParam String ids) { return R.data(waybillService.batchComplete(ids)); } @PostMapping("/road-loading") - @ApiOperationSupport(order = 21) + @ApiOperationSupport(order = 22) @Operation(summary = "公路配载", description = "传入ids") public R roadLoading(@Parameter(description = "主键集合", required = true) @RequestParam String ids) { return R.data(waybillService.roadLoading(ids)); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IReceivablePayableDetailService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IReceivablePayableDetailService.java index b5150b0..454e311 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IReceivablePayableDetailService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IReceivablePayableDetailService.java @@ -38,6 +38,8 @@ import org.springblade.transport.pojo.vo.ReceivablePayableFeeDetailVO; import java.util.List; import java.util.Map; +import java.util.Collection; +import java.util.Set; /** * 应收应付明细服务 @@ -50,6 +52,8 @@ public interface IReceivablePayableDetailService extends BaseService selectList(ReceivablePayableDetailVO query); + Set settlementLinkedWaybillIds(Collection waybillIds); + ReceivablePayableFeeDetailVO feeDetail(Long id); IPage changeRecords(IPage page, Long detailId); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IWaybillService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IWaybillService.java index c73eb58..791d1fc 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IWaybillService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IWaybillService.java @@ -29,6 +29,7 @@ import org.springblade.transport.pojo.entity.Waybill; import org.springblade.transport.pojo.vo.BusinessRemoveResultVO; import org.springblade.transport.pojo.vo.LoadingManageVO; import org.springblade.transport.pojo.vo.WaybillVO; +import org.springblade.transport.pojo.dto.WaybillMileageRequest; import java.util.List; @@ -47,6 +48,7 @@ public interface IWaybillService extends BaseService { List importWaybill(List data); WaybillVO copy(Long id); boolean changeRoute(Waybill waybill); + boolean maintainMileage(WaybillMileageRequest request); boolean cancel(Long id); boolean reassign(Long id); boolean complete(Long id); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java index 64a8b88..e32d29c 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java @@ -25,6 +25,8 @@ import org.springblade.transport.mapper.FormalSettlementInvoiceMapper; import org.springblade.transport.mapper.FormalSettlementSourceMapper; import org.springblade.transport.mapper.FormalSettlementSummaryFeeMapper; import org.springblade.transport.mapper.FormalSettlementPaymentMapper; +import org.springblade.transport.mapper.InvoiceReceiptMapper; +import org.springblade.transport.mapper.InvoiceReceiptSettlementMapper; import org.springblade.transport.mapper.PreSettlementDetailMapper; import org.springblade.transport.mapper.PreSettlementDetailFeeMapper; import org.springblade.transport.mapper.PreSettlementMapper; @@ -48,6 +50,8 @@ import org.springblade.transport.pojo.entity.FormalSettlementInvoice; import org.springblade.transport.pojo.entity.FormalSettlementSource; import org.springblade.transport.pojo.entity.FormalSettlementSummaryFee; import org.springblade.transport.pojo.entity.FormalSettlementPayment; +import org.springblade.transport.pojo.entity.InvoiceReceipt; +import org.springblade.transport.pojo.entity.InvoiceReceiptSettlement; import org.springblade.transport.pojo.entity.ContractManage; import org.springblade.transport.pojo.entity.PreSettlement; import org.springblade.transport.pojo.entity.PreSettlementDetail; @@ -80,6 +84,7 @@ import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -108,6 +113,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpllambdaQuery() .eq(FormalSettlementPayment::getFormalSettlementId, id).orderByDesc(FormalSettlementPayment::getCreateTime))); - vo.setInvoices(invoiceMapper.selectList(Wrappers.lambdaQuery() - .eq(FormalSettlementInvoice::getFormalSettlementId, id).orderByAsc(FormalSettlementInvoice::getLineNo))); + vo.setInvoices(listInvoices(settlement)); List preSettlementIds = sources.stream().map(FormalSettlementSource::getPreSettlementId).toList(); LambdaQueryWrapper paymentApplicationQuery = Wrappers.lambdaQuery(); if (preSettlementIds.isEmpty()) { @@ -225,6 +231,63 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl listInvoices(FormalSettlement settlement) { + List settlementInvoices = invoiceMapper.selectList( + Wrappers.lambdaQuery() + .eq(FormalSettlementInvoice::getFormalSettlementId, settlement.getId()) + .orderByAsc(FormalSettlementInvoice::getLineNo)); + Map invoiceMap = new LinkedHashMap<>(); + for (FormalSettlementInvoice invoice : settlementInvoices) { + invoiceMap.put(invoiceKey(invoice.getInvoiceNo(), "settlement:" + invoice.getId()), invoice); + } + + List receiptRelations = invoiceReceiptSettlementMapper.selectList( + Wrappers.lambdaQuery() + .and(wrapper -> wrapper + .eq(InvoiceReceiptSettlement::getFormalSettlementId, settlement.getId()) + .or() + .eq(InvoiceReceiptSettlement::getFormalSettlementNo, settlement.getFormalSettlementNo())) + .orderByAsc(InvoiceReceiptSettlement::getCreateTime)); + if (!receiptRelations.isEmpty()) { + List receiptIds = receiptRelations.stream() + .map(InvoiceReceiptSettlement::getInvoiceReceiptId) + .filter(Objects::nonNull) + .distinct() + .toList(); + Map receiptMap = receiptIds.isEmpty() ? Map.of() + : invoiceReceiptMapper.selectByIds(receiptIds).stream() + .filter(receipt -> !VOIDED.equals(receipt.getApprovalStatus()) + && !Objects.equals(receipt.getIsDeleted(), 1)) + .collect(Collectors.toMap(InvoiceReceipt::getId, Function.identity())); + for (InvoiceReceiptSettlement relation : receiptRelations) { + InvoiceReceipt receipt = receiptMap.get(relation.getInvoiceReceiptId()); + if (receipt == null) continue; + FormalSettlementInvoice invoice = new FormalSettlementInvoice(); + invoice.setFormalSettlementId(settlement.getId()); + invoice.setInvoiceNo(receipt.getInvoiceNo()); + invoice.setInvoiceDate(receipt.getInvoiceDate()); + invoice.setInvoiceType(receipt.getInvoiceType()); + invoice.setTaxRate(receipt.getTaxRate()); + invoice.setInvoiceAmount(money(receipt.getInvoiceAmount())); + invoice.setAvailableInvoiceAmount(money(receipt.getInvoiceAmount())); + invoice.setMatchedAmount(money(relation.getAllocatedInvoiceAmount())); + invoice.setAttachmentJson(receipt.getAttachmentsJson()); + invoiceMap.put(invoiceKey(receipt.getInvoiceNo(), "receipt:" + receipt.getId()), invoice); + } + } + + List invoices = new ArrayList<>(invoiceMap.values()); + for (int index = 0; index < invoices.size(); index++) { + invoices.get(index).setLineNo(index + 1); + } + return invoices; + } + + private String invoiceKey(String invoiceNo, String fallback) { + String normalizedInvoiceNo = invoiceNo == null ? "" : invoiceNo.trim(); + return normalizedInvoiceNo.isEmpty() ? fallback : normalizedInvoiceNo; + } + @Override @Transactional(rollbackFor = Exception.class) public Long saveDraft(FormalSettlementSaveRequest request) { @@ -282,6 +345,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl requestRows) { + if (Func.isEmpty(requestRows)) return; + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(FormalSettlementDetail::getFormalSettlementId, settlementId)); + Map preSettlementDetailMap = details.stream() + .filter(item -> item.getSourcePreSettlementDetailId() != null) + .collect(Collectors.toMap(FormalSettlementDetail::getSourcePreSettlementDetailId, + Function.identity(), (first, second) -> first)); + Map sourceDetailMap = details.stream() + .filter(item -> item.getSourcePreSettlementDetailId() == null && item.getSourceDetailId() != null) + .collect(Collectors.toMap(FormalSettlementDetail::getSourceDetailId, + Function.identity(), (first, second) -> first)); + Set adjustedDetailKeys = new LinkedHashSet<>(); + for (FormalSettlementSaveRequest.DetailAdjustment requestRow : requestRows) { + if (requestRow == null) throw new ServiceException("存在无效的结算明细调整"); + Long preSettlementDetailId = requestRow.getSourcePreSettlementDetailId(); + Long sourceDetailId = requestRow.getSourceDetailId(); + if (preSettlementDetailId != null && sourceDetailId != null) { + throw new ServiceException("结算明细调整只能指定一个来源明细"); + } + String detailKey = preSettlementDetailId != null + ? "pre:" + preSettlementDetailId : sourceDetailId == null ? null : "source:" + sourceDetailId; + if (detailKey == null || !adjustedDetailKeys.add(detailKey)) { + throw new ServiceException("结算明细调整数据无效或重复"); + } + FormalSettlementDetail detail = preSettlementDetailId != null + ? preSettlementDetailMap.get(preSettlementDetailId) : sourceDetailMap.get(sourceDetailId); + if (detail == null) throw new ServiceException("待调整的结算明细不属于当前正式结算单"); + BigDecimal adjustAmount = money(requestRow.getAdjustAmount()); + BigDecimal settlementAmount = money(detail.getOriginalAmount()).add(adjustAmount); + if (settlementAmount.signum() < 0) { + throw new ServiceException("单据" + detail.getDocumentNo() + "调整后的结算金额不能小于0"); + } + applyDetailFeeAmount(detail, settlementAmount); + detail.setAdjustAmount(adjustAmount); + detail.setSettlementAmountTax(settlementAmount); + detailMapper.updateById(detail); + } + } + + private void applyDetailFeeAmount(FormalSettlementDetail detail, BigDecimal settlementAmount) { + List fees = detailFees(detail.getId()); + if (fees.isEmpty()) throw new ServiceException("正式结算明细费用不存在"); + BigDecimal currentAmount = fees.stream().map(FormalSettlementDetailFee::getSettlementAmountTax) + .map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal difference = settlementAmount.subtract(currentAmount); + if (difference.signum() > 0) { + FormalSettlementDetailFee fee = fees.get(0); + fee.setSettlementAmountTax(money(fee.getSettlementAmountTax()).add(difference)); + fee.setAdjustAmount(fee.getSettlementAmountTax().subtract(money(fee.getOriginalAmount()))); + detailFeeMapper.updateById(fee); + return; + } + BigDecimal remainingDeduction = difference.abs(); + for (FormalSettlementDetailFee fee : fees) { + if (remainingDeduction.signum() == 0) break; + BigDecimal currentFeeAmount = money(fee.getSettlementAmountTax()); + BigDecimal deduction = currentFeeAmount.min(remainingDeduction); + fee.setSettlementAmountTax(currentFeeAmount.subtract(deduction)); + fee.setAdjustAmount(fee.getSettlementAmountTax().subtract(money(fee.getOriginalAmount()))); + detailFeeMapper.updateById(fee); + remainingDeduction = remainingDeduction.subtract(deduction); + } + if (remainingDeduction.signum() > 0) { + throw new ServiceException("结算明细调整后的金额无效"); + } + } + private void appendFeeAggregates(Map aggregates, Map feeTypeMap, List detailFees) { for (FormalSettlementDetailFee fee : detailFees) { @@ -648,6 +781,9 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl= 0 ? "paid" : "partial"; } + private String invoiceStatus(BigDecimal invoiceAmount, BigDecimal settlementAmount) { + BigDecimal matchedAmount = money(invoiceAmount); + if (matchedAmount.compareTo(BigDecimal.ZERO) <= 0) return "unreceived"; + return matchedAmount.compareTo(money(settlementAmount)) == 0 ? "completed" : "partial"; + } + private record PaymentSummary(BigDecimal appliedAmount, BigDecimal paidAmount) { } 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 ba1724f..eff9419 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 @@ -521,7 +521,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl= 0 ? "completed" : "partial"; + : allocated.compareTo(money(settlement.getSettlementAmount())) == 0 ? "completed" : "partial"; settlement.setInvoiceAmount(allocated); settlement.setInvoiceStatus(status); formalSettlementMapper.updateById(settlement); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java index f6b71bb..2d254ea 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java @@ -500,7 +500,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl= 0 ? "completed" : "partial"; + : invoiceAmount.compareTo(money(settlement.getSettlementAmount())) == 0 ? "completed" : "partial"; settlement.setInvoiceAmount(invoiceAmount); settlement.setInvoiceStatus(invoiceStatus); formalSettlementMapper.updateById(settlement); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java index 3a91d01..09b27ce 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java @@ -103,7 +103,17 @@ public class ReceivablePayableDetailServiceImpl private static final String SOURCE_MASTER_ORDER = "总单系统生成"; private static final String SOURCE_LOADING_ORDER = "配载单系统生成"; private static final String FEE_SOURCE_AUTO = "自动生成"; - private static final String FEE_SOURCE_MANUAL = "手工录入"; + private static final String FEE_SOURCE_MANUAL = "手动录入"; + private static final Set FEE_SOURCE_MANUAL_LEGACY = Set.of("手工录入", "手动添加"); + private static final Map> MANUAL_BILLING_TYPES = Map.of( + "按重量", List.of("固定单价", "区间单价", "阶梯单价", "区间阶梯一口价"), + "按体积", List.of("固定单价", "区间单价", "阶梯单价", "区间阶梯一口价"), + "按车辆", List.of("固定单价"), + "按里程", List.of("固定单价", "区间单价", "阶梯单价", "区间阶梯一口价"), + "按吨·公里", List.of("固定单价", "区间单价", "阶梯单价", "区间阶梯一口价"), + "固定金额(整单一口价)", List.of("固定一口价"), + "按数量", List.of("固定单价", "区间单价", "阶梯单价", "区间阶梯一口价") + ); private final ReceivablePayableCargoFeeMapper cargoFeeMapper; private final ReceivablePayableChangeRecordMapper changeRecordMapper; @@ -148,6 +158,44 @@ public class ReceivablePayableDetailServiceImpl return result; } + @Override + public Set settlementLinkedWaybillIds(Collection waybillIds) { + Set candidateIds = waybillIds == null ? Set.of() : waybillIds.stream() + .filter(Objects::nonNull) + .collect(Collectors.toCollection(LinkedHashSet::new)); + if (candidateIds.isEmpty()) { + return Set.of(); + } + Set result = list(settlementLinkedQuery() + .in(ReceivablePayableDetail::getWaybillId, candidateIds)) + .stream() + .map(ReceivablePayableDetail::getWaybillId) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(LinkedHashSet::new)); + List cargoFees = cargoFeeMapper.selectList( + Wrappers.lambdaQuery() + .eq(ReceivablePayableCargoFee::getIsDeleted, 0) + .in(ReceivablePayableCargoFee::getWaybillId, candidateIds)); + Set cargoDetailIds = cargoFees.stream() + .map(ReceivablePayableCargoFee::getDetailId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (cargoDetailIds.isEmpty()) { + return result; + } + Set settlementLinkedDetailIds = list(settlementLinkedQuery() + .in(ReceivablePayableDetail::getId, cargoDetailIds)) + .stream() + .map(ReceivablePayableDetail::getId) + .collect(Collectors.toSet()); + cargoFees.stream() + .filter(item -> settlementLinkedDetailIds.contains(item.getDetailId())) + .map(ReceivablePayableCargoFee::getWaybillId) + .filter(Objects::nonNull) + .forEach(result::add); + return result; + } + @Override public ReceivablePayableFeeDetailVO feeDetail(Long id) { ReceivablePayableDetail detail = getExisting(id); @@ -282,11 +330,11 @@ public class ReceivablePayableDetailServiceImpl throw new ServiceException("变更原因不能超过300个字"); } if (Boolean.TRUE.equals(adjusted.getManualFee())) { - if (existing == null && !"receivable".equals(detail.getSettlementType())) { - throw new ServiceException("仅应收明细允许新增手工费用"); + if (existing == null && !"payable".equals(detail.getSettlementType())) { + throw new ServiceException("仅应付明细允许新增费用"); } if (existing != null && !isManualFee(existing)) { - throw new ServiceException("自动生成费用行不能变更为手工录入"); + throw new ServiceException("自动生成费用行不能变更为手动录入"); } validateAdjustRow(adjusted, true); Map manualItems = validatedFeeItems(adjusted.getFeeItems(), allowedFeeItems); @@ -304,8 +352,6 @@ public class ReceivablePayableDetailServiceImpl BigDecimal oldAmount = money(existing.getAfterAmount()); applyEditableFields(existing, adjusted, true); existing.setDataSource(FEE_SOURCE_MANUAL); - existing.setBillingFactor("-"); - existing.setBillingType("-"); existing.setFreightAmount(freightAmount); existing.setFeeItemsJson(JsonUtil.toJson(manualItems)); existing.setAdjustAmount(afterAmount.subtract(money(existing.getOriginalAmount()))); @@ -318,7 +364,7 @@ public class ReceivablePayableDetailServiceImpl } else { cargoFeeMapper.updateById(existing); } - changes.add("【手工费用】从[" + Objects.toString(oldCargoName, "") + " " + changes.add("【手动录入】从[" + Objects.toString(oldCargoName, "") + " " + formatValue(oldAmount) + "]调整为[" + Objects.toString(existing.getCargoName(), "") + " " + formatValue(afterAmount) + "]"); continue; @@ -327,7 +373,7 @@ public class ReceivablePayableDetailServiceImpl throw new ServiceException("存在无效的费用调整行"); } if (isManualFee(existing)) { - throw new ServiceException("手工录入费用行不能变更为自动生成"); + throw new ServiceException("手动录入费用行不能变更为自动生成"); } validateAdjustRow(adjusted, false); Map feeItems = validatedFeeItems(adjusted.getFeeItems(), allowedFeeItems); @@ -335,6 +381,14 @@ public class ReceivablePayableDetailServiceImpl BigDecimal mileage = money(adjusted.getMileage()); BigDecimal freightAmount = money(adjusted.getFreightAmount()); Map effectiveFeeItems = feeItems; + boolean billingBasisChanged = money(existing.getTransportQuantity()).compareTo(transportQuantity) != 0 + || money(existing.getMileage()).compareTo(mileage) != 0; + if (billingBasisChanged) { + AdjustedFeeCalculation calculation = calculateAdjustedFee(detail, existing, + transportQuantity, mileage, freightAmount, feeItems); + freightAmount = calculation.freightAmount(); + effectiveFeeItems = calculation.feeItems(); + } appendChange(changes, "规格", existing.getSpecification(), adjusted.getSpecification()); appendChange(changes, "型号", existing.getModel(), adjusted.getModel()); appendChange(changes, "计费要素", existing.getBillingFactor(), adjusted.getBillingFactor()); @@ -983,6 +1037,17 @@ public class ReceivablePayableDetailServiceImpl return wrapper.orderByDesc(ReceivablePayableDetail::getCreateTime); } + private LambdaQueryWrapper settlementLinkedQuery() { + return Wrappers.lambdaQuery() + .eq(ReceivablePayableDetail::getIsDeleted, 0) + .and(wrapper -> wrapper + .isNotNull(ReceivablePayableDetail::getPreSettlementNo) + .ne(ReceivablePayableDetail::getPreSettlementNo, "") + .or() + .isNotNull(ReceivablePayableDetail::getFormalSettlementNo) + .ne(ReceivablePayableDetail::getFormalSettlementNo, "")); + } + private LambdaQueryWrapper buildUpdateQuery(ReceivablePayableUpdateFeeRequest request) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .eq(ReceivablePayableDetail::getIsDeleted, 0) @@ -1276,6 +1341,7 @@ public class ReceivablePayableDetailServiceImpl } Map, ReceivablePayableCargoFee> feesByCargo = new LinkedHashMap<>(); Map, Map> feeItemsByCargo = new LinkedHashMap<>(); + Map, List>> billingRulesByCargo = new LinkedHashMap<>(); Set> freightBillingCargoKeys = new LinkedHashSet<>(); for (Object value : (List) plan.get("rules")) { if (!(value instanceof Map raw)) continue; @@ -1292,8 +1358,12 @@ public class ReceivablePayableDetailServiceImpl key -> buildCalculatedCargoFee(waybill, feeWaybill, feeGoods, rule)); Map feeItems = feeItemsByCargo.computeIfAbsent(cargoKey, key -> new LinkedHashMap<>()); + List> billingRules = billingRulesByCargo.computeIfAbsent(cargoKey, + key -> new ArrayList<>()); + billingRules.add(new LinkedHashMap<>(rule)); feeItems.merge(feeItem, amount, BigDecimal::add); fee.setFeeItemsJson(JsonUtil.toJson(feeItems)); + fee.setBillingRulesJson(JsonUtil.toJson(billingRules)); fee.setOriginalAmount(money(fee.getOriginalAmount()).add(amount)); fee.setAfterAmount(fee.getOriginalAmount()); if (isFreightRule(rule)) { @@ -1648,13 +1718,25 @@ public class ReceivablePayableDetailServiceImpl } private boolean isManualFee(ReceivablePayableCargoFee fee) { - return FEE_SOURCE_MANUAL.equals(fee.getDataSource()) || "手工调整".equals(fee.getBillingFactor()); + return FEE_SOURCE_MANUAL.equals(fee.getDataSource()) + || FEE_SOURCE_MANUAL_LEGACY.contains(fee.getDataSource()) + || "手工调整".equals(fee.getBillingFactor()); } private void validateAdjustRow(ReceivablePayableAdjustFeeRequest.AdjustRow row, boolean manualFee) { if (manualFee) { + if (isBlank(row.getCargoName())) { + throw new ServiceException("货物名称不能为空"); + } validateLength(row.getCargoName(), 100, "货物名称"); validateLength(row.getCargoType(), 100, "货物类型"); + List billingTypes = MANUAL_BILLING_TYPES.get(row.getBillingFactor()); + if (billingTypes == null) { + throw new ServiceException("请选择计费要素"); + } + if (!billingTypes.contains(row.getBillingType())) { + throw new ServiceException("请选择计费要素对应的计费类型"); + } } validateLength(row.getSpecification(), 255, "规格"); validateLength(row.getModel(), 255, "型号"); @@ -1688,10 +1770,10 @@ public class ReceivablePayableDetailServiceImpl } private void applyEditableFields(ReceivablePayableCargoFee fee, - ReceivablePayableAdjustFeeRequest.AdjustRow adjusted, - boolean manualFee) { + ReceivablePayableAdjustFeeRequest.AdjustRow adjusted, + boolean manualFee) { if (manualFee) { - fee.setCargoName(adjusted.getCargoName()); + fee.setCargoName(adjusted.getCargoName().trim()); fee.setCargoType(adjusted.getCargoType()); } fee.setSpecification(adjusted.getSpecification()); @@ -1727,12 +1809,18 @@ public class ReceivablePayableDetailServiceImpl if (isManualFee(fee)) { throw new ServiceException("手工费用不支持按合同计费规则试算"); } - ContractManage contract = contractManageService.getById(detail.getContractId()); - if (contract == null) { - throw new ServiceException("关联合同不存在"); - } Waybill adjustedWaybill = adjustedWaybill(detail, fee, transportQuantity, mileage); - List> rules = matchingAdjustedRules(contract, fee, adjustedWaybill); + List> rules = parseList(fee.getBillingRulesJson()); + if (rules.isEmpty()) { + ContractManage contract = contractManageService.getById(detail.getContractId()); + if (contract == null) { + throw new ServiceException("关联合同不存在"); + } + rules = matchingAdjustedRules(contract, fee, adjustedWaybill); + if (!rules.isEmpty()) { + fee.setBillingRulesJson(JsonUtil.toJson(rules)); + } + } if (rules.isEmpty()) { throw new ServiceException("未找到费用明细对应的合同计费规则,请先更新费用"); } @@ -1760,7 +1848,8 @@ public class ReceivablePayableDetailServiceImpl private Waybill adjustedWaybill(ReceivablePayableDetail detail, ReceivablePayableCargoFee fee, BigDecimal transportQuantity, BigDecimal mileage) { - Waybill source = detail.getWaybillId() == null ? null : waybillService.getById(detail.getWaybillId()); + Long waybillId = fee.getWaybillId() == null ? detail.getWaybillId() : fee.getWaybillId(); + Waybill source = waybillId == null ? null : waybillService.getById(waybillId); Waybill waybill = source == null ? new Waybill() : Objects.requireNonNull(BeanUtil.copyProperties(source, Waybill.class)); waybill.setQuantity(transportQuantity); @@ -1791,15 +1880,23 @@ public class ReceivablePayableDetailServiceImpl List> firstCandidates = List.of(); List> defaultCandidates = List.of(); List> billingMatchedCandidates = List.of(); + List> billingFieldCandidates = List.of(); for (Map plan : parseList(contract.getBillingPlanJson())) { if (!(plan.get("rules") instanceof List rules)) continue; List> candidates = new ArrayList<>(); + List> feeItemCandidates = new ArrayList<>(); for (Object value : rules) { if (!(value instanceof Map raw)) continue; Map rule = new LinkedHashMap<>(); raw.forEach((key, item) -> rule.put(String.valueOf(key), item)); - if (!feeItemNames.contains(stringValue(rule, "feeItem")) || !matchesRule(rule, waybill)) continue; - candidates.add(rule); + if (!feeItemNames.contains(stringValue(rule, "feeItem"))) continue; + feeItemCandidates.add(rule); + if (matchesRule(rule, waybill)) candidates.add(rule); + } + if (feeItemCandidates.stream().anyMatch(rule -> matchesBillingFields(rule, fee))) { + if (billingFieldCandidates.isEmpty() || isDefaultPlan(plan)) { + billingFieldCandidates = feeItemCandidates; + } } if (candidates.isEmpty()) continue; if (firstCandidates.isEmpty()) firstCandidates = candidates; @@ -1811,6 +1908,7 @@ public class ReceivablePayableDetailServiceImpl } } if (!billingMatchedCandidates.isEmpty()) return billingMatchedCandidates; + if (!billingFieldCandidates.isEmpty()) return billingFieldCandidates; return defaultCandidates.isEmpty() ? firstCandidates : defaultCandidates; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java index 6970ebd..d45f106 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java @@ -13,6 +13,7 @@ import org.springblade.transport.mapper.FormalSettlementDetailFeeMapper; import org.springblade.transport.mapper.FormalSettlementDetailMapper; import org.springblade.transport.mapper.FormalSettlementChangeRecordMapper; import org.springblade.transport.mapper.FormalSettlementMapper; +import org.springblade.transport.mapper.FormalSettlementSummaryFeeMapper; import org.springblade.transport.mapper.SettlementAdjustmentDetailMapper; import org.springblade.transport.mapper.SettlementAdjustmentMapper; import org.springblade.transport.pojo.dto.SettlementAdjustmentSaveRequest; @@ -21,6 +22,7 @@ import org.springblade.transport.pojo.entity.FormalSettlement; import org.springblade.transport.pojo.entity.FormalSettlementChangeRecord; import org.springblade.transport.pojo.entity.FormalSettlementDetail; import org.springblade.transport.pojo.entity.FormalSettlementDetailFee; +import org.springblade.transport.pojo.entity.FormalSettlementSummaryFee; import org.springblade.transport.pojo.entity.SettlementAdjustment; import org.springblade.transport.pojo.entity.SettlementAdjustmentDetail; import org.springblade.transport.pojo.vo.SettlementAdjustmentVO; @@ -46,10 +48,12 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl> candidateFormalSettlements(String keyword) { List rows = formalMapper.selectList(Wrappers.lambdaQuery() .eq(FormalSettlement::getApprovalStatus, APPROVED) + .and(wrapper -> wrapper.isNull(FormalSettlement::getPaymentStatus) + .or().ne(FormalSettlement::getPaymentStatus, PAID)) .like(Func.isNotEmpty(keyword), FormalSettlement::getFormalSettlementNo, keyword) .orderByDesc(FormalSettlement::getCreateTime)); List> result = new ArrayList<>(); @@ -104,8 +110,7 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl> formalDetails(Long formalSettlementId) { - FormalSettlement settlement = formalMapper.selectById(formalSettlementId); - if (settlement == null || !APPROVED.equals(settlement.getApprovalStatus())) throw new ServiceException("仅审批通过的正式结算单可调整"); + FormalSettlement settlement = adjustableFormalSettlement(formalSettlementId); List> result = new ArrayList<>(); List details = formalDetailMapper.selectList(Wrappers.lambdaQuery() .eq(FormalSettlementDetail::getFormalSettlementId, formalSettlementId).orderByAsc(FormalSettlementDetail::getLineNo)); @@ -126,38 +131,64 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpllambdaQuery().eq(SettlementAdjustmentDetail::getAdjustmentId, adjustment.getId())); - if (adjustment.getId() == null) { adjustment.setAdjustmentNo(nextNo()); adjustment.setApprovalStatus(DRAFT); } - adjustment.setFormalSettlementId(formal.getId()); adjustment.setFormalSettlementNo(formal.getFormalSettlementNo()); - adjustment.setSettlementType(formal.getSettlementType()); adjustment.setProjectName(formal.getProjectName()); - adjustment.setDeptName(formal.getDeptName()); adjustment.setCustomerName("receivable".equals(formal.getSettlementType()) ? formal.getPayerName() : formal.getPayeeName()); - adjustment.setContractNo(formal.getContractNo()); adjustment.setContractName(formal.getContractName()); - adjustment.setKingdeeSyncStatus(formal.getKingdeeSyncStatus()); - adjustment.setOriginalSettlementAmount(money(formal.getSettlementAmount())); adjustment.setRemark(limit(request.getRemark(), 200)); + FormalSettlement formal = request.getFormalSettlementId() == null + ? null : formalMapper.selectById(request.getFormalSettlementId()); + if (adjustment.getId() == null) adjustment.setAdjustmentNo(nextNo()); + adjustment.setApprovalStatus(DRAFT); + adjustment.setCurrentNode("草稿"); + adjustment.setCurrentProcessor(AuthUtil.getUserName()); + adjustment.setApprovedTime(null); + applyFormalSnapshot(adjustment, formal, request.getFormalSettlementId()); + adjustment.setRemark(request.getRemark()); adjustment.setAttachmentsJson(request.getAttachmentsJson()); + adjustment.setAdjustmentAmount(BigDecimal.ZERO.setScale(2)); + adjustment.setAdjustedSettlementAmount(money(adjustment.getOriginalSettlementAmount())); + saveOrUpdate(adjustment); + detailMapper.delete(Wrappers.lambdaQuery() + .eq(SettlementAdjustmentDetail::getAdjustmentId, adjustment.getId())); BigDecimal total = BigDecimal.ZERO; if (request.getDetails() != null) for (SettlementAdjustmentSaveRequest.Detail row : request.getDetails()) { - FormalSettlementDetailFee fee = validateFee(formal.getId(), row.getFormalSettlementDetailId(), row.getFormalSettlementDetailFeeId()); - if (adjustment.getId() == null) save(adjustment); + if (row == null) continue; SettlementAdjustmentDetail detail = new SettlementAdjustmentDetail(); detail.setAdjustmentId(adjustment.getId()); detail.setFormalSettlementDetailId(row.getFormalSettlementDetailId()); detail.setFormalSettlementDetailFeeId(row.getFormalSettlementDetailFeeId()); - detail.setFeeType(row.getFeeType()); detail.setFeeItem(row.getFeeItem()); detail.setOriginalAmountTax(fee.getSettlementAmountTax()); - detail.setAdjustmentAmountTax(row.getAdjustmentAmountTax() == null ? BigDecimal.ZERO : row.getAdjustmentAmountTax()); - detail.setAdjustmentAmountNoTax(row.getAdjustmentAmountNoTax()); detail.setRemark(limit(row.getRemark(), 200)); detailMapper.insert(detail); + detail.setFeeType(row.getFeeType()); detail.setFeeItem(row.getFeeItem()); + detail.setOriginalAmountTax(money(row.getOriginalAmountTax())); + detail.setAdjustmentAmountTax(money(row.getAdjustmentAmountTax())); + detail.setAdjustmentAmountNoTax(row.getAdjustmentAmountNoTax()); detail.setRemark(row.getRemark()); detailMapper.insert(detail); total = total.add(detail.getAdjustmentAmountTax()); } - adjustment.setAdjustmentAmount(total); adjustment.setAdjustedSettlementAmount(adjustment.getOriginalSettlementAmount().add(total)); saveOrUpdate(adjustment); + adjustment.setAdjustmentAmount(total); adjustment.setAdjustedSettlementAmount(money(adjustment.getOriginalSettlementAmount()).add(total)); updateById(adjustment); return adjustment.getId(); } @Override @Transactional(rollbackFor = Exception.class) public void removeDraft(Long id) { SettlementAdjustment item = editable(id); detailMapper.delete(Wrappers.lambdaQuery().eq(SettlementAdjustmentDetail::getAdjustmentId, id)); removeById(item.getId()); } - @Override public void submit(SettlementAdjustmentStatusRequest request) { changeStatus(request.getId(), DRAFT, REVIEWING, "审批中", null); } + @Override + @Transactional(rollbackFor = Exception.class) + public void submit(SettlementAdjustmentStatusRequest request) { + SettlementAdjustment item = existing(request.getId()); + if (!DRAFT.equals(item.getApprovalStatus())) throw new ServiceException("仅草稿状态的调整单允许提交"); + FormalSettlement formal = adjustableFormalSettlement(item.getFormalSettlementId()); + List details = detailMapper.selectList( + Wrappers.lambdaQuery() + .eq(SettlementAdjustmentDetail::getAdjustmentId, item.getId())); + if (details.isEmpty()) throw new ServiceException("请至少添加一条调整费用"); + for (SettlementAdjustmentDetail detail : details) { + boolean manualFee = isManualFee(detail); + if (!manualFee && (detail.getFormalSettlementDetailId() == null + || detail.getFormalSettlementDetailFeeId() == null)) { + throw new ServiceException("费用明细关联信息不完整"); + } + if (!manualFee) validateFee(formal.getId(), detail.getFormalSettlementDetailId(), + detail.getFormalSettlementDetailFeeId()); + requiredText(detail.getFeeType(), "费用类型", 100); + requiredText(detail.getFeeItem(), "费用项目", 100); + limit(detail.getRemark(), 200); + } + limit(item.getRemark(), 200); + changeStatus(item.getId(), DRAFT, REVIEWING, "审批中", null); + } @Override public void returnBill(SettlementAdjustmentStatusRequest request) { changeStatus(request.getId(), REVIEWING, RETURNED, "已驳回", limit(request.getReason(), 200)); } @Override @@ -177,19 +208,26 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpllambdaQuery().eq(SettlementAdjustmentDetail::getAdjustmentId, adjustment.getId()))) { - FormalSettlementDetailFee fee = validateFee(formal.getId(), item.getFormalSettlementDetailId(), item.getFormalSettlementDetailFeeId()); - BigDecimal beforeAmount = money(fee.getSettlementAmountTax()); - fee.setSettlementAmountTax(money(fee.getSettlementAmountTax()).add(money(item.getAdjustmentAmountTax()))); - if (item.getAdjustmentAmountNoTax() != null) fee.setSettlementAmountNoTax(money(fee.getSettlementAmountNoTax()).add(item.getAdjustmentAmountNoTax())); - fee.setAdjustAmount(money(fee.getAdjustAmount()).add(item.getAdjustmentAmountTax())); formalFeeMapper.updateById(fee); - FormalSettlementDetail formalDetail = formalDetailMapper.selectById(item.getFormalSettlementDetailId()); - saveFormalChange(formal.getId(), "结算明细项", formalDetail == null ? null : formalDetail.getLineNo(), - "调整", "【" + (Func.isEmpty(item.getFeeItem()) ? "结算费用" : item.getFeeItem()) - + "】从【" + beforeAmount + "】调整为【" + fee.getSettlementAmountTax() + "】", - Func.isEmpty(item.getRemark()) ? adjustment.getRemark() : item.getRemark()); + if (money(item.getAdjustmentAmountTax()).signum() == 0) continue; + if (isManualFee(item)) { + saveFormalChange(formal.getId(), "合计费用项", null, "调整", + "新增【" + item.getFeeItem() + "】调整费用【" + money(item.getAdjustmentAmountTax()) + "】", + Func.isEmpty(item.getRemark()) ? adjustment.getRemark() : item.getRemark()); + } else { + FormalSettlementDetailFee fee = validateFee(formal.getId(), item.getFormalSettlementDetailId(), item.getFormalSettlementDetailFeeId()); + BigDecimal beforeAmount = money(fee.getSettlementAmountTax()); + fee.setSettlementAmountTax(beforeAmount.add(money(item.getAdjustmentAmountTax()))); + if (item.getAdjustmentAmountNoTax() != null) fee.setSettlementAmountNoTax(money(fee.getSettlementAmountNoTax()).add(item.getAdjustmentAmountNoTax())); + fee.setAdjustAmount(money(fee.getAdjustAmount()).add(item.getAdjustmentAmountTax())); formalFeeMapper.updateById(fee); + FormalSettlementDetail formalDetail = formalDetailMapper.selectById(item.getFormalSettlementDetailId()); + saveFormalChange(formal.getId(), "结算明细项", formalDetail == null ? null : formalDetail.getLineNo(), + "调整", "【" + (Func.isEmpty(item.getFeeItem()) ? "结算费用" : item.getFeeItem()) + + "】从【" + beforeAmount + "】调整为【" + fee.getSettlementAmountTax() + "】", + Func.isEmpty(item.getRemark()) ? adjustment.getRemark() : item.getRemark()); + } + applySummaryAdjustment(formal.getId(), item); } for (FormalSettlementDetail detail : formalDetailMapper.selectList(Wrappers.lambdaQuery().eq(FormalSettlementDetail::getFormalSettlementId, formal.getId()))) { List fees = formalFeeMapper.selectList(Wrappers.lambdaQuery().eq(FormalSettlementDetailFee::getFormalSettlementDetailId, detail.getId())); @@ -197,8 +235,12 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpllambdaQuery().eq(FormalSettlementDetail::getFormalSettlementId, formal.getId())).stream().map(FormalSettlementDetail::getSettlementAmountTax).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); - formal.setSettlementAmount(amount); formal.setLocalSettlementAmount(amount.multiply(formal.getExchangeRate() == null ? BigDecimal.ONE : formal.getExchangeRate())); formalMapper.updateById(formal); + BigDecimal amount = money(formal.getSettlementAmount()).add(money(adjustment.getAdjustmentAmount())); + formal.setSettlementAmount(amount); + formal.setLocalSettlementAmount(amount.multiply(formal.getExchangeRate() == null ? BigDecimal.ONE : formal.getExchangeRate())); + formal.setRemainingPayableAmount(amount.subtract(money(formal.getAppliedPaymentAmount())) + .subtract(money(formal.getPaidAmount())).max(BigDecimal.ZERO)); + formalMapper.updateById(formal); saveFormalChange(formal.getId(), "合计费用项", null, "调整", "调整单" + adjustment.getAdjustmentNo() + "调整金额【" + money(adjustment.getAdjustmentAmount()) + "】", adjustment.getRemark()); @@ -222,11 +264,66 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl formalSummaryFees(Long formalId) { return formalSummaryFeeMapper.selectList(Wrappers.lambdaQuery().eq(FormalSettlementSummaryFee::getFormalSettlementId, formalId).eq(FormalSettlementSummaryFee::getIsDeleted, 0).orderByAsc(FormalSettlementSummaryFee::getLineNo)); } + private void applySummaryAdjustment(Long formalId, SettlementAdjustmentDetail detail) { + List summaryFees = formalSummaryFees(formalId); + FormalSettlementSummaryFee summaryFee = summaryFees.stream() + .filter(item -> Objects.equals(item.getFeeType(), detail.getFeeType()) && Objects.equals(item.getFeeItem(), detail.getFeeItem())) + .findFirst().orElse(null); + BigDecimal adjustmentAmount = money(detail.getAdjustmentAmountTax()); + if (summaryFee == null) { + summaryFee = new FormalSettlementSummaryFee(); + summaryFee.setFormalSettlementId(formalId); + summaryFee.setLineNo(summaryFees.stream().map(FormalSettlementSummaryFee::getLineNo) + .filter(Objects::nonNull).max(Integer::compareTo).orElse(0) + 1); + summaryFee.setFeeType(detail.getFeeType()); + summaryFee.setFeeItem(detail.getFeeItem()); + summaryFee.setOriginalAmount(BigDecimal.ZERO.setScale(2)); + summaryFee.setAdjustAmount(adjustmentAmount); + summaryFee.setSettlementAmount(adjustmentAmount); + summaryFee.setRemark(""); + summaryFee.setManualFlag(1); + formalSummaryFeeMapper.insert(summaryFee); + return; + } + summaryFee.setAdjustAmount(money(summaryFee.getAdjustAmount()).add(adjustmentAmount)); + summaryFee.setSettlementAmount(money(summaryFee.getSettlementAmount()).add(adjustmentAmount)); + formalSummaryFeeMapper.updateById(summaryFee); + } private SettlementAdjustmentVO toVO(SettlementAdjustment item) { SettlementAdjustmentVO vo = new SettlementAdjustmentVO(); org.springframework.beans.BeanUtils.copyProperties(item, vo); vo.setCreateUserName(UserCache.getUserRealName(item.getCreateUser())); vo.setApprovalStatusName(statusName(item.getApprovalStatus())); vo.setSettlementTypeName(typeName(item.getSettlementType())); return vo; } private String statusName(String value) { return Map.of(DRAFT, "草稿", REVIEWING, "审批中", APPROVED, "审批通过", RETURNED, "已驳回").getOrDefault(value, value); } - private String typeName(String value) { return "receivable".equals(value) ? "应收" : "应付"; } + private String typeName(String value) { return "receivable".equals(value) ? "应收" : "payable".equals(value) ? "应付" : ""; } private synchronized String nextNo() { String prefix = "TZ" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); long count = count(Wrappers.lambdaQuery().likeRight(SettlementAdjustment::getAdjustmentNo, prefix)); return prefix + String.format("%04d", count + 1); } private BigDecimal money(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; } + private String requiredText(String value, String field, int max) { if (Func.isEmpty(value)) throw new ServiceException(field + "不能为空"); return limit(value.trim(), max); } private String limit(String value, int max) { if (value != null && value.length() > max) throw new ServiceException("内容不能超过" + max + "个字"); return value; } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java index 7b51e3d..ce1e61e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java @@ -40,6 +40,7 @@ import org.springblade.transport.pojo.entity.LoadingManage; import org.springblade.transport.pojo.entity.ContractManage; import org.springblade.transport.pojo.entity.ProcessConfig; import org.springblade.transport.pojo.entity.Waybill; +import org.springblade.transport.pojo.dto.WaybillMileageRequest; import org.springblade.transport.pojo.vo.BusinessRemoveResultVO; import org.springblade.transport.pojo.vo.LoadingManageVO; import org.springblade.transport.pojo.vo.WaybillVO; @@ -60,6 +61,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; /** @@ -89,12 +91,16 @@ public class WaybillServiceImpl extends BaseServiceImpl @Override public IPage selectWaybillPage(IPage page, WaybillVO waybill) { IPage entityPage = page(page, buildQuery(waybill)); - return WaybillWrapper.build().pageVO(entityPage); + IPage result = WaybillWrapper.build().pageVO(entityPage); + fillMileageMaintainable(result.getRecords()); + return result; } @Override public WaybillVO detail(Long id) { - return WaybillWrapper.build().entityVO(loadEditable(id, false)); + WaybillVO result = WaybillWrapper.build().entityVO(loadEditable(id, false)); + fillMileageMaintainable(List.of(result)); + return result; } @Override @@ -108,8 +114,10 @@ public class WaybillServiceImpl extends BaseServiceImpl waybill.setLoadingNo(oldRecord.getLoadingNo()); waybill.setDeptId(oldRecord.getDeptId()); waybill.setDeptName(oldRecord.getDeptName()); + waybill.setMileageRemark(oldRecord.getMileageRemark()); } else { waybill.setLoadingNo(null); + waybill.setMileageRemark(null); fillProjectProcessConfig(waybill); } prepare(waybill); @@ -306,6 +314,32 @@ public class WaybillServiceImpl extends BaseServiceImpl return updateById(oldRecord); } + @Override + @Transactional(rollbackFor = Exception.class) + public boolean maintainMileage(WaybillMileageRequest request) { + if (request == null || request.getId() == null) { + throw new ServiceException("运单里程维护数据不能为空"); + } + Waybill waybill = loadEditable(request.getId(), true); + if (!"completed".equals(waybill.getBusinessStatus())) { + throw new ServiceException("仅已完成运单允许维护里程"); + } + if (receivablePayableDetailService.settlementLinkedWaybillIds(List.of(waybill.getId())) + .contains(waybill.getId())) { + throw new ServiceException("该运单已生成结算单,无法维护里程"); + } + BigDecimal mileage = request.getMileage(); + if (mileage == null || mileage.compareTo(BigDecimal.ZERO) <= 0 + || mileage.stripTrailingZeros().scale() > 0 || mileage.stripTrailingZeros().precision() > 10) { + throw new ServiceException("里程必须为不超过10位的正整数"); + } + String mileageRemark = TransportBusinessSupport.trimToNull(request.getMileageRemark()); + TransportBusinessSupport.validateLength(mileageRemark, 200, "里程维护备注不能超过200字"); + waybill.setMileage(mileage); + waybill.setMileageRemark(mileageRemark); + return updateById(waybill); + } + @Override @Transactional(rollbackFor = Exception.class) public boolean cancel(Long id) { @@ -504,6 +538,22 @@ public class WaybillServiceImpl extends BaseServiceImpl return queryWrapper; } + private void fillMileageMaintainable(List waybills) { + waybills.forEach(item -> item.setMileageMaintainable(false)); + List completedIds = waybills.stream() + .filter(item -> "completed".equals(item.getBusinessStatus())) + .map(Waybill::getId) + .filter(Objects::nonNull) + .toList(); + if (completedIds.isEmpty()) { + return; + } + Set settlementLinkedIds = receivablePayableDetailService.settlementLinkedWaybillIds(completedIds); + waybills.stream() + .filter(item -> completedIds.contains(item.getId())) + .forEach(item -> item.setMileageMaintainable(!settlementLinkedIds.contains(item.getId()))); + } + private void prepare(Waybill waybill) { if (isSentinelMinusOne(waybill.getQuantity())) waybill.setQuantity(null); if (isSentinelMinusOne(waybill.getMileage())) waybill.setMileage(null); diff --git a/doc/sql/transport/blade_receivable_payable_cargo_fee_billing_rules_20260830.sql b/doc/sql/transport/blade_receivable_payable_cargo_fee_billing_rules_20260830.sql new file mode 100644 index 0000000..5bcfde3 --- /dev/null +++ b/doc/sql/transport/blade_receivable_payable_cargo_fee_billing_rules_20260830.sql @@ -0,0 +1,28 @@ +-- MySQL 5.7+ 兼容:保存应收应付费用生成时实际命中的计费规则。 +-- 请在 transport 数据库执行。本脚本使用 information_schema 判断,可重复执行。 + +DELIMITER $$ + +DROP PROCEDURE IF EXISTS `upgrade_receivable_payable_cargo_fee_billing_rules_20260830`$$ +CREATE PROCEDURE `upgrade_receivable_payable_cargo_fee_billing_rules_20260830`() +BEGIN + DECLARE db_name varchar(128); + SET db_name = DATABASE(); + + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_schema = db_name + AND table_name = 'blade_receivable_payable_cargo_fee' + AND column_name = 'billing_rules_json' + ) THEN + ALTER TABLE `blade_receivable_payable_cargo_fee` + ADD COLUMN `billing_rules_json` text COLLATE utf8mb4_general_ci DEFAULT NULL + COMMENT '命中计费规则JSON' AFTER `billing_type`; + END IF; +END$$ + +CALL `upgrade_receivable_payable_cargo_fee_billing_rules_20260830`()$$ +DROP PROCEDURE `upgrade_receivable_payable_cargo_fee_billing_rules_20260830`$$ + +DELIMITER ; diff --git a/doc/sql/transport/blade_receivable_payable_detail_20260812.sql b/doc/sql/transport/blade_receivable_payable_detail_20260812.sql index 5e77871..bb7ecab 100644 --- a/doc/sql/transport/blade_receivable_payable_detail_20260812.sql +++ b/doc/sql/transport/blade_receivable_payable_detail_20260812.sql @@ -64,13 +64,14 @@ CREATE TABLE IF NOT EXISTS `blade_receivable_payable_cargo_fee` ( `detail_id` bigint(20) NOT NULL COMMENT '应收应付明细ID', `waybill_id` bigint(20) DEFAULT NULL COMMENT '运单ID', `line_no` varchar(30) DEFAULT NULL COMMENT '行号', - `data_source` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '自动生成' COMMENT '来源:自动生成/手工录入', + `data_source` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '自动生成' COMMENT '来源:自动生成/手动录入', `cargo_name` varchar(100) DEFAULT NULL COMMENT '货物名称', `cargo_type` varchar(100) DEFAULT NULL COMMENT '货物类型', `specification` varchar(255) DEFAULT NULL COMMENT '规格', `model` varchar(255) DEFAULT NULL COMMENT '型号', `billing_factor` varchar(100) DEFAULT NULL COMMENT '计费要素', `billing_type` varchar(100) DEFAULT NULL COMMENT '计费类型', + `billing_rules_json` text COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '命中计费规则JSON', `transport_quantity` decimal(18,6) DEFAULT NULL COMMENT '运输量', `quantity_unit` varchar(50) DEFAULT NULL COMMENT '数量单位', `price_unit` varchar(50) DEFAULT NULL COMMENT '运费计算单位', diff --git a/doc/sql/transport/blade_settlement_adjustment_20260818.sql b/doc/sql/transport/blade_settlement_adjustment_20260818.sql index 71c66db..3576194 100644 --- a/doc/sql/transport/blade_settlement_adjustment_20260818.sql +++ b/doc/sql/transport/blade_settlement_adjustment_20260818.sql @@ -3,8 +3,8 @@ CREATE TABLE IF NOT EXISTS `blade_settlement_adjustment` ( `id` bigint(20) NOT NULL, `tenant_id` varchar(12) NOT NULL DEFAULT '000000', `create_user` bigint(20) DEFAULT NULL, `create_dept` bigint(20) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_user` bigint(20) DEFAULT NULL, `update_time` datetime DEFAULT NULL, `status` int(11) DEFAULT '1', `is_deleted` int(11) DEFAULT '0', - `adjustment_no` varchar(100) NOT NULL COMMENT '结算调整单号', `formal_settlement_id` bigint(20) NOT NULL COMMENT '关联正式结算单ID', - `formal_settlement_no` varchar(100) NOT NULL COMMENT '关联正式结算单号', `settlement_type` varchar(30) NOT NULL, + `adjustment_no` varchar(100) NOT NULL COMMENT '结算调整单号', `formal_settlement_id` bigint(20) DEFAULT NULL COMMENT '关联正式结算单ID', + `formal_settlement_no` varchar(100) DEFAULT NULL COMMENT '关联正式结算单号', `settlement_type` varchar(30) DEFAULT NULL, `project_name` varchar(100) DEFAULT NULL, `dept_name` varchar(100) DEFAULT NULL, `customer_name` varchar(200) DEFAULT NULL, `contract_no` varchar(100) DEFAULT NULL, `contract_name` varchar(100) DEFAULT NULL, `adjustment_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '调整金额', @@ -21,7 +21,7 @@ CREATE TABLE IF NOT EXISTS `blade_settlement_adjustment_detail` ( `id` bigint(20) NOT NULL, `tenant_id` varchar(12) NOT NULL DEFAULT '000000', `create_user` bigint(20) DEFAULT NULL, `create_dept` bigint(20) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_user` bigint(20) DEFAULT NULL, `update_time` datetime DEFAULT NULL, `status` int(11) DEFAULT '1', `is_deleted` int(11) DEFAULT '0', - `adjustment_id` bigint(20) NOT NULL, `formal_settlement_detail_id` bigint(20) NOT NULL, `formal_settlement_detail_fee_id` bigint(20) NOT NULL, + `adjustment_id` bigint(20) NOT NULL, `formal_settlement_detail_id` bigint(20) DEFAULT NULL, `formal_settlement_detail_fee_id` bigint(20) DEFAULT NULL, `fee_type` varchar(100) DEFAULT NULL, `fee_item` varchar(200) DEFAULT NULL, `original_amount_tax` decimal(18,2) DEFAULT NULL, `adjustment_amount_tax` decimal(18,2) NOT NULL DEFAULT '0.00', `adjustment_amount_no_tax` decimal(18,2) DEFAULT NULL, `remark` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_adjustment_detail_bill` (`adjustment_id`), diff --git a/doc/sql/transport/blade_settlement_adjustment_draft_nullable_20260831.sql b/doc/sql/transport/blade_settlement_adjustment_draft_nullable_20260831.sql new file mode 100644 index 0000000..4b561a3 --- /dev/null +++ b/doc/sql/transport/blade_settlement_adjustment_draft_nullable_20260831.sql @@ -0,0 +1,5 @@ +-- 结算调整单草稿允许暂不完善关联正式结算信息 +ALTER TABLE `blade_settlement_adjustment` + MODIFY COLUMN `formal_settlement_id` bigint(20) DEFAULT NULL COMMENT '关联正式结算单ID', + MODIFY COLUMN `formal_settlement_no` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '关联正式结算单号', + MODIFY COLUMN `settlement_type` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL; diff --git a/doc/sql/transport/blade_settlement_adjustment_manual_fee_20260830.sql b/doc/sql/transport/blade_settlement_adjustment_manual_fee_20260830.sql new file mode 100644 index 0000000..34e69a1 --- /dev/null +++ b/doc/sql/transport/blade_settlement_adjustment_manual_fee_20260830.sql @@ -0,0 +1,5 @@ +-- 结算调整单支持手工新增费用 + +ALTER TABLE `blade_settlement_adjustment_detail` + MODIFY COLUMN `formal_settlement_detail_id` bigint(20) DEFAULT NULL COMMENT '正式结算明细ID,手工费用为空', + MODIFY COLUMN `formal_settlement_detail_fee_id` bigint(20) DEFAULT NULL COMMENT '正式结算明细费用ID,手工费用为空'; diff --git a/doc/sql/transport/blade_tms_business.sql b/doc/sql/transport/blade_tms_business.sql index a892e3c..92632b8 100644 --- a/doc/sql/transport/blade_tms_business.sql +++ b/doc/sql/transport/blade_tms_business.sql @@ -262,6 +262,7 @@ CREATE TABLE `blade_waybill` ( `escort_name` varchar(100) DEFAULT NULL COMMENT '押运人', `escort_phone` varchar(50) DEFAULT NULL COMMENT '押运人手机号', `mileage` decimal(18,2) DEFAULT NULL COMMENT '里程', + `mileage_remark` varchar(200) DEFAULT NULL COMMENT '里程维护备注', `estimated_start_time` date DEFAULT NULL COMMENT '预计发货日期', `estimated_end_time` date DEFAULT NULL COMMENT '预计完成日期', `unit_price` decimal(18,2) DEFAULT NULL COMMENT '单价', @@ -415,6 +416,7 @@ INSERT IGNORE INTO `blade_menu` (`id`, `parent_id`, `code`, `name`, `alias`, `pa (2090000000000000611, 2090000000000000600, 'waybill_manage_import', '导入运单', 'waybill_manage_import', '', '', 11, 2, 0, 1, NULL, '', 0), (2090000000000000612, 2090000000000000600, 'waybill_manage_template', '下载模板', 'waybill_manage_template', '', '', 12, 2, 0, 1, NULL, '', 0), (2090000000000000613, 2090000000000000600, 'waybill_manage_road_loading', '公路配载', 'waybill_manage_road_loading', '', '', 13, 2, 0, 1, NULL, '', 0), +(2090000000000000614, 2090000000000000600, 'waybill_manage_mileage', '维护里程', 'waybill_manage_mileage', '', '', 14, 2, 0, 1, NULL, '', 0), (2090000000000000700, 2090000000000000000, 'loading_manage', '配载管理', 'loading_manage', '/business/loading-manage', 'iconfont icon-caidanguanli', 70, 1, 0, 1, NULL, '', 0), (2090000000000000701, 2090000000000000700, 'loading_manage_view', '查看', 'loading_manage_view', '', '', 1, 2, 0, 1, NULL, '', 0), (2090000000000000702, 2090000000000000700, 'loading_manage_add', '新增', 'loading_manage_add', '', '', 2, 2, 0, 1, NULL, '', 0), diff --git a/doc/sql/transport/blade_waybill_mileage_remark_20260831.sql b/doc/sql/transport/blade_waybill_mileage_remark_20260831.sql new file mode 100644 index 0000000..0b55e24 --- /dev/null +++ b/doc/sql/transport/blade_waybill_mileage_remark_20260831.sql @@ -0,0 +1,8 @@ +ALTER TABLE `blade_waybill` + ADD COLUMN `mileage_remark` varchar(200) DEFAULT NULL COMMENT '里程维护备注' AFTER `mileage`; + +INSERT INTO `blade_menu` +(`id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `component`, `remark`, `is_deleted`) +VALUES +(2090000000000000614, 2090000000000000600, 'waybill_manage_mileage', '维护里程', 'waybill_manage_mileage', '', '', 14, 2, 0, 1, NULL, '', 0) +ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `alias` = VALUES(`alias`), `sort` = VALUES(`sort`), `is_deleted` = 0;