天天看点

magento create shipping method

这一章节里, 我们来了解一下如何在 Magento 中创建自定义的送货/配送方式(Shipping Method)

创建自定义配送方式并不是很复杂, 不过需要了解在 shipping method 类中所有有用的方法,然后加以利用, 那就变得十分简单了, 我会在这一节中示例不同 cases 情况下所使用的方法

现在我们就先来创建一个配送方式, 在接下去的示例中, 我将使用模块 Excellence_Ship。 你可以创建你自己的模块, 注意修改类名就可以了, 同样我先附上源码:

Shipping Method.zip (8.08KB)

当创建完成后, 配送方式主要会在如下两个地方被显示:

后台 - Admin Panel

magento create shipping method

前台 - Frontend

magento create shipping method

为了实现这些, 我们需要对如下三个文件进行修改:

config.xml | system.xml | Shipping Module

步骤一

在我们创建的时候, 需要为我们的配送方式决定一个标识, 在示例中, 我使用唯一标识就是 "excellence", 接下来创建 system.xml, 这样就可以在后台 configuration 中进行配置

<?xmlversion="1.0"encoding="UTF-8"?>
<config>
    <sections>
        <carriers>
            <groups>
                <excellencetranslate="label"module="ship">
                    <label>Excellence Shipping Module</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>99</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>1</show_in_store>
                    <fields>
                        <activetranslate="label">
                            <label>Enabled</label>
                            <frontend_type>select</frontend_type>
                            <source_model>adminhtml/system_config_source_yesno</source_model>
                            <sort_order>1</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </active>
                        <titletranslate="label">
                            <label>Title</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>2</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </title>
                        <nametranslate="label">
                            <label>Method Name</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>2</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </name>
                        <pricetranslate="label">
                            <label>Price</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>3</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </price>
                        <specificerrmsgtranslate="label">
                            <label>Displayed Error Message</label>
                            <frontend_type>textarea</frontend_type>
                            <sort_order>4</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </specificerrmsg>
                        <sallowspecifictranslate="label">
                            <label>Ship to Applicable Countries</label>
                            <frontend_type>select</frontend_type>
                            <sort_order>90</sort_order>
                            <frontend_class>shipping-applicable-country</frontend_class>
                            <source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </sallowspecific>
                        <specificcountrytranslate="label">
                            <label>Ship to Specific Countries</label>
                            <frontend_type>multiselect</frontend_type>
                            <sort_order>91</sort_order>
                            <source_model>adminhtml/system_config_source_country</source_model>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                            <can_be_empty>1</can_be_empty>
                        </specificcountry>
                    </fields>
                </excellence>
            </groups>
        </carriers>
    </sections>
</config>
           

这里需要说明一下的就是, 我们需要将配送方式代码写在如下标签中, 和创建支付方式类似:

<sections>
    <carriers>
        <groups>
           

从这里你可以看出在 'excellence' 标签中的就是我们配送方式的代码, 这些代码就是用来创建该配送方式是否启用, title, name, 和 price, 当然这些都是每一个配送方式所必须的

这里我们也同时创建了2个额外的标签, sallowspecific 和 specificcountry, 其实这也是需要, 因为有可能该配送方式只对某一些国家开放, 比如说有一个用户选择配送到冰岛, 然而我们的后台配置中并没有包括该国家, 为了达到限制, 我们只需要在我们的 xml 中写入这两个标签,并在后台加以配置就可以了, 不需要做其他额外的工作

还有一个就是 specificerrmsg 标签 - 错误信息, 当配送方式产生错误的时候, 这个标签里的内容就能显示给用户

步骤二

在 config.xml 中的 <config> 标签里写入如下代码:

<default>
    <carriers>
        <excellence>
            <active>1</active>
            <model>ship/carrier_excellence</model>
            <title>Carrier Title</title>
            <name>Method Name</name>
            <price>5.00</price>
            <specificerrmsg>This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us.</specificerrmsg>
        </excellence>
     </carriers>
</default>
           

这里的 <default> 标签里的内容就是用来在后台 configuration 中为刚创建的标签设置默认值的, 可以看出基本和刚刚由 system.xml 所创建的一一对应, 唯一需要注意的就是 <model> 标签, 它包含了该配送方式的 model 路径, 这个十分重要, 否则该配送方式不会在前端页面显示

现在你可以到 Admin -> System -> Configuration -> Shipping Methods 中看到你刚新建的标签以及初始化的默认值

magento create shipping method

步骤三

现在我们就要来创建我们配送方式的 model 类文件了, 对应和之前 <model> 标签中所申明的

Excellence_Ship_Model_Carrier_Excellence

<?php
 
