Exclude one specific payment gateway from auto-restock in WooCommerce

寵の児 提交于 2019-12-11 10:35:27

问题


One of my payment getaway is ipay88 which only reduce stock after payment is cleared.

During the time when customer is making the payment, the order is under "pending payment" which the stock does not reduce. However, when customer does not make the payment in time, the order will automatically be marked as "cancelled".

As I have integrated with auto-restock plugin, "pending payment" to "cancelled" will increase the stock.

I would like to ask how do prevent restock for a specific payment getaway which is ipay88.

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

if ( ! class_exists( 'WC_Auto_Stock_Restore' ) ) {

class WC_Auto_Stock_Restore {

    public function __construct() {
    add_action( 'woocommerce_order_status_processing_to_cancelled', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_on-hold_to_cancelled', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_pending_to_cancelled', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_completed_to_cancelled', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_processing_to_refunded', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_completed_to_refunded', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_on-hold_to_refunded', array( $this, 'restore_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_cancelled_to_completed', array( $this, 'remove_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_cancelled_to_processing', array( $this, 'remove_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_cancelled_to_on-hold', array( $this, 'remove_order_stock' ), 10, 1 );
        add_action( 'woocommerce_order_status_cancelled_to_pending', array( $this, 'remove_order_stock' ), 10, 1 );
        //add_action( 'woocommerce_order_status_changed', array( $this, 'adjust_order_stock' ), 10, 3 );
    } // End __construct()

    //public function adjust_order_stock( $order_id, $old_status, $new_status ) {
        //$valid_new_statuses = array( 'complete' );
        //if ( $old_status == cancelled AND $new_status )
    //}

    public function remove_order_stock( $order_id ) {
        $order = new WC_Order( $order_id );

        if ( ! get_option('woocommerce_manage_stock') == 'yes' && ! sizeof( $order->get_items() ) > 0 ) {
            return;
        }

        foreach ( $order->get_items() as $item ) {

            if ( $item['product_id'] > 0 ) {
                $_product = $order->get_product_from_item( $item );

                if ( $_product && $_product->exists() && $_product->managing_stock() ) {
                    $old_stock = $_product->stock;

                    $qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $this, $item );

                    $new_quantity = $_product->reduce_stock( $qty );

                    do_action( 'woocommerce_auto_stock_restored', $_product, $item );

                    $order->add_order_note( sprintf( __( 'Item #%s stock decremented from %s to %s.', 'woocommerce' ), $item['product_id'], $old_stock, $new_quantity) );

                    $order->send_stock_notifications( $_product, $new_quantity, $item['qty'] );
                }
            }
        }
    }

    public function restore_order_stock( $order_id ) {
        $order = new WC_Order( $order_id );

        if ( ! get_option('woocommerce_manage_stock') == 'yes' && ! sizeof( $order->get_items() ) > 0 ) {
            return;
        }

        foreach ( $order->get_items() as $item ) {

            if ( $item['product_id'] > 0 ) {
                $_product = $order->get_product_from_item( $item );

                if ( $_product && $_product->exists() && $_product->managing_stock() ) {
                    $old_stock = $_product->stock;

                    $qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $this, $item );

                    $new_quantity = $_product->increase_stock( $qty );

                    do_action( 'woocommerce_auto_stock_restored', $_product, $item );

                    $order->add_order_note( sprintf( __( 'Item #%s stock incremented from %s to %s.', 'woocommerce' ), $item['product_id'], $old_stock, $new_quantity) );

                    $order->send_stock_notifications( $_product, $new_quantity, $item['qty'] );
                }
            }
        }
    } // End restore_order_stock()
}
$GLOBALS['wc_auto_stock_restore'] = new WC_Auto_Stock_Restore();
}

回答1:


Updated, tested and fully functional for Woocommerce versions 3+

Your code is really obsolete since WooCommerce version 3. So I have revisited all the code…

Also instead using multiple hooks for each kind of status change, you can replace all the hooks by a unique one: woocommerce_order_status_changed

Finally with that unique hook, you will need a unique function, where it will be possible to exclude easily your 'ipay88' payment gateway ID when order status is changed from 'pending' to 'cancelled'.

For the generated order note, It's better to get a unique order note when there is multiple items in the order…

So the complete code for this plugin is:

## ---- for WooCommerce versions 3+ - Plugin code version ---- ##

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

if ( ! class_exists( 'WC_Auto_Stock_Restore' ) ) {

    class WC_Auto_Stock_Restore {

        public function __construct() {
            add_action( 'woocommerce_order_status_changed', array( $this, 'adjust_order_stock' ), 10, 3 );
        }

        public function adjust_order_stock( $order_id, $old_status, $new_status ) {
            $order = new WC_Order( $order_id );
            $items = $order->get_items();

            if ( ! get_option('woocommerce_manage_stock') == 'yes' && ! count( $items ) > 0 )
                return; // We exit

            // EXCEPTION for 'ipay88' payment method id, when Order status change from 'pending' to 'cancelled'
            if( $order->get_payment_method() == 'ipay88' && $old_status == 'pending' && $new_status == 'cancelled' )
                return; // We exit

            // We don't need from 'pending' to 'refunded' order status
            if( $old_status == 'pending' && $new_status == 'refunded' )
                return; // We exit

            // Group Order statuses in 2 groups (array)
            $statuses_group1 = array( 'processing', 'on-hold', 'pending', 'completed' );
            $statuses_group2 = array( 'cancelled', 'refunded' );

            $change_stock = false;
            $order_note = array();

            ## 1. Restore Order stock (7 order status change types)
            if ( in_array( $old_status, $statuses_group1 ) && in_array( $new_status, $statuses_group2 ) ) {
                $change_stock = true;
                $change_type = 'increase';
                $change_text =  __( 'incremented', 'woocommerce' );
            }
            ## 2. Restore Order stock (4 order status change types)
            elseif ( $old_status == 'cancelled' && in_array( $new_status, $statuses_group1 ) ) {
                $change_stock = true;
                $change_type = 'decrease';
                $change_text =  __( 'decremented', 'woocommerce' );
            }
            ## 3. Other cases
            else return; // We exit

            if( $change_stock ){
                // Iterating through each order 'line_item'
                // Since WC 3, $item is a WC_Order_Item_Product object
                foreach ( $items as $item ) {
                    $product_id = $item->get_product_id(); // The product ID
                    if ( $product_id > 0 ) {
                         // Get tan instance of the WC_Product object
                        $product = $item->get_product();
                        if ( $product && $product->exists() && $product->managing_stock() ) {

                            // Get the product initial stock quantity (before update)
                            $initial_stock = $product->get_stock_quantity();

                            $item_qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $this, $item );

                            // Update the product stock quantity
                            // Replace DEPRECATED methods: increase_stock() & discrease_stock()
                            wc_update_product_stock( $product, $item_qty, $change_type );

                            // Get the product updated stock quantity
                            $updated_stock = ( $change_type == 'increase' ) ? $initial_stock + $item_qty : $initial_stock - $item_qty;

                            do_action( 'woocommerce_auto_stock_restored', $product, $item );

                            // A unique Order note: Store each order note in an array…
                            $order_note[] = sprintf( __( 'Product ID #%s stock %s from %s to %s.', 'woocommerce' ), $product_id, $change_text, $initial_stock, $updated_stock);

                            // DEPRECATED & NO LONGER NEEDED - can be removed
                            //$order->send_stock_notifications( $product, $updated_stock, $item_qty );
                        }
                    }
                }
                // Adding a unique composite order note (for multiple items)
                $order_notes = count($order_note) > 1 ? implode(' | ', $order_note) : $order_note[0];
                $order->add_order_note( $order_notes );
            }
        }
    }
    $GLOBALS['wc_auto_stock_restore'] = new WC_Auto_Stock_Restore();
}

