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

Magento 2:如何为每个商品生成独立发票?

Magento 2 自动生成单个商品独立发票并合并PDF发送解决方案

核心实现步骤

1. 监听订单完成事件

通过sales_order_save_after事件触发发票生成逻辑,创建自定义模块的events.xml配置文件:

<!-- app/code/YourVendor/YourModule/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="yourmodule_order_create_item_invoices" instance="YourVendor\YourModule\Observer\CreateItemInvoices" />
    </event>
</config>

2. 编写Observer生成单个商品发票

遍历订单内的每个有效订单项,为每个商品单独生成发票:

// app/code/YourVendor/YourModule/Observer/CreateItemInvoices.php
<?php
namespace YourVendor\YourModule\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Model\Order\InvoiceFactory;
use Magento\Sales\Model\Order\Item as OrderItem;
use Magento\Framework\Exception\LocalizedException;
use Magento\Sales\Model\Order;

class CreateItemInvoices implements ObserverInterface
{
    protected $invoiceFactory;

    public function __construct(InvoiceFactory $invoiceFactory)
    {
        $this->invoiceFactory = $invoiceFactory;
    }

    public function execute(Observer $observer)
    {
        /** @var Order $order */
        $order = $observer->getOrder();
        // 仅处理可开票且处于处理状态的订单,可按需调整状态判断
        if (!$order->canInvoice() || $order->getState() !== Order::STATE_PROCESSING) {
            return;
        }

        $invoices = [];
        foreach ($order->getAllItems() as $item) {
            /** @var OrderItem $item */
            if (!$item->getQtyToInvoice() || $item->isDummy()) {
                continue;
            }

            try {
                $invoice = $this->invoiceFactory->create();
                $invoice->setOrder($order);
                $invoice->addItem($item, $item->getQtyToInvoice());
                $invoice->collectTotals();
                $invoice->setState(\Magento\Sales\Model\Order\Invoice::STATE_PAID);
                $invoice->save();

                $invoices[] = $invoice;
            } catch (LocalizedException $e) {
                // 异常处理:可添加日志记录逻辑
                continue;
            }
        }

        if (!empty($invoices)) {
            $this->mergeInvoicesToPdfAndSend($order, $invoices);
        }
    }

    protected function mergeInvoicesToPdfAndSend(Order $order, array $invoices)
    {
        $pdfMerger = \Magento\Framework\App\ObjectManager::getInstance()->get(\YourVendor\YourModule\Model\PdfMerger::class);
        $pdfContent = $pdfMerger->mergeInvoices($invoices);

        $mailSender = \Magento\Framework\App\ObjectManager::getInstance()->get(\YourVendor\YourModule\Model\InvoiceMailSender::class);
        $mailSender->sendMergedInvoiceEmail($order, $pdfContent);
    }
}

3. 实现PDF合并逻辑

将多个独立发票的PDF内容合并为单个文件:

// app/code/YourVendor/YourModule/Model/PdfMerger.php
<?php
namespace YourVendor\YourModule\Model;

use Magento\Sales\Model\Order\Pdf\Invoice as InvoicePdf;
use Zend_Pdf;

class PdfMerger
{
    protected $invoicePdf;

    public function __construct(InvoicePdf $invoicePdf)
    {
        $this->invoicePdf = $invoicePdf;
    }

    public function mergeInvoices(array $invoices)
    {
        $mergedPdf = new Zend_Pdf();
        foreach ($invoices as $invoice) {
            $invoicePdf = $this->invoicePdf->getPdf([$invoice]);
            foreach ($invoicePdf->pages as $page) {
                $mergedPdf->pages[] = $page;
            }
        }
        return $mergedPdf->render();
    }
}

4. 发送包含合并PDF的邮件

构建邮件并添加合并后的PDF附件发送给客户:

// app/code/YourVendor/YourModule/Model/InvoiceMailSender.php
<?php
namespace YourVendor\YourModule\Model;

use Magento\Sales\Model\Order;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;

class InvoiceMailSender
{
    protected $transportBuilder;
    protected $scopeConfig;

    public function __construct(
        TransportBuilder $transportBuilder,
        ScopeConfigInterface $scopeConfig
    ) {
        $this->transportBuilder = $transportBuilder;
        $this->scopeConfig = $scopeConfig;
    }

    public function sendMergedInvoiceEmail(Order $order, $pdfContent)
    {
        $storeId = $order->getStoreId();
        $templateId = 'sales_email_invoice_template'; // 可替换为自定义邮件模板ID

        $this->transportBuilder
            ->setTemplateIdentifier($templateId)
            ->setTemplateOptions([
                'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
                'store' => $storeId
            ])
            ->setTemplateVars([
                'order' => $order,
                'billing' => $order->getBillingAddress(),
                'comment' => ''
            ])
            ->setFrom([
                'name' => $this->scopeConfig->getValue('trans_email/ident_general/name', ScopeInterface::SCOPE_STORE, $storeId),
                'email' => $this->scopeConfig->getValue('trans_email/ident_general/email', ScopeInterface::SCOPE_STORE, $storeId)
            ])
            ->addTo($order->getCustomerEmail(), $order->getCustomerName());

        $transport = $this->transportBuilder->getTransport();
        $attachment = new \Zend_Mime_Part($pdfContent);
        $attachment->type = 'application/pdf';
        $attachment->filename = 'merged_invoices_' . $order->getIncrementId() . '.pdf';
        $attachment->disposition = \Zend_Mime::DISPOSITION_ATTACHMENT;
        $attachment->encoding = \Zend_Mime::ENCODING_BASE64;

        $message = $transport->getMessage();
        $message->addAttachment($attachment);

        $transport->sendMessage();
    }
}

注意事项

  • 替换代码中的YourVendor\YourModule为实际的厂商名和模块名,按Magento规范创建自定义模块。
  • 可根据业务需求调整订单状态判断逻辑,确保仅在订单支付完成等合适时机触发发票生成。
  • 异常处理部分可补充日志记录,便于排查问题。
  • 可在后台Marketing > Communications > Email Templates中创建自定义邮件模板,替换上述代码中的templateId。
  • 若订单包含大量商品,需考虑性能优化,比如异步处理发票生成和PDF合并。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:57:10