classExcellence_Ship_Model_Carrier_Excellence 
    extendsMage_Shipping_Model_Carrier_Abstract 
        implementsMage_Shipping_Model_Carrier_Interface
{
 
    protected$_code = 'excellence';
  
    publicfunction collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
        if(!Mage::getStoreConfig('carriers/'.$this->_code.'/active')) {
            returnfalse;
        }
          
        $handling= Mage::getStoreConfig('carriers/'.$this->_code.'/handling');
        $result  = Mage::getModel('shipping/rate_result');
        $show    = true;
        if($show) {  // 这里这个 if 仅仅是为了演示如何在 shipping methods 中返回成功和错误的
             
            $method= Mage::getModel('shipping/rate_result_method');
            $method->setCarrier($this->_code);
            $method->setMethod($this->_code);
            $method->setCarrierTitle($this->getConfigData('title'));
            $method->setMethodTitle($this->getConfigData('name'));
            $method->setPrice($this->getConfigData('price'));
            $method->setCost($this->getConfigData('price'));
            $result->append($method);
  
        }else{
         
            $error= Mage::getModel('shipping/rate_result_error');
            $error->setCarrier($this->_code);
            $error->setCarrierTitle($this->getConfigData('name'));
            $error->setErrorMessage($this->getConfigData('specificerrmsg'));
            $result->append($error);
        }
         
        return$result;
    }
     
    publicfunction getAllowedMethods()
    {
        returnarray('excellence'=>$this->getConfigData('name'));
    }
}
           

如上的代码还是比较容易理解的, 不过还是来逐行了解下:

publicfunction collectRates(Mage_Shipping_Model_Rate_Request $request)
           

这个方法需要被执行, 正确来说会被 Magento 自身调用, 用来查找出 shipping rates

</pre><pre name="code" class="php">if(!Mage::getStoreConfig('carriers/'.$this->_code.'/active')) {
    returnfalse;
}
           

这个 if 只是来检查该配送方式在后台配置中是否被开启

$result= Mage::getModel('shipping/rate_result');
           

这里我们创建了 result 对象, 它总是在配送方式中的 collectRate 方法里被返回出来

$method= Mage::getModel('shipping/rate_result_method');
$method->setCarrier($this->_code);
$method->setMethod($this->_code);
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethodTitle($this->getConfigData('name'));
$method->setPrice($this->getConfigData('price'));
$method->setCost($this->getConfigData('price'));
$result->append($method);
           

这些就是用来返回出运费价格(shipping price)的

$error= Mage::getModel('shipping/rate_result_error');
$error->setCarrier($this->_code);
$error->setCarrierTitle($this->getConfigData('name'));
$error->setErrorMessage($this->getConfigData('specificerrmsg'));
$result->append($error);
           

很明显,这些就是用来返回错误信息的

Model 类文件创建完毕后, 该配送方式应该就可以工作了, 你也可以在 checkout 和 cart 页面中看到

不同 cases 情况下所使用的方法

如下我所写的内容只适用在 collectRates 方法中, 下面我会分别列出不同的情况, 你可以根据自己的需求加以利用, 不过价格最后需要被放在 $result 变量中, 和上面示例中一样

运费价格基于目的地国家,州和邮政编码

//Case1: 运费价格基于目的地国家,州和邮政编码
        echo$destCountry = $request->getDestCountryId().': Dest Country<br>';
        echo$destRegion  = $request->getDestRegionId().': Dest Region<br>';
        echo$destRegionCode = $request->getDestRegionCode().': Dest Region Code<br>';
        print_r($destStreet= $request->getDestStreet());echo': Dest Street<br>';
        echo$destCity = $request->getDestCity().': Dest City<br>';
        echo$destPostcode = $request->getDestPostcode().': Dest Postcode<br>';
        echo$country_id = $request->getCountryId().': Package Source Country ID<br>';
        echo$region_id = $request->getRegionId().': Package Source Region ID<br>';
        echo$city = $request->getCity().': Package Source City<br>';
        echo$postcode = $request->getPostcode().': Package Source Post Code<br>';
           

可以根据自己业务逻辑的需求添加 if 条件来得出最后的价格

运费价格基于订单的价格或重量

//Case2: 运费价格基于订单的价格或重量
        echo$packageValue = $request->getPackageValue().': Dest Package Value<br>';
        echo$packageValueDiscout = $request->getPackageValueWithDiscount().': Dest Package Value After Discount<br>';
        echo$packageWeight = $request->getPackageWeight().': Package Weight<br>';
        echo$packageQty = $request->getPackageQty().': Package Quantity <br>';
        echo$packageCurrency = $request->getPackageCurrency().': Package Currency <br>';
           

运费价格基于尺寸(Dimension)

//Case3: 运费价格基于尺寸
        echo$packageheight = $request->getPackageHeight() .': Package height <br>';
        echo$request->getPackageWeight().': Package Width <br>';
        echo$request->getPackageDepth().': Package Depth <br>';
           

运费价格基于产品属性

假如你想让每个产品都有自己不同的运费价格, 为此, 我们需要创建一个产品属性叫: 'shipping_price’', 在每一个产品编辑页面填写该产品自己的运费价格, 这样我们就可以在配送方法中通过这个 'shipping_price' 来计算出总运费价格

