You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中支付方式实体无法同步已确认发票信息的问题排查

问题描述

开发Spring Boot应用时,需要在发票确认后将已确认发票信息更新至支付方式实体(如CardEntity、CashEntity)。目前PaymentEntity能正确关联已确认发票,但CardEntity的confirmInvoiceEntity字段始终无法更新,尝试两种实现方式均无效。


现有代码实现

CardEntity.java

@Entity
@Table(name = "card_tbl")
public class CardEntity {
    @Id
    private Long cardRefNo;

    private Double paidAmount;
    private Date paidDate;

    private Long paymentId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tempInvoiceId")
    private TempInvoiceEntity tempInvoiceEntity;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "confirmInvoiceId")
    private ConfirmInvoiceEntity confirmInvoiceEntity;

    // Getters and Setters
}

CardRepo.java

@Repository
public interface CardRepo extends JpaRepository<CardEntity, Long> {
    List<CardEntity> findByTempInvoiceEntity_TempInvoiceId(Long tempInvoiceId);
}

第一种实现:ConfirmInvoiceServiceImple.java

@Service
@RequiredArgsConstructor
public class ConfirmInvoiceServiceImple implements ConfirmInvoiceService {

    private final TempInvoiceRepo tempInvoiceRepo;
    private final ConfirmInvoiceRepo confirmInvoiceRepo;
    private final ConfirmProductCartService confirmProductCartService;
    private final PaymentsRepo paymentsRepo;
    private final CardRepo cardRepo;
    private final CashRepo cashRepo;
    private final ChequeRepo chequeRepo;

    @Override
    @Transactional
    public NonPaginatedResponse insertIntoConfirmInvoice(Long invoiceId) {
        NonPaginatedResponse response = new NonPaginatedResponse();
        try {
            TempInvoiceEntity selectedTempInvoice = tempInvoiceRepo.findById(invoiceId).get();
            ConfirmInvoiceEntity confirmedInvoice = createNewConfirmInvoiceData(selectedTempInvoice);
            Boolean isCartItemsConfirmed = confirmProductCartService.confirmTheCartItems(invoiceId, confirmedInvoice);
            if (isCartItemsConfirmed) {
                List<PaymentsEntity> selectAllPayments = paymentsRepo.findBySalesInvoice_TempInvoiceId(confirmedInvoice.getConfirmInvoiceId());
                List<PaymentsEntity> listOfPayments = selectAllPayments.stream().map(
                        payment -> {
                            PaymentsEntity aPay = new PaymentsEntity();
                            aPay.setPaymentType(payment.getPaymentType());
                            aPay.setPaidDate(payment.getPaidDate());
                            aPay.setPaidAmount(payment.getPaidAmount());
                            aPay.setConfirmInvoice(confirmedInvoice);
                            aPay.setSalesInvoice(null);
                            alterPaymentMethConfirmInvoice(payment, confirmedInvoice);
                            return aPay;
                        }
                ).toList();
                paymentsRepo.saveAll(listOfPayments);
                tempInvoiceRepo.deleteById(confirmedInvoice.getConfirmInvoiceId());
            }
            response.setStatus(HttpStatus.ACCEPTED);
            response.setSuccessMessage("Invoice has been confirmed.");
            response.setResult(null);
        } catch (Exception e) {
            e.printStackTrace();
            response.setErrors(Collections.singletonList("Couldn't confirm the selected invoice"));
            response.setStatus(HttpStatus.BAD_GATEWAY);
        }
        return response;
    }

    public void alterPaymentMethConfirmInvoice(PaymentsEntity payment, ConfirmInvoiceEntity confirmedInvoice) {
        if (payment.getPaymentType().equalsIgnoreCase("card")) {
            List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(payment.getPaymentId());
            for (CardEntity cardEntity : cardEntities) {
                cardEntity.setConfirmInvoiceEntity(confirmedInvoice);
            }
            cardRepo.saveAll(cardEntities);
        }
    }

    private ConfirmInvoiceEntity createNewConfirmInvoiceData(TempInvoiceEntity tempInvoiceEntity) {
        ConfirmInvoiceEntity confirmInvoiceEntity = new ConfirmInvoiceEntity();
        confirmInvoiceEntity.setConfirmInvoiceId(tempInvoiceEntity.getTempInvoiceId());
        confirmInvoiceEntity.setInvoiceNumber(tempInvoiceEntity.getTempInvoiceNumber());
        confirmInvoiceEntity.setDate(new Date());
        confirmInvoiceEntity.setPaidAmount(tempInvoiceEntity.getPaidAmount());
        confirmInvoiceEntity.setNetAmount(tempInvoiceEntity.getNetAmount());
        confirmInvoiceEntity.setCustomer(tempInvoiceEntity.getCustomer());
        return confirmInvoiceRepo.save(confirmInvoiceEntity);
    }
}

第二种尝试的实现(修改后的核心方法)