This should go in a plugin php file (see this related to WooCommerce plugins creation).


The normal version (for themes function.php file):

## ---- for WooCommerce versions 3+ - Theme code version ---- ##

add_action( 'woocommerce_order_status_changed', 'adjust_order_stock', 10, 3 );
function adjust_order_stock( $order_id, $old_status, $new_status ) {
    $order = new WC_Order( $order_id );
    $items = $order->get_items();

    if ( ! get_option('woocommerce_manage_stock') == 'yes' && ! count( $items ) > 0 )
        return; // We exit

    // EXCEPTION for 'ipay88' payment method id, when Order status change from 'pending' to 'cancelled'
    if( $order->get_payment_method() == 'ipay88' && $old_status == 'pending' && $new_status == 'cancelled' )
        return; // We exit

    // We don't need from 'pending' to 'refunded' order status
    if( $old_status == 'pending' && $new_status == 'refunded' )
        return; // We exit

    // Group Order statuses in 2 groups (array)
    $statuses_group1 = array( 'processing', 'on-hold', 'pending', 'completed' );
    $statuses_group2 = array( 'cancelled', 'refunded' );

    $change_stock = false;
    $order_note = array();

    ## 1. Restore Order stock (7 order status change types)
    if ( in_array( $old_status, $statuses_group1 ) && in_array( $new_status, $statuses_group2 ) ) {
        $change_stock = true;
        $change_type = 'increase';
        $change_text =  __( 'incremented', 'woocommerce' );
    }
    ## 2. Restore Order stock (4 order status change types)
    elseif ( $old_status == 'cancelled' && in_array( $new_status, $statuses_group1 ) ) {
        $change_stock = true;
        $change_type = 'decrease';
        $change_text =  __( 'decremented', 'woocommerce' );
    }
    ## 3. Other cases
    else return; // We exit

    if( $change_stock ){
        // Iterating through each order 'line_item'
        // Since WC 3, $item is a WC_Order_Item_Product object
        foreach ( $items as $item ) {
            $product_id = $item->get_product_id(); // The product ID
            if ( $product_id > 0 ) {
                 // Get tan instance of the WC_Product object
                $product = $item->get_product();
                if ( $product && $product->exists() && $product->managing_stock() ) {

                    // Get the product initial stock quantity (before update)
                    $initial_stock = $product->get_stock_quantity();

                    $item_qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $this, $item );

                    // Update the product stock quantity
                    // Replace DEPRECATED methods: increase_stock() & discrease_stock()
                    wc_update_product_stock( $product, $item_qty, $change_type );

                    // Get the product updated stock quantity
                    $updated_stock = ( $change_type == 'increase' ) ? $initial_stock + $item_qty : $initial_stock - $item_qty;

                    do_action( 'woocommerce_auto_stock_restored', $product, $item );

                    // A unique Order note: Store each order note in an array…
                    $order_note[] = sprintf( __( 'Product ID #%s stock %s from %s to %s.', 'woocommerce' ), $product_id, $change_text, $initial_stock, $updated_stock);

                    // DEPRECATED & NO LONGER NEEDED - can be removed
                    //$order->send_stock_notifications( $product, $updated_stock, $item_qty );
                }
            }
        }
        // Adding a unique composite order note (for multiple items)
        $order_notes = count($order_note) > 1 ? implode(' | ', $order_note) : $order_note[0];
        $order->add_order_note( $order_notes );
    }
}

This code goes in function.php file of your active child theme (or theme).

All the code is tested and works only for WooCommerce versions 3+


Woocommerce Order related:

  • How to get WooCommerce order details
  • Order items and WC_Order_Item_Product object in Woocommerce 3


来源:https://stackoverflow.com/questions/47181651/exclude-one-specific-payment-gateway-from-auto-restock-in-woocommerce

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!