Skip to content
Snippets Groups Projects
Observer.php 7.47 KiB
<?php

/**
 * Open Tools Ordernumber module for Magento
 *
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * @category   OpenTools
 * @package    Ordernumber
 * @copyright  Copyright (c) 2010 Fooman Limited (http://www.fooman.co.nz)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */
class OpenTools_Ordernumber_Model_Observer extends Mage_Core_Model_Abstract
{
    protected $_dbModel = null;
    protected function _getModel()
    {
        return Mage::getModel('opentools_ordernumber/ordernumber');
    }

    public function getModel()
    {
        if (is_null($this->_dbModel))
            $this->_dbModel = $this->_getModel();
        return $this->_dbModel;
    }

    public function _construct()
    {
        parent::_construct();
        $this->_init('ordernumber/ordernumber');
    }

    /** This trigger is called directly after the increment ID is reserved for an order
     * Ideally, we would overwrite the reserveOrderId function, so that magento does not
     * create/reserve an order number in the first place
     * Problem is, no order information is passed to the increment id model,
     * so we would have to hack (i.e. rewrite) many more models to pass on this information,
     * which will in the end lead to an even worse code quality...
     */
    public function sales_model_service_quote_submit_before ($observer)
    {
        $order = $observer->getEvent()->getOrder();
        return $this->handle_new_number('order', $order, $order);
    }
    public function sales_order_save_before ($observer)
    {
        $order = $observer->getEvent()->getOrder();
        return $this->handle_new_number('order', $order, $order);
    }

    public function sales_order_invoice_save_before ($observer)
    {
        $invoice = $observer->getEvent()->getInvoice();
        return $this->handle_new_number('invoice', $invoice, $invoice->getOrder());
    }

    public function sales_order_shipment_save_before ($observer)
    {
        $shipment = $observer->getEvent()->getShipment();
        return $this->handle_new_number('shipment', $shipment, $shipment->getOrder());
    }

    public function sales_order_creditmemo_save_before ($observer)
    {
        $creditmemo = $observer->getEvent()->getCreditmemo();
        return $this->handle_new_number('creditmemo', $creditmemo, $creditmemo->getOrder());
    }

    public function handle_new_number ($nrtype, $object, $order)
    {
        $store = $order->getStore();
        $storeId = $store->getStoreId();
        $cfgprefix = 'ordernumber/'.$nrtype.'numbers';
        $enabled = Mage::getStoreConfig($cfgprefix.'/active', $storeId);

        if ($enabled && !$object->getId() && !$object->getOrdernumberProcessed()) {
            // This trigger might be called twice, so ignore it the second time!
            $object->setOrdernumberProcessed(true);

            $format = Mage::getStoreConfig($cfgprefix.'/format', $storeId);
            $scope = Mage::getStoreConfig($cfgprefix.'/scope', $storeId);
            $reset = Mage::getStoreConfig($cfgprefix.'/reset', $storeId);
            $counterfmt = Mage::getStoreConfig($cfgprefix.'/resetformat', $storeId);
            $digits = Mage::getStoreConfig($cfgprefix.'/digits', $storeId);
            $increment = Mage::getStoreConfig($cfgprefix.'/increment', $storeId);

            // First, replace all variables:
            $helper = Mage::helper('ordernumber');
            $info = array('order'=>$order, $nrtype=>$object);

            // The ordernumber/...numbers/reset contains some pre-defined counter names as
            // well as enum values indicating certain behavior. Replace those by the actual
            // counter names for the current counter:
            if (is_string($reset)) {
                $format = $format . '|' . $reset;
            } else {
                switch ($reset) {
                    case 0:
                        $format = $format . '|';
                        break;
                    case 1:
                        $format = $format . '|' . $format;
                        break;
                    case -1:
                        $format = $format . '|' . $counterfmt;
                        break;
                    default:
                        /* Pre-defined counter formats saved in the /reset config field */
                        $format = $format . '|' . $reset;
                        break;
                }
            }
            $customvars = Mage::getStoreConfig('ordernumber/replacements', $storeId);
            if (isset($customvars['replacements'])) {
                $customvars = $customvars['replacements'];
            }
            if ($customvars) {
                $customvars = unserialize($customvars);
            } else {
                $customvars = array();
            }
// Mage::Log('customvars: '.print_r($customvars,1), null, 'ordernumber.log');

            // Now apply the replacements
            $nr = $helper->replace_fields ($format, $nrtype, $info, $customvars);

            // Split at a | to get the number format and a possibly different counter increment format
            // If a separate counter format is given after the |, use it, otherwise reuse the number format itself as counter format
            $parts = explode ("|", $nr);
            $format = $parts[0];
            $counterfmt = $parts[(count($parts)>1)?1:0];

            // Now find the next counter that does not lead to duplicate
            $newnumber = null;
            $model = $this->getModel();

            $count = 0;
            $created = false;
            // Make up to 150 attempts to create a number...
            while (empty($newnumber) && ($count<150)) {
                $count += 1;

                // Find the next counter value
                $scopeId = '';
                if ($scope>=1) $scopeId = $store->getWebsiteId();
                if ($scope>=2) $scopeId .= '/' . $store->getGroupId();
                if ($scope>=3) $scopeId .= '/' . $store->getStoreId();
                $count = $model->getCounterValueIncremented($nrtype, $counterfmt, $increment, $scopeId);
                $newnumber = str_replace ("#", sprintf('%0' . (int)$digits . 's', $count), $format);

                // Check whether that number is already in use. If so, attempt to create the next number:
                $modelname=($nrtype=='order') ? 'sales/order' : ('sales/order_'.$nrtype);
                $collection = Mage::getModel($modelname)->getCollection()->addFieldToFilter('increment_id', $newnumber);
                if ($collection->getAllIds()) {
                    Mage::Log("$nrtype number $newnumber already in use, trying again", null, 'ordernumber.log');
                    //number already exists => next attempt in the loop
                    $newnumber = null;
                } else {
                    $object->setIncrementId($newnumber);
                    $created = true;
                }
            }
            if (!$created) {
                Mage::Log("Unable to create $nrtype number for counter format $nr (name $counterfmt, scope $scopeId)...", null, 'ordernumber.log');
            }
        }
    }

}