Jump to content

Automated Order Status Module PS 1.7


Recommended Posts

Hi,

I've tried to make a module that automatically changed the status of new orders depending on payment method, stock levels and warehouses, but I've got to a point where there are no errors but the module is just no doing anything at all.

The module is triggered when new orders are placed. All products have to be in stock. Then depending on which payment method is chosen by the customer, the module will change the order status to a certain ID.

The only difficulty if set for orders paid by CC online, so there are 3 possible scenarios as we have Advanced Stock and various warehouses:
- All products of the order are on warehouse 1
- All products on warehouse 2
- The order contains products on various warehouses

So this is the code of the module:

<?php

if (!defined('_PS_VERSION_')) {
    exit;
}

class AutoStatusUpdate extends Module
{
    public function __construct()
    {
        $this->name = 'autostatusupdate';
        $this->tab = 'administration';
        $this->version = '1.0.0';
        $this->author = 'Me';
        $this->need_instance = 0;
        $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('Auto Status Update');
        $this->description = $this->l('Automatically update order status when conditions are met.');

        $this->confirmUninstall = $this->l('Are you sure you want to uninstall?');
    }

    public function install()
    {
        if (!parent::install() || !$this->registerHook('actionObjectOrderAddAfter')) {
            return false;
        }
        Configuration::updateValue('ASU_NEW_ORDER_STATE', 0);
        return true;
    }

    public function uninstall()
    {
        if (!parent::uninstall() || !Configuration::deleteByName('ASU_NEW_ORDER_STATE')) {
            return false;
        }
        return true;
    }

    public function getContent()
    {
        $output = null;

        if (Tools::isSubmit('submit' . $this->name)) {
            $new_order_state = (int)(Tools::getValue('ASU_NEW_ORDER_STATE'));
            Configuration::updateValue('ASU_NEW_ORDER_STATE', $new_order_state);
            $output .= $this->displayConfirmation($this->l('Settings updated'));
        }

        return $output . $this->renderForm();
    }

    public function renderForm()
    {
        $fields_form = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Settings'),
                ),
                'input' => array(
                    array(
                        'type' => 'select',
                        'label' => $this->l('New order status'),
                        'name' => 'ASU_NEW_ORDER_STATE',
                        'options' => array(
                            'query' => OrderState::getOrderStates((int)$this->context->language->id),
                            'id' => 'id_order_state',
                            'name' => 'name',
                        ),
                    ),
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                ),
            ),
        );

        $helper = new HelperForm();
        $helper->show_toolbar = false;
        $helper->table = $this->table;
        $helper->module = $this;
        $helper->default_form_language = (int)$this->context->language->id;
        $helper->allow_employee_form_lang = (int)$this->context->language->id;
        $helper->identifier = $this->identifier;
        $helper->submit_action = 'submit' . $this->name;
        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');

        $helper->tpl_vars = array(
            'fields_value' => $this->getConfigFieldsValues(),
            'languages' => $this->context->controller->getLanguages(),
            'id_language' => $this->context->language->id,
        );

        return $helper->generateForm(array(array('form' => $fields_form)));
    }

    public function getConfigFieldsValues()
    {
        return array(
            'ASU_NEW_ORDER_STATE' => (int)Tools::getValue('ASU_NEW_ORDER_STATE', Configuration::get('ASU_NEW_ORDER_STATE')),
        );
    }

    public function hookActionObjectOrderAddAfter($params)
    {
        $order = $params['object'];
        $new_order_status_id = (int)Configuration::get('ASU_NEW_ORDER_STATE');

        if ($new_order_status_id > 0) {
            $order_state = new OrderState($new_order_status_id, (int)$order->id_lang);

            if (Validate::isLoadedObject($order_state)) {
                $order->setCurrentState($new_order_status_id);
                $order->save();
            }
        }
    }
}

 

Link to comment
Share on other sites

2 hours ago, ventura said:

