拆解Magento’s 搜集Totals: 的Core Process
拆解Magento’s 搜集Totals: 的Core Process

拆解Magento’s 搜集Totals: 的Core Process

2013年5月1日发布 in 发展历程
拆解Magento’s 搜集Totals: Introduction
2013年4月24日
拆解Magento’s 搜集Totals: Orders and Caveats
2013年5月8日

以前的条目

在本系列中,我们’重新看Magento’用于计算和显示购物车总计的过程。在介绍中,我们简要介绍了“total” or “total 搜集or”是,看看如何在config.xml中定义一个。现在它’s time to take a closer look at the models and data structure 在volved. 的job of a 总 搜集or model can be divided 在to two processes: Calculation and display.

您’强烈建议您打开Magento代码库,并遵循引用的代码。

的搜集Totals process

As mentioned 在 the previous 文章, the calculation of cart 总s is kicked off with a call to Mage_Sales_Model_Quote::collectTotals. Before taking a look at the code, there are a few things to take note of about the underlying data structure for 总s:

  • 虽然它’s not required, many 总s have database fields dedicated to them – usually “totalname_amount” and “base_totalname_amount”用于商店和基础货币。 (例如“gift_cards_amount” and “base_gift_cards_amount”)
  • Since 总s calculations are done 上 each 在dividual quote address, these fields are typically 在 sales_flat_quote_address, and there are methods for automatically adding to these amounts and 在corporating them 在to the quote address’s 总.
  • It’s not uncommon for fields of the same name to exist 在 sales_flat_quote_address_item and be managed directly by the 总 搜集or.
  • There are no restrictions 上 what values a particular 总 搜集or can modify. Example: 的“subtotal” 搜集or modifies several values, 在cluding “price” and “row_total” 上 quote items.
  • sales_flat_quote确实包含“subtotal” and “grand_total,” which are special 在 that 搜集Totals automatically takes care of populating them 后 all 总 搜集ors have run.

有了它,它’s time to examine the general flow of execution for 搜集Totals. 搜集Totals is run at various points, almost always immediately 之前 the quote is saved. Examples would 在clude during a visit to the cart page, upon the submission of each step during the checkout, and immediately 之前 final order placement. Here’是collectTotals的截短版本,主要代码区域是’re concerned with:

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    上市 功能 搜集Totals()
    {
        / **
         * Protect double 总s 搜集ion
         * /
        如果 ($ this->getTotalsCollectedFlag()) {
            返回 $ this;
        }
 
        . . .
 
        前言 ($ this->getAllAddresses() $ address) {
            $ address->setSubtotal(0);
            $ address->setBaseSubtotal(0);
 
            $ address->setGrandTotal(0);
            $ address->setBaseGrandTotal(0);
 
            $ address->搜集Totals();
 
            $ this->setSubtotal((浮动) $ this->getSubtotal()
                + $ address->getSubtotal());
            $ this->setBaseSubtotal((浮动) $ this->getBaseSubtotal()
                + $ address->getBaseSubtotal());
 
            $ this->setSubtotalWithDiscount(
                (浮动) $ this->getSubtotalWithDiscount()
                    + $ address->getSubtotalWithDiscount()
            );
            $ this->setBaseSubtotalWithDiscount(
                (浮动) $ this->getBaseSubtotalWithDiscount()
                    + $ address->getBaseSubtotalWithDiscount()
            );
 
            $ this->setGrandTotal((浮动) $ this->getGrandTotal()
                + $ address->getGrandTotal());
            $ this->setBaseGrandTotal((浮动) $ this->getBaseGrandTotal()
                + $ address->getBaseGrandTotal());
        }
 
        . . .
 
        $ this->setTotalsCollectedFlag(真正);
        返回 $ this;
    }

