• Resolved isodos

    (@isodos)


    Hi mates – so here’s the issue:

    I have the code below – it works well except for when we go to update the order’s status, it decreases the main woocommerce stock. I can’t for the life of me figure out how to block the mechanism from kicking in for the main store stock and only for the warehouse.

    ? It works fine when we place the order – the main woocommerce stocks are not touched at this stage so far and the warehouse stock for “Sobe” goes down fine.

    ? Same with when refunding/cancel, the stock levels go up fine and the main WooCommerce stock levels for this product are not touched.

    <span style=”text-decoration: underline;”>Issue is just when we update the order from say “processing” to anything</span> else but cancelled/refunded.

    Can anyone help?

    // Custom Sobe Brampton Pickups Shipping Method
    function custom_sobe_brampton_pickups_shipping_method() {
        if (!class_exists('WC_Custom_Sobe_Brampton_Pickups_Method')) {
            class WC_Custom_Sobe_Brampton_Pickups_Method extends WC_Shipping_Method {
                public function __construct() {
                    $this->id                 = 'custom_sobe_brampton_pickups';
                    $this->method_title       = __('Sobe Pickup - Brampton', 'woocommerce');
                    $this->method_description = __('Custom Shipping Method for Sobe Pickup - Brampton', 'woocommerce');
                    $this->enabled            = 'yes';
                    $this->title              = 'Sobe Pickup - Brampton';
    
                    $this->init();
                }
    
                function init() {
                    $this->init_form_fields();
                    $this->init_settings();
    
                    add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
                }
    
                private function check_stock_availability($package) {
                    global $wpdb;
    
                    $valid_stock = true;
    
                    foreach ($package['contents'] as $item) {
                        $product_id = isset($item['variation_id']) && $item['variation_id'] != 0 ? $item['variation_id'] : $item['product_id'];
                        $quantity_in_cart = $item['quantity'];
    
                        $warehouse_id = '105986';
                        $stock_field = '_op_qty_warehouse_' . $warehouse_id;
    
                        $stock_level = $wpdb->get_var($wpdb->prepare(
                            "SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s",
                            $product_id, $stock_field
                        ));
    
                        if ($quantity_in_cart > intval($stock_level)) {
                            $valid_stock = false;
                            break;
                        }
                    }
    
                    return $valid_stock;
                }
    
                public function calculate_shipping($package = []) {
                    if (!$this->check_stock_availability($package)) {
                        return; // No stock available
                    }
    
                    $valid_class = false;
    
                    foreach (WC()->cart->get_cart() as $cart_item) {
                        if ('partner-pickup-brampton-sobe-treats' === $cart_item['data']->get_shipping_class()) {
                            $valid_class = true;
                            break;
                        }
                    }
    
                    if ($valid_class) {
                        $rate = array(
                            'id'       => $this->id,
                            'label'    => $this->title,
                            'cost'     => 0,
                            'calc_tax' => 'per_item'
                        );
    
                        $this->add_rate($rate);
                    }
                }
            }
        }
    }
    
    add_action('woocommerce_shipping_init', 'custom_sobe_brampton_pickups_shipping_method');
    
    function add_custom_sobe_brampton_pickups($methods) {
        $methods['custom_sobe_brampton_pickups'] = 'WC_Custom_Sobe_Brampton_Pickups_Method';
        return $methods;
    }
    
    add_filter('woocommerce_shipping_methods', 'add_custom_sobe_brampton_pickups');
    
    // Decrease stock for Sobe warehouse when order is processed
    add_action('woocommerce_order_status_processing', 'custom_handle_sobe_stock_on_completed', 10, 1);
    add_action('woocommerce_order_status_completed', 'custom_handle_sobe_stock_on_completed', 10, 1);
    
    function custom_handle_sobe_stock_on_completed($order_id) {
        $order = wc_get_order($order_id);
    
        // Check if the order has the custom Sobe shipping method
        $has_sobe_shipping_method = false;
        foreach ($order->get_shipping_methods() as $shipping_method) {
            if ($shipping_method->get_method_id() === 'custom_sobe_brampton_pickups') {
                $has_sobe_shipping_method = true;
                break;
            }
        }
    
        // Decrease Sobe stock levels only if the Sobe shipping method is used
        if ($has_sobe_shipping_method) {
            decrease_sobe_stock_levels($order_id);
        }
    }
    
    function decrease_sobe_stock_levels($order_id) {
        global $wpdb;
        $warehouse_id = '105986'; // Your warehouse ID
        $stock_field = '_op_qty_warehouse_' . $warehouse_id;
    
        $order = wc_get_order($order_id);
        $order_notes = array();
    
        foreach ($order->get_items() as $item) {
            $product_id = $item->get_product_id();
            $variation_id = $item->get_variation_id(); // Get the variation ID if it's a variation
    
            if ($variation_id) {
                // It's a variation, update the variation's stock
                $current_stock = (int) get_post_meta($variation_id, $stock_field, true);
                $new_stock = $current_stock - $item->get_quantity();
                $new_stock = max($new_stock, 0);
                update_post_meta($variation_id, $stock_field, $new_stock);
    
                // Add note to order
                $order_notes[] = sprintf(__('Sobe Treats Brampton Stock reduced for "%s": Before - %d, After - %d', 'woocommerce'), get_the_title($variation_id), $current_stock, $new_stock);
            } else {
                // It's a simple product, update its stock
                $current_stock = (int) get_post_meta($product_id, $stock_field, true);
                $new_stock = $current_stock - $item->get_quantity();
                $new_stock = max($new_stock, 0);
                update_post_meta($product_id, $stock_field, $new_stock);
    
                // Add note to order
                $order_notes[] = sprintf(__('Sobe Treats Brampton Stock reduced for "%s": Before - %d, After - %d', 'woocommerce'), get_the_title($product_id), $current_stock, $new_stock);
            }
        }
    
        // Add notes to order
        foreach ($order_notes as $note) {
            $order->add_order_note($note);
        }
    }
    
    // Increase stock for Sobe warehouse when order is cancelled or refunded
    add_action('woocommerce_order_status_cancelled', 'custom_handle_sobe_stock_on_cancel', 10, 1);
    add_action('woocommerce_order_status_refunded', 'custom_handle_sobe_stock_on_cancel', 10, 1);
    
    function custom_handle_sobe_stock_on_cancel($order_id) {
        increase_sobe_stock_levels($order_id);
    }
    
    function increase_sobe_stock_levels($order_id) {
        global $wpdb;
        $warehouse_id = '105986'; // Your warehouse ID
        $stock_field = '_op_qty_warehouse_' . $warehouse_id;
    
        $order = wc_get_order($order_id);
        $order_notes = array();
    
        foreach ($order->get_items() as $item) {
            $product_id = $item->get_product_id();
            $variation_id = $item->get_variation_id(); // Get the variation ID if it's a variation
    
            if ($variation_id) {
                // It's a variation, update the variation's stock
                $current_stock = (int) get_post_meta($variation_id, $stock_field, true);
                $new_stock = $current_stock + $item->get_quantity();
                update_post_meta($variation_id, $stock_field, $new_stock);
    
                // Add note to order
                $order_notes[] = sprintf(__('Sobe Treats Brampton Stock increased for "%s": Before - %d, After - %d', 'woocommerce'), get_the_title($variation_id), $current_stock, $new_stock);
            } else {
                // It's a simple product, update its stock
                $current_stock = (int) get_post_meta($product_id, $stock_field, true);
                $new_stock = $current_stock + $item->get_quantity();
                update_post_meta($product_id, $stock_field, $new_stock);
    
                // Add note to order
                $order_notes[] = sprintf(__('Sobe Treats Brampton Stock increased for "%s": Before - %d, After - %d', 'woocommerce'), get_the_title($product_id), $current_stock, $new_stock);
            }
        }
    
        // Add notes to order
        foreach ($order_notes as $note) {
            $order->add_order_note($note);
        }
    }
    
    // Function to disable automatic stock management for Sobe products
    function disable_automatic_stock_management_for_sobe_products($product) {
        if (is_sobe_treats_product($product)) {
            $product->set_manage_stock(false);
        }
    }
    
    add_action('woocommerce_product_object', 'disable_automatic_stock_management_for_sobe_products');
    
    function is_sobe_treats_product($product) {
        $shipping_class = 'partner-pickup-brampton-sobe-treats';
        $product_shipping_class_id = $product->get_shipping_class_id();
        
        if ($product_shipping_class_id) {
            $product_shipping_class = get_term($product_shipping_class_id)->slug;
            return $product_shipping_class === $shipping_class;
        }
    
        return false;
    }
    
    // Prevent automatic stock reduction for Sobe orders
    add_filter('woocommerce_can_reduce_order_stock', 'prevent_automatic_stock_reduction_for_sobe_orders', 10, 2);
    
    function prevent_automatic_stock_reduction_for_sobe_orders($reduce_stock, $order) {
        foreach ($order->get_shipping_methods() as $shipping_method) {
            if ($shipping_method->get_method_id() === 'custom_sobe_brampton_pickups') {
                return false;
            }
        }
        return $reduce_stock;
    }
    

    Here’s an explanation of the code:

    1. custom_sobe_brampton_pickups_shipping_method Function: This function defines a custom shipping method for WooCommerce. It creates a new class WC_Custom_Sobe_Brampton_Pickups_Method that extends the WC_Shipping_Method class. This custom shipping method checks stock availability for specific products and adds a shipping rate if the conditions are met.
    2. init Method: Inside the WC_Custom_Sobe_Brampton_Pickups_Method class, the init method is called to initialize the shipping method. It sets up form fields and settings for the method and hooks into the WooCommerce settings update process.
    3. check_stock_availability Method: This private method checks the stock availability of products in a package by querying the database for stock levels. It compares the quantity in the cart with the available stock for each product.
    4. calculate_shipping Method: This method is called when WooCommerce calculates shipping rates. It uses the check_stock_availability method to determine if the products in the cart have sufficient stock. If there’s enough stock and the cart contains a specific shipping class (“partner-pickup-brampton-sobe-treats”), it adds a free shipping rate for the “Sobe Pickup – Brampton” method.
    5. Hooks for Adding and Enabling the Custom Shipping Method: These functions add_custom_sobe_brampton_pickups and custom_sobe_brampton_pickups_shipping_method add the custom shipping method to WooCommerce and enable it.
    6. Stock Management Hooks: The code includes hooks to decrease stock levels in the warehouse when an order is processed (custom_handle_sobe_stock_on_completed) and to increase stock levels when an order is canceled or refunded (custom_handle_sobe_stock_on_cancel). These hooks are essential for managing inventory accurately.
    7. Disabling Automatic Stock Management for Sobe Products: The function disable_automatic_stock_management_for_sobe_products disables the automatic stock management for products with a specific shipping class (“partner-pickup-brampton-sobe-treats”). This allows the code to control stock levels manually.
    8. Preventing Automatic Stock Reduction for Sobe Orders: The prevent_automatic_stock_reduction_for_sobe_orders function prevents automatic stock reduction for orders using the “Sobe Pickup – Brampton” shipping method. This ensures that the custom code manages stock levels for Sobe products.

    In summary, this code creates a custom shipping method for WooCommerce, checks stock availability for specific products, manages stock levels for a warehouse, and ensures that stock is not automatically reduced for Sobe orders.

    • This topic was modified 10 months ago by isodos.
Viewing 1 replies (of 1 total)
  • Plugin Support Shameem R. a11n

    (@shameemreza)

    Hi @isodos,

    It seems that this has been marked as resolved. Have you managed to get this sorted, or do you still need help resolving this?

    If the issue continues, we recommend asking development questions on the #developers channel of the WooCommerce Community Slack. Many of our developers hang out there and will be able to offer insights into your question. You can also seek help from the following:

    Looking forward to your response!

Viewing 1 replies (of 1 total)
  • The topic ‘Need help with custom shipping method & custom warehouse stock’ is closed to new replies.