Im trying to set a value "paid" in my custom table when the payment was successful / the customer gets redirectd to the thankyou page.
Im not sure if its secure enough to insert "paid => 1" just when the buyer reached the thankyou page. Thats why i wanted to check if the order was really paid, completed or processing.
Now i figured some payment methods are slow? When i checkout with Klarna my method works and it inserts paid = 1, but when I choose Paypal my Method will die and return: "WASNT PAID". But when I refresh the thankyou-page like 30 secs later it works. So i came to the conclusion that the order_status isnt set fast enough? Is there a cleaner way than mine?
add_action('woocommerce_thankyou', 'ceb_order_complete', 10, 1);
function ceb_order_complete( $order_id ) {
if ( ! $order_id )
return;
// Getting an instance of the order object
$order = wc_get_order( $order_id );
if($order->is_paid() || $order->has_status('processing') || $order->has_status('completed')) {
global $wpdb;
$payID = WC()->session->get( 'payID' );
if(!empty($payID)) {
if(!$wpdb->update($wpdb->prefix."ceb_registrations", array("paid"=>1), array("payID"=>$payID))) {
die("ERROR IN PAYMENT COMPLETE");
}
}
} else {
die("WASNT PAID");
}
}
"woocommerce_thankyou" hook will run each time you see/refresh thankyou page.
The most suitable way is to process data after payment received. For that you can use "woocommerce_payment_complete".
add_action('woocommerce_payment_complete', 'payment_complete_callback');
function payment_complete_callback($order_id)
{
$order = wc_get_order($order_id);
$user = $order->get_user();
// do what ever you want to do using $order object of the WC_Order class providing many functions
}
Related
I used artificial intelligence for the first time
But the code you told me is not working
To convert veins automatically from treatment to complete after 30 seconds
Only on virtual products
There are two specific payment methods
But it doesn't work
// Add a 30 second delay for virtual products
add_filter( 'woocommerce_payment_complete_order_status', 'wc_delay_virtual_order', 10, 2 );
function wc_delay_virtual_order( $order_status, $order ) {
if ( $order->has_downloadable_item() && ! $order->has_status( 'completed' ) ) {
return 'on-hold'; // change to any other status you wish to use.
}
return $order_status;
}
add_action( 'woocommerce_thankyou', 'wc_delay_virtual', 30 );
function wc_delay_virtual( $orderid ) {
// Get the order object and check for downloadable items.
$order = new WCOrder($orderid);
if ( $order->hasDownloadableItem() ) {
// Set a 30 second delay for virtual products.
sleep(30);
// Update the order status to complete.
$order->updateStatus('completed');
}
}
// Add a custom payment gateway for MobileWallet and Reference Code payments.
add-filter('woocommerce-payment-gateways','wc-add-mobilewallet-referencecode');
function wc-add-mobilewallet-referencecode($methods){
$methods[] = 'WCMobileWallet'; // MobileWallet payment gateway class name.
$methods[] = 'WCReferenceCode'; // Reference Code payment gateway class name.
return $methods;
}
I tried to add this code inside plugin and inside function.php
I am waiting for your response to solve my problem, thank you
The part of your code posted below has an issue. you cant use - in between function name like wc-add-mobilewallet-referencecode instead it should be wc_add_mobilewallet_referencecode using and underscore "_"
Your correct code should look so:
add_filter('woocommerce-payment-gateways','wc_add_mobilewallet_referencecode');
function wc_add_mobilewallet_referencecode($methods){
$methods[] = 'WCMobileWallet'; // MobileWallet payment gateway class name.
$methods[] = 'WCReferenceCode'; // Reference Code payment gateway class name.
return $methods;
}
And since you just need to change order status to complete on downloadable product, just need the code below:
add_filter( 'woocommerce_payment_complete_order_status', 'wc_delay_virtual_order', 10, 2 );
function wc_delay_virtual_order( $order_status, $order ) {
if ( $order->has_downloadable_item() && ! $order->has_status( 'completed' ) ) {
sleep(30);
return 'completed'; //Here should be complete.
}
return $order_status;
}
The requirement doesn't seem to work for the following reasons:
Payment gateways will have their configuration where after each successful order, the status will be updated based on the configuration.
Making the customer wait 30 seconds on the browser is not recommended.
Even if you forcefully update the order status on the thankyou page hook, what will happen next is if the woocommerce or any third-party plugin or payment plugin has different order statuses, those will be updated as soon as your update is done.
Nevertheless, there are three possible ways for your requirement.
Search for payment configuration and update the order completion status there. For example, in the case of Novalnet Payment Gateway, I use their configuration, so I need not do anything here.
On the WooCommerce shop backend, you have the settings you can use it. Refer https://woocommerce.com/document/woocommerce-order-status-control/
Based on your business logic, you can set up a cron to update all the virtual orders that aren't on complete order status. Refer https://developer.wordpress.org/plugins/cron/
I have made a simple webshop with woocommerce, with three payment methods. iDeal and by direct bank transfer and on account. The order ID is created based on the payment method. for example, if payment is made with iDEAL, the order id becomes ID190100; if payment is made on account, the order id becomes RK190100. I get this working with the plugin
"Sequential Order Numbers for WooCommerce" from BeRocket but these are already created before the payment is complete. The order ID must only be finalized once the payment has been made. Now orders that have not yet paid, and may not be paying, will receive a fixed order ID. So is it possible to create a temporary order id and when the order is completed change the order id based on payment method?
Woocommerce by default will use the post ID of the order for the order ID. This is evident when viewing the WC_Order::get_order_number() method. If you want to use a custom order number to display, you'll need to add a filter on woocommerce_order_number to load in a different value.
An example script would be:
add_action( 'woocommerce_order_status_completed', 'wc_change_order_id' );
function wc_change_order_id( $order_id ) {
$order = wc_get_order( $order_id );
$method = $order->get_payment_method(); // need check this
if ( $method === 'account' ) {
$number = 'ID' . $order->get_id();
$order->update_meta_data('_new_order_number', $number );
}
}
add_filter('woocommerce_order_number', function($default_order_number, \WC_Order $order) {
//Load in our meta value. Return it, if it's not empty.
$order_number = $order->get_meta('_new_order_number');
if(!empty($order_number)) {
return $order_number;
}
// use whatever the previous value was, if a plugin modified it already.
return $default_order_number;
},10,2);
Try this. It's very quick example. Hope help.
add_action( 'woocommerce_order_status_completed', 'wc_change_order_id' );
function wc_change_order_id( $order_id ) {
$order = wc_get_order( $order_id );
$method = $order->get_payment_method(); // need check this
if ( $method === 'account' ) {
$number = 'ID' . $order->get_id();
$order->set_id( $number );
$order->save();
}
}
I am using Woocommerce with Woocommerce Booking plugin and I would like to update the order status to refunded every time a paid booking is cancelled.
I've found some answers on StackOverFlow, but still can't manage to solve this requirement.
I know I might be completely wrong, but this the last try I made and obviously it didn't work:
add_action('woocommerce_booking_paid_to_cancelled','change_status_to_refund', 10, 2);
function change_status_to_refund($booking_id, $order_id) {
$booking = new WC_Order($booking_id);
$order = new WC_Order($order_id);
$booking_status = $booking->get_status();
if($booking_status != 'paid'){
$order->update_status('refund', 'order_note');
}
}
Any help is welcome.
You are not using the correct arguments for woocommerce_booking_{ status_from }_to_{ status_to } action hook in your function, which are:
The booking ID: $booking_id,
The Booking Object $booking.
So you need to get the Order from the Booking in your code, to be able to update the Order status.
Note: The condition $booking_status != 'paid' is not really needed.
So your code will be much simpler and effective:
add_action('woocommerce_booking_paid_to_cancelled','cancelled_booking_order_status_cahnged_to_refund', 10, 2);
function cancelled_booking_order_status_cahnged_to_refund( $booking_id, $booking ) {$
// Get the WC_Order object from a booking
$order = wc_get_order( wp_get_post_parent_id( $booking_id ) );
// Update order status
if( is_a($order, 'WC_Order') )
$order->update_status('refund');
}
Code goes on function.php file of your active child theme (or active theme). It should works.
Documentation: Woocommerce booking developer documentation for filter and action hooks
I have set up a custom Woocommerce off-side payment gateway, the communication from my website to the Gateway works fine. The user gets redirected to the gateway and after the payment he gets returned to the (by Woocommerce) defined return URL.
In the API documentation of the gateway, it says that the payment gateway will add a query string variable to the return url. This variable can have the following values:
response=approved
response=declined
response=error
In the documentation is this exampple:
If backURL = http://www.test.com/return.asp
Then the response will be http://www.test.com/return.asp?response=approved
To process the order I have created the code below (first just for the state of response=approved)
However, the order status does not get updated, when I test it. I hope somebody can point me in the right direction to find the error.
On top of the gateway I have extended query_vars with:
function add_query_vars_filter( $vars ){
$vars[] = "response";
return $vars;
}
add_filter( 'query_vars', 'add_query_vars_filter' );
After sending the user to the gateway I have this function to handle and process the query string in the return URL:
function check_example_response(){
global $woocommerce;
$transaction_id = get_query_var( 'response' );
$order = new WC_Order( $order_id );
// check if payment was successful
if ($transaction_id == 'approved') {
//Update order status
$order->update_status( 'processing', 'Payment received, your order is currently being processed.' );
//Add admin order noote
$order->add_order_note('Payment Via Example Gateway<br />Transaction ID: '.$order);
//Add customer order note
$order->add_order_note('Payment Received.<br />Your order is currently being processed.<br />We will be shipping your order to you soon.<br />Transaction ID: '.$order, 1);
$message = 'Thank you for shopping with us.<br />Your transaction was successful, payment was received.<br />Your order is currently being processed.';
$message_type = 'success';
}
// Reduce stock levels
$order->reduce_order_stock();
// Empty cart
WC()->cart->empty_cart();
}}
I have also registered this function with:
add_action( 'woocommerce_api_wc_example', array( $this, 'check_example_response' ) );
Wordpress also does not give any hints in DEBUG mode, so I am right now quite frustrated and hope somebody can help me.
Thank you!
I am in the middle of creating an additional plugin which is a custom payment gateway using the Woocommerce plugin and a child theme to style it.
This is working and I see the payment form correctly and items which is great.
The issue I have is with the payment process option.
The checkout page has an i-frame to the payment solution and is supposed to show only when an order is created and an ID is present. And to make sure we have all the persons details etc.
However the process payment take you to the thanks you page instead.
It also dumps the cart session.
even if I redirect the URL back to the cart page by playing around with it, it still kills the cart.
This would be fine in normal circumstances as I'd expect it to go to a payment page, checkout and be done. But I do not want to do this because this site has to mirror one that is currently live and how that works.
The function in my extended class is this.
public function process_payment( $order_id ) {
global $woocommerce;
#$order = wc_create_order();
///
$order = new WC_Order( $order_id );
// Mark as on-hold (we're awaiting the cheque)
$order->update_status('on-hold', __( 'Awaiting Confirmation of Funds', 'woocommerce' ));
// Reduce stock levels
///$order->reduce_order_stock();
// Remove cart
//$woocommerce->cart->empty_cart();
// Return thankyou redirect
return array(
'refresh' => true,
'reload' => false,
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
///return $order_id;
}
As you can see I commented out the bit where to empty the cart and the also the endpoint brings in the thank you template instead of just staying on the same page.
So far I have tried:
Replicating the code on my checkout to the thank you page and that
results in an undefined checkout, because the process removes it by
then
Changing the end-point reference to the same as checkout
Creating another page and putting the same shortcode on it
Nothing works, and I have been through the plugin and can see a few things I could do.
Copy the process_payment function into my extended class and
effectively re-write it
or
Find a filter similar to below that could do what I need
add_action( 'woocommerce_thankyou', function(){
global $woocommerce;
$order = new WC_Order();
if ( $order->status != 'failed' ) {
wp_redirect( home_url() ); exit; // or whatever url you want
}
});
What I need is it to stay on the same page (refresh) the same way it does when it checks the details to refresh the totals.
Create an order with those current details in and return an order number
Will not kill the cart session at that point, so if I was to refresh the browser for arguments sake it would stay live. (I will work out a way to kill the cart when the person navigates away and a unique session has been created at that point).
Its just this bit I have been fighting with for the past couple of days and not sure the best way.
Any help or pointers would be greatly appreciated.
thanks
Andi
Ok figured this one out.
There is a header action that clears the cart.
We needed to add some more statuses to the array so that it ignores it.
1st remove the action and then add your own method.
function st_wc_clear_cart_after_payment( $methods ) {
global $wp, $woocommerce;
if ( ! empty( $wp->query_vars['order-received'] ) ) {
$order_id = absint( $wp->query_vars['order-received'] );
if ( isset( $_GET['key'] ) )
$order_key = $_GET['key'];
else
$order_key = '';
if ( $order_id > 0 ) {
$order = wc_get_order( $order_id );
if ( $order->order_key == $order_key ) {
WC()->cart->empty_cart();
}
}
}
if ( WC()->session->order_awaiting_payment > 0 ) {
$order = wc_get_order( WC()->session->order_awaiting_payment );
if ( $order->id > 0 ) {
// If the order has not failed, or is not pending, the order must have gone through
if ( ! $order->has_status( array( 'failed', 'pending','pending-st-cleared-funds','on-hold' ) ) ) { ///// <- add your custom status here....
WC()->cart->empty_cart();
}
}
}
}
function override_wc_clear_cart_after_payment() {
remove_filter('get_header', 'wc_clear_cart_after_payment' );
add_action('get_header', 'st_wc_clear_cart_after_payment' );
}
add_action('init', 'override_wc_clear_cart_after_payment');