Applying programmatically a coupon to an Order in WooCommerce3 Applying programmatically a coupon to an Order in WooCommerce3 wordpress wordpress

Applying programmatically a coupon to an Order in WooCommerce3


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


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 couponglobal $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 discountforeach($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.