Add A Discount Programmatically To An Order In Woocommerce 3.2+


Answer :

The only available feature to make a discount programmatically for an Order, is tricking the Fee API. For info, this trick is not recommended by woocommerce, but used by many people as there is not a discount feature in Woocommerce outside Coupons.

The following function will allow you to make a fixed discount of any amount or a percentage discount. The order need to exist (to be saved before).

The function code (For Woocommerce versions 3.2+):

/**  * Add a discount to an Orders programmatically  * (Using the FEE API - A negative fee)  *  * @since  3.2.0  * @param  int     $order_id  The order ID. Required.  * @param  string  $title  The label name for the discount. Required.  * @param  mixed   $amount  Fixed amount (float) or percentage based on the subtotal. Required.  * @param  string  $tax_class  The tax Class. '' by default. Optional.  */ function wc_order_add_discount( $order_id, $title, $amount, $tax_class = '' ) {     $order    = wc_get_order($order_id);     $subtotal = $order->get_subtotal();     $item     = new WC_Order_Item_Fee();      if ( strpos($amount, '%') !== false ) {         $percentage = (float) str_replace( array('%', ' '), array('', ''), $amount );         $percentage = $percentage > 100 ? -100 : -$percentage;         $discount   = $percentage * $subtotal / 100;     } else {         $discount = (float) str_replace( ' ', '', $amount );         $discount = $discount > $subtotal ? -$subtotal : -$discount;     }      $item->set_tax_class( $tax_class );     $item->set_name( $title );     $item->set_amount( $discount );     $item->set_total( $discount );      if ( '0' !== $item->get_tax_class() && 'taxable' === $item->get_tax_status() && wc_tax_enabled() ) {         $tax_for   = array(             'country'   => $order->get_shipping_country(),             'state'     => $order->get_shipping_state(),             'postcode'  => $order->get_shipping_postcode(),             'city'      => $order->get_shipping_city(),             'tax_class' => $item->get_tax_class(),         );         $tax_rates = WC_Tax::find_rates( $tax_for );         $taxes     = WC_Tax::calc_tax( $item->get_total(), $tax_rates, false );         print_pr($taxes);          if ( method_exists( $item, 'get_subtotal' ) ) {             $subtotal_taxes = WC_Tax::calc_tax( $item->get_subtotal(), $tax_rates, false );             $item->set_taxes( array( 'total' => $taxes, 'subtotal' => $subtotal_taxes ) );             $item->set_total_tax( array_sum($taxes) );         } else {             $item->set_taxes( array( 'total' => $taxes ) );             $item->set_total_tax( array_sum($taxes) );         }         $has_taxes = true;     } else {         $item->set_taxes( false );         $has_taxes = false;     }     $item->save();      $order->add_item( $item );     $order->calculate_totals( $has_taxes );     $order->save(); } 

Code goes in function.php file of your active child theme (active theme). Tested and works.


USAGE Examples:

1) Fixed discount of $12 (with a dynamic $order_id):

wc_order_add_discount( $order_id, __("Fixed discount"), 12 ); 

enter image description here

2) Percentage discount of 5% (with a dynamic $order_id):

wc_order_add_discount( $order_id, __("Discount (5%)"), '5%' ); 

enter image description here

The amount (or the percentage) can be also a dynamic variable…


Actually you can just make hook before calculate tax etc, get subtotal, apply discount, done :) It automatically apply for Order message etc, it is visible also in backend in proper way. Even after remove hook, info about discount stay in order information.

// Hook before calculate fees add_action('woocommerce_cart_calculate_fees' , 'add_user_discounts'); /**  * Add custom fee if more than three article  * @param WC_Cart $cart  */ function add_user_discounts( WC_Cart $cart ){     //any of your rules     // Calculate the amount to reduce     $discount = $cart->get_subtotal() * 0.5;      $cart->add_fee( 'Test discount 50%', -$discount); } 

Comments

Popular posts from this blog

Converting A String To Int In Groovy

"Cannot Create Cache Directory /home//.composer/cache/repo/https---packagist.org/, Or Directory Is Not Writable. Proceeding Without Cache"

Android How Can I Convert A String To A Editable