Try it implementing the logic in another hook, eg

actionOrderStatusUpdate

 

Thanks for answering, but that will trigger the logic whenever an order's status is updated, which will be a complete disaster in this case and can even create redundancies. For example, in my code what I want is:
- if all products in stock and customer wants payment by bankwire, then automatic payment instructions are sent with this order status change
- Same for COD method
- In the case of CC payments, it will put the order in preparation depending on (ASM) the warehouses of the products in the order:
   + All products on Warehouse A
   + All products on Warehouse B
   + Products on A & B

You may say, why not doing this directly from the payment modules? simple, because we allow pre-orders on products not available in stock, and for those cases we need to check first with suppliers before sending further instructions to customers or putting the order in preparation.

This is how I wrote this logic for the module:

public function hookActionObjectOrderAddAfter($params)
{
    // Retrieve the order and cart objects from the hook parameters
    $order = $params['object'];
    $cart = $params['cart'];
    // Get the payment method used for the order
    $payment_method = $order->module;

    // Get the stock manager instance to manage product stock
    $stock_manager = Adapter_ServiceLocator::get('Core_Business_Stock_StockManager');

    // Initialize warehouses array and a flag to track product availability
    $warehouses = array();
    $all_products_available = true;

    // Loop through all products in the cart
    foreach ($cart->getProducts() as $product) {
        $product_id = $product['id_product'];
        $product_attribute_id = $product['id_product_attribute'];

        // Get the list of warehouses containing the product
        $warehouse_stocks = Warehouse::getProductWarehouseList($product_id, $product_attribute_id, $this->context->shop->id);
        $product_stock = array();

        // Get the stock quantities available for the product in each warehouse
        foreach ($warehouse_stocks as $warehouse_stock) {
            $product_stock[$warehouse_stock['id_warehouse']] = StockAvailable::getQuantityAvailableByProduct($product_id, $product_attribute_id, $warehouse_stock['id_warehouse']);
        }

        // Find a warehouse that has enough stock to fulfill the order
        foreach ($product_stock as $warehouse_id => $quantity) {
            if ($quantity >= $product['cart_quantity']) {
                $warehouses[$product_id] = $warehouse_id;
                break;
            }
        }

        // If no suitable warehouse is found, set the flag to false and break the loop
        if (!isset($warehouses[$product_id])) {
            $all_products_available = false;
            break;
        }
    }

    // If all products are available, determine the new order status based on payment method and warehouse(s)
    if ($all_products_available) {
        $new_order_status_id = null;
        $unique_warehouses = count(array_unique($warehouses));

        // Set the new order status ID based on the payment method used
        if ($payment_method == 'cashondelivery') {
            $new_order_status_id = 2;
        } elseif ($payment_method == 'bankwire') {
            $new_order_status_id = 3;
        } elseif ($payment_method == 'cc') {
            if ($unique_warehouses == 1) {
                $first_warehouse = reset($warehouses);
                if ($first_warehouse == 1) {
                    $new_order_status_id = 5;
                } elseif ($first_warehouse == 2) {
                    $new_order_status_id = 6;
                }
            } else {
                $new_order_status_id = 7;
            }
        }

        // If a new order status ID is determined, update the order status and save the changes
        if ($new_order_status_id !== null) {
            $order_state = new OrderState($new_order_status_id, $order->id_lang);
            if (Validate::isLoadedObject($order_state)) {
                $order->setCurrentState($new_order_status_id);
                $order->save();

                // Create a new order history object, update the order status, and send an email notification
                $history = new OrderHistory();
                $history->id_order = (int) $order->id;
                $history->id_employee = (int) $this->context->employee->id;
                $history->changeIdOrderState
            ((int) $new_order_status_id, $order, true);
            // Add the new order status to the order's history and send an email notification to the customer
            $history->addWithemail(true);
        }
    }
}

 

Link to comment
Share on other sites

  • 8 months later...
On 3/26/2023 at 3:19 PM, Eutanasio said:

Thanks for answering, but that will trigger the logic whenever an order's status is updated, which will be a complete disaster in this case and can even create redundancies. For example, in my code what I want is:
- if all products in stock and customer wants payment by bankwire, then automatic payment instructions are sent with this order status change
- Same for COD method
- In the case of CC payments, it will put the order in preparation depending on (ASM) the warehouses of the products in the order:
   + All products on Warehouse A
   + All products on Warehouse B
   + Products on A & B

You may say, why not doing this directly from the payment modules? simple, because we allow pre-orders on products not available in stock, and for those cases we need to check first with suppliers before sending further instructions to customers or putting the order in preparation.

This is how I wrote this logic for the module:

public function hookActionObjectOrderAddAfter($params)
{
    // Retrieve the order and cart objects from the hook parameters
    $order = $params['object'];
    $cart = $params['cart'];
    // Get the payment method used for the order
    $payment_method = $order->module;

    // Get the stock manager instance to manage product stock
    $stock_manager = Adapter_ServiceLocator::get('Core_Business_Stock_StockManager');

    // Initialize warehouses array and a flag to track product availability
    $warehouses = array();
    $all_products_available = true;

    // Loop through all products in the cart
    foreach ($cart->getProducts() as $product) {
        $product_id = $product['id_product'];
        $product_attribute_id = $product['id_product_attribute'];

        // Get the list of warehouses containing the product
        $warehouse_stocks = Warehouse::getProductWarehouseList($product_id, $product_attribute_id, $this->context->shop->id);
        $product_stock = array();

        // Get the stock quantities available for the product in each warehouse
        foreach ($warehouse_stocks as $warehouse_stock) {
            $product_stock[$warehouse_stock['id_warehouse']] = StockAvailable::getQuantityAvailableByProduct($product_id, $product_attribute_id, $warehouse_stock['id_warehouse']);
        }

        // Find a warehouse that has enough stock to fulfill the order
        foreach ($product_stock as $warehouse_id => $quantity) {
            if ($quantity >= $product['cart_quantity']) {
                $warehouses[$product_id] = $warehouse_id;
                break;
            }
        }

        // If no suitable warehouse is found, set the flag to false and break the loop
        if (!isset($warehouses[$product_id])) {
            $all_products_available = false;
            break;
        }
    }

    // If all products are available, determine the new order status based on payment method and warehouse(s)
    if ($all_products_available) {
        $new_order_status_id = null;
        $unique_warehouses = count(array_unique($warehouses));

        // Set the new order status ID based on the payment method used
        if ($payment_method == 'cashondelivery') {
            $new_order_status_id = 2;
        } elseif ($payment_method == 'bankwire') {
            $new_order_status_id = 3;
        } elseif ($payment_method == 'cc') {
            if ($unique_warehouses == 1) {
                $first_warehouse = reset($warehouses);
                if ($first_warehouse == 1) {
                    $new_order_status_id = 5;
                } elseif ($first_warehouse == 2) {
                    $new_order_status_id = 6;
                }
            } else {
                $new_order_status_id = 7;
            }
        }

        // If a new order status ID is determined, update the order status and save the changes
        if ($new_order_status_id !== null) {
            $order_state = new OrderState($new_order_status_id, $order->id_lang);
            if (Validate::isLoadedObject($order_state)) {
                $order->setCurrentState($new_order_status_id);
                $order->save();

                // Create a new order history object, update the order status, and send an email notification
                $history = new OrderHistory();
                $history->id_order = (int) $order->id;
                $history->id_employee = (int) $this->context->employee->id;
                $history->changeIdOrderState
            ((int) $new_order_status_id, $order, true);
            // Add the new order status to the order's history and send an email notification to the customer
            $history->addWithemail(true);
        }
    }
}

 

Hey is there a way You to edit the module and make a module that will send email if specific product is bought that is set in module?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...