0

Every 30min I want to export all NEW orders, I don't want to re-export orders I've already done.

Later I'm going to access these files to import into a third party program through FTP automatically.

Here is the code that I have so far. app/code/local/Sean/NavisionExport/etc/config.xml

<config>
    <global>
        <models>
            <seannavisionexport>
                <class>Sean_NavisionExport_Model</class>
            </seannavisionexport>
        </models>
    </global>
    <crontab>
        <jobs>
            <seannavisionexport>
                <name>Export orders every 30 minutes</name>
                <short_description>Orders</short_description>
                <description>Runs every 30 minutes to export orders</description>
                <schedule>
                    <cron_expr>0 * * * *</cron_expr>
                </schedule>
                <run>
                    <model>seannavisionexport/observer::runOrdersExport</model>
                </run>
            </seannavisionexport>
        </jobs>
    </crontab>
</config>

app/code/local/Sean/NavisionExport/Model/Observer.php

<?php

class Sean_NavisionExport_Model_Observer {

    public function runOrdersExport(Varien_Event_Observer $observer) {

    //How should I do this here?

    }

}

2 Answers 2

1

The easiest solution, that doesn't require adding an attribute to orders, would be saving the last exported order id in core_config_data.

Firstly, create a new default config value that contains the order id you want to start at:

<config>
    <global>
        <models>
            <seannavisionexport>
                <class>Sean_NavisionExport_Model</class>
            </seannavisionexport>
        </models>
    </global>
    <crontab>
        <jobs>
            <seannavisionexport>
                <name>Export orders every 30 minutes</name>
                <short_description>Orders</short_description>
                <description>Runs every 30 minutes to export orders</description>
                <schedule>
                    <cron_expr>*/30 * * * *</cron_expr>
                </schedule>
                <run>
                    <model>seannavisionexport/cron::runOrdersExport</model>
                </run>
            </seannavisionexport>
        </jobs>
    </crontab>
    <default>
        <seannavisionexport>
            <order_export>
                <last_exported_id>1</last_exported_id>
            </order_export>
        </seannavisionexport>
    <default>
</config>

Next, update your observer to read the config value, use it to filter the collection and then save the config so it holds the last processed id:

<?php
class Sean_NavisionExport_Model_Cron {
    const XML_PATH_ORDER_EXPORT_LAST_ID = 'seannavisionexport/order_export/last_exported_id';

    public function runOrdersExport() {
        $lastExportedId = Mage::getStoreConfig(self::XML_PATH_ORDER_EXPORT_LAST_ID);
        $collection     = Mage::getResourceModel('sales/order_collection')
                              ->addFieldToFilter('entity_id', array('gt' => $lastExportedId));

        //Do any required export logic

        //Save the last exported id from the loaded collection
        Mage::app()->getConfig()->saveConfig(self::XML_PATH_ORDER_EXPORT_LAST_ID, $collection->getLastItem()->getId());
    }
}
5
  • The export logic is sort of what I'm most afraid of, because it may contain sensitive information I can't put it in a media folder for example right? Is there a place where I can just safely place these export files? Commented Feb 8, 2017 at 1:35
  • Hmm actually there is a var/export directory I suppose I could just put it in there since manual exports I've done have automatically gone in there Commented Feb 8, 2017 at 1:39
  • You should be writing the files to a directory that isn't accessible from the browser. The ideal place would in var/export. You could also make further subdirectories within that to separate different types of exports ex. var/export/orders /var/export/products etc. Commented Feb 8, 2017 at 1:39
  • Awesome thanks thats what I thought Andrew, I'll try out this solution later tonight and if it works I'll make sure to mark your answer! i'll upvote for now though :) Commented Feb 8, 2017 at 1:42
  • Last thing how do I keep the collection in such a way that when I move it to var/exportNavision it stays as a CSV? Commented Feb 8, 2017 at 1:48
1

A couple of things about your code:

  1. Your cron expression would not yield a 30-minute interval
  2. Your responding job method runOrdersExport uses a wrong argument type

You appear to be mixing event observers with cron jobs. By convention, cron job class names would suggest that you write your class like this:

<?php

class Sean_NavisionExport_Model_Cron {

    public function runOrdersExport(Mage_Cron_Model_Schedule $schedule);

}

And so your model declared in config.xml would change to seannavisionexport/cron::runOrdersExport.

Now we can get to your question:

How do I export new orders every X interval since the last run?

The answer requires storage of a positioning marker. I have seen this solved in either of the following ways:

  1. You add an attribute to the order table to track export status
  2. You track the last export order ID somewhere in the database

The first path gives you a finer degree of control per-order when working out the logic to determine export candidacy. The second path is much simpler, and more simply answers your question. That said, I'll only give you an answer for the latter path. You can Google option 1 if interested.

Tracking Last Export ID

The most convenient way to do this is to leverage Magento system configuration; eg:

// Set data
Mage::app()->getConfig()
    ->saveConfig('sales/general/last_navision_export_id', $lastOrderId);

// Get data
$lastOrderId = Mage::getStoreConfig('sales/general/last_navision_export_id');

That is going to be the fastest way to setup a storage mechanism. But it does come with a minor drawback: system configuration is cached. Therefore Mage::getStoreConfig becomes problematic for you unless config cache is disabled or cleared before each export run. There is another way around it, though.

So let me fill in your export method with the final answer and you should be able to make sense of it all:

<?php

class Sean_NavisionExport_Model_Cron {

    const XML_CONFIG_PATH_LAST_EXPORT_ID = 'sales/general/last_navision_export_id';

    private function _getLastOrderId()
    {
        $resource   = Mage::getSingleton('core/resource');
        $adapter    = $resource->getConnection('core_read');
        $select     = $adapter->select()
            ->from($resource->getTableName('core/config_data'), array('value'))
            ->where('path = ?', self::XML_CONFIG_PATH_LAST_EXPORT_ID);

        return (int) $adapter->fetchOne($select);
    }

    public function runOrdersExport(Mage_Cron_Model_Schedule $schedule)
    {
        try {
            $lastOrderId    = $this->_getLastOrderId();
            $orders         = Mage::getResourceModel('sales/order_collection')
                ->setPageSize(100) // Optionally limit the batch, could pull from config value also
                ->setCurPage(1)
                ->setOrder('entity_id', 'ASC');

            if ($lastOrderId) {
                $orders->addFieldToFilter('entity_id', array('gt' => $lastOrderId));
            }

            foreach ($orders as $order) {
                $data           = $order->toJson(); // Just a sample, you need to figure out the export format
                $lastOrderId    = $order->getId();
            }

            Mage::app()->getConfig()
                ->saveConfig(self::XML_CONFIG_PATH_LAST_EXPORT_ID, $lastOrderId);
        } catch (Exception $error) {
            // Error handling, might want to reset last ID config value
        }
    }

}

Some closing thoughts on this:

  • The method _getLastOrderId bypasses system config cache to read straight from the database.
  • The config path sales/general/last_navision_export_id is arbitrary and will work right away without additional code. But I will also tell you that you can declare this config value as a real field in your module's system.xml, so that it can be updated by the end-user in the admin panel for debugging purposes.
  • Notice the use of Mage::getResourceModel -> this is the preferred way to access a collection of records.
  • I gave you some hints at limiting the export batch size. System configuration is also a good way to control this value if it needs to be managed.
  • All models in Magento implement a toJson method. There are also toArray, getData, and magic getters available.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.