Blog

How to Add Backorder Support to Your Zen Cart Store

As your store grows and you have to manage a larger inventory, you’ll often find items are out of stock as you await new stock from your suppliers.  You can either set Zen Cart to disallow checkout when items are out of stock and potentially lose a large number of orders, or you can display a message to customers that products will be backordered and shipped when they become available.  However, in the default Zen Cart, there is no way to set individual products as backordered or shipped so out of the box, this isn’t really an option.

This tutorial is going to show you how to add the ability to assign backordered or shipped status to individual products in an order and how to generally setup a usable backorder system in your Zen Cart store.

So, let’s begin!

Step 1

Begin by installing the Edit Order module.

Step 2

Go to ADMIN->LOCALIZATION->ORDER STATUS and create two new statuses called ‘Backordered’ and ‘Shipped’.

Step 3

Go to ADMIN->TOOLS->INSTALL SQL PATCHES and paste the following code into the textarea:

ALTER TABLE orders_products ADD backorder tinyint(1) NOT NULL DEFAULT '0';
ALTER TABLE orders_products ADD shipped tinyint(1) NOT NULL DEFAULT '0';

Step 4

Open /admin/edit_orders.php and perform the following modifications:

Add near the top of the file around line 80:

// Backorder / Shipped Support Modification
$dropdown_options = array(array("id" => 0, "text" => "no"),
 array("id" => 1, "text" => "yes"));

Find:

$Query = "update " . TABLE_ORDERS_PRODUCTS . " set

Add After:

 shipped = '" . $products_details["shipped"] . "',
 backorder = '" . $products_details["backorder"] . "',

Find:

<!-- Begin Products Listing Block -->
 <table border="0" width="100%" cellspacing="0" cellpadding="2">
 <tr>
 <td colspan="2"><?php echo TABLE_HEADING_PRODUCTS; ?></td>

Add After:

 <td><?php echo TABLE_HEADING_SHIPPED; ?></td>
 <td><?php echo TABLE_HEADING_BACKORDER; ?></td>

Find:

