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

Magento 2.2.3通过sales_order_save_after观察者自动创建发票报错

解决Magento 2.2.3中自动生成发票的事务冲突问题

我来帮你搞定这个棘手的问题!你遇到的报错和发票生成异常,核心原因是**sales_order_save_after事件本身就运行在Magento订单保存的事务上下文里**,手动加事务操作会和原生事务机制冲突,导致回滚异常;而去掉事务后,发票的持久化操作没在正确的事务流程里完成,所以只更新了订单状态,实际发票数据没写入数据库。

修正后的观察者代码

直接替换你的MyCompany/MyModule/Observer/SalesOrderSaveAfter.php代码,用Magento官方推荐的方式生成发票,避免手动事务操作:

<?php
namespace MyCompany\MyModule\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Model\Service\InvoiceService;
use Magento\Framework\DB\Transaction;
use Magento\Sales\Model\Order\Invoice;

class SalesOrderSaveAfter implements ObserverInterface
{
    /** @var InvoiceService */
    private $invoiceService;
    
    /** @var Transaction */
    private $transaction;

    public function __construct(
        InvoiceService $invoiceService,
        Transaction $transaction
    ) {
        $this->invoiceService = $invoiceService;
        $this->transaction = $transaction;
    }

    public function execute(Observer $observer)
    {
        $order = $observer->getOrder();
        
        // 关键:只处理可开票且未处理过的订单,避免重复执行
        if (!$order->canInvoice() || $order->getState() !== \Magento\Sales\Model\Order::STATE_PROCESSING) {
            return $this;
        }

        try {
            // 用官方服务创建发票
            $invoice = $this->invoiceService->prepareInvoice($order);
            
            // 校验发票是否有商品数量,避免空发票
            if (!$invoice->getTotalQty()) {
                throw new \Magento\Framework\Exception\LocalizedException(
                    __('无法创建空发票,请检查订单商品。')
                );
            }

            // 设置发票捕获方式并注册
            $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE);
            $invoice->register();
            $order->setIsInProcess(true);

            // 用Magento事务工厂处理关联保存,无需手动管理事务
            $this->transaction
                ->addObject($invoice)
                ->addObject($order)
                ->save();
        } catch (\Exception $e) {
            // 异常时记录到订单备注,不影响订单保存
            $order->addStatusHistoryComment(
                __('自动生成发票失败:%1', $e->getMessage()),
                false
            );
            $order->save();
        }

        return $this;
    }
}

核心要点说明

  • 别碰手动事务:Magento在触发sales_order_save_after时,订单保存的事务还没提交,手动开事务会触发嵌套事务冲突,这就是报错的根源。
  • 用官方服务类:InvoiceService和Transaction是Magento原生的发票处理工具,能完美兼容系统的事务流程,确保发票和订单状态同步保存。
  • 加重复校验:$order->canInvoice()会自动判断订单是否已开票、是否符合开票条件,避免重复执行逻辑导致的异常。
  • 异常兜底:捕获所有异常并写入订单备注,这样即使发票生成失败,订单也能正常保存,方便后续排查问题。

额外检查步骤

  1. 确认你的etc/events.xml配置正确(如果还没加的话):
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_order_save_after">
        <observer name="mycompany_mymodule_auto_invoice" instance="MyCompany\MyModule\Observer\SalesOrderSaveAfter" />
    </event>
</config>
  1. 清理缓存并重新编译:
php bin/magento cache:clean
php bin/magento setup:di:compile

这样调整后,订单提交时就能自动生成有效发票,也不会再出现事务回滚的报错了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:09:50