天天看點

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;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
           

這些是我能想到所有的關于運費的, 如有更好的建議和代碼片段,歡迎留言提出