的parts I’ve truncated deal with dispatching events, zeroing out values 之前 the process begins, validation, and setting item quantities 上 the quote. Here’s an explanation of the main 搜集ion process:

  • Mage_Sales_Model_Quote :: 总计遍历每个报价地址并调用Mage_Sales_Model_Quote_Address :: 总计。
  • In 搜集Totals for an address, getTotalCollector()->getCollectors is used to get a sorted 数组 of the defined 总 models and loop through them.
  • 的“collect” method is run 上 each 总 model (all of which extend Mage_Sales_Model_Quote_Address_Total_Abstract). This method accepts the address 如 a parameter and does the heavy lifting of 总s calculation.
    • 逻辑几乎总是涉及遍历地址’s quote items via _getAddressItems. 的handy methods _addAmount and _addBaseAmount can be used to add to the value of a field 上 the address matching the name of the 总 搜集or (like “discount_amount”), which will also add to the grand 总 for the address.
    • 对引用地址本身上的值的任何修改也在此处完成。
  • In Mage_Sales_Model_Quote::collectTotals, 小计 and 累计 are accumulated from the 总s 上 each address.
  • With few 例外情况, the quote (and by extension its addresses and items) is immediately saved 后 搜集Totals is run.

To re-emphasize, no 价钱 在formation exists 上 the quote at all until this process has run the first time. When a product is added to the cart, it is added without 价钱 在fo, and the appropriate 价钱 is looked up and applied 在 上e of the 总 搜集ors.

在报价单上同时收集运输地址和账单地址,然后将其总计,这似乎很奇怪。首先,它’s appropriate for calculations to be done 在 the context of a specific address, because address 在formation may affect things like 税 and 运输. But 如果 the two addresses’总计相加,结果如何正确?密钥位于整个模型的_getAddressItems中,它将返回项目 只要 for the relevant address. (Typically the 运输 address, or the billing address 上 a virtual quote.) Thus you end up with $0 总s 上 the address for which no items are 返回ed. And for multi-shipping, quote items are explicitly 如sociated with 上e address or another, which makes the general 搜集Totals process work out nicely.

Displaying 总s

计算报价总额的过程似乎仍然有些模糊,但是如果您花一些时间检查核心中定义的各种总量模型,则应该可以点击常规功能。那里’但是,它是总体模型的另一个关键组成部分:在购物车或结帐处(或任何地方)显示总计。它’总计不需要显示,但总计如下“subtotal,” “discount,” “tax” and “grand_total”应该在页面上逐项列出。

您’我看到报价模型上的collectTotals和“collect” 上 a 总 model are the key methods 在volved with calculating and saving 在fo. For displaying, getTotals 上 the quote model and “fetch” 上 the 总 model comprise the main event. Here’s the basic process:

  • Mage_Checkout_Block_Cart_Totals is the block 在cluded 在 the layout. 的corresponding template outputs the results of renderTotals 上 this block.
  • Mage_Checkout_Block_Cart_Totals :: renderTotals循环遍历该块的结果’自己的getTotals方法,该方法依次调用Mage_Sales_Model_Quote :: getTotals。
  • 毫不奇怪,在每个引用地址上都调用了getTotals方法。并与我们在集合中看到的过程getTotalCollector()-并行>getRetrievers is used to get the sorted 总 models. (This is distinct from getCollectors. In this case, admin configuration can actually be used to dictate the order 在 which 总s are displayed.)
  • 的“fetch” method is called 上 each 总 model, 上ce again with the address passed 如 a parameter.
    • Ultimately, this method calls addTotal 上 the quote address, passing an 数组 with the 总’s代码,显示标题和要显示的值。
    • 最终存储在报价地址上的是Mage_Sales_Model_Quote_Address_Total的实例,该实例是Varien_Object,并添加了“merge”便于求和两个这样的对象的值的方法。
  • 当Mage_Sales_Model_Quote :: getTotals遍历每个地址时,它使用“merge”上面提到的协调每个地址的方法’s data for a particular 总 在to 上e final set of 在formation to display.
  • Finally, Mage_Checkout_Block_Cart_Totals::renderTotals calls renderTotal for each 总, which 在stantiates the appropriate block (more 上 this 在 a moment) and 返回s the results of toHtml.

Exactly which block 类 is used to render a specific 总 is determined 如 follows:

  • A block can be defined directly 在 layout XML for any 总. It should simply have the name “{totalcode} _total_renderer,” and this block will be used to render the corresponding 总.
  • 如果在布局中未定义渲染器,则检查的下一个位置是全局配置XML。我们’我们已经看到了总计的定义位置(在节点路径中)“全球/销售/报价/总计”)。特定总数的节点可以定义<renderer> 在 addition to <class>, <before> and <after>. 的expected value is a block code. An example can be found 在 config.xml for Mage_Checkout, where the 渲染器 “结帐/合计名义”为“nominal” 总.
  • If neither of the above defined a 渲染器, the default Mage_Checkout_Block_Total_Default is used.

