zoukankan      html  css  js  c++  java
  • Magento 0元订单 支付方式 -- Magento 0 Subtotal Payment Method

    需求

    现有购物网站支持2种支付方式,但是考虑到会出现如下情况: 在一个优惠活动中,假如有一些订单的总金额为0, 那么这些订单就不必跳转到支付网关,现有支付方式无法处理此种情况。

    分析

    当customer输入订单的收货信息后,点击确认按钮,页面就会跳转到选择支付方式页面,默认流程是直接给出所有支付方式供customer选择,但是对于上面需求中提到的情况:假如订单总金额为0,那么就不应该直接给出所有支付方式,因为根本没有支付需求嘛。修改后的流程应该是先检测订单总金额,假如订单总金额等于0,则只提供一种支付方式——Free Payment支付方式,供customer选择,Free Payment支付方式无需支付,在用户同意并点击checkout-agreements后直接将订单信息发送至服务器;假如订单总金额大于0,则返回全部原有的支付方式供customer选择(应除去新增的Free Payment支付方式)。

    解决方案

    我查看了Magento的Payment Module的源码之后,发现Magento1.9原生支持0金额订单支付(如果有经验的话根本不需要看源代码),在后台System->Configration->SALES->Payment Methods->Zero Subtotal Checkout可进行配置以开启此支付方式。

    配置选项如下:

    • “Title”控制前端显示的名称
    • “New Order Status”表示通过此方式支付后的订单状态
    • “Automatically Invoice All Items”:自动invoice订单内包含的所有项目

    通过配置这些参数,就可以实现上面提出的需求。

    源码分析

    下面记录了一下我查看Magento支付模块(Payment Module)源码的过程:

    Magento返回支付方式是在的URL是base_url/checkout/onepage/saveShippingMethod/, 可以看出,这个动作是在onepageController中的saveShippingMethodAction()方法中完成的。

     1 //file: base_dir/app/code/core/Mage/Checkout/controllers/onepageController.php
     2 /**
     3  * Shipping method save action
     4  */
     5 public function saveShippingMethodAction()
     6 {
     7     if ($this->_expireAjax()) {
     8         return;
     9     }
    10     if ($this->getRequest()->isPost()) {
    11         $data = $this->getRequest()->getPost('shipping_method', '');
    12         $result = $this->getOnepage()->saveShippingMethod($data);
    13         // $result will contain error data if shipping method is empty
    14         if (!$result) {
    15             Mage::dispatchEvent(
    16                 'checkout_controller_onepage_save_shipping_method',
    17                  array(
    18                       'request' => $this->getRequest(),
    19                       'quote'   => $this->getOnepage()->getQuote()));
    20             $this->getOnepage()->getQuote()->collectTotals();
    21             $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
    22 
    23             $result['goto_section'] = 'payment';
    24             $result['update_section'] = array(
    25                 'name' => 'payment-method',
    26                 'html' => $this->_getPaymentMethodsHtml()
    27             );
    28         }
    29         $this->getOnepage()->getQuote()->collectTotals()->save();
    30         $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
    31     }
    32 }

    在这个方法中,首先获取了POST过来的 "shipping_method" 数据,检测有否有error,如果没有error就生成$result数组,最后在 Mage_Core_Helper_Data 类的 jsonEncode() 方法中将$result数组编码为JSON格式,最后发送到浏览器。

    生成$result['update_section']['html']的方法$this->_getPaymentMethodsHtml()代码如下:

     1 //file: base_dir/app/code/core/Mage/Checkout/controllers/onepageController.php
     2 /**
     3  * Get payment method step html
     4  *
     5  * @return string
     6  */
     7 protected function _getPaymentMethodsHtml()
     8 {
     9     $layout = $this->getLayout();
    10     $update = $layout->getUpdate();
    11     $update->load('checkout_onepage_paymentmethod');
    12     $layout->generateXml();
    13     $layout->generateBlocks();
    14 
    15     //---------only for debug------------------
    16     /** @var Mage_Core_Block_Template $block */
    17     foreach ($layout->getAllBlocks() as $block) {
    18         Mage::log($block->getTemplate());
    19     }
    20     //---------only for debug------------------
    21 
    22     $output = $layout->getOutput();
    23     return $output;
    24 }

    此方法生成了供前台页面使用的HTML。可以通过做Log来快速定位PaymentMethod Block的Template。其中,$layout为 Mage_Core_Model_Layout 的实例,查看它的 getOutput() 方法:

     1 //file: base_url/app/code/core/Mage/Core/Model/Layout.php
     2 /**
     3  * Get all blocks marked for output
     4  *
     5  * @return string
     6  */
     7 public function getOutput()
     8 {
     9     $out = '';
    10     if (!empty($this->_output)) {
    11         foreach ($this->_output as $callback) {
    12             //---------only for debug------------------ 
    13             Mage::log($callback);
    14             Mage::log(get_class($this->getBlock($callback[0])));
    15             Mage::log($this->getBlock($callback[0])->getTemplate());
    16             //---------only for debug------------------
    17             $out .= $this->getBlock($callback[0])->$callback[1]();
    18         }
    19     }
    20 
    21     return $out;
    22 }

    通过对$callback做log,可以知道$callback的结构如下:

     1 //Mage::log($callback);
     2 Array
     3 (
     4     [0] => root
     5     [1] => toHtml
     6 )
     7 //Mage::log(get_class($this->getBlock($callback[0])));
     8 Mage_Checkout_Block_Onepage_Payment_Methods 
     9 //Mage::log($this->getBlock($callback[0])->getTemplate());
    10 checkout/onepage/payment/methods.phtml
    11 */

    进而可以知道Payment Methods的Block是 Mage_Checkout_Block_Onepage_Payment_Methods (如果你有经验的话应该早就猜到了是这个Block了,Magento是通过Block和template文件结合起来渲染页面的)。 结合 Mage_Checkout_Block_Onepage_Payment_Methods 和它的Template文件, 可以确定它是通过 getMethods() 这个方法来获取合适的支付方式的。

     1 //file: base_dir/app/code/core/Mage/Payment/Block/Form/Container.php
     2 /**
     3  * Retrieve available payment methods
     4  *
     5  * @return array
     6  */
     7 public function getMethods()
     8 {
     9     $methods = $this->getData('methods');
    10     if ($methods === null) {
    11         $quote = $this->getQuote();
    12         $store = $quote ? $quote->getStoreId() : null;
    13         $methods = array();
    14         foreach ($this->helper('payment')->getStoreMethods($store, $quote) as $method) {
    15             if ($this->_canUseMethod($method) && $method->isApplicableToQuote(
    16                 $quote,
    17                 Mage_Payment_Model_Method_Abstract::CHECK_ZERO_TOTAL
    18             )) {
    19                 $this->_assignMethod($method);
    20                 $methods[] = $method;
    21             }
    22         }
    23         $this->setData('methods', $methods);
    24     }
    25     return $methods;
    26 }

    在 getMethods() 中,一共有三种方式可以控制某个quote的支付方式:

    • 第一种是$this->helper('payment')->getStoreMethods($store, $quote),这个是“源头”;
    • 第二个是$this->_canUseMethod($method);
    • 第三个是$method->isApplicableToQuote($quote, Mage_Payment_Model_Method_Abstract::CHECKZEROTOTAL);

    结合这三种方式,就可以筛选出合适的支付方式。假如你新增了一种支付方式,但是前台显示不出来,就应该从这三个筛选方式着手。

    这次的Magento源码“探索之旅”就到这里吧 :D

    如果您觉得阅读本文对您有帮助,欢迎转载本文,但是转载文章之后必须在文章页面明显位置保留此段声明,否则保留追究法律责任的权利。

    作  者:blog.jpdou.top

    原文链接:http://blog.jpdou.top/magento-0-subtotal-payment-method/

  • 相关阅读:
    hdu 1455 N个短木棒 拼成长度相等的几根长木棒 (DFS)
    hdu 1181 以b开头m结尾的咒语 (DFS)
    hdu 1258 从n个数中找和为t的组合 (DFS)
    hdu 4707 仓鼠 记录深度 (BFS)
    LightOJ 1140 How Many Zeroes? (数位DP)
    HDU 3709 Balanced Number (数位DP)
    HDU 3652 B-number (数位DP)
    HDU 5900 QSC and Master (区间DP)
    HDU 5901 Count primes (模板题)
    CodeForces 712C Memory and De-Evolution (贪心+暴力)
  • 原文地址:https://www.cnblogs.com/jpdoutop/p/Magento-Zero-Subtotal-Payment-Method.html
Copyright © 2011-2022 走看看