@Override
@Transactional
public NonPaginatedResponse insertIntoConfirmInvoice(Long invoiceId) {
    NonPaginatedResponse response = new NonPaginatedResponse();
    try {
        TempInvoiceEntity selectedTempInvoice = tempInvoiceRepo.findById(invoiceId).get();

        ConfirmInvoiceEntity confirmedInvoice = createNewConfirmInvoiceData(selectedTempInvoice);
        Boolean isCartItemsConfirmed = confirmProductCartService.confirmTheCartItems(invoiceId, confirmedInvoice);
        if (isCartItemsConfirmed) {
            List<PaymentsEntity> selectAllPayments = paymentsRepo.findBySalesInvoice_TempInvoiceId(confirmedInvoice.getConfirmInvoiceId());
            alterPaymentMethConfirmInvoice(selectAllPayments, confirmedInvoice);
            List<PaymentsEntity> listOfPayments = selectAllPayments.stream().map(
                    payment -> {
                        PaymentsEntity aPay = new PaymentsEntity();
                        aPay.setPaymentType(payment.getPaymentType());
                        aPay.setPaidDate(payment.getPaidDate());
                        aPay.setPaidAmount(payment.getPaidAmount());
                        aPay.setConfirmInvoice(confirmedInvoice);
                        aPay.setSalesInvoice(null);

                        return aPay;
                    }
            ).toList();
            paymentsRepo.saveAll(listOfPayments);
            tempInvoiceRepo.deleteById(confirmedInvoice.getConfirmInvoiceId());
        }
        response.setStatus(HttpStatus.ACCEPTED);
        response.setSuccessMessage(ConfirmInvoiceConsonants.INVOICE_HAS_BEEN_CONFIRMED);
        response.setResult(null);
    } catch (Exception e) {
        e.printStackTrace();
        response.setErrors(Arrays.asList("Couldn't Confirm the selected invoice"));
        response.setStatus(HttpStatus.BAD_GATEWAY);
    }
    return response;
}


public void alterPaymentMethConfirmInvoice(List<PaymentsEntity> selectAllPayments, ConfirmInvoiceEntity confirmedInvoice) {
    selectAllPayments.stream().filter(
            allPay->{
                if (allPay.getPaymentType().equalsIgnoreCase("card")) {
                    List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(confirmedInvoice.getConfirmInvoiceId());
                    for (CardEntity cardEntity : cardEntities) {
                        cardEntity.setConfirmInvoiceEntity(confirmedInvoice);
                    }
                    cardRepo.saveAll(cardEntities);
                }
                return false;
            }
    ).toList();
}

问题原因分析及解决方案

核心问题1:查询条件错误(第一种实现)

第一种实现的alterPaymentMethConfirmInvoice方法中,使用payment.getPaymentId()作为参数调用cardRepo.findByTempInvoiceEntity_TempInvoiceId(),属于逻辑错误:

  • payment.getPaymentId()是支付记录的ID,而findByTempInvoiceEntity_TempInvoiceId()需要的是临时发票ID,两者语义完全不同,导致查询不到对应的CardEntity,自然无法更新。

修复方案:
使用当前确认的发票对应的原临时发票ID(即传入的invoiceId)作为查询参数:

public void alterPaymentMethConfirmInvoice(PaymentsEntity payment, ConfirmInvoiceEntity confirmedInvoice, Long originalTempInvoiceId) {
    if (payment.getPaymentType().equalsIgnoreCase("card")) {
        // 使用原临时发票ID查询关联的CardEntity
        List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(originalTempInvoiceId);
        for (CardEntity cardEntity : cardEntities) {
            cardEntity.setConfirmInvoiceEntity(confirmedInvoice);
        }
        cardRepo.saveAll(cardEntities);
    }
}

调用时传入invoiceId:

alterPaymentMethConfirmInvoice(payment, confirmedInvoice, invoiceId);

核心问题2:Stream API使用错误(第二种实现)

第二种实现的alterPaymentMethConfirmInvoice方法中,将业务逻辑写在filter()里且返回false:

  • Stream的filter()用于过滤元素,只有返回true的元素才会进入后续操作;结合Stream的惰性求值特性,当所有元素都返回false时,内部的更新代码根本不会执行。

修复方案:
将filter()改为forEach(),专门用于执行更新操作:

public void alterPaymentMethConfirmInvoice(List<PaymentsEntity> selectAllPayments, ConfirmInvoiceEntity confirmedInvoice, Long originalTempInvoiceId) {
    selectAllPayments.stream()
            .filter(allPay -> allPay.getPaymentType().equalsIgnoreCase("card"))
            .forEach(allPay -> {
                List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(originalTempInvoiceId);
                for (CardEntity cardEntity : cardEntities) {
                    cardEntity.setConfirmInvoiceEntity(confirmedInvoice);
                }
                cardRepo.saveAll(cardEntities);
            });
}

同时传入正确的originalTempInvoiceId(即invoiceId)。

额外注意点

  1. 事务一致性:确保所有更新操作都在同一个事务中(当前方法已标注@Transactional,满足要求)。
  2. Lazy加载问题:如果TempInvoiceEntity是懒加载,查询CardEntity时确保会话未关闭(事务内操作不会有此问题)。
  3. 主键冲突验证:确认ConfirmInvoiceEntity的confirmInvoiceId设置正确(当前复用原临时发票ID,需确保无主键冲突)。

内容的提问来源于stack exchange,提问作者Kabil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:12:03