在那里,您拥有了!收集和显示过程就这么简单。好吧“simple”可能不是用来形容它们的单词。但是,通过上面的概述,您应该有能力检查所涉及的各种模型的代码,并了解执行流程。

一个简单的例子

All of the native 总 搜集ors have their own quirks, complexities, and “exceptions”遵守规则,因此找到一个简单明了的例子是一个挑战。为了尽可能简化,我’ll present the following pseudo example of how the two key methods 上 a 总 work. Most 总s follow the same basic process 在 some fashion.

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
MySite_MyModule_Model_Sales_Quote_Address_Total_Mytotal
    延伸 Mage_Sales_Model_Quote_Address_Total_Abstract
{
    上市 功能 __构造()
    {
        $ this->setCode('mytotal');
    }
    
    上市 功能 搜集(Mage_Sales_Model_Quote_Address $ address)
    {
        父母::搜集($ address);
        
        前言 ($ this->_getAddressItems($ address) $项目) {
            //这两行代表您所使用的任何逻辑
            //用于计算这些金额
            $ baseAmt = ...
            $ amt = ...
        
            // Set the item's 总
            $项目->setBaseMytotalAmount($ baseAmt);
            $项目->setMytotalAmount($ amt);
        
            //这些方法自动进行求和
            //报价地址上的“ mytotal_amount”
            $ this->_addBaseAmount($ baseAmt);
            $ this->_addAmount($ amt);
        }
        返回 $ this;
    }
    
    上市 功能 (Mage_Sales_Model_Quote_Address $ address)
    {
        // Naturally, this exists 上 the quote address because "搜集" ran already
        $ amt = $ address->getMytotalAmount();
        
        如果 ($ amt!=0) {
            $ address->addTotal(数组(
                    '码' => $ this->getCode(),
                    '标题' => 法师::帮手('mysite_mymodule')->__(“我的总计”),
                    '值' => $ amt
            ));
        }
        返回 $ this;
    }
}

在下一部分中,我们’ll discuss some final points that are worth consideration 之前 Magento 总s can be considered well and truly conquered.

下一页条目

5 评论

  1. $ address-如何>getMytotalAmount();获得由$ item-设置的值>setMytotalAmount($ amt);

    不会’t您需要从商品中获取值或在地址对象上设置值,例如$ address->getMyTotalAmount();

    • 维奈·科普 说:

      你好

      首先,感谢您的精彩系列!它写得很好,很好地涵盖了一个复杂的主题,将其分解为易于处理的内容。
      虽然有一个小音符(可以’不能帮助但要聪明 – sorry). It is not required to set the 总 code within the 总 model 在 the __构造() method of the example. 的总 code is set 上 the model 后 在stantiation by Mage_Sales_Model_Quote_Address_Total_Collector::_initModelInstance().
      在构造函数中设置代码赢了’不会造成任何伤害,它将再次被覆盖。如果XML中指定的代码与构造函数中指定的代码之间存在差异,这可能会造成混淆。

      再次感谢您的贡献!

    • 克里斯·南宁加 说:

      If memory serves, $ this->_addAmount 在 the “fetch” method takes care of setting the 总 上 the address.

  2. 很棒的文章集!
    我有一个问题,如果你不愿意’t mind helping.

    I have a shopping cart rule set up for a certain product to get discounted 100%. In the Discount 小计 it DOUBLES the 折扣, but 在 the Grand Total, it calculates the discount correctly.

    知道为什么吗?我可以’似乎找不到为什么折扣可能在前端加倍。太奇怪了。

发表评论

您r email address will not be published. 必需的地方已做标记 *

该网站使用Akismet减少垃圾邮件。 了解如何处理您的评论数据.

最近的帖子查看全部
2020年10月22日
通过 阿什莉·科利弗 商业见解, 优雅的骆马 2020年10月22日
毫无疑问,2020年是历史性的一年。火灾,全球大流行,暴动,老虎王等’只是冰山一角。如 […]