Posted on 3 Comments

Customize surcharge price logic for Phoenix Cash on Delivery Magento extension

Magento Logo

A recent customer had the requirement to calculate cash on delivery surcharges in relation to the shipping costs. For instance, let’s say that shipping to Germany costs EUR 8 whereas customers from Austria are charged only EUR 5, unless the total order reaches a certain amount resulting in free shipping.

Now the requirement in this case was that shipping costs and cash on delivery surcharges should in total be EUR 12 for shipments to Germany and EUR 8 for shipments to Austria. So the cash on delivery surcharge has to be calculated in relation to the shipping costs selected to match the desired total cash on delivery surcharge + shipping costs.

Using Phoenix Cash on Delivery extension enables us to set fixed or percentage surcharge values depending in inland and foreign shipments. But these settings do not contain special logic for shipping methods and their respective costs. The extension by default only allows us to disable certain shipping methods when using cash on delivery and limit the list of allowed countries, which in general is sufficient enough but not in our particular case.

So, using the vanilla version of the Phoenix Cash on delivery extension would in the example described above result in duplicate costs (shipping + cash on delivery surcharge) for customers during the checkout process, i.e. EUR 8 for shipping + EUR 12 cash on delivery surcharge for German customers, where in fact we only want to charge German customers EUR 12 in total when cash on delivery is selected as payment method and in total EUR 8 for Austrian customers.

Customize Phoenix Cash on Delivery extension

Having a look at the Phoenix Cash on Delivery extension quickly reveals that for our price logic to work we need to customize the price calculcation in Phoenix_CashOnDelivery_Model_CashOnDelivery and especially the functions getInlandCosts and getForeignCountryCosts.

First, copy app/code/community/Phoenix/CashonDelivery/Model/CashOnDelivery.php to app/code/local/Phoenix/CashonDelivery/Model/CashOnDelivery.php to overwrite the model class in the local code pool.

Note that this should be done using a custom module. The example here only serves as demonstration of the required code pieces.

Next, add the function getConditionalCosts in your local CashOnDelivery.php file:

public function getConditionalCost($baseCost) {
  $quote = Mage::getModel('checkout/session')->getQuote();
  if ($quote) {
    if ($quote->getShippingAddress()) {
      // check customer shipping address country
      $shippingData = $quote->getShippingAddress()->getData();

      if (isset($shippingData['country_id'])) {
        if ($shippingData['country_id'] === 'DE') {
          $baseCost; // do some calculation here
        } else if ($shippingData['country_id'] === 'AT') {
          if (floatval($quote->getGrandTotal()) < 70) {
            $baseCost = // do some calculation here

  return floatval($baseCost);

And to actually integrate the custom logic by adding the required calls to getConditionalCost in getInlandCosts and getForeignCountryCosts:

public function getInlandCosts($address = null) {

  $inlandCost = $this->getConfigData('inlandcosts');
  $minInlandCost = $this->getConfigData('minimum_inlandcosts');

  if (is_object($address) && Mage::getStoreConfigFlag(self::XML_CONFIG_PATH_CASHONDELIVERY_COST_TYPE)) {
    $calcBase = $this->getConfigData('cost_calc_base');
    $inlandCost = ($address->getData($calcBase) / 100) * $inlandCost;
    if ($inlandCost < $minInlandCost) {
      $inlandCost = $minInlandCost;

  return $this->getConditionalCost($inlandCost);

  //return floatval($inlandCost);

public function getForeignCountryCosts($address = null) {
  $foreignCost = $this->getConfigData('foreigncountrycosts');
  $minForeignCost = $this->getConfigData('minimum_foreigncountrycosts');

  if (is_object($address) && Mage::getStoreConfigFlag(self::XML_CONFIG_PATH_CASHONDELIVERY_COST_TYPE)) {
    $calcBase = $this->getConfigData('cost_calc_base');
    $foreignCost = ($address->getData($calcBase) / 100) * $foreignCost;
    if ($foreignCost < $minForeignCost) {
      $foreignCost = $minForeignCost;

  return $this->getConditionalCost($foreignCost);

  //return floatval($foreignCost);

Possible optimizations

Note that with a custom module can easily administrate the price values using by getConditionalCost through the admin backend. As always use system.xml to add your backend options. In addition, make sure to rewrite the model through config.xml. But I’ll leave that to you as an additional excercise 😉