Auto update order status to complete after 24 hours from booking end - woocommerce

I've a site based on wordpress. I'm using wc vendor plugin, woocommerce bookings and wc vendors for woocommerce bookings. I need the status of each order to automatically change to "complete" (wc-completed) 24 hours after the end of each rental (indicated with _booking_end as meta value in the database). I need the function to run once a day at 1pm. I wrote this code in my theme's functions.php file, but it doesn't work. Can you tell me if there are any errors and how can I correct them? Thank you
// Funzione per impostare gli ordini come completati se sono passate 24 ore dal booking_end
function imposta_ordine_completo() {
global $wpdb;
$orders = $wpdb->get_results(
"SELECT * FROM {$wpdb->prefix}posts WHERE post_type = 'shop_order' AND post_status = 'wc-processing'"
);
$count = 0;
// Loop through each order
foreach ( $orders as $order ) {
$order_id = $order->ID;
$booking_end = get_post_meta( $order_id, '_booking_end', true );
if ( $booking_end ) {
$current_time = current_time( 'timestamp' );
$booking_end_timestamp = strtotime( $booking_end );
$time_difference = $current_time - $booking_end_timestamp;
if ( $time_difference >= 86400 ) { // 24 hours in seconds
$order = wc_get_order( $order_id );
if ( $order && $order->get_status() === 'wc-processing' ) {
$order->update_status( 'completed' );
$count++;
}
}
}
}
error_log( "La funzione imposta_ordine_completo è stata eseguita. Sono stati completati $count ordini." );
}
// Registro il cron job che avvia la funzione ogni 24 ore
add_action( 'init', 'register_imposta_ordine_completo_event' );
function register_imposta_ordine_completo_event() {
if ( ! wp_next_scheduled( 'imposta_ordine_completo_event' ) ) {
wp_schedule_event( strtotime( '13:00:00' ), 'daily', 'imposta_ordine_completo_event' );
}
}
// Aggiungo l'hook che chiama la funzione
add_action( 'imposta_ordine_completo_event', 'imposta_ordine_completo' );
I had no results with this code

Related

Save value from a custom row added after the order table and display it in WooCommerce orders and emails

This code I wrote displays personalized information on the WooCommerce checkout page.
add_action( 'woocommerce_cart_totals_after_order_total', 'show_total_discount_cart_checkout', 9999 );
add_action( 'woocommerce_review_order_after_order_total', 'show_total_discount_cart_checkout', 9999 );
function show_total_discount_cart_checkout() {
$discount_total = 0;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$subtotal = WC()->cart->get_product_subtotal( $product, $cart_item['quantity'] );
$total = WC()->cart->total;
$pctm = 90.00;
$valor_descontado = $total - ($total / 100 * $pctm);
$sale_price = '10%';
$discount = ( WC()->cart->total - $valor_descontado );
$discount_total = $discount;
}
if ( $discount_total > 0 ) {
echo '<tr><th>VOCÊ RECEBERÁ DE CASHBACK:</th><td data-title="You">' . wc_price( $discount_total + WC()->cart->get_discount_total() ) .'</td></tr>';
}
}
The result:
I need this information to also be displayed in WooCommerce orders and emails. I believe I can come up with a solution myself to display this value on several other pages, but can someone first tell me how to save/store the value of this calculation?
First of all, I've rewritten your existing code for the following reasons:
Requesting subtotals and totals is best done outside the foreach loop, because otherwise these values ​​will be overwritten every time
The result of $subtotal is not used anywhere in your code
Since the result of $subtotal is not used anyway, loop through the cart seems unnecessary
$sale_price is also not used anywhere in your code
Since $discount_total = $discount it is not necessary to use a new variable
A session variable is created/added
Your existing code, but optimized:
function action_woocommerce_after_order_total() {
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Get cart
$cart = WC()->cart;
// Getters
$cart_total = $cart->total;
$cart_discount_total = $cart->get_discount_total();
// Settings
$pctm = 90;
// Calculations
$discounted_value = $cart_total - ( $cart_total / 100 * $pctm );
$discount_total = $cart_total - $discounted_value;
// Greater than
if ( $discount_total > 0 ) {
// Result
$result = $discount_total + $cart_discount_total;
// The Output
echo '<tr class="my-class">
<th>' . __( 'VOCÊ RECEBERÁ DE CASHBACK', 'woocommerce' ) . '</th>
<td data-title="You">' . wc_price( $result ) . '</td>
</tr>';
// Set session
WC()->session->set( 'session_result', $result );
}
}
}
add_action( 'woocommerce_cart_totals_after_order_total', 'action_woocommerce_after_order_total', 10 );
add_action( 'woocommerce_review_order_after_order_total', 'action_woocommerce_after_order_total', 10 );
To answer your question:
Step 1) We get the result from the session variable and add it as order data, so that we can use/obtain this information everywhere via the $order object
// Add as custom order meta data and reset WC Session variable
function action_woocommerce_checkout_create_order( $order, $data ) {
// Isset
if ( WC()->session->__isset( 'session_result' ) ) {
// Get
$result = (float) WC()->session->get( 'session_result' );
// Add as meta data
$order->update_meta_data( 'result', $result );
// Unset
WC()->session->__unset( 'session_result' );
}
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );
Step 2) Use the woocommerce_get_order_item_totals filter hook, which will allow you to add a new row to the existing tables with the $result.
The new row will be added in:
Email notifications
Order received (thank you page)
My account -> view order
function filter_woocommerce_get_order_item_totals( $total_rows, $order, $tax_display ) {
// Get meta
$result = $order->get_meta( 'result' );
// NOT empty
if ( ! empty ( $result ) ) {
// Add new row
$total_rows['total_result']['label'] = __( 'VOCÊ RECEBERÁ DE CASHBACK', 'woocommerce' );
$total_rows['total_result']['value'] = wc_price( $result );
}
return $total_rows;
}
add_filter( 'woocommerce_get_order_item_totals', 'filter_woocommerce_get_order_item_totals', 10, 3 );

