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/

  • 相关阅读:
    IE8下提示'console'未定义错误
    左右添加和删除
    箭头函数
    事件冒泡
    选中状态改变,并且实现左边选中便便添加
    appcan里面模板的使用
    白面机器学习笔记(一)
    常见的模型加速方法
    相机的参数
    深度学习和机器学习的区别
  • 原文地址:https://www.cnblogs.com/jpdoutop/p/Magento-Zero-Subtotal-Payment-Method.html
Copyright © 2011-2022 走看看