Woocommerce Subscriptions on-hold in COD [duplicate] - woocommerce

This question already has answers here:
Change COD default order status to "On Hold" instead of "Processing" in Woocommerce
(3 answers)
Change default order status for COD payment gateway based on user role in Woocommerce
(1 answer)
Closed 4 years ago.
I'm using Cash on delivery on my store to collect the subscriptions from users
But I have a very serious problem that the subscription are goes active without completing the order
I used this code to stop that but it didn't work
add_action( 'updated_users_subscriptions_for_order', 'wc_subs_suspend_on_cod' );
function wc_subs_suspend_on_cod( $order ) {
if ( ! is_object( $order ) ) {
$order = new WC_Order( $order );
}
foreach ( WC_Subscriptions_Order::get_recurring_items( $order ) as $order_item ) {
$subscription_key = WC_Subscriptions_Manager::get_subscription_key( $order->id, WC_Subscriptions_Order::get_items_product_id( $order_item ) );
$payment_gateways = WC()->payment_gateways->payment_gateways();
$payment_gateway = isset( $payment_gateways[ $order->recurring_payment_method ] ) ? $payment_gateways[ $order->recurring_payment_method ] : '';
if ( $payment_gateway->id == 'cod' && $order->get_status() != 'completed' ) {
WC_Subscriptions_Manager::put_subscription_on_hold( $order->user_id, $subscription_key );
}
}
}

I found it
It was the COD order statues
fixed it bu change the order to "pending"
function sv_wc_cod_order_status( $status ) {
return 'pending';
}
add_filter( 'woocommerce_cod_process_payment_order_status', 'sv_wc_cod_order_status', 15 );

Related

Change WooCommerce Status Based On Payment Method Interac (etransfer)

I want when a customer chooses to pay through Email Transfer (Interac) to go ahead and set the order status to Pending etransfer.
– My custom gateway name is custom_b9599316cc4fd28.
– My custom status slug is pending-etransfer.
add_action( 'woocommerce_order_status_changed', 'woocommerce_payment_complete_order_status', 10, 3 );
function woocommerce_payment_complete_order_status( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( $order->data['status'] == 'processing' ) {
$payment_method = $order->get_payment_method();
if ( $payment_method != 'custom_b9599316cc4fd28' ) {
$order->update_status( 'pending-etransfer' );
}
}
}
Any help is greatly appreciated.
The code as you see it.

Get relating order id on product stock change when order placed

I am developing stock status log feature to collect data of all products stock changes. I am using "woocommerce_product_set_stock" hook to write changes to custom database table. One big issue is that I cannot find out how to get related order to stock change when someone has placed a new order. When stock change is based on order cancel/refund I can get the order id from $_SERVER info but when placed a new order via checkout, there's nothing related to order id.
Customer requires order id information on stock change log so any hints, please?
When order cancelled or pending WooCommerce called this wc_reduce_stock_levels and wc_increase_stock_levels function to handle stock quantity.
You can use woocommerce_reduce_order_stock and woocommerce_restore_order_stock to write changes to your custom database table
function update_in_custom_table( $order ){
$order_id = $order->get_id();
$order = wc_get_order( $order_id );
// We need an order, and a store with stock management to continue.
if ( ! $order || 'yes' !== get_option( 'woocommerce_manage_stock' ) ) {
return;
}
// Loop over all items.
foreach ( $order->get_items() as $item ) {
if ( ! $item->is_type( 'line_item' ) ) {
continue;
}
$product = $item->get_product();
if ( ! $product || ! $product->managing_stock() ) {
continue;
}
$stock_quantity = $product->get_stock_quantity();
}
}
add_action( 'woocommerce_reduce_order_stock', 'update_in_custom_table', 10, 1 );
add_action( 'woocommerce_restore_order_stock', 'update_in_custom_table', 10, 1 );

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.

Disable specific payment methods depending on Woocommerce order status syntax error, unexpected 'elseif' (T_ELSEIF) [duplicate]

