diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementVO.java index 504febcd..1c68aef6 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementVO.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/FormalSettlementVO.java @@ -72,6 +72,7 @@ public class FormalSettlementVO extends FormalSettlement implements KingdeeUnloc @TableField(exist = false) @Schema(description = "开票申请经金蝶回写的发票结果(含文件地址,只读展示)") private List issuedInvoices; @TableField(exist = false) private List paymentApplications; + @TableField(exist = false) private List advancePayments; @TableField(exist = false) private List adjustments; @TableField(exist = false) private List changeRecords; } diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/SettlementAdvancePaymentVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/SettlementAdvancePaymentVO.java new file mode 100644 index 00000000..9ec5616e --- /dev/null +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/SettlementAdvancePaymentVO.java @@ -0,0 +1,72 @@ +/** + * 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.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 结算单统一预付付款记录(进度预付 / 项目预付核销,供付款记录合并展示) + * + * @author Chill + */ +@Data +@Schema(description = "结算单统一预付付款记录") +public class SettlementAdvancePaymentVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "记录类型:progress_advance 进度预付 / project_advance 项目预付核销") + private String recordType; + + @Schema(description = "付款单号") + private String paymentNo; + + @Schema(description = "申请金额(进度预付为申请预付金额,项目预付为本次核销金额)") + private BigDecimal appliedAmount; + + @Schema(description = "已付款金额(底层付款申请实付)") + private BigDecimal paidAmount; + + @Schema(description = "单据状态") + private String billStatus; + + @Schema(description = "金蝶单据号") + private String kingdeeBillNo; + + @Schema(description = "创建人姓名") + private String createUserName; + + @Schema(description = "创建时间(统一取底层付款申请创建时间)") + private Date createTime; + +} diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.java index a9aa2767..973be9bf 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.java @@ -15,6 +15,9 @@ import org.apache.ibatis.annotations.Param; import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff; import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * 结算单项目预付核销 Mapper @@ -37,4 +40,12 @@ public interface SettlementProjectAdvanceWriteOffMapper extends BaseMapper> sumWriteOffBySettlementIds(@Param("settlementType") String settlementType, + @Param("settlementIds") Collection settlementIds); + } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.xml b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.xml index 3c21ab32..5fd71743 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.xml +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementProjectAdvanceWriteOffMapper.xml @@ -32,4 +32,16 @@ AND settlement_id = #{settlementId} + + diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ISettlementProjectAdvanceWriteOffService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ISettlementProjectAdvanceWriteOffService.java index 9c1d7368..3c8886d8 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ISettlementProjectAdvanceWriteOffService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/ISettlementProjectAdvanceWriteOffService.java @@ -14,7 +14,9 @@ import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff; import org.springblade.transport.pojo.vo.ProjectAdvanceWriteOffOptionVO; import java.math.BigDecimal; +import java.util.Collection; import java.util.List; +import java.util.Map; /** * 结算单项目预付核销服务 @@ -24,7 +26,7 @@ import java.util.List; public interface ISettlementProjectAdvanceWriteOffService { /** - * 按合同查询可选项目预付(审批通过且仍有可核销余额)。 + * 按合同查询可选项目预付(审批通过、金蝶已付款且仍有可核销余额)。 */ List listOptions(Long contractId, String excludeSettlementType, Long excludeSettlementId); @@ -39,6 +41,11 @@ public interface ISettlementProjectAdvanceWriteOffService { */ BigDecimal sumBySettlement(String settlementType, Long settlementId); + /** + * 按结算单集合分组统计核销合计(一次 group-by,供批量刷新与列表页使用)。 + */ + Map sumBySettlementIds(String settlementType, Collection settlementIds); + /** * 覆盖保存核销明细,并校验不超过可核销金额与结算单金额。 */ @@ -50,4 +57,14 @@ public interface ISettlementProjectAdvanceWriteOffService { */ void deleteBySettlement(String settlementType, Long settlementId); + /** + * 删除指定结算单集合上的核销明细(核销行转移/结算单作废联动),返回删除行数。 + */ + int deleteBySettlementIds(String settlementType, Collection settlementIds); + + /** + * 按付款申请删除其核销明细(付款申请作废联动),返回受影响的正式结算单id。 + */ + List deleteByPaymentApplicationIds(Collection paymentApplicationIds); + } 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 7e37cd0d..ba94adfd 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 @@ -33,12 +33,14 @@ import org.springblade.transport.mapper.InvoiceApplicationMapper; import org.springblade.transport.mapper.InvoiceApplicationSettlementMapper; import org.springblade.transport.mapper.PreSettlementDetailMapper; import org.springblade.transport.mapper.PreSettlementDetailFeeMapper; +import org.springblade.transport.mapper.PreSettlementAdvanceMapper; import org.springblade.transport.mapper.PreSettlementMapper; import org.springblade.transport.mapper.PreSettlementSummaryFeeMapper; import org.springblade.transport.mapper.PaymentApplicationMapper; import org.springblade.transport.mapper.PaymentApplicationInvoiceMapper; import org.springblade.transport.mapper.PaymentApplicationSettlementMapper; import org.springblade.transport.mapper.ReceiptClaimSettlementMapper; +import org.springblade.transport.mapper.SettlementProjectAdvanceWriteOffMapper; import org.springblade.transport.constant.KingdeeAttachmentConstant; import org.springblade.transport.config.BfiProperties; import org.springblade.transport.constant.KingdeeBfiConstant; @@ -69,6 +71,7 @@ import org.springblade.transport.pojo.entity.InvoiceApplicationInvoice; import org.springblade.transport.pojo.entity.InvoiceApplicationSettlement; import org.springblade.transport.pojo.entity.ContractManage; import org.springblade.transport.pojo.entity.PreSettlement; +import org.springblade.transport.pojo.entity.PreSettlementAdvance; import org.springblade.transport.pojo.entity.PreSettlementDetail; import org.springblade.transport.pojo.entity.PreSettlementDetailFee; import org.springblade.transport.pojo.entity.PreSettlementSummaryFee; @@ -79,9 +82,11 @@ import org.springblade.transport.pojo.entity.ReceiptClaimSettlement; import org.springblade.transport.pojo.entity.ReceivablePayableDetail; import org.springblade.transport.pojo.entity.ReceivablePayableCargoFee; import org.springblade.transport.pojo.entity.SettlementAdjustment; +import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff; import org.springblade.transport.pojo.entity.Waybill; import org.springblade.transport.pojo.vo.FormalSettlementVO; import org.springblade.transport.pojo.vo.PreSettlementVO; +import org.springblade.transport.pojo.vo.SettlementAdvancePaymentVO; import org.springblade.transport.pojo.vo.SettlementAdjustmentVO; import org.springblade.transport.service.IFormalSettlementService; import org.springblade.transport.service.IInvoiceReceiptService; @@ -113,6 +118,8 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -162,6 +169,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl result = page(page, wrapper.orderByDesc(FormalSettlement::getCreateTime)); - IPage voPage = result.convert(this::toVO); + // 本页应付结算单的项目预付核销合计一次查询,避免逐行 toVO 重算汇总时的 N+1 + Map writeOffAmounts = this.projectAdvanceWriteOffService.sumBySettlementIds( + TransportBusiConstant.SETTLEMENT_BILL_FORMAL, + result.getRecords().stream() + .filter(item -> "payable".equals(item.getSettlementType())) + .map(FormalSettlement::getId).toList()); + IPage voPage = result.convert(item -> this.toVO(item, writeOffAmounts)); fillAttachmentSyncStatus(voPage.getRecords()); fillKingdeeLockStatus(voPage.getRecords()); return voPage; @@ -322,6 +337,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl relationApplicationIds = paymentApplicationSettlementMapper.selectList( Wrappers.lambdaQuery() .select(PaymentApplicationSettlement::getPaymentApplicationId) @@ -545,12 +561,17 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl 新单[{}](明细{}条)", - source.getFormalSettlementNo(), clone.getFormalSettlementNo(), details.size()); + // 核销行迁移:克隆到新单并删除原单行,避免预付可核销额度双占(原单为调整存档,收付口径以新单为准) + List writeOffRows = this.projectAdvanceWriteOffMapper.selectList( + Wrappers.lambdaQuery() + .eq(SettlementProjectAdvanceWriteOff::getSettlementType, TransportBusiConstant.SETTLEMENT_BILL_FORMAL) + .eq(SettlementProjectAdvanceWriteOff::getSettlementId, sourceSettlementId) + .eq(SettlementProjectAdvanceWriteOff::getIsDeleted, 0)); + for (SettlementProjectAdvanceWriteOff writeOffRow : writeOffRows) { + SettlementProjectAdvanceWriteOff cloneWriteOff = Objects.requireNonNull( + BeanUtil.copyProperties(writeOffRow, SettlementProjectAdvanceWriteOff.class)); + resetAuditFields(cloneWriteOff); + cloneWriteOff.setSettlementId(clone.getId()); + this.projectAdvanceWriteOffMapper.insert(cloneWriteOff); + } + this.projectAdvanceWriteOffService.deleteBySettlementIds( + TransportBusiConstant.SETTLEMENT_BILL_FORMAL, List.of(sourceSettlementId)); + this.refreshPaymentSummaries(List.of(sourceSettlementId, clone.getId())); + log.info("结算调整重推克隆正式结算单:原单[{}] -> 新单[{}](明细{}条,核销迁移{}条)", + source.getFormalSettlementNo(), clone.getFormalSettlementNo(), details.size(), writeOffRows.size()); return new CloneResult(clone.getId(), detailIdMap, feeIdMap); } @@ -1601,6 +1644,11 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl money(item.getAllocatedReceiptAmount()), BigDecimal::add))) : Map.of(); + // 项目预付核销合计(仅应付结算单需要,一次 group-by 避免逐单查询) + Map writeOffAmountsBySettlement = hasPayable + ? this.projectAdvanceWriteOffService.sumBySettlementIds( + TransportBusiConstant.SETTLEMENT_BILL_FORMAL, settledIds) + : Map.of(); for (FormalSettlement settlement : settlements) { List relations = relationsBySettlement @@ -1616,7 +1664,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl writeOffAmounts) { FormalSettlementVO vo = FormalSettlementWrapper.build().entityVO(entity); vo.setInvoiceStatus(invoiceStatus(entity.getInvoiceAmount(), entity.getSettlementAmount())); - PaymentSummary summary = calculatePaymentSummary(entity); + PaymentSummary summary = this.calculatePaymentSummary(entity, writeOffAmounts); vo.setAppliedPaymentAmount(summary.appliedAmount()); vo.setPaidAmount(summary.paidAmount()); vo.setRemainingPayableAmount(money(entity.getSettlementAmount()).subtract(summary.paidAmount()) @@ -1837,6 +1893,10 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl) null); + } + + private PaymentSummary calculatePaymentSummary(FormalSettlement settlement, Map writeOffAmounts) { List relations = paymentApplicationSettlementMapper.selectList( Wrappers.lambdaQuery() .eq(PaymentApplicationSettlement::getFormalSettlementId, settlement.getId()) @@ -1854,7 +1914,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl relations, List directApplications, Map relationStatuses, - List sources, BigDecimal receiptClaimPaid) { + List sources, BigDecimal receiptClaimPaid, + Map writeOffAmounts) { } private SettlementAdjustmentVO toAdjustmentVO(SettlementAdjustment entity) { @@ -1937,6 +2006,74 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl listAdvancePayments(List sources, + List writeOffs) { + List records = new ArrayList<>(); + List preSettlementIds = sources.stream().map(FormalSettlementSource::getPreSettlementId) + .filter(Objects::nonNull).distinct().toList(); + if (!preSettlementIds.isEmpty()) { + List advances = this.preSettlementAdvanceMapper.selectList( + Wrappers.lambdaQuery() + .eq(PreSettlementAdvance::getIsDeleted, 0) + .ne(PreSettlementAdvance::getBillStatus, TransportBusiConstant.VOIDED) + .in(PreSettlementAdvance::getPreSettlementId, preSettlementIds)); + // 进度预付行的展示时间取底层付款申请创建时间(advanceNo 即付款申请单号) + List advanceNos = advances.stream().map(PreSettlementAdvance::getAdvanceNo) + .filter(Func::isNotEmpty).distinct().toList(); + Map applicationTimes = advanceNos.isEmpty() ? Map.of() + : this.paymentApplicationMapper.selectList(Wrappers.lambdaQuery() + .select(PaymentApplication::getPaymentNo, PaymentApplication::getCreateTime) + .eq(PaymentApplication::getIsDeleted, 0) + .in(PaymentApplication::getPaymentNo, advanceNos)) + .stream().filter(item -> item.getCreateTime() != null) + .collect(Collectors.toMap(PaymentApplication::getPaymentNo, + PaymentApplication::getCreateTime, (first, second) -> first)); + for (PreSettlementAdvance advance : advances) { + SettlementAdvancePaymentVO record = new SettlementAdvancePaymentVO(); + record.setRecordType(TransportBusiConstant.PAYMENT_TYPE_PROGRESS_ADVANCE); + record.setPaymentNo(advance.getAdvanceNo()); + record.setAppliedAmount(advance.getAppliedAmount()); + record.setPaidAmount(advance.getPaidAmount()); + record.setBillStatus(advance.getBillStatus()); + record.setKingdeeBillNo(advance.getKingdeeAdvanceNo()); + record.setCreateUserName(UserCache.getUserRealName(advance.getCreateUser())); + record.setCreateTime(applicationTimes.getOrDefault(advance.getAdvanceNo(), advance.getCreateTime())); + records.add(record); + } + } + if (Func.isNotEmpty(writeOffs)) { + List applicationIds = writeOffs.stream() + .map(SettlementProjectAdvanceWriteOff::getPaymentApplicationId) + .filter(Objects::nonNull).distinct().toList(); + Map applications = applicationIds.isEmpty() ? Map.of() + : this.paymentApplicationMapper.selectBatchIds(applicationIds).stream() + .collect(Collectors.toMap(PaymentApplication::getId, Function.identity(), + (first, second) -> first)); + for (SettlementProjectAdvanceWriteOff writeOff : writeOffs) { + PaymentApplication application = applications.get(writeOff.getPaymentApplicationId()); + SettlementAdvancePaymentVO record = new SettlementAdvancePaymentVO(); + record.setRecordType(TransportBusiConstant.PAYMENT_TYPE_PROJECT_ADVANCE); + record.setPaymentNo(writeOff.getPaymentNo()); + record.setAppliedAmount(writeOff.getWriteOffAmount()); + record.setPaidAmount(application == null ? null : application.getPaidAmount()); + record.setBillStatus(application == null ? null : application.getApprovalStatus()); + record.setKingdeeBillNo(writeOff.getKingdeeBillNo()); + record.setCreateUserName(UserCache.getUserRealName(application == null + ? writeOff.getCreateUser() : application.getCreateUser())); + record.setCreateTime(writeOff.getPaymentCreateTime() != null + ? writeOff.getPaymentCreateTime() : writeOff.getCreateTime()); + records.add(record); + } + } + records.sort(Comparator.comparing(SettlementAdvancePaymentVO::getCreateTime, + Comparator.nullsLast(Comparator.reverseOrder()))); + return records; + } + private String approvalStatusName(String value) { if (value == null) { return ""; diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java index 6650afd0..f8860776 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java @@ -456,6 +456,11 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl writeOffSettlementIds = this.projectAdvanceWriteOffService.deleteByPaymentApplicationIds(List.of(entity.getId())); + if (!writeOffSettlementIds.isEmpty()) { + formalSettlementService.refreshPaymentSummaries(writeOffSettlementIds); + } refreshFormalSettlement(entity); } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java index cdf17b02..d832ea60 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java @@ -461,6 +461,9 @@ public class PreSettlementServiceImpl extends BaseServiceImpl 0) { + throw new ServiceException("调整后结算金额不能低于项目预付核销合计" + money(writeOffTotal) + ",请先调减项目预付核销"); + } formal.setSettlementAmount(amount); formal.setLocalSettlementAmount(amount.multiply(formal.getExchangeRate() == null ? BigDecimal.ONE : formal.getExchangeRate())); formal.setRemainingPayableAmount(amount.subtract(money(formal.getPaidAmount())).max(BigDecimal.ZERO)); formalMapper.updateById(formal); + // 重算收付汇总(含核销计入),保持付款状态与剩余可付准确 + formalSettlementService.refreshPaymentSummary(formal.getId()); } /** 涉事事务的自代理:跨方法调用确保 {@link #cloneAndApplyForRepush} 的事务注解生效 */ diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementProjectAdvanceWriteOffServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementProjectAdvanceWriteOffServiceImpl.java index 52e7dbc4..473ee3d3 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementProjectAdvanceWriteOffServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementProjectAdvanceWriteOffServiceImpl.java @@ -14,6 +14,7 @@ import lombok.RequiredArgsConstructor; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.tool.utils.Func; import org.springblade.system.cache.UserCache; +import org.springblade.transport.constant.KingdeeBfiConstant; import org.springblade.transport.constant.TransportBusiConstant; import org.springblade.transport.mapper.PaymentApplicationMapper; import org.springblade.transport.mapper.SettlementProjectAdvanceWriteOffMapper; @@ -28,8 +29,11 @@ import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -56,6 +60,7 @@ public class SettlementProjectAdvanceWriteOffServiceImpl implements ISettlementP .eq(PaymentApplication::getContractId, contractId) .eq(PaymentApplication::getPaymentType, TransportBusiConstant.PAYMENT_TYPE_PROJECT_ADVANCE) .eq(PaymentApplication::getApprovalStatus, TransportBusiConstant.APPROVED) + .eq(PaymentApplication::getKingdeeStatus, KingdeeBfiConstant.KINGDEE_STATUS_PAID) .eq(PaymentApplication::getIsDeleted, 0) .orderByDesc(PaymentApplication::getCreateTime)); List options = new ArrayList<>(); @@ -121,6 +126,20 @@ public class SettlementProjectAdvanceWriteOffServiceImpl implements ISettlementP return money(writeOffMapper.sumWriteOffBySettlement(settlementType, settlementId)); } + @Override + public Map sumBySettlementIds(String settlementType, Collection settlementIds) { + if (Func.isEmpty(settlementType) || Func.isEmpty(settlementIds)) { + return Map.of(); + } + Map result = new HashMap<>(); + for (Map row : writeOffMapper.sumWriteOffBySettlementIds(settlementType, settlementIds)) { + if (row.get("settlementId") instanceof Number settlementId && row.get("totalAmount") instanceof BigDecimal totalAmount) { + result.put(settlementId.longValue(), money(totalAmount)); + } + } + return result; + } + @Override @Transactional(rollbackFor = Exception.class) public void replaceWriteOffs(String settlementType, Long settlementId, Long contractId, @@ -157,6 +176,9 @@ public class SettlementProjectAdvanceWriteOffServiceImpl implements ISettlementP if (!TransportBusiConstant.APPROVED.equals(application.getApprovalStatus())) { throw new ServiceException("仅可选择审核通过的项目预付单"); } + if (!KingdeeBfiConstant.KINGDEE_STATUS_PAID.equals(application.getKingdeeStatus())) { + throw new ServiceException("预付单" + Func.toStr(application.getPaymentNo(), "") + "尚未付款,项目预付须金蝶付款完成后方可核销"); + } if (!Objects.equals(contractId, application.getContractId())) { throw new ServiceException("项目预付单与结算单合同不一致"); } @@ -203,6 +225,40 @@ public class SettlementProjectAdvanceWriteOffServiceImpl implements ISettlementP .eq(SettlementProjectAdvanceWriteOff::getSettlementId, settlementId)); } + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteBySettlementIds(String settlementType, Collection settlementIds) { + if (Func.isEmpty(settlementType) || Func.isEmpty(settlementIds)) { + return 0; + } + return writeOffMapper.delete(Wrappers.lambdaQuery() + .eq(SettlementProjectAdvanceWriteOff::getSettlementType, settlementType) + .in(SettlementProjectAdvanceWriteOff::getSettlementId, settlementIds)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List deleteByPaymentApplicationIds(Collection paymentApplicationIds) { + if (Func.isEmpty(paymentApplicationIds)) { + return List.of(); + } + List rows = writeOffMapper.selectList( + Wrappers.lambdaQuery() + .eq(SettlementProjectAdvanceWriteOff::getIsDeleted, 0) + .in(SettlementProjectAdvanceWriteOff::getPaymentApplicationId, paymentApplicationIds)); + if (rows.isEmpty()) { + return List.of(); + } + writeOffMapper.delete(Wrappers.lambdaQuery() + .in(SettlementProjectAdvanceWriteOff::getPaymentApplicationId, paymentApplicationIds)); + return rows.stream() + .filter(row -> TransportBusiConstant.SETTLEMENT_BILL_FORMAL.equals(row.getSettlementType())) + .map(SettlementProjectAdvanceWriteOff::getSettlementId) + .filter(Objects::nonNull) + .distinct() + .toList(); + } + private BigDecimal money(BigDecimal value) { return value == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : value.setScale(2, RoundingMode.HALF_UP);