$order->products[$index] = array('qty' => $orders_products_query->fields['products_quantity'],                   
                                 'name' => zen_html_quotes($orders_products_query->fields['products_name']),

Add After:

 'shipped' => zen_html_quotes($orders_products_query->fields['shipped']),
 'backorder' => zen_html_quotes($orders_products_query->fields['backorder']),

Find:

echo '      </td>' . "\n" .
     '      <td valign="top">' . "<input name='update_products[$orders_products_id][model]' size='12' value='" . $order->products[$i]['model'] . "'>" . '</td>' . "\n" .
     '      <td align="center" valign="top">' . "<input name='update_products[$orders_products_id][tax]' size='3' value='" . zen_display_tax_value($order->products[$i]['tax']) . "'>" . '%</td>' . "\n" .
     '      <td align="right" valign="top">' . "<input name='update_products[$orders_products_id][final_price]' size='5' value='" . number_format($order->products[$i]['final_price'], 2, '.', '') . "'>" . '</td>' . "\n" .
     '      <td align="right" valign="top">' . $currencies->format($order->products[$i]['final_price'] * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value']) . '</td>' . "\n" .
     '    </tr>' . "\n";

Replace With:

echo '      </td>' . "\n" .
     '      <td valign="top">' . zen_draw_pull_down_menu("update_products[$orders_products_id][shipped]", $dropdown_options, $order->products[$i]['shipped']) . '</td>' . "\n" .
     '      <td valign="top">' . zen_draw_pull_down_menu("update_products[$orders_products_id][backorder]", $dropdown_options, $order->products[$i]['backorder']) . '</td>' . "\n" .
     '      <td valign="top">' . "<input name='update_products[$orders_products_id][model]' size='12' value='" . $order->products[$i]['model'] . "'>" . '</td>' . "\n" .
     '      <td align="center" valign="top">' . "<input name='update_products[$orders_products_id][tax]' size='3' value='" . zen_display_tax_value($order->products[$i]['tax']) . "'>" . '%</td>' . "\n" .
     '      <td align="right" valign="top">' . "<input name='update_products[$orders_products_id][final_price]' size='5' value='" . number_format($order->products[$i]['final_price'], 2, '.', '') . "'>" . '</td>' . "\n" .
     '      <td align="right" valign="top">' . $currencies->format($order->products[$i]['final_price'] * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value']) . '</td>' . "\n" .
     '    </tr>' . "\n";

Step 5

Open /admin/includes/languages/english/edit_orders.php and add the following definition somewhere in the file:

define('TABLE_HEADING_BACKORDER', 'Backordered');
define('TABLE_HEADING_SHIPPED', 'Shipped');

Step 6

Open /admin/includes/classes/order.php and find:

$orders_products = $db->Execute("select orders_products_id, products_id, products_name, products_model, products_price, products_tax, products_quantity, final_price, onetime_charges, product_is_free      
                                 from " . TABLE_ORDERS_PRODUCTS . " 
                                 where orders_id = '" . (int)$order_id . "'           
                                 order by orders_products_id");

Replace With:

$orders_products = $db->Execute("select orders_products_id, products_id, products_name, products_model, products_price, products_tax, products_quantity, final_price, onetime_charges, product_is_free, backorder, shipped  
                                 from " . TABLE_ORDERS_PRODUCTS . "
                                 where orders_id = '" . (int)$order_id . "'    
                                 order by orders_products_id");

Find:

$this->products[$index] = array('qty' => $new_qty, 
                                'id' => $orders_products->fields['products_id'],
                                'name' => $orders_products->fields['products_name'],
                                'model' => $orders_products->fields['products_model'],
                                'tax' => $orders_products->fields['products_tax'],
                                'price' => $orders_products->fields['products_price'],
                                'onetime_charges' => $orders_products->fields['onetime_charges'],
                                'final_price' => $orders_products->fields['final_price'],
                                'product_is_free' => $orders_products->fields['product_is_free']);

Replace With:

$this->products[$index] = array('qty' => $new_qty,
                                'id' => $orders_products->fields['products_id'],
                                'name' => $orders_products->fields['products_name'],
                                'model' => $orders_products->fields['products_model'],
                                'tax' => $orders_products->fields['products_tax'],
                                'price' => $orders_products->fields['products_price'],
                                'onetime_charges' => $orders_products->fields['onetime_charges'],
                                'final_price' => $orders_products->fields['final_price'],
                                'product_is_free' => $orders_products->fields['product_is_free'],
                                'backorder' => $orders_products->fields['backorder'],
                                'shipped' => $orders_products->fields['shipped']);

Step 7

Open /admin/invoice.php and find:

for ($i = 0, $n = sizeof($order->products); $i < $n; $i++) {

Add After (anywhere inside the for loop):

 if ($order->products[$i]['backorder'] == 1) {
   echo '<br /><nobr><small><strong>* Backordered *</strong></small></nobr>';
 } elseif ($order->products[$i]['shipped'] == 1) {
   echo '<br /><nobr><small><strong>* Previously Shipped *</strong></small></nobr>';
 }

Step 8

Repeat step 7 inside /admin/packingslip.php

Step 9

Open /includes/classes/order.php and find:

$this->notify('NOTIFY_ORDER_PROCESSING_STOCK_DECREMENT_END');

Add After:

// begin back-order modification
 $backorder = 0;
 if ($stock_left < 0 || $attribute_stock_left < 0) { // less then 0 because this is the quantity remaining after this order 
   $backorder = 1;
 }

Notice this edit also adds support for stock by attributes if you have that module installed.

Find:

zen_db_perform(TABLE_ORDERS_PRODUCTS, $sql_data_array);

Add Before:

$sql_data_array['backorder'] = $backorder;

Step 10

Go to ADMIN->CONFIGURATION->STOCK and set Allow Checkout to true.

Finished!

Now, when customers go to order a product that is out of stock, a message will display to the customer (you can change this message in your language definitions;  search for the text in ADMIN->TOOLS->DEVELOPER’S TOOLKIT) and they will still be able to order the product.  When your shipper goes to ship the order, they will already see the out of stock items have been marked as backordered (as per the edits to the order() class).  They can then ship the order and set the status of the individual products that were shipped to “Shipped” and set the entire order to “Backordered”.  When the items come into stock, the shipper can set the individual items that were previously backordered to “Shipped” and also set the entire order to “Shipped”.

Numinix is currently working on shipping modules that will rely on this type of backorder system to be in place in order to better manage shipments.  For example, our Endicia XML Exporter / Importer module is setup to only ship orders that do not have “Shipped” status and for orders that are “Backordered” it will skip any products that have been marked as “Shipped”.  Furthermore, the module will import any completed shipments back into Zen Cart and set the overall status of the order to “Shipped” if all products in the order have been shipped.

If I’ve missed any steps or made a mistake, please let me know right away and I’ll update this tutorial with the corrected information.  Otherwise, I hope this will help managing backorders a lot easier for your store!

18 thoughts on “How to Add Backorder Support to Your Zen Cart Store



  1. Getting an error with the code at step 4…. “Parse error: syntax error, unexpected T_VARIABLE, expecting T_CASE or T_DEFAULT or ‘}’ in /public_html/saffireblue/saffire_admin/edit_orders.php on line 81”

    Any advice?


  2. Pingback: Fedex Web Services

  3. Didn’t work for me on 1.3.9h. Didn’t break the site, but just didn’t set order status to Backordered when product quantity was 0 or less. Also took the tax out of the product price even though the tax rate was still there when editing the order.

    Ended up just using the Edit Order module and added an Order Status of Backordered and will just do it all manually.





  4. I added the SQL patches but could not complete the steps. I want to remove the SQL patches. Right now, my site is useless. If you can PLEASE email me as soon as possible and tell me how to remove those patches I would be VERY GRATEFUL.


    1. You can use this command:
      ALTER TABLE table_name DROP COLUMN column_name

      That would be:
      ALTER TABLE orders_products DROP COLUMN backorder;
      ALTER TABLE orders_products DROP COLUMN shipped;

      Removing these columns probably won’t have an effect on your site unless you have a script blindly creating rows in the orders_products table. For anyone else, it would be safe to leave these columns after undoing any file modifications.


  5. Thanks , it shows, but I tried to test order, there is not display or marked as Backordered inside the order page product detail . And the order status won’t change.

    Thank you for your advise.


  6. I am testing this with a new installation of 139g and did extactly your above step.
    I tested with a backorder order.

    and I click into the edit order , there has a new field for backorder / ship, but the drop down menu is empty (nothing to chooice. ) and there isn’t any backorder displayed in the order section.

    Best Regards.



  7. I am currently using Zen Cart 1.3.8a.

    Which part should be change? If this will work in 1.3.8a too?
    So the step 9 order.php is at inculdes and not admin/inculdes? Since such code isn’t exist in 138a.

    Sorry for bother, but I need this for a long time with no solution until I see this post



  8. Hi Developer,

    In step 9, I can’t find $this->notify(‘NOTIFY_ORDER_PROCESSING_STOCK_DECREMENT_END’);
    is that /includes/classes/order.php or admin/includes/classes/order.php?
    I could only found notify(‘NOTIFY_ORDER_PROCESSING_STOCK_DECREMENT_END’); at
    admin/includes/classes/order.php?

    Is the Edit Order module from
    http://www.zen-cart.com/index.php?main_page=product_contrib_info&products_id=444

    Also, if that could be possible to show (backorder notice on both customer and admin email in product detail) ?

    Please PM to my email if you have time, I am really happy to see something I look for long time and really want to get it done and work on my site.

    One more question, sorry for my Eng, is this modification will automatically put those out of stock item into Backordered status and let both customer and me to know which product is available and not?

    Best Regards

    Tim .




Leave a Reply

Your email address will not be published. Required fields are marked *

    Get quote Live
    Chat