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

Magento自定义折扣在发票中不显示的问题求助

问题原因及修复方案

你的自定义折扣仅在报价(Quote)阶段生效,未配置订单(Order)和发票(Invoice)的总计处理逻辑,也没有正确将折扣数据同步到后续流程,同时代码中直接修改Quote核心总计字段的方式不符合Magento的总计系统逻辑,导致发票无法识别该折扣。

1. 完善sales.xml配置,覆盖全流程总计处理

需要在配置文件中补充订单和发票的总计节点,让Magento在生成订单、发票时加载自定义折扣处理类:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd">
    <!-- 原有报价阶段配置 -->
    <section name="quote">
        <group name="totals">
            <item name="prepaiddiscount" instance="Vendorname\Modulename\Model\Quote\Address\Total\PrepaidDiscount" sort_order="400"/>
        </group>
    </section>
    <!-- 添加订单总计配置 -->
    <section name="order">
        <group name="totals">
            <item name="prepaiddiscount" instance="Vendorname\Modulename\Model\Order\Total\PrepaidDiscount" sort_order="400"/>
        </group>
    </section>
    <!-- 添加发票总计配置 -->
    <section name="invoice">
        <group name="totals">
            <item name="prepaiddiscount" instance="Vendorname\Modulename\Model\Invoice\Total\PrepaidDiscount" sort_order="400"/>
        </group>
    </section>
</config>

2. 修正Quote总计模型的collect方法,添加fetch方法

不要直接修改Quote的subtotal、grandTotal等核心字段,交由Magento总计系统自动计算,同时实现fetch方法用于后台/前端显示折扣条目:

修改app/code/Vendorname/Modulename/Model/Quote/Address/Total/PrepaidDiscount.php:

<?php
namespace Vendorname\Modulename\Model\Quote\Address\Total;

class PrepaidDiscount extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
{
    public function collect(
        \Magento\Quote\Model\Quote $quote,
        \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
        \Magento\Quote\Model\Quote\Address\Total $total
    )
    {
        parent::collect($quote, $shippingAssignment, $total);
        
        $items = $shippingAssignment->getItems();
        if (!count($items)) {
            return $this;
        }
        
        $prepaidDiscount = 10;
        if ($prepaidDiscount > 0) {
            $discountAmount = $prepaidDiscount;
            $label = 'Prepaid Discount';
            
            // 合并已有折扣
            if ($total->getDiscountAmount()) {
                $discountAmount += abs($total->getDiscountAmount());
                $label = $total->getDiscountDescription() . ', ' . $label;
            }
            
            // 按Magento规范添加总计金额
            $total->addTotalAmount('prepaiddiscount', -$discountAmount);
            $total->addBaseTotalAmount('prepaiddiscount', -$discountAmount);
            
            // 更新折扣核心字段
            $total->setDiscountAmount(-$discountAmount);
            $total->setBaseDiscountAmount(-$discountAmount);
            $total->setDiscountDescription($label);
            
            // 将折扣值存入Quote自定义属性(需提前定义该属性)
            $quote->setPrepaidDiscount($discountAmount);
        }

        return $this;           
    }
    
    // 实现fetch方法,返回显示用的折扣条目
    public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
    {
        $discountAmount = $quote->getPrepaidDiscount();
        if ($discountAmount > 0) {
            return [
                'code' => 'prepaiddiscount',
                'title' => __('Prepaid Discount'),
                'value' => -$discountAmount
            ];
        }
        return [];
    }
}

3. 创建订单总计模型,同步折扣到订单

新建app/code/Vendorname/Modulename/Model/Order/Total/PrepaidDiscount.php:

<?php
namespace Vendorname\Modulename\Model\Order\Total;

class PrepaidDiscount extends \Magento\Sales\Model\Order\Total\AbstractTotal
{
    public function collect(\Magento\Sales\Model\Order $order, \Magento\Sales\Model\Order\Invoice\Item $item = null)
    {
        parent::collect($order);
        
        $quote = $order->getQuote();
        if ($quote && $quote->getPrepaidDiscount()) {
            $discountAmount = $quote->getPrepaidDiscount();
            $order->setPrepaidDiscount($discountAmount);
            
            // 添加到订单总计
            $order->addTotalAmount('prepaiddiscount', -$discountAmount);
            $order->addBaseTotalAmount('prepaiddiscount', -$discountAmount);
            
            // 更新订单折扣总计
            $currentDiscount = $order->getDiscountAmount();
            $order->setDiscountAmount($currentDiscount - $discountAmount);
            $order->setBaseDiscountAmount($order->getBaseDiscountAmount() - $discountAmount);
        }
        
        return $this;
    }
}

4. 创建发票总计模型,让发票识别折扣

新建app/code/Vendorname/Modulename/Model/Invoice/Total/PrepaidDiscount.php:

<?php
namespace Vendorname\Modulename\Model\Invoice\Total;

class PrepaidDiscount extends \Magento\Sales\Model\Order\Invoice\Total\AbstractTotal
{
    public function collect(\Magento\Sales\Model\Order\Invoice $invoice)
    {
        parent::collect($invoice);
        
        $order = $invoice->getOrder();
        if ($order->getPrepaidDiscount()) {
            $discountAmount = $order->getPrepaidDiscount();
            // 支持部分发票的折扣比例计算
            $invoiceDiscount = $discountAmount * ($invoice->getBaseGrandTotal() / $order->getBaseGrandTotal());
            
            $invoice->addTotalAmount('prepaiddiscount', -$invoiceDiscount);
            $invoice->addBaseTotalAmount('prepaiddiscount', -$invoiceDiscount);
            
            // 更新发票折扣总计
            $currentDiscount = $invoice->getDiscountAmount();
            $invoice->setDiscountAmount($currentDiscount - $invoiceDiscount);
            $invoice->setBaseDiscountAmount($invoice->getBaseDiscountAmount() - $invoiceDiscount);
        }
        
        return $this;
    }
}

5. 定义Quote和Order的自定义属性

在模块的安装数据文件app/code/Vendorname/Modulename/Setup/InstallData.php中添加属性定义:

<?php
namespace Vendorname\Modulename\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Quote\Setup\QuoteSetupFactory;

class InstallData implements InstallDataInterface
{
    protected $quoteSetupFactory;

    public function __construct(QuoteSetupFactory $quoteSetupFactory)
    {
        $this->quoteSetupFactory = $quoteSetupFactory;
    }

    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]);
        // 添加Quote属性
        $quoteSetup->addAttribute('quote', 'prepaid_discount', [
            'type' => 'decimal',
            'nullable' => true,
            'visible' => false,
            'required' => false,
            'user_defined' => false,
            'default' => 0.00
        ]);
        
        // 添加Order属性
        $quoteSetup->addAttribute('order', 'prepaid_discount', [
            'type' => 'decimal',
            'nullable' => true,
            'visible' => false,
            'required' => false,
            'user_defined' => false,
            'default' => 0.00
        ]);
    }
}

最后执行系统更新命令

完成文件修改后,执行以下命令生效:

php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:flush

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:31:15