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 );
2) Percentage discount of 5%
(with a dynamic $order_id
):
wc_order_add_discount( $order_id, __("Discount (5%)"), '5%' );
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
Post a Comment