Mass update stock levels in Magento – FAST

This isn’t ground-breaking code, but rather just using some core code in a rather stripped out manner. As we’re not big fans of Magento data flow here, we perform most of our stock and catalogue updates using external scripts to Mage::app. We have been trickling elements of these out to the wider world so you can also benefit from them.

Managing large catalogues and updating stock levels regularly can be mission impossible in Magento, but not any more. With this script – we processed 120,000 stock updates in the blink of an eye. Next time we’ll teach you how to import products at 0.7 seconds each …

  • 1

    Create a CSV with a minimum of 2 columns, the SKU and any of the following,

    qty
    min_qty
    use_config_min_qty
    is_qty_decimal
    backorders
    use_config_backorders
    min_sale_qty
    use_config_min_sale_qty
    max_sale_qty
    use_config_max_sale_qty
    is_in_stock
    use_config_notify_stock_qty
    manage_stock
    use_config_manage_stock
    stock_status_changed_automatically
    type_id

    Then save it to ./app/var/import/updateStockLevels.csv. For examples sake, we will use,

    "sku","qty"
    "prod1","11"
  • 2

    Copy the code below into a new file, ./quick_updateStock.php

    <?
     
     define('MAGENTO', realpath(dirname(__FILE__)));
     require_once MAGENTO . '/app/Mage.php';
     
     umask(0);
     Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
     $count = 0;
     
     $file = fopen(MAGENTO . '/var/import/updateStockLevels.csv', 'r');
     while (($line = fgetcsv($file)) !== FALSE) {
     
     if ($count == 0) {
     foreach ($line as $key=>$value) {
     $cols[$value] = $key;
     }
     }
     
     $count++;
     
     if ($count == 1) continue;
     
     #Convert the lines to cols
     if ($count > 0) {
     foreach($cols as $col=>$value) {
     unset(${$col});
     ${$col} = $line[$value];
     }
     }
     
     // Check if SKU exists
     $product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
     
     if ( $product ) {
     
     $productId = $product->getId();
     $stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);
     $stockItemId = $stockItem->getId();
     $stock = array();
     
     if (!$stockItemId) {
     $stockItem->setData('product_id', $product->getId());
     $stockItem->setData('stock_id', 1);
     } else {
     $stock = $stockItem->getData();
     }
     
     foreach($cols as $col=>$value) {
     $stock[$col] = $line[$value];
     }
     
     foreach($stock as $field => $value) {
     $stockItem->setData($field, $value?$value:0);
     }
     
     
     
     $stockItem->save();
     
     unset($stockItem);
     unset($product);
     }
     
     echo "<br />Stock updated $sku";
     
     }
     fclose($file);
     
    ?>
  • 3

    Visit the file above in your browser, or via command line. It runs very quickly (approx 0.03 seconds per product), so don’t be too surprised if its over quickly!
This entry was posted in Magento and tagged , , , , , , . Bookmark the permalink.