Auto update product custom field based on WooCommerce product stock

I have an ACF field "DeliverySpeed" attached to Products with the values 'Fast' and 'Slow'
I would like to update this field to change to value 'Slow' every time the product stock is zero or less (product on backorder)
I am still learning PHP so far this is what I got to but I am sure different things are missing, I just don't know in which direction to go:
based on acf update field documentation
function automatically_change_delivery( ) {
global $product;
$fieldkey = "DeliverySpeed";
$valueslow = "Slow";
if($product->get_stock_quantity()<0) { update_field( $field_key, $valueslow, $post_id );
} }
Thank you in advance for the attention and advice.
The following code will update automatically your product custom field once order has reduced product stock levels. So when product has stock the custom field value will be 'Fast' otherwise 'Slow'.
The code:
add_action( 'woocommerce_payment_complete', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
add_action( 'woocommerce_order_status_completed', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
add_action( 'woocommerce_order_status_processing', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
add_action( 'woocommerce_order_status_on-hold', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
function update_product_custom_field_( $order_id, $order = '' ) {
// Continue only when order has reduced product stock levels
if ( wc_string_to_bool( get_post_meta( $order_id, '_order_stock_reduced', true ) ) )
return $order_id; // Exit
if( ! $order || ! is_a( $order, 'WC_Order') ) {
$order = wc_get_order( $order_id ); // Get the WC_Order object if it's empty
}
$field_key = 'DeliverySpeed';
// Loop through order items
foreach ( $order->get_items() as $item ) {
$product = $cart_item['data'];
$product_id = $product->get_id();
$stock_qty = $product->get_stock_quantity();
$field_value = get_field( $field_key, $product_id ); // Get ACF field value
if ( $stock_qty <= 0 && $field_value === 'Fast' ) {
update_field( $field_key, 'Slow', $product_id );
}
elseif ( $stock_qty > 0 && $field_value === 'Slow' ) {
update_field( $field_key, 'Fast', $product_id );
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should works.

WooCommerce change price when adding product to order in admin

We have customers who have different discount percentages. This is all programmed and working on the front end when adding products to the cart, but if using the back end order admin to add a new product I can't seem to find a way to calculate the new product price based on the user's discount. Is there a way to change the price in the woocommerce_new_order_item hook when adding a product to an existing order in the order admin?
Here's what I have so far:
function action_woocommerce_new_order_item( $item_id, $item, $order_id ) {
// only run this from the WP admin section
if ( !is_admin() )
return;
$item_type = $item->get_type();
// return if this is not a product (i.e. fee, tax, etc.)
if ( $item_type != 'line_item' )
return;
$product = wc_get_product( $item->get_product_id() );
if ( !$product )
return;
$current_price = $product->get_price();
$quantity = $item->get_quantity();
// here I get the order's user's discount percentage and calculate the new discounted price
// custom function
$discounted_price = get_discounted_price( $current_price, $users_discount );
$new_price = ( !empty($discounted_price) ) ? $discounted_price : $current_price;
// this doesn't work
$item->set_price( $new_price );
// and this doesn't work
$product->set_price( $new_price );
// this appears to work but I'm not sure if this the best way to accomplish this
$item->set_total( $price * $quantity );
}
add_action( 'woocommerce_new_order_item', 'action_woocommerce_new_order_item', 10, 3 );
Any help would be greatly appreciated!
Thanks
This works for adding item meta and changing the item price in the order admin screen:
function action_woocommerce_new_order_item( $item_id, $item, $order_id ) {
// only run this from the WP admin section
if ( !is_admin() )
return;
$item_type = $item->get_type();
// return if this is not a product (i.e. fee, tax, etc.)
if ( $item_type != 'line_item' )
return;
$product = wc_get_product( $item->get_product_id() );
if ( !$product )
return;
$current_price = $product->get_price();
$size = $product->get_attribute('size');
// add custom item meta to order
if ( $size ) {
wc_add_order_item_meta( $item_id, 'Size', $size , false );
}
$order = wc_get_order( $order_id );
$order_user = $order->get_user();
$order_user_id = $order->get_user_id();
// get this order's user's discount %
$users_discount = get_user_meta( $order_user_id, 'discount', true );
$users_discount = ( $users_discount > 0 ) ? $users_discount : 0;
// calculate the discounted price based on the user's discount (custom function)
$discounted_price = get_discounted_price( $current_price, $users_discount );
$quantity = $item->get_quantity();
$new_price = ( !empty($discounted_price) ) ? $discounted_price : $current_price;
$item->set_total( $new_price * $quantity );
};
add_action( 'woocommerce_new_order_item', 'action_woocommerce_new_order_item', 10, 3 );

Update Order Programmatically Doesn't Update Totals

I'm trying to update the quantities of an ordered product and when doing so I would like the order to reflect the actual cost. What I find happens is that the Product Cost is reduced to match the total and the order total is never actually updated. I've supplied a simple sample below:
function prefix_update_woo_order() {
$order_id = 123; // This needs to be a real order or there will be errors
$order_item_id = 5; // This needs to be a real order item ID or there will be errors.
$order = new WC_Order( $order_id );
$order_items = $order->get_items();
$order_items[ $order_item_id ]->set_quantity( 2 );
$order->calculate_taxes();
$order->calculate_totals();
$order->save();
}
add_action( 'admin_init', 'prefix_update_woo_order' );
For example, a "Beanie with Logo" product is on sale for $18.00 and I originally buy 1. I want to programmitically update the order item to a quantity of 2 instead of 1 after the order has been placed. I would expect the total to be $36.00 but what I'm finding is that the product cost changes to match the total price. Instead of a cost of $18.00 for a "Beanie with Logo" the quantity is updated to 2 and the cost is reduced to $9.00ea.
In short, what I want to do is update an existing order items quantity and have the totals updated to reflect the new quantity cost, discount, taxes. What methods do I need to use to achieve this?
Hello I think this code will change your problem
add_action( 'admin_init', 'test_order_update_order' );
function test_order_update_order() {
$order_id = 80; // This needs to be a real order or there will be errors
$order_item_id = 11; // This needs to be a real order item ID or there will be errors.
$quantity = 2; //quantity which you want to set.
$order = new WC_Order( $order_id );
$order_items = $order->get_items();
foreach ( $order_items as $key => $value ) {
if ( $order_item_id == $key ) {
$product_value = $value->get_data();
$product_id = $product_value['product_id'];
}
}
$product = wc_get_product( $product_id );
$price = $product->get_price();
$price = ( int ) $quantity * $price;
$order_items[ $order_item_id ]->set_quantity( 2 );
$order_items[ $order_item_id ]->set_subtotal( $price );
$order->calculate_taxes();
$order->calculate_totals();
$order->save();
}
i have not tried what you are trying to achieve before. What i see in your code is that $order_items is an array of Items Objects produced from WC_Order::get_items(), but i dont see the WC_Order Instance being notified that the order items have changed. I would expect a method like $order->update_cart($order_items); I believe i found some usefull links for more research
https://hotexamples.com/examples/-/WC_Order/-/php-wc_order-class-examples.html
woocommerce - programmatically update cart item quantity
Sorry, i was not much of help!
Use the follows code snippet to do the above task -
function prefix_update_woo_order() {
$order_id = 123; // This needs to be a real order or there will be errors
$order_item_id = 5; // This needs to be a real order item ID or there will be errors.
$order = wc_get_order( $order_id );
if( $order && !wc_get_order_item_meta( $order_item_id, '_order_item_data_updated', true ) ) {
$item_price = wc_get_order_item_meta( $order_item_id, '_line_total', true );
$updated_item_quantity = 2;
wc_update_order_item_meta( $order_item_id, '_qty', $updated_item_quantity );
wc_update_order_item_meta( $order_item_id, '_line_total', $item_price * $updated_item_quantity );
$order->calculate_totals();
$order->save();
// set flag
wc_add_order_item_meta( $order_item_id, '_order_item_data_updated', true, true );
}
}
add_action( 'admin_init', 'prefix_update_woo_order' );
Codes goes to your active theme's functions.php
This is what I've come up with. I've tried to use the wc_format_decimal() where applicable. Seems like a lot of work to simply update an order items quantity but it is what it is.
The bottom comment is unnecessary but if you're using the Cost of Goods plugin then that will take care of that.
/**
* Update the order item quantity and totals
* #param Integer $order_id
* #param Integer $order_item_id
* #param Integer $quantity - Quantity to set
*
* #return void
*/
function prefix_update_woo_order( $order_id, $order_item_id, $quantity ) {
// Get Order, Item, and Product Data
$order = new WC_Order( $order_id );
$order_items = $order->get_items();
$line_item = $order_items[ $order_item_id ];
$variation_id = $line_item->get_variation_id();
$product_id = $line_item->get_product_id();
$product = wc_get_product( $variation_id ? $variation_id : $product_id );
$quantity_old = $line_item->get_quantity();
// Calculate Old and New Discounts
$discount = wc_format_decimal( $line_item->get_subtotal() - $line_item->get_total(), '' );
if( ! empty( $discount ) ) {
$discount_per_qty = wc_format_decimal( ( $discount / $quantity_old ), '' );
$discount = wc_format_decimal( ( $discount_per_qty * $quantity ), '' );
}
// Set Quantity and Order Totals
$line_item->set_quantity( $quantity );
$total = wc_get_price_excluding_tax( $product, array( 'qty' => $line_item->get_quantity() ) ); // Also see `wc_get_price_excluding_tax()`
$line_item->set_subtotal( $total ); // Without Discount
$line_item->set_total( $total - $discount ); // With Discount
// Save Everything
$line_item->save();
wc_save_order_items( $order_id, $order_items );
/**
* If using the 'Cost of Goods' Plugin
* - - - - - -
* $cog = $line_item->get_meta( '_wc_cog_item_cost', true );
* $new_cog = wc_format_decimal( ( $quantity * $cog ), '' );
* $line_item->update_meta_data( '_wc_cog_item_total_cost', $new_cog );
* wc_cog()->set_order_cost_meta( $order_id, true );
*/
}

woocommerce_cancel_unpaid_orders filter is not working on live - Woocommerce

The below code is working fine on localhost but is not working on live server
The code is used to Mark all unpaid order as 'Failed' if the payment is not received even after 10 minutes of order creation
The code is a modified version of code taken from Woocommerce plugin (line 852 to 877)
// Unpaid orders marked as Failed if payment is not received even after 10 minutes of order creation
function custom_wc_cancel_unpaid_orders() {
$held_duration = strtotime( '-10 minutes');
$data_store = WC_Data_Store::load( 'order' );
$unpaid_orders = $data_store->get_unpaid_orders( strtotime( '-10 minutes', current_time( 'timestamp' ) ) );
if ( $unpaid_orders ) {
foreach ( $unpaid_orders as $unpaid_order ) {
$order = wc_get_order( $unpaid_order );
if ( apply_filters( 'woocommerce_cancel_unpaid_order', 'checkout' === $order->get_created_via(), $order ) ) {
$order->update_status( 'failed', __( 'Unpaid order marked failed - time limit reached.', 'woocommerce' ) );
}
}
}
wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
}
add_action( 'woocommerce_cancel_unpaid_orders', 'custom_wc_cancel_unpaid_orders' );
Can someone tell me why it works on localhost but not on live server?
Use this plugin and use a cron job for function: woocommerce_cancel_unpaid_orders_woo
<?php
/**
* Plugin Name: WooCommerce Cron Proxy
*/
add_action( 'woocommerce_cancel_unpaid_orders_woo', function() {
do_action_ref_array( 'woocommerce_cancel_unpaid_orders', func_get_args() );
}, 10, 10 );
?>

Resources