Apply Coupon code on the final total amount, not cart total - wordpress

Apply Coupon code on the final total amount, not cart total:
/*Installtion Chrages Discount */
add_action( 'woocommerce_cart_calculate_fees', 'mysite_box_discount', 10, 1);
function mysite_box_discount( $cart )
{
$installation_price = 100;
$cart->add_fee( __($cartQty.'Installation', 'woocommerce'),$installation_price,false );
global $woocommerce;
if(WC()->cart->get_applied_coupons()){
$coupon_code = WC()->cart->get_applied_coupons();
$coupon = new WC_Coupon($coupon_code[0]);
$coupon_amount = (float) $coupon->amount;
$discount_on_fee = (float) $coupon_amount/100;
$installation_discount = $discount_on_fee*$installation_price;
$cart->add_fee( __($cartQty.'Installation Discount', 'woocommerce'), -$installation_fee_discount,false );
}
}
This apply discount but I need complete total discount including fees too.

Related

Discount for a specific product category in WooCommerce cart based on quantity and multiples

The discount I currently have essentially says
If 6 products within a specific category are in the cart --- discount the total price of $10
This piece of the code works fine. My issue is, this does not work
If there are 7 products, the 7th product being from a different category.
My goal is to give the discount no matter how many products are in the cart so long as there are 6 products within "Category A".
The following code works so long as there is 6 products in the "discounted category" or there is 1 product with a quantity of 6 etc. It falls apart when I add a product from another category. Feel free to rip it apart.
add_action( 'woocommerce_before_calculate_totals', 'this_item_free' );
function this_item_free() {
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$valid_product_category_id = array('soup-mix');
$has_category = false;
$count = WC()->cart->get_cart_contents_count();
foreach ( WC()->cart->get_cart() as $product ) {
$quantity = $product['quantity'];
$price = $product['data']->get_price();
}
if ( has_term( $valid_product_category_id, 'product_cat', $product['product_id'],
$product['quantity'] ) ) {
$has_category = true;
$cart_total = floatval( preg_replace( '#[^\d.]#', '', WC()->cart->get_cart_total() ) );
if($count == 6 && $has_category = true){
add_action( 'woocommerce_cart_calculate_fees', 'discount_based_on_total', 25, 1 );
function discount_based_on_total( $cart ) {
$total = $cart->cart_contents_total;
$discount = 9.95;
$cart->add_fee( __('discount', 'woocommerce'), -$discount );
wc_add_notice( apply_filters( 'discount_applied', 'You just got a free soup!') );
}
}
}
}
Your code contains some unnecessary steps and what you want to achieve can be obtained with just the woocommerce_cart_calculate_fees action hook
My answer contains:
Give a discount no matter how many products are in the cart so long as there are 6 products or there is 1 product with a quantity of 6, etc.. within "Category A".
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
/* SETTINGS */
// Specific categories
$specific_categories = array( 'Categorie-A' );
// Discount
$discount = 10;
// Min quantity
$minimun_quantity = 6;
/* END SETTINGS */
// Counter
$current_quantity = 0;
// Loop though each cart item
foreach ( $cart->get_cart() as $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// Has certain category
if ( has_term( $specific_categories, 'product_cat', $product_id ) ) {
// Quantity
$product_quantity = $cart_item['quantity'];
// Add to total
$current_quantity += $product_quantity;
}
}
// Greater than or equal to
if ( $current_quantity >= $minimun_quantity ) {
// Add fee
$cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
To apply the discount per 6 products (6 = $10, 12 = $20, 18 = $30, etc..)
Replace
// Greater than or equal to
if ( $current_quantity >= $minimun_quantity ) {
// Add fee
$cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );
}
With
// Greater than or equal to
if ( $current_quantity >= $minimun_quantity ) {
// Modulo
$mod = $current_quantity % $minimun_quantity;
// Times it fit
$times = ( $current_quantity - $mod ) / $minimun_quantity;
// Discount * times
$discount = $discount * $times;
// Add fee
$cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );
}