This question already has answers here:
Disable specific payment methods depending on Woocommerce order status
(2 answers)
Closed 2 years ago.
help i get this error
I am doing the same function Disable specific payment methods depending on Woocommerce order status I get
Copy and paste the same code and it didn't work
syntax error, unexpected 'elseif' (T_ELSEIF)
add_filter( 'woocommerce_available_payment_gateways', 'conditionally_hide_payment_gateways', 100, 1 );
function conditionally_hide_payment_gateways( $available_gateways ) {
// 1. On Order Pay page
if( is_wc_endpoint_url( 'order-pay' ) ) {
// Get an instance of the WC_Order Object
$order = wc_get_order( get_query_var('order-pay') );
// Loop through payment gateways 'pending', 'on-hold', 'processing'
foreach( $available_gateways as $gateways_id => $gateways ){
// Keep paypal only for "pending" order status
elseif ($gateways_id !== 'paypal' && $order->has_status('pending') ) {
unset($available_gateways[$gateways_id]);
}
}
}
// 2. On Checkout page
elseif( is_checkout() && ! is_wc_endpoint_url() ) {
// Disable paypal
if( isset($available_gateways['paypal']) ) {
unset($available_gateways['paypal']);
}
}
return $available_gateways;
}
enter image description here
The elseif inside the foreach doesn't have a preceding if, so that's your error.
add_filter( 'woocommerce_available_payment_gateways', 'conditionally_hide_payment_gateways', 100, 1 );
function conditionally_hide_payment_gateways( $available_gateways ) {
// 1. On Order Pay page
if( is_wc_endpoint_url( 'order-pay' ) ) {
// Get an instance of the WC_Order Object
$order = wc_get_order( get_query_var('order-pay') );
// Loop through payment gateways 'pending', 'on-hold', 'processing'
foreach( $available_gateways as $gateways_id => $gateways ){
// Keep paypal only for "pending" order status
if ($gateways_id !== 'paypal' && $order->has_status('pending') ) {
unset($available_gateways[$gateways_id]);
}
}
}
// 2. On Checkout page
elseif( is_checkout() && ! is_wc_endpoint_url() ) {
// Disable paypal
if( isset($available_gateways['paypal']) ) {
unset($available_gateways['paypal']);
}
}
return $available_gateways;
}

WooCommerce variables in Webhooks

I'm using WooCommerce Bookings & WooCommerce Vendors plugins and I want to get the booking & vendor information in a Webhook (on order confirmation) along with the order information to send to a 3rd party.
Currently, the Order Created webhook only contains the product order details (not Booking & Vendor).
I've been searching a lot for different answers and trying to go down a few different paths (inputting into the webhook directly vs add_order_item_meta.
Here's one way I've tried:
add_action('woocommerce_add_order_item_meta', 'add_order_item_meta', 10, 2);
function add_order_item_meta($item_id, $values) {
// Get order id to get booking details
global $post;
$order = wc_get_order( $post->ID );
$order_id = $order->get_id();
$items = $order->get_items();
$booking_data = new WC_Booking_Data_Store();
$booking_ids = $booking_data->get_booking_ids_from_order_id( $order_id );
if ( is_array( $booking_ids ) && count( $booking_ids ) > 0 ) {
foreach ( $booking_ids as $booking_id ) {
$booking = get_wc_booking( $booking_id );
$booking_product = $booking->get_product()->get_title()
$booker_start_date = $booking->get_start_date();
$booker_end_date = $booking->get_end_date();
if ( ! empty( $booking_id ) ){
woocommerce_add_order_item_meta($item_id, "Booking Title", $booking_product);
}
if ( ! empty( $booking_id ) ){
woocommerce_add_order_item_meta($item_id, "Booking ID", $booking_id);
}
if ( ! empty( $booker_start_date ) ){
woocommerce_add_order_item_meta($item_id, "Booking Start Date", $booker_start_date);
}
if ( ! empty( $booker_end_date ) ){
woocommerce_add_order_item_meta($item_id, "Booking End Date", $booker_end_date);
}
}
}
The output of this is a large array of bookings that have been made under the user, so it seems the $order_id isn't passing into the $bookings_id properly.
Also, for some reason, I haven't been able to get $items = $order->get_items(); as I keep getting Uncaught Error: Call to a member function get_items() on boolean. I want to use this to get the vendor email.
I'd prefer a webhook rather than using the API because it looks like you can't filter through booking in the API (ie you have to fetch all bookings).
Happy to get any guidance on the best way to approach it.
Thanks, Andy
So I ended up creating a hook based on payment confirmed.
It might not be the best way, but it's piping the info through based on the correct trigger.
add_action('woocommerce_webhook_payload', 'my_woocommerce_webhook_payload', 1, 4);
function my_woocommerce_webhook_payload($payload, $resource, $resource_id, $id) {
// Get Order details via order id
$payload['order_id'] = $resource_id;
$order_id = $resource_id;
$order = wc_get_order( $order_id );
$order_data = $order->get_data();
// Get booking ids from Order
$booking_ids = WC_Booking_Data_Store::get_booking_ids_from_order_id( $order_id );
$payload['booking_ids'] = $booking_ids;
// Add relevant information to each booking
if ( is_array( $booking_ids ) && count( $booking_ids ) > 0 ) {
foreach ( $booking_ids as $key=>$booking_id ) {
// Fetch booking details
$booking = get_wc_booking( $booking_id );
$booking_product = $booking->get_product()->get_title();
$booker_start_date = $booking->get_start_date();
$booker_end_date = $booking->get_end_date();
$booking_details = [];
// Add booking details
$payload["bookings"][$key] = $booking_details;
}
}
return $payload;
}

Resources