88 Responses to Mass update stock levels in Magento – FAST

  1. Great script – If you want to update prices or any other atribute for that matter change
    $stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);

    to

    $stockItem = Mage::getSingleton("catalog/Product")->load($productId);

    It’s slower, but does the trick :)

    Reply



    • Jason

      Pete, do you see the behavior of the product special price etc getting corrupted if they are not explicitly set using
      $stockItem = Mage::getSingleton(“catalog/Product”)->load($productId);

      Reply


      • I had this issue. Special prices were set to zero after modifying the script this way.

        Reply


    • I am not sure why you would do this anyway, as you can set other data utilising the $product object and you don’t slow the script down any. (or am I missing something?)
      For example, change the product name:
      $product->setName("new product name");
      You do, of course, have to also save the $product object with:
      $product->save();
      Works for me.

      Reply


      • We’re all aware of this, but we are not setting product data – we are setting product STOCK levels – its a different model.

        On a sidenote, loading and saving the product model has significant overheads – so whilst convenient and quick to code – its by far the slowest method to modify product attributes.

        Reply



  2. Kevin Giles

    Please could someone post an actual piece of XML which shows the layout for updating a single product stock qty. Not everyone uses PHP!
    I have this much but don’t understand the sub-format for defining that I want to update qty field. Perhaps I have missed this in the magento on-line docs.
    I want to test the XML in SOAPUI.exe .
    Thanks.
    Kevin

    Reply


    • This method intentionally doesn’t use Data Flow (which I am assuming you are referring to when talking about XML upload profiles) or Web Services. Data Flow is SLOW, hence the use of this script. If you are looking to change status by web services, look here http://www.magentocommerce.com/wiki/doc/webservices-api/introduction

      It can be tweaked to use XML instead of CSV, its not really a large amount of work, get in touch if you are interested.

      Reply



  3. Kevin Giles

    Sorry – when I said “This much” I meant:-

    d0c88544d5b3f8e76172656591dabb05
    cataloginventory_stock_item.update

    product_id
    164

    plus the normal header stuff.

    Reply



  4. Giuseppe Barbiero

    Hi guis and thanks for nice snippet

    this idea is very clear congratulations

    I have an only problem. Calling directly the file like you say to execute it I cannot bypass the magento router , so the file is not found

    I come from joomla where this problem doesn’t exit. May you help me on how to call this file directly if it’s saved inside same Magento Folder?

    thanks

    Reply


  5. Hi I am an outcoming virtuemart user who want to pass to magento cart
    I am testing your snippet, and many many thanks for your effort, this is a nice functionality
    If I am right, the script to update stock should be placed in the same root folder of Magento.

    I am trying it on the 1.5.0 version and the result is it loops many many times until the max execution time is reached, and then it stops.

    The csv is made of one line only to test.

    Do you know why it may fails? I need thie feature so much (everyone I think they need ) as modiftying stock in magento is really tedious

    Thanks

    Reply


  6. Ok I found the error of the loop

    I put csv file inside app/var/import, but this is not correct, i should have put it inside the var folder

    Thanks and sorry to bother

    Reply



  7. Rachita

    Other than our agency updating the usual stuff on a Magento, can I update them at the back-end for some urgencies too?

    How much time does it take for an updation to reflect on the website – i. instant ii. is it time-consuming

    Reply


  8. Awesome script. As I look at this, I think that Magento’s API should be abandoned in favor of short scripts such as this. I take it this is your experience? I’m asking as I am new to Magento (not programming) and it is incredible how slow the API is!

    Reply


  9. This is the best solution by far if you also want to update is_in_stock so that out of stock items don’t appear on your site. It’s also very fast. Thanks

    Reply



  10. pepper

    I have the same problem with Tim Thurlow. The script updates quantities but not the “is_in_stock” parameter. That way the products are always available, even if the stock quantity is set to 0.

    Reply


  11. I’ve found that SOAP calls and Mage.php calls are noticeably slower than direct database updates. The downside, is that doing direct database updates also require an API-based re-index at the end. I usually just throw this in to the function destruct to re-index at the end.
    The database takes a little while to reverse engineer, but there are some capable tools out there.

    Reply


    • We do a lot of direct DB queries for stock/product import etc., the overheads of using the native models are sometimes too much for big/frequent jobs.

      Reply


  12. Nope not working for me any help here, someone I can contact?
    Would be brilliant to get this working as we have a lot of skus at the moment and its taking about 8 hours yet we have far fewer then your quoted 120k

    Reply


    • Sure you can, go to the contact page.

      Just remember, speed will be platform dependant, run it on a slow/poorly set up server – and it will be slow.

      Reply


  13. Does the CSV file need to have quotation marks for each field?

    Reply


  14. Don’t worry got it to work with a couple of tweaks
    Thanks

    Reply


  15. Brilliant, exactly what I needed. Thanks !!!

    Reply



  16. André

    Hi, i have been using this with no problems, and its very very useful.

    Now that we have more than 6000 products to update, the server is timing out the function. Can i split the update into two functions until i do not find a better server? Can someone help me wiht that? Thank you.

    Reply


    • 6,000 products shouldn’t be an issue at all.

      Your time-outs are because your server hasn’t been set up properly for Magento – get in touch with our team at http://www.sonassihosting.com for truly optimised Magento dedicated servers.

      Reply



      • Bishar

        Great script! Just one request, can someone help me map the columns to different headings please? For eg. ‘sku’ = “Product Code”

        Reply


  17. Hi thanks for the script.

    I have a quick question. On my magento test server (shared hosting). This script runs very quick. On my live VPS however it crawls. At it’s current rate it would of imported about a thousand records in an hour.

    From debugging your code; it seems the slow down on my live server is caused by this line -> $stockItem->save(); Taking this out and the script runs fine.

    Any ideas why this would cause such a slow down issue on the VPS?

    Many Thanks,
    Marcus

    Reply


    • Its not much of a surprise. A VPS is a less than ideal environment for running Magento – you’re trying to run all your services in a tiny set up (mysql/dns/web/email), whereas with shared, although contended, you’re likely to have more in the way of “burstable” resources.

      Our shared hosting (www.sonassihosting.com), would outperform any VPS of similar price by quite a margin.

      Reply


      • Thanks for the info. I will certainly bear you in mind once the hosting runs out for this year.

        I think, in this case it might be down to Google Shopping though. It saves to the database locally and then uses the Google Shopping API to update prices there.

        Also if I used the price update line
        :
        $stockItem = Mage::getSingleton(“catalog/Product”)->load($productId);

        My price updates, but the categories my products are in get jumbled up. Not good on 2000 products :) Any ideas why?

        I am using Magneto 1.5.0.1

        Reply


  18. After you run this script do you need to reindex the data, I have been experimenting with using MAGMI for stock updates but we have a very large catalog (up to 800K items) and a few people are saying reindexing after an update will take substantially longer than the update itself.

    Reply


  19. It’s good to check that the script actually finds the stock file you feed it (if you put one in a different place as I did) so you can do this with an initial check, otherwise every value is NULL and nothing of course works :->

    $stockFile = ‘/home/inbox/updateStockLevels.csv’;
    if (($file = fopen($stockFile, ‘r’)) !== FALSE) {
    … rest of the code …
    }

    Reply


  20. Great script!, I have tested in my website and it works like a charm, I have a question, I get XML feed of all active products only , which I will convert to csv and store in var/import folder, as the daily feed contains only active products i need to update all products qty=0 and is_in_stock=0 before running the script.

    direct query to DB will do ?
    update cataloginventory_stock_item set qty=0, is_in_stock=0

    any help is appreciated

    Thank you

    Reply


  21. Anyone have luck running this with v 1.6.1.0? I had it running perfect on 1.5.1, when I upgraded to 1.6.1.0 it will run but doesnt update the stock.

    Reply


  22. WELL DONE PEOPLE!!!!!!! thank you so so so so much for this! it’s great, i have an website with over 20k products and with the standard magento import tools it took me over 12 hours to update the stock and price, but with this…when the updating day is coming there are no worries :) . THANK YOU!

    Reply



  23. M van Dongen

    Lifesaver

    Reply


  24. Well done! Integrated this code into my code that generates the stock outputfile from another back-office system. Much faster than the regular import capabilties of Magento.

    Reply


  25. One question? Why not read the total file in memory and then do the update? Should increase the performance a bit more with al lot of products. Now lines are read and processed one by one….

    Reply



  26. drooped

    hi
    when im using this script for my price update all of empty field are changed to “0″
    can you help me for this?????
    tnx

    Reply


  27. Does anyone know how to map the sku and qty to different headings within the csv since the stock update file comes from a third party each morning? Thanks!

    Reply


  28. It doesn’t work for me in my store using magento 1.6.1 .

    ;(

    Reply


  29. Hello,
    I’ve try this and it works perfect for a while, but now I receive Fatal error: Maximum execution time of 30 seconds exceeded in…The hosting provider says that they didn’t change anything, I didn’t change anything, but the script does not work anymore (only 800 SKU’s at a time) Can you please help?

    Thank you,

    Reply


    • If it was working, and now its not – it’ll be your host :)

      Try switching to a Magento hosting provider … we are taking on new customers at the moment starting at £30 per month.

      Reply


Leave a Reply

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

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">