Add discount per certain number of products on the cheapest products in WooCommerce

I'm adding the discount rule for every 3 products: 3,6,9,12,15.. on the cart and it should apply to discount 50% only the cheapest products.
So if you have 9, only the 3 cheapest gets 50% off.
This code applies a discount to all products, so it should only be every 3 products
add_action('woocommerce_cart_calculate_fees', 'ts_add_custom_discount', 10, 1 );
function ts_add_custom_discount( $wc_cart ){
$discount = 0;
$product_ids = array();
$item_prices = array();
$in_cart = false;
foreach ( $wc_cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_product = $cart_item['data'];
if ( has_term( 'get2', 'product_cat', $cart_product->get_id() ) ) { // get2 selected category
$in_cart = true;
}else {
$in_cart = true;
$product_ids[] = $cart_product->get_id();
$item_prices[$cart_product->get_id()] = $cart_product->get_price();
}
}
if( $in_cart ) {
$count_ids = count($product_ids);
asort( $item_prices ); //Sort the prices from lowest to highest
$cartQuantity = WC()->cart->cart_contents_count;
$count = 0;
if( $count_ids > 3 || $cartQuantity >= 3 ) {
foreach( $item_prices as $id => $price ) {
if( $count >= 1 ) {
break;
}
//$product = wc_get_product( $id );
//$price = $product->get_price();
$discount -= ($price * 50) /100;
$count++;
}
}
}
if( $discount != 0 ){
$wc_cart->add_fee( 'Discount', $discount, true );
}
}
I have attached a screenshot, you can see there is a red outline for every 3rd cheapest product.
This answer will apply a 50% discount per 3 products on the cheapest products. (explanation via comment tags added to the code)
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
// Products in cart
$products_in_cart = count( $cart->get_cart() );
// Every so many products
$every = 3;
// When products in cart greater than or equal to every so many products
if ( $products_in_cart >= $every ) {
// Set array
$product_prices = array();
// Loop though cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Product
$product = $cart_item['data'];
// Get price
$product_price = $product->get_price();
// Push
$product_prices[] = $product_price;
}
// Sort: low to high
asort( $product_prices );
// Number of products receive a discount
$products_receive_discount = floor( $products_in_cart / $every );
// Set variable
$total = 0;
// Loop trough
foreach ( array_slice( $product_prices, 0, $products_receive_discount ) as $product_price ) {
// Calculate
$total += $product_price;
}
// Calculate discount
$discount = ( $total * 50 ) / 100;
// Discount
$cart->add_fee( __( 'Discount', 'woocommerce' ), -$discount, true );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

How to calculate savings total in Woocommerce

