Created
July 16, 2014 16:51
-
-
Save herveguetin/9546aedce530d1016fa5 to your computer and use it in GitHub Desktop.
A powerful and easy freeshipping remainder block for Magento based on shopping cart promo rules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Just create as many shopping cart price rules that are elligible for free shipping | |
and this block class will use the most appropriate one to define: | |
- minimum amount to get freeshipping | |
- remaining amount to purchase to get freeshipping. | |
If no rule is elligible, the block falls back to a CMS block. | |
Just call this block from layout and define a template from which you can call: | |
- $this->getMinimumPurchaseAmount() | |
- $this->getRemainingShippingAmount() | |
*/ | |
/** | |
* Checkout_Freeshipping_Remainder Block | |
*/ | |
class Namespace_Module_Block_Checkout_Freeshipping_Remainder extends Mage_Core_Block_Template | |
{ | |
/** | |
* CMS block identifier for fallback | |
*/ | |
const CMS_BLOCK_ID = 'my_cms_block_id'; | |
/** | |
* Amount remaining to get freeshipping | |
* | |
* @var int | |
*/ | |
protected $_remainingShippingAmount = 0; | |
/** | |
* Minimum purchase amount to get freeshipping | |
* | |
* @var int | |
*/ | |
protected $_minimumPurchaseAmount = 0; | |
/** | |
* Retrieve minimum purchase amount to get freeshipping | |
* | |
* @return float | |
*/ | |
public function getMinimumPurchaseAmount() | |
{ | |
return $this->_minimumPurchaseAmount; | |
} | |
/** | |
* Retrieve remaining shipping amount | |
* | |
* @return float | |
*/ | |
public function getRemainingShippingAmount() | |
{ | |
return $this->_remainingShippingAmount; | |
} | |
/** | |
* Retrieve shipping cart promo rules that may be used | |
* | |
* @return array | |
*/ | |
protected function _getApplicableRules() | |
{ | |
$currentWebsiteId = Mage::app()->getStore()->getWebsiteId(); | |
$currentCustomerGroup = (Mage::helper('customer')->isLoggedIn()) ? Mage::helper('customer')->getCustomer()->getGroupId() : Mage_Customer_Model_Group::NOT_LOGGED_IN_ID; | |
// Get sales rules that are active, with free shipping enabled and without any coupon | |
$availableRules = Mage::getModel('salesrule/rule')->getCollection() | |
->addWebsiteGroupDateFilter($currentWebsiteId, $currentCustomerGroup) | |
->addFieldToFilter('simple_free_shipping', Mage_SalesRule_Model_Rule::FREE_SHIPPING_ADDRESS) | |
->addFieldToFilter('coupon_type', Mage_SalesRule_Model_Rule::COUPON_TYPE_NO_COUPON) | |
; | |
$applicableRules = array(); | |
foreach($availableRules as $rule) { | |
/* @var $rule Mage_SalesRule_Model_Rule */ | |
/** | |
* Check if rule may be a candidate to be applicable. | |
* This is done by removing all conditions based on cart subtotal amount and testing rule against remaining conditions | |
*/ | |
$originalConditions = $rule->getConditionsSerialized(); | |
$conditions = unserialize($originalConditions); | |
// If there is no condition, rule is a candidate! | |
if(!isset($conditions['conditions'])) { | |
$applicableRules[] = $rule; | |
continue; | |
} | |
// If there is a condition based on cart subtotal, remove it... | |
foreach($conditions['conditions'] as $k => $condition) { | |
if(isset($condition['attribute']) && $condition['attribute'] == 'base_subtotal') { | |
unset($conditions['conditions'][$k]); | |
} | |
} | |
// ... and rebase conditions | |
$conditions['conditions'] = array_values($conditions['conditions']); | |
// If there is no condition anymore, remove its entry in its associated rule | |
if(count($conditions['conditions']) < 1) { | |
unset($conditions['conditions']); | |
} | |
// Update rule with reworked conditions | |
$rule->setConditionsSerialized(serialize($conditions)); | |
// And check if updated rule is valid. If so, push it into $applicableRules array. | |
$address = Mage::helper('checkout/cart')->getQuote()->getShippingAddress(); | |
if($rule->validate($address)) { | |
// Rollback rule to its original state for further processing | |
$rule->setConditionsSerialized($originalConditions); | |
$applicableRules[] = $rule; | |
} | |
} | |
return $applicableRules; | |
} | |
/** | |
* Calculate remaining amount to get free shipping | |
* | |
* @param array $rules | |
* @return Undiz_Local_Block_Checkout_Freeshipping_Remainder | |
*/ | |
public function setRemainingShippingAmount($rules) | |
{ | |
$lowestValue = null; | |
// Retrieve lowest minimum value to get free shipping | |
foreach($rules as $rule) { | |
$conditions = unserialize($rule->getConditionsSerialized()); | |
// If there is no condition, value for free shipping is 0 | |
if(!isset($conditions['conditions'])) { | |
$value = 0; | |
} | |
else { | |
foreach($conditions['conditions'] as $condition) { | |
if(isset($condition['attribute']) && $condition['attribute'] == 'base_subtotal') { | |
$value = $condition['value']; | |
if(is_null($lowestValue) || $value < $lowestValue) { | |
$lowestValue = $value; | |
} | |
} | |
} | |
} | |
if(is_null($lowestValue) || $value < $lowestValue) { | |
$lowestValue = $value; | |
} | |
} | |
if($lowestValue) { | |
$store = Mage::app()->getStore(); | |
// Get cart subtotal excl. tax | |
$cartSubtotal = Mage::helper('checkout/cart')->getQuote()->getBaseSubtotal(); | |
// Check if tax application for shipping is required | |
// If so, retrieve tax rate based on current store and using shipping tax class | |
$taxRate = 0; | |
if(Mage::getStoreConfig('tax/calculation/discount_tax') == 1) { // @see Mage_Tax_Model_System_Config_Source_PriceType | |
$request = Mage::getSingleton('tax/calculation')->getRateRequest(false, false, false, $store); | |
$taxRate = Mage::getSingleton('tax/calculation') | |
->getRate($request->setProductClassId(Mage::getStoreConfig('tax/classes/shipping_tax_class'))); | |
} | |
// Get cart subtotal updated with tax rate | |
$cartSubtotal = $cartSubtotal * (1 + $taxRate/100); | |
// Calculate remaining shipping amount. If < 0, set it to 0 | |
$remainingShippingAmount = ($lowestValue - $cartSubtotal < 0) ? 0 : $lowestValue - $cartSubtotal; | |
// Calculate remaining shipping amount for real | |
$this->_remainingShippingAmount = $store->roundPrice($remainingShippingAmount); | |
// Update minimum purchase amount to get free shiupping | |
$this->_minimumPurchaseAmount = $store->roundPrice($lowestValue); | |
} | |
return $this; | |
} | |
/** | |
* Switch html rendering: | |
* - if there is some available sales rule => calculate remaining shipping amount | |
* - else => render some CMS block | |
* | |
* @return string | |
*/ | |
protected function _toHtml() | |
{ | |
$applicableRules = $this->_getApplicableRules(); | |
if(count($applicableRules) < 1) { | |
$cmsBlock = $this->getLayout() | |
->createBlock('cms/block') | |
->setBlockId(self::CMS_BLOCK_ID); | |
return $cmsBlock->toHtml(); | |
} | |
$this->setRemainingShippingAmount($applicableRules); | |
return parent::_toHtml(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment