11/5/21 Update
It's really tricky that find out the wc_order couldn't access the calculate_totals and calculate_taxes.I find out the solution is put $order = wc_get_order( $order->get_id() ); before calulation. The 2 $order type is different , one is (object)WC_Order and another one is (Object)Automattic\WooCommerce\Admin\Overrides\Order. The method of second object works.
I wanna make the AJAX function to place an order programmatically. The product price is base on metadata so I have to calculate every line item. It doesn't with any issue from the client side that sends the post the request to place. The problem point, even I set the price to the line item, and use calculate_totals for the WC_Order but the price didn't correct. The only correction is the cost and subtotal. Though I hit the recalculate button the price would be right.
code
function place_an_order($data){
$screen_prodcut = new WC_Product_Simple(6310);
$userid = get_current_user_id();
$order = wc_create_order(array('customer_id'=>$userid));
$screen_quantity = 2;
$item_id = $order->add_product($screen_prodcut,$screen_quantity);
wc_add_order_item_meta($item_id,'width','1201');
wc_add_order_item_meta($item_id,'height','1201');
wc_add_order_item_meta($item_id,'note','** this is testing**');
$screen_price = 50;
$new_line_screen_price = $screen_price * $screen_quantity;
$item = $order->get_item($item_id);
$item->set_subtotal( $new_line_screen_price / 11 * 10 );
$item->set_total( $new_line_screen_price / 11 * 10 );
$item->save();
// ###section 1###
$order->calculate_taxes();
$order->calculate_totals();
// ###section 2###
}
When run in section 1, the $item subtotal and total are correct. But run in section 2 there is the failure out when printing $order and retrieve the total is wrong. In the dashboard, the price would be shown wrong but the total and subtotal are correct.
After clicking the recalculate, the order total is corrected.
I have no idea why calculate_totals and calculate_taxes don't work. woocommerce_calc_line_taxes is the AJAX action via hit the recalculate button. Usage is calculate_totals and taxes as well. Alternatively, I have to use the set_total instead of calculate_totals?
Related
I see when I look at an order it will show the specific item that was refunded if the whole order wasn't.
Is there a way to find using the WC_Order_Item_Product if an item was refunded? Also, is there a way to get the discount amount that shows up below the item in the order view?
I'm currently doing it manually but if there is a function for it already, I would rather use it.
To get refunded orders you could use some dedicated WC_Order methods like the following ones that have Item Id as argument:
$item_qty_refunded = $order->get_qty_refunded_for_item( $item_id ); // Get the refunded amount for a line item.
$item_total_refunded = $order->get_total_refunded_for_item( $item_id ); // Get the refunded amount for a line item.
You can access an array WC_Order_Refund Objects for this order using get_refunds() method:
For each refund, you can use the WC_Order_Refund methods.
For each refund, you can access items using WC_Abstract_Order method get_items() that will give you the refunded items for the current Order refund.
Each refund "line" item is a WC_Order_Item_Product (with negative values in general) see this related answer: Get Order items and WC_Order_Item_Product in WooCommerce 3
So you can use the following example code:
// Get the WC_Order Object instance (from the order ID)
$order = wc_get_order( $order_id );
// Get the Order refunds (array of refunds)
$order_refunds = $order->get_refunds();
// Loop through the order refunds array
foreach( $order_refunds as $refund ){
// Loop through the order refund line items
foreach( $refund->get_items() as $item_id => $item ){
## --- Using WC_Order_Item_Product methods --- ##
$refunded_quantity = $item->get_quantity(); // Quantity: zero or negative integer
$refunded_line_subtotal = $item->get_subtotal(); // line subtotal: zero or negative number
// ... And so on ...
// Get the original refunded item ID
$refunded_item_id = $item->get_meta('_refunded_item_id'); // line subtotal: zero or negative number
}
}
To get the order items discounted values that appear in admin order edit pages you will use the following code:
// Get the WC_Order Object instance (from the order ID)
$order = wc_get_order($order_id);
// Loop through the order refund line items
foreach( $order->get_items() as $item_id => $item ){
$line_subtotal = $item->get_subtotal();
$line_total = $item->get_total();
$line_subtotal_tax = $item->get_subtotal_tax();
$line_total_tax = $item->get_total_tax();
// Get the negative discount values
$line_discount = $line_total - $line_subtotal; // (Negative number)
$line_discount_tax = $line_total_tax - $line_subtotal_tax; // (Negative number)
}
Related Answers:
How to get WooCommerce order details
Get Order items and WC_Order_Item_Product in WooCommerce 3
Woocommerce - Getting the order item price and quantity.
If you are using get_qty_refunded_for_item( $item_id ) or get_total_refunded_for_item( $item_id ) returns 0 use absint().
$item_qty_refunded = $order->get_qty_refunded_for_item( $item_id ); // Get the refunded amount for a line item.
$item_total_refunded = $order->get_total_refunded_for_item( $item_id ); // Get the refunded amount for a line item.
I'm trying to update 2 ACF custom fields every time an order is created.
We have orders coming from our own website and orders coming from an external marketplace integration. My goal is to differentiate the 2 type of orders using custom fields in the order.
The data for the custom fields is provided by an external marketplace integration. The first field has to be filled with the ordernumber (if it it exists) and the other field is just a simple true/false field.
For website orders we're using "Free shipping". For external orders, the provided shipping details are as follows:
Shipping "Verzending voor bol(xxxxx)"
I'm trying to get the shipping method using the woocomerce_new_order action, and using $order->get_shipping_method()
However, when a new order is created, the custom fields won't update.
This is what I've tried so far:
add_action( 'woocommerce_new_order', 'vliegwerk_bolcom_order_filter', 99, 2);
function vliegwerk_bolcom_order_filter( $order_id, $order ) {
$order = wc_get_order( $order_id );
$verzendmethode = $order->get_shipping_method();
$bol_ordernummer = (int) filter_var($verzendmethode, FILTER_SANITIZE_NUMBER_INT);
if ($bol_ordernummer > 0) {
update_field('field_61fa977c8dff9', $bol_ordernummer, $order_id );
update_field('field_61fa95f594b13', 1, $order_id );
}
}
I already tested the woocommerce_new_order trigger, it works as expected.
I've also tried updating the fields using a foreach loop, and triggering the function with a shortcode. This also works as expected.
However, when combining it all together, the fields won't update. Any help would be appreciated!
On a Wordpress-Shop I use WooCommerce (WC) with Advenced-Custom-Fields (ACF)
and WP-All-Import (WPAI) + WP-All-Export (WPAE).
I added a ACF field CustomerNumber to the WC-Customer (which enhanced the WP-User).
On the WPAI-XML-Import I set the CustomerNumber with a value from a ERP.
So all customers have a unique CustomerNumber.
I now need to export the WC-Orders (to import them in the ERP again).
The Order-XML must include the CustomerNumber from the Customer belongs to the Order.
As I see, the other standard fields from the customer – like name and address – are copied automatically to the order (by WooCommerce itself).
My question is now: How I have to do this for the ACF’s?
Did I have to do this by code on my own? Adding the same AC-fields to the WC-Order and hook into the order checkout and copy the values from the customer to the order?
Or is there some kind of setup which do that and which I did not recognize?
Thx
I did not really found an answer.
My current solution is now as I described it in my question.
I added a new rule for these acf to also make them available on the orders.
Then I added a hook to new created orders, determine the acf from the user and copied the necessary values into the order acf.
function di_woocommerce_new_order( $order_id ) {
$order = new WC_Order( $order_id );
if ( !$order ) return;
$customer_id = $order->get_customer_id();
if ( !$customer_id ) return;
$customer = new WC_Customer($customer_id);
if ( !$customer ) return;
$customer_number = $customer->get_meta('customernumber');
if ( !$customer_number ) return;
// add customer number
$order->add_meta_data('customernumber', $customer_number);
// update order modified timestamp
$order->add_meta_data('order_last_updated', current_time( 'mysql' ));
$order->save_meta_data();
}
add_action( 'woocommerce_checkout_order_processed', 'di_woocommerce_new_order', 10, 1);
I want to apply a coupon when a renewal order for a subscription is created.
I use stripe as payment gateway for woocommerce subscription.
I found the filter 'wcs_renewal_order_created' from the docs : https://docs.woocommerce.com/document/subscriptions/develop/filter-reference/
I manage to apply it, it's well trigger and I can apply a coupon to this order.
The order amount is reduce by the amount of the coupon.
Problem: Stripe charges the full amount of the order, without the discount. It's just like if the order I changed was not used by Stripe.
Here is the code sample, that reduce by 5 any renewal order :
function gens_renewal_order_created($order, $subscription){
$order = new WC_Order( $order->id );
$order->set_total($order->get_total() - 5);
return $order;
}
This is a bit late but there has been no reply.
If you take a look at 'wcs_create_order_from_subscription()'
This the function where the new order is created. here also has a different filter that isn't mentioned within the documentation 'wcs_new_order_created'.
So here is what your code should be.
function gens_renewal_order_created($order, $subscription){
$order = new WC_Order( $order->id );
$order->set_total($order->get_total() - 5);
return $order;
}
add_filter('wcs_new_order_created','gens_renewal_order_created', 10, 2 );
I am trying to hook into a 3rd party application when a cart is checked out. Essentially i need to pass information about the order such as the products that are inside the order.
Everything i find points me towards the hook: woocommerce_new_order
When i use that hook i can get some information about the order but not everything.
add_action('woocommerce_new_order','order_check',10,1);
function order_check($order_id){
echo 'Order id is: '.$order_id;
$order = new WC_Order($order_id);
print_r($order);
echo '-----';
/** CHECK IF order has items */
$order_item = $order->get_items();
print_r($order_item);
exit;
}
For instance the above code sample will print the order array but when it call $order->get_items() nothing is returned.
At the time woocommerce_new_order fires, order items is not yet populated.
Instead, use the hook woocommerce_checkout_order_processed and you'll find that all items are then populated.