UPD
Solved:
function wc_discount_total_30() {
global $woocommerce;
$discount_total = 0;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if ( $_product->is_on_sale() ) {
$regular_price = $_product->get_regular_price();
$sale_price = $_product->get_sale_price();
$discount = ($regular_price - $sale_price) * $values['quantity'];
$discount_total += $discount;
}
}
if ( $woocommerce->cart->subtotal + $woocommerce->cart->shipping_total > $woocommerce->cart->total + $woocommerce->cart->shipping_total || $discount_total >0 ) {
echo '<tr class="cart-discount">
<th>'. __( 'Saved:', 'woocommerce' ) .'</th>
<td data-title=" '. __( 'Saved', 'woocommerce' ) .' ">'
. wc_price( $woocommerce->cart->subtotal - $woocommerce->cart->total + $woocommerce->cart->shipping_total + $discount_total ) .'</td>
</tr>';
}
}
// Hook our values to the Basket and Checkout pages
add_action( 'woocommerce_cart_totals_after_order_total', 'wc_discount_total_30', 99);
add_action( 'woocommerce_review_order_after_order_total', 'wc_discount_total_30', 99);
--------------------------------------------------------------------
ORIGINAL QUESTION:
I want to calculate and display «Total Savings» in Cart and Checkout page (Woocommerce). I've tried to use this code, but it only works if I have at least one discounted item in my cart:
function wc_discount_total_30() {
global $woocommerce;
$discount_total = 0;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if ( $_product->is_on_sale() ) {
$regular_price = $_product->get_regular_price();
$sale_price = $_product->get_sale_price();
$discount = ($regular_price - $sale_price) * $values['quantity'];
$discount_total += $discount;
}
}
if ( $discount_total > 0 ) {
echo '<tr class="cart-discount">
<th>'. __( 'Saved', 'tsavedis' ) .'</th>
<td data-title=" '. __( 'Saved', 'tsavedis' ) .' ">'
. wc_price( $discount_total + $woocommerce->cart->discount_cart ) .'</td>
</tr>';
}
}
// Hook our values to the Basket and Checkout pages
add_action( 'woocommerce_cart_totals_after_order_total', 'wc_discount_total_30', 99);
add_action( 'woocommerce_review_order_after_order_total', 'wc_discount_total_30', 99);
But I need to calculate the discount amount considering the coupon and the amount of items in the cart (whether there are discounted items in the cart or not). Here is my code for displaying discount based on the number of items in shopping cart:
function woo_discount_total(WC_Cart $cart) {
$woo_count_item = $cart->get_cart_contents_count(); // Number of items in the shopping cart
if($woo_count_item >= 3 && $woo_count_item <= 4) {
$discount = $cart->subtotal * 0.10; // 0.10 — 10%
$cart->add_fee("10% discount for 3-4 items in the shopping cart", -$discount);
} elseif($woo_count_item >= 5 && $woo_count_item <= 100) {
$discount = $cart->subtotal * 0.20; // 0.20 — 20%
$cart->add_fee("20% discount for 5 and more items in the shopping cart", -$discount);
}
}
add_action("woocommerce_cart_calculate_fees" , "woo_discount_total");
What I want to display:
Cart Subtotal: $1000
Coupon: -$50
10% discount for 3 items in Cart: -$100
Order Total: $850
Saved: $150
I think the easiest way to do that is to subtract «order total» from «cart subtotal». Is there any way to do this?

Woocommerce Calculate amount by customer input in product page

