Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying programmatically a coupon to an Order in WooCommerce3

I'm developing a plugin that creates an order directly (no cart) and applies a coupon. In version 3.0 of the woo API the function add_coupon() has been deprecated in favour of a WC_Order_Item_Coupon object you add to the order.

Create the coupon

$coupon = new WC_Order_Item_Coupon();
$coupon->set_props(array('code' => $coupon, 'discount' => $discount_total, 
'discount_tax' => 0));
$coupon->save();

This is successful. I can validate by calling $coupon->get_discount().

I then add the coupon to the order and recalculate totals:

$order->add_item($item);
$order->calculate_totals($discount_total);
$order->save(); 

Logging into wp-admin I can see the order with coupon code visible. However, the coupon has had no effect on line items or total.

Have a misunderstood how api v3.0 intends us to handle coupons?

like image 631
Benjamin Beaumont Avatar asked Jan 10 '18 13:01

Benjamin Beaumont


People also ask

How do I create a coupon programmatically in WooCommerce?

When working with WooCommerce data since 3.0 version it is always recommended to use CRUD objects. And coupons are not an exception. In order to create a coupon programmatically in code we have to use WC_Coupon object. Once the object is created we are able to use its methods for coupon configuration.


2 Answers

How about using WC_Abstract_Order::apply_coupon?

/**
 * Apply a coupon to the order and recalculate totals.
 *
 * @since 3.2.0
 * @param string|WC_Coupon $raw_coupon Coupon code or object.
 * @return true|WP_Error True if applied, error if not.
 */
public function apply_coupon( $raw_coupon )

Here is my code.

$user = wp_get_current_user();

$order = new WC_Order();
$order->set_status('completed');
$order->set_customer_id($user->ID);
$order->add_product($product , 1); // This is an existing SIMPLE product
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
$order->set_customer_user_agent( wc_get_user_agent() );
$order->set_address([
    'first_name' => $user->first_name,
    'email'      => $user->user_email,
], 'billing' );
// $order->calculate_totals();  // You don't need this

$order->apply_coupon($coupon_code);

$order->save();
like image 194
Donghyeok Kang Avatar answered Oct 24 '22 13:10

Donghyeok Kang


OK, so I played about a little longer and it looks like in V3 things are a little more manual.

Adding a WC_Order_Item_Coupon item to a woo order does simply that. It adds the coupon object to the order object. No calculations are made and the product line items remain unchanged. You have to iterate over the product items manually and apply the coupon yourself by calculating the line item totals and subtotals. calculate_totals() then does as expected.

// Create the coupon
global $woocommerce;
$coupon = new WC_Coupon($coupon_code);

// Get the coupon discount amount (My coupon is a fixed value off)
$discount_total = $coupon->get_amount();

// Loop through products and apply the coupon discount
foreach($order->get_items() as $order_item){
    $product_id = $order_item->get_product_id();

    if($this->coupon_applies_to_product($coupon, $product_id)){
        $total = $order_item->get_total();
        $order_item->set_subtotal($total);
        $order_item->set_total($total - $discount_total);
        $order_item->save();
    }
}
$order->save();

I wrote a helper function to make sure the coupon applies to the product in question coupon_applies_to_product(). Strictly not needed given I'm creating the order entirely in code.. but I use it it other places so added it.

// Add the coupon to the order
$item = new WC_Order_Item_Coupon();
$item->set_props(array('code' => $coupon_code, 'discount' => $discount_total, 'discount_tax' => 0));
$order->add_item($item);
$order->save();

You now get the nicely formatted order in wp-admin with line items showing the specific discount + the coupon code etc.

like image 31
Benjamin Beaumont Avatar answered Oct 24 '22 13:10

Benjamin Beaumont