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
相关产品推荐
相关产品推荐