In product page to get input from customer as number of words. To calculate the amount from products add-ons fixed amount to additional 10$ for each above 500 words.
ex: 1. Number of Words: 530
Normal Price + additional price: 180$ + 10$
Total: 190$
Number of Words: 1040
Normal Price + additional price: 180$ + 20$
Total: 200$
This process as to create dynamic input form customer to calculate amount the price and total amount.
`$extra_amount = (int)'10';
$amount = (int)'180'; // how to get amount from woocommerce data
if(isset($_POST['wordnumber'])){ // how to get this paramater form woocommerce post values
$test =$_POST['wordnumber'];
$original_amount = '';
if($test <= (int)'500'){
$original_amount = $amount;
}
elseif($test > (int)'500'){
$div_amount = $test/(int)'500';
$round = floor($div_amount);
//echo '<br/>';
$total_extra = $round*$extra_amount;
$original_amount = $amount+$total_extra;
}
echo $original_amount;
}`
I installed WC Fields Factory plugin then i got value from one field using key. in that i written a function and i overrided the price value.
function calculate_gift_wrap_fee( $cart_object ) {
/* Gift wrap price */
$additionalPrice = 10;
foreach ( $cart_object->cart_contents as $key => $value ) {
$test = $value['custom field'];
if( $test <= 100 ) {
$quantity = floatval( $value['quantity'] );
$orgPrice = floatval( $value['data']->price );
$value['data']->price = ( $orgPrice );
}
elseif( $test > 100 ) {
$div_amount = floatval($test/500);
$round = floor($div_amount);
$total_extra = floatval($round * $additionalPrice);
$quantity = floatval( $value['quantity'] );
$orgPrice = floatval( $value['data']->price );
$pp = ($value['price']);
$total = floatval($pp + $total_extra);
$value['data']->price = ( $orgPrice + $total );
}
}}
add_action( 'woocommerce_before_calculate_totals', calculate_gift_wrap_fee', 1, 1 );

Woocommerce - Can I intercept the Line Price (Cart) calculation?

So for example, I have a product which costs £2/item if you buy singles or £1/item if you buy it in packs of 6.
Customers enter their quantity required, let's say 7, and then add it to the basket.
The total cost should be £8. £6 (1 pack) + £2 (1 single). But if I add it to the basket currently the price will come out as £7 as you'd expect (it just does 7 x the price set which is £1).
I need to intercept/filter the line price so that it calculates the number of packs, and the number of singles, and then returns the right amount. I can design the function and the math, I just need to know where to hook into.
i.e. is there a filter like woocommerce_get_cart or something similar? And if so, how do I alter the line price?
(p.s. I know I could achieve the with variable products for instance but that's not an option for stock control reasons).
public function calculate_totals() {
$this->reset();
$this->coupons = $this->get_coupons();
do_action( 'woocommerce_before_calculate_totals', $this );
if ( $this->is_empty() ) {
$this->set_session();
return;
}
$tax_rates = array();
$shop_tax_rates = array();
/**
* Calculate subtotals for items. This is done first so that discount logic can use the values.
*/
foreach ( $this->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
// Count items + weight
$this->cart_contents_weight += $_product->get_weight() * $values['quantity'];
$this->cart_contents_count += $values['quantity'];
// Prices
$line_price = $_product->get_price() * $values['quantity'];
$line_subtotal = 0;
$line_subtotal_tax = 0;
/**
* No tax to calculate
*/
if ( ! $_product->is_taxable() ) {
// Subtotal is the undiscounted price
$this->subtotal += $line_price;
$this->subtotal_ex_tax += $line_price;
/**
* Prices include tax
*
* To prevent rounding issues we need to work with the inclusive price where possible
* otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would
* be 8.325 leading to totals being 1p off
*
* Pre tax coupons come off the price the customer thinks they are paying - tax is calculated
* afterwards.
*
* e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that
*/
} elseif ( $this->prices_include_tax ) {
// Get base tax rates
if ( empty( $shop_tax_rates[ $_product->tax_class ] ) ) {
$shop_tax_rates[ $_product->tax_class ] = WC_Tax::get_base_tax_rates( $_product->tax_class );
}
// Get item tax rates
if ( empty( $tax_rates[ $_product->get_tax_class() ] ) ) {
$tax_rates[ $_product->get_tax_class() ] = WC_Tax::get_rates( $_product->get_tax_class() );
}
$base_tax_rates = $shop_tax_rates[ $_product->tax_class ];
$item_tax_rates = $tax_rates[ $_product->get_tax_class() ];
/**
* ADJUST TAX - Calculations when base tax is not equal to the item tax
*/
if ( $item_tax_rates !== $base_tax_rates ) {
// Work out a new base price without the shop's base tax
$taxes = WC_Tax::calc_tax( $line_price, $base_tax_rates, true, true );
// Now we have a new item price (excluding TAX)
$line_subtotal = $line_price - array_sum( $taxes );
// Now add modified taxes
$tax_result = WC_Tax::calc_tax( $line_subtotal, $item_tax_rates );
$line_subtotal_tax = array_sum( $tax_result );
/**
* Regular tax calculation (customer inside base and the tax class is unmodified
*/
} else {
// Calc tax normally
$taxes = WC_Tax::calc_tax( $line_price, $item_tax_rates, true );
$line_subtotal_tax = array_sum( $taxes );
$line_subtotal = $line_price - array_sum( $taxes );
}
/**
* Prices exclude tax
*
* This calculation is simpler - work with the base, untaxed price.
*/
} else {
// Get item tax rates
if ( empty( $tax_rates[ $_product->get_tax_class() ] ) ) {
$tax_rates[ $_product->get_tax_class() ] = WC_Tax::get_rates( $_product->get_tax_class() );
}
$item_tax_rates = $tax_rates[ $_product->get_tax_class() ];
// Base tax for line before discount - we will store this in the order data
$taxes = WC_Tax::calc_tax( $line_price, $item_tax_rates );
$line_subtotal_tax = array_sum( $taxes );
$line_subtotal = $line_price;
}
// Add to main subtotal
$this->subtotal += $line_subtotal + $line_subtotal_tax;
$this->subtotal_ex_tax += $line_subtotal;
}
/**
* Calculate totals for items
*/
foreach ( $this->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
// Prices
$base_price = $_product->get_price();
$line_price = $_product->get_price() * $values['quantity'];
// Tax data
$taxes = array();
$discounted_taxes = array();
/**
* No tax to calculate
*/
if ( ! $_product->is_taxable() ) {
// Discounted Price (price with any pre-tax discounts applied)
$discounted_price = $this->get_discounted_price( $values, $base_price, true );
$line_subtotal_tax = 0;
$line_subtotal = $line_price;
$line_tax = 0;
$line_total = WC_Tax::round( $discounted_price * $values['quantity'] );
/**
* Prices include tax
*/
} elseif ( $this->prices_include_tax ) {
$base_tax_rates = $shop_tax_rates[ $_product->tax_class ];
$item_tax_rates = $tax_rates[ $_product->get_tax_class() ];
/**
* ADJUST TAX - Calculations when base tax is not equal to the item tax
*/
if ( $item_tax_rates !== $base_tax_rates ) {
// Work out a new base price without the shop's base tax
$taxes = WC_Tax::calc_tax( $line_price, $base_tax_rates, true, true );
// Now we have a new item price (excluding TAX)
$line_subtotal = round( $line_price - array_sum( $taxes ), WC_ROUNDING_PRECISION );
$taxes = WC_Tax::calc_tax( $line_subtotal, $item_tax_rates );
$line_subtotal_tax = array_sum( $taxes );
// Adjusted price (this is the price including the new tax rate)
$adjusted_price = ( $line_subtotal + $line_subtotal_tax ) / $values['quantity'];
// Apply discounts
$discounted_price = $this->get_discounted_price( $values, $adjusted_price, true );
$discounted_taxes = WC_Tax::calc_tax( $discounted_price * $values['quantity'], $item_tax_rates, true );
$line_tax = array_sum( $discounted_taxes );
$line_total = ( $discounted_price * $values['quantity'] ) - $line_tax;
/**
* Regular tax calculation (customer inside base and the tax class is unmodified
*/
} else {
// Work out a new base price without the item tax
$taxes = WC_Tax::calc_tax( $line_price, $item_tax_rates, true );
// Now we have a new item price (excluding TAX)
$line_subtotal = $line_price - array_sum( $taxes );
$line_subtotal_tax = array_sum( $taxes );
// Calc prices and tax (discounted)
$discounted_price = $this->get_discounted_price( $values, $base_price, true );
$discounted_taxes = WC_Tax::calc_tax( $discounted_price * $values['quantity'], $item_tax_rates, true );
$line_tax = array_sum( $discounted_taxes );
$line_total = ( $discounted_price * $values['quantity'] ) - $line_tax;
}
// Tax rows - merge the totals we just got
foreach ( array_keys( $this->taxes + $discounted_taxes ) as $key ) {
$this->taxes[ $key ] = ( isset( $discounted_taxes[ $key ] ) ? $discounted_taxes[ $key ] : 0 ) + ( isset( $this->taxes[ $key ] ) ? $this->taxes[ $key ] : 0 );
}
/**
* Prices exclude tax
*/
} else {
$item_tax_rates = $tax_rates[ $_product->get_tax_class() ];
// Work out a new base price without the shop's base tax
$taxes = WC_Tax::calc_tax( $line_price, $item_tax_rates );
// Now we have the item price (excluding TAX)
$line_subtotal = $line_price;
$line_subtotal_tax = array_sum( $taxes );
// Now calc product rates
$discounted_price = $this->get_discounted_price( $values, $base_price, true );
$discounted_taxes = WC_Tax::calc_tax( $discounted_price * $values['quantity'], $item_tax_rates );
$discounted_tax_amount = array_sum( $discounted_taxes );
$line_tax = $discounted_tax_amount;
$line_total = $discounted_price * $values['quantity'];
// Tax rows - merge the totals we just got
foreach ( array_keys( $this->taxes + $discounted_taxes ) as $key ) {
$this->taxes[ $key ] = ( isset( $discounted_taxes[ $key ] ) ? $discounted_taxes[ $key ] : 0 ) + ( isset( $this->taxes[ $key ] ) ? $this->taxes[ $key ] : 0 );
}
}
// Cart contents total is based on discounted prices and is used for the final total calculation
$this->cart_contents_total += $line_total;
// Store costs + taxes for lines
$this->cart_contents[ $cart_item_key ]['line_total'] = $line_total;
$this->cart_contents[ $cart_item_key ]['line_tax'] = $line_tax;
$this->cart_contents[ $cart_item_key ]['line_subtotal'] = $line_subtotal;
$this->cart_contents[ $cart_item_key ]['line_subtotal_tax'] = $line_subtotal_tax;
// Store rates ID and costs - Since 2.2
$this->cart_contents[ $cart_item_key ]['line_tax_data'] = array( 'total' => $discounted_taxes, 'subtotal' => $taxes );
}
// Only calculate the grand total + shipping if on the cart/checkout
if ( is_checkout() || is_cart() || defined('WOOCOMMERCE_CHECKOUT') || defined('WOOCOMMERCE_CART') ) {
// Calculate the Shipping
$this->calculate_shipping();
// Trigger the fees API where developers can add fees to the cart
$this->calculate_fees();
// Total up/round taxes and shipping taxes
if ( $this->round_at_subtotal ) {
$this->tax_total = WC_Tax::get_tax_total( $this->taxes );
$this->shipping_tax_total = WC_Tax::get_tax_total( $this->shipping_taxes );
$this->taxes = array_map( array( 'WC_Tax', 'round' ), $this->taxes );
$this->shipping_taxes = array_map( array( 'WC_Tax', 'round' ), $this->shipping_taxes );
} else {
$this->tax_total = array_sum( $this->taxes );
$this->shipping_tax_total = array_sum( $this->shipping_taxes );
}
// VAT exemption done at this point - so all totals are correct before exemption
if ( WC()->customer->is_vat_exempt() ) {
$this->remove_taxes();
}
// Allow plugins to hook and alter totals before final total is calculated
do_action( 'woocommerce_calculate_totals', $this );
// Grand Total - Discounted product prices, discounted tax, shipping cost + tax
$this->total = max( 0, apply_filters( 'woocommerce_calculated_total', round( $this->cart_contents_total + $this->tax_total + $this->shipping_tax_total + $this->shipping_total + $this->fee_total, $this->dp ), $this ) );
} else {
// Set tax total to sum of all tax rows
$this->tax_total = WC_Tax::get_tax_total( $this->taxes );
// VAT exemption done at this point - so all totals are correct before exemption
if ( WC()->customer->is_vat_exempt() ) {
$this->remove_taxes();
}
}
do_action( 'woocommerce_after_calculate_totals', $this );
$this->set_session();
}
this is the original total calculations on WooCommerce.
near the bottom you have:
// Allow plugins to hook and alter totals before final total is calculated
do_action( 'woocommerce_calculate_totals', $this );
of which I believe you can use to do something like this:
add_action('woocommerce_calculate_totals','my_woocommerce_calculate_totals');
function my_woocommerce_calculate_totals($cart) {
// get some hints from the code above and do something like foreach ( $cart->get_cart() as $cart_item_key => $values ) { }
// do your math, then set $cart->cart_contents_total
}

Resources