0

I would like to set the price of individual products to 0 in the checkout when a specific payment method is selected. My code sets the price of these products to 0 and the subtotal is calculated correctly. However, the taxes and the total sum are wrong. Woocommerce assumes that the price has not changed.

Can someone check this code and find the error?

function update_product_prices_and_totals($cart_object) {
    if (is_admin() && !defined('DOING_AJAX')) {
        return;
    }

    if (is_checkout() && isset($_POST['payment_method']) && $_POST['payment_method'] === 'invoice') {
        // Set subtotal, tax, and total to 0
        $subtotal = 0;
        $total = 0;
        $included_products = array(338991, 353754); // Array of product IDs to include

        // Loop through the products in the cart
        foreach ($cart_object->get_cart() as $cart_item_key => $cart_item) {
            $product_id = $cart_item['product_id'];

            // Check the product IDs
            if (in_array($product_id, $included_products)) {
                // Set the price to 0
                $cart_item['data']->set_price(0);

                // Calculate taxes for this product and subtract from the subtotal
                $taxes = array_sum($cart_item['line_tax_data']['subtotal']);
                $subtotal -= $taxes;

                continue; // Skip the iteration for included products
            }

            // Update the subtotal
            $subtotal += $cart_item['line_subtotal'];
        }

        // Update the total
        $total = $subtotal + $cart_object->get_cart_contents_tax();

        // Set the updated subtotal and total
        $cart_object->subtotal = $subtotal;
        $cart_object->total = $total;
    }
}
add_action('woocommerce_cart_calculate_fees', 'update_product_prices_and_totals', 10, 1);

I have tried to change the total and the taxes from Woocommerece methods. A better way would be to set the taxes for these products directly to 0, which also did not work.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Aykut
  • 9
  • 1

2 Answers2

2

You are not using the right hook and making things much more complicated than they are. Try the following:

add_action('woocommerce_before_calculate_totals', 'update_product_prices_and_totals' );
function update_product_prices_and_totals( $cart ) {
    if ( is_admin() && ! defined('DOING_AJAX') )
        return;

    if (  is_checkout() && ! is_wc_endpoint_url() && WC()->session->get('chosen_payment_method') === 'invoice') {
        // Define here the array of targeted product IDs
        $targeted_ids = array(338991, 353754);

        // Loop through cart items
        foreach ( $cart->get_cart() as $cart_item ) {
            // Check for the targeted product (IDs) to be changed
            if ( in_array($cart_item['product_id'], $targeted_ids) || in_array($cart_item['variation_id'], $targeted_ids) ) {
                $cart_item['data']->set_price(0); // Set the price to 0
            }
        }
    }
}

// Refresh checkout on payment method change.
add_action('woocommerce_checkout_init', 'payment_methods_trigger_update_checkout');
function payment_methods_trigger_update_checkout() {
    wc_enqueue_js("$('form.checkout').on('change', 'input[name=payment_method]', function() {
        $(document.body).trigger('update_checkout');
    });");
}

This code goes in functions.php file of your active child theme (or active theme).
Tested and works without needing to update any taxes or totals.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
-1

I've worked on many E-com apps so I have an idea but m not so sure if it will work .

you have to subtract the taxes inside the if condition just before continue;

$total -= $taxes;

then you have to include line_subtotal for each product in the total calc

$subtotal += $cart_item['line_subtotal'];
$total += $cart_item['line_subtotal'];

so your code should look like this I guess.

  function update_product_prices_and_totals($cart_object) {
    if (is_admin() && !defined('DOING_AJAX')) {
        return;
    }

    if (is_checkout() && isset($_POST['payment_method']) && $_POST['payment_method'] === 'invoice') {
        // Set subtotal, tax, and total to 0
        $subtotal = 0;
        $total = 0;
        $included_products = array(338991, 353754); // Array of product IDs to include

        // Loop through the products in the cart
        foreach ($cart_object->get_cart() as $cart_item_key => $cart_item) {
            $product_id = $cart_item['product_id'];

            // Check the product IDs
            if (in_array($product_id, $included_products)) {
                // Set the price to 0
                $cart_item['data']->set_price(0);

                // Calculate taxes for this product and subtract from the subtotal
                $taxes = array_sum($cart_item['line_tax_data']['subtotal']);
                $subtotal -= $taxes;
                $total -= $taxes;

                continue; // Skip the iteration for included products
            }

            // Update the subtotal
            $subtotal += $cart_item['line_subtotal'];
            $total += $cart_item['line_subtotal'];
        }

        // Set the updated subtotal and total
        $cart_object->subtotal = $subtotal;
        $cart_object->total = $total;
    }
}
add_action('woocommerce_cart_calculate_fees', 'update_product_prices_and_totals', 10, 1);

NOTE: I have no idea what does this $cart_object->get_cart_contents_tax() (I don't have enough reputation to comment so if you don't mind telling me) check this solution and give me your feedback if it works or no

  • 1
    [get_cart_contents_tax](https://woocommerce.github.io/code-reference/classes/WC-Cart.html#method_get_cart_contents_tax) is a documented function. This answer does not seem entirely accurate since it’s not using the calculated taxes on the items in the cart. I assume taxes on the item must be collected on their original price for tax liability reasons. If I were to answer this question, i would find the answer to that assumption, before answering the question. – Security Hound Jul 15 '23 at 00:00