//Case4: 运费价格基于产品属性
        if($request->getAllItems()) {
            foreach($request->getAllItems()as$item) {
                if($item->getProduct()->isVirtual() || $item->getParentItem()) {
                    continue;
                }
  
                if($item->getHasChildren() && $item->isShipSeparately()) {
                    foreach($item->getChildren()as$child) {
                        if($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
                            $product_id= $child->getProductId();
                            $productObj= Mage::getModel('catalog/product')->load($product_id);
                            $ship_price= $productObj->getData('shipping_price');//获取产品运费属性
                            $price+= (float)$ship_price;
                        }
                    }
                }else{
                    $product_id= $item->getProductId();
                    $productObj= Mage::getModel('catalog/product')->load($product_id);
                    $ship_price= $productObj->getData('shipping_price');//获取产品运费属性
                    $price+= (float)$ship_price;
                }
            }
        }
           

运费价格基于产品属性选项

假说说网站上有个产品含有多个尺寸, 在页面中提供下拉框来供用户选择, 小号(small)运费为 15, 中号(medium)运费为: 20, 大号(large)运费为: 25

//Case5: 运费价格基于产品属性选项
        if($request->getAllItems()) {
            foreach($request->getAllItems()as$item) {
                if($item->getProduct()->isVirtual() || $item->getParentItem()) {
                    continue;
                }
                if($item->getHasChildren() && $item->isShipSeparately()) {
                    foreach($item->getChildren()as$child) {
                        if($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
                            $product_id= $child->getProductId();
                            $value= $item->getOptionByCode('info_buyRequest')->getValue();
                            $params= unserialize($value);
                            $attributeObj= Mage::getModel('eav/config')->getAttribute(Mage_Catalog_Model_Product::ENTITY,'shirt_size');// our configurable attribute
                            $attribute_id= $attributeObj->getAttributeId();
                            $attribute_selected= $params['super_attribute'][$attribute_id];
  
                            $label= '';
                            foreach($attributeObj->getSource()->getAllOptions(false)as$option){
                                if($option['value'] == $attribute_selected){
                                    $label=  $option['label'];
                                }
                            }
                            if($label= 'Small'){
                                $price+= 15;
                            }elseif($label= 'Medium'){
                                $price+= 20;
                            }elseif($label= 'Large'){
                                $price+= 22;
                            }
                        }
                    }
                }else{
                    $product_id= $item->getProductId();
                    $value= $item->getOptionByCode('info_buyRequest')->getValue();
                    $params= unserialize($value);
                    $attributeObj= Mage::getModel('eav/config')->getAttribute(Mage_Catalog_Model_Product::ENTITY,'shirt_size');// our configurable attribute
                    $attribute_id= $attributeObj->getAttributeId();
                    $attribute_selected= $params['super_attribute'][$attribute_id];
  
                    $label= '';
                    foreach($attributeObj->getSource()->getAllOptions(false)as$option){
                        if($option['value'] == $attribute_selected){
                            $label=  $option['label'];
                        }
                    }
                    if($label= 'Small'){
                        $price+= 15;
                    }elseif($label= 'Medium'){
                        $price+= 20;
                    }elseif($label= 'Large'){
                        $price+= 22;
                    }
                }
            }
        }
           

运费价格基于产品自定义选项

假如说网站上有某些产品, 拥有下拉框选项: 快递(Express) 和 邮局普递(Normal), 当用户选择快递(Express)时, 运费价格就是 50, 而邮局普递(Normal)价格则是 10

//运费价格基于产品自定义选项
        if($request->getAllItems()) {
            foreach($request->getAllItems()as$item) {
                if($item->getProduct()->isVirtual() || $item->getParentItem()) {
                    continue;
                }
                if($item->getHasChildren() && $item->isShipSeparately()) {
                    foreach($item->getChildren()as$child) {
                        if($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
                            $product_id= $child->getProductId();
                            $value= $item->getOptionByCode('info_buyRequest')->getValue();
                            $params= unserialize($value);
                            $options_select= $params['options'];
  
                            $product= Mage::getModel('catalog/product')->load($product_id);
                            $options= $product->getOptions();
                            foreach($optionsas $option) {
                                if($option->getGroupByType() == Mage_Catalog_Model_Product_Option::OPTION_GROUP_SELECT) {
                                    $option_id=  $option->getId();
                                    foreach($option->getValues()as$value) {
                                        if($value->getId() == $options_select[$option_id]){
                                            if($value->getTitle() == 'Express'){
                                                $price+= 50;
                                            }elseif($value->getTitle() == 'Normal'){
                                                $price+= 10;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }else{
                    $product_id= $item->getProductId();
                    $value= $item->getOptionByCode('info_buyRequest')->getValue();
                    $params= unserialize($value);
                    $options_select= $params['options'];
  
                    $product= Mage::getModel('catalog/product')->load($product_id);
                    $options= $product->getOptions();
                    foreach($optionsas $option) {
                        if($option->getGroupByType() == Mage_Catalog_Model_Product_Option::OPTION_GROUP_SELECT) {
                            $option_id=  $option->getId();
                            foreach($option->getValues()as$value) {
                                if($value->getId() == $options_select[$option_id]){
                                    if($value->getTitle() == 'Express'){
                                        $price+= 50;
                                    }elseif($value->getTitle() == 'Normal'){
                                        $price+= 10;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
           

这些是我能想到所有的关于运费的, 如有更好的建议和代码片段,欢迎留言提出