Reputation: 356
I need to filter the product price for products which use the custom-tax-class when the product is added to cart so i can calculate the tax based on the margin = price - purchase price rather than the price.
add_filter('woocommerce_calc_tax', 'modify_price_for_tax_calculation_v4', 10, 5);
function modify_price_for_tax_calculation_v4( $taxes, $price, $rates, $price_includes_tax, $suppress_rounding ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Get the global cart
$cart = WC()->cart;
if (!$cart) return $taxes; // Ensure cart exists
// Loop through each cart item
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
// Check if the product uses the custom tax class
if ( 'custom-tax-class' === $product->get_tax_class() ) {
// Get the purchase price (replace '_purchase_price' with actual meta key)
$purchase_price = 100;
// Ensure product price is a float
$product_price = floatval( $product->get_price() );
$quantity = intval($cart_item['quantity']);
// Calculate the margin (product price - purchase price)
$margin = max(($product_price - $purchase_price) * $quantity, 0); // Ensure margin is not negative
// Apply tax rates to margin instead of the product price
foreach ( $rates as $rate_id => $rate ) {
// Loop through each cart ite
$rate_percentage = floatval( $rate['rate']); // Convert rate to decimal
$modified_price = round( $margin * $rate_percentage, 2 ); // Apply margin-based tax calculation
// Set modified tax amount
$taxes[$rate_id] = $modified_price;
}
}
}
return $taxes; // Return the modified tax values
}
I tried this code but 1. it doesn't modify the custom tax, it modifies the standard tax and 2. the calculations are all wrong.
Example : If the product price = $200 and the purchase price = $100 the $margin = $100
If the tax rate for the custom-tax-class = 10%, the tax should be $10 but its displaying as $20 and modifying the tax for the product with the standard tax class when it should modify the tax for the product with the custom tax class.
Update 1 : I think i need to filter the $price used in the tax calculation rather than modify the $taxes variable as i need to modify the price in the cart totals based on the difference between the purchase price and the product price for tax purposes.
Update 2 : The new code works when 1 product added to cart but not when more than 1 added.
Upvotes: 1
Views: 267
Reputation: 1018
This should properly calculate the tax based on the profit margin for your specific products. Just make sure you've got the cost prices entered in the '_purchase_price' field (or adjust the code to match your field name).
// FINALLY WORKING! This hook runs per cart item which is exactly what we need
add_filter('woocommerce_calculate_item_totals_taxes', 'margin_based_tax_calc', 10, 3);
function margin_based_tax_calc($taxes, $item, $cart_totals) {
// Don't run in admin except for AJAX requests
if (is_admin() && !defined('DOING_AJAX')) {
return $taxes;
}
// Only care about products with our special tax class
if ($item->tax_class != 'custom-tax-class') {
return $taxes; // Leave other products alone
}
// TODO: Move this to settings page later?
$prod_id = $item->product->get_id();
// Get cost price from meta - I'm using _purchase_price but you might use something else
$cost = get_post_meta($prod_id, '_purchase_price', true);
// Fallback if someone forgot to add purchase price
if (!$cost || $cost == '') {
$cost = 100; // Maybe log this somewhere?
}
// Price minus cost = profit margin
$price = floatval($item->price);
$margin = $price - floatval($cost);
// Don't allow negative margins
if ($margin < 0) $margin = 0;
// Need to multiply by quantity! Forgot this in my first version
$qty = $item->quantity;
$total_margin = $margin * $qty;
// This is where my previous code was failing!
// Tax rates in WC are stored as percentages (10.0) not decimals (0.1)
$result = array();
foreach ($item->tax_rates as $id => $rate_info) {
// SUPER IMPORTANT: Must divide rate by 100
$decimal_rate = floatval($rate_info['rate']) / 100;
$tax = round($total_margin * $decimal_rate, 2);
$result[$id] = $tax;
}
return $result;
}
Upvotes: -1
Reputation: 5169
You are using the wrong filter. You should instead use the woocommerce_calculate_item_totals_taxes
filter. With this filter you don't have to access the cart. This filter will be called for each item in the cart and you will get the cart item in the callback function. Based on this you can calculate the taxes for each cart item.
Example:
add_filter('woocommerce_calculate_item_totals_taxes', 'modify_price_for_tax_calculation_v4', 10, 3);
/**
* Calculate item tax.
*
* @param array $taxes
* @param \stdClass $item
* @param \WC_Cart_Totals $wc_cart_totals
* @return array
*/
function modify_price_for_tax_calculation_v4( $taxes, $item, $wc_cart_totals ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Check if the product uses the custom tax class
if ( 'custom-tax-class' === $item->tax_class ) {
// Get the purchase price (replace '_purchase_price' with actual meta key)
$purchase_price = 100;
// Ensure product price is a float
$product_price = floatval( $item->price );
$quantity = intval($item->quantity);
// Calculate the margin (product price - purchase price)
$margin = max(($product_price - $purchase_price) * $quantity, 0); // Ensure margin is not negative
// Apply tax rates to margin instead of the product price
foreach ( $item->tax_rates as $rate_id => $rate ) {
// Loop through each cart ite
$rate_percentage = floatval( $rate['rate']); // Convert rate to decimal
$modified_price = round( $margin * $rate_percentage, 2 ); // Apply margin-based tax calculation
// Set modified tax amount
$taxes[$rate_id] = $modified_price;
}
}
return $taxes; // Return the modified tax values
}
Upvotes: 0