Add a discount programmatically to an Order in Woocommerce 3.2+

独自空忆成欢 提交于 2019-11-30 19:34:10

问题


In woocommerce, we can add a discount to any order using Coupons feature (fixed amount, percent amount…).

Is it possible to add discount amount to any order programmatically where the discount amount can be any amount?

Any help will be appreciated.


回答1:


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…




回答2:


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);
}


来源:https://stackoverflow.com/questions/52646869/add-a-discount-programmatically-to-an-order-in-woocommerce-3-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!