Set tax on checkout based off user payment selection woocommerce - wordpress

When a user is on my woocommerce store checkout, I want to set the tax to 0 if they choose a certain payment gateway like "paypal_pro", "cheque", "bacs", or in my case "wdc_woo_credits". Which is a woocredits plugin that allows users to pay with credits instead of a credit card.
I know this function sets the taxes correctly because when I print_r($cart_object) I see I set all the taxes to 0, but yet the checkout still applies the tax in the total.
I think I need a function that recalculates the taxes after I set it using the function below.
add_action( 'woocommerce_cart_calculate_fees','shipping_method_discount', 20, 1 );
function shipping_method_discount( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$chosen_payment_method = WC()->session->get('chosen_payment_method');
//if( $chosen_payment_method == 'cheque' ){
if( $chosen_payment_method == 'wdc_woo_credits' ){
$cart_object->set_cart_contents_taxes(0);
$cart_object->set_cart_contents_tax(0);
$cart_object->set_subtotal_tax(0);
$cart_object->set_shipping_tax(0);
$cart_object->set_total_tax(0);
$cart_object->set_fee_tax(0);
$cart_object->set_fee_taxes(0);
$cart_object->set_subtotal_tax(0);
foreach($cart_object->cart_contents as $product){
$cart_object->cart_contents[$product['key']]['line_tax'] = 0;
$cart_object->cart_contents[$product['key']]['line_subtotal_tax'] = 0;
$cart_object->cart_contents[$product['key']]['line_tax_data']['subtotal'] = 0;
$cart_object->cart_contents[$product['key']]['line_tax_data']['total'] = 0;
}
}
//echo '<pre>'; print_r($cart_object); echo '</pre>';
}
This function detects what payment selection they choose and re-runs the update checkout function. But yet the tax is still in the total.
add_action( 'woocommerce_review_order_before_payment', 'refresh_payment_methods' );
function refresh_payment_methods(){
// jQuery code
?>
<script type="text/javascript">
(function($){
$( 'form.checkout' ).on( 'change', 'input[name^="payment_method"]', function() {
$('body').trigger('update_checkout');
});
})(jQuery);
</script>
<?php
}

After lots of googling, i found out that I don't need to mess with the cart totals at all. I need to alter the current logged in customer.
I can do it with this function which removes tax for the current logged in user.
WC()->customer->set_is_vat_exempt( true );
all this goes in functions.php. You still need the woocommerce_review_order_before_payment function from above which triggers the ajax. So here's the complete code to hide tax on a certain payment gateway for only logged in users.
// calculate fees on checkout page
add_action( 'woocommerce_cart_calculate_fees','shipping_method_discount', 20, 1 );
function shipping_method_discount( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$chosen_payment_method = WC()->session->get('chosen_payment_method');
//if( $chosen_payment_method == 'cheque' ){
if( $chosen_payment_method == 'wdc_woo_credits' ){
// if user buys with credits, dont allow tax.
WC()->customer->set_is_vat_exempt( true );
}else{
// if user buys with credit card, allow tax
WC()->customer->set_is_vat_exempt( false );
}
}
// refresh the checkout page totals once user selects
add_action( 'woocommerce_review_order_before_payment', 'refresh_payment_methods' );
function refresh_payment_methods(){
// jQuery code
?>
<script type="text/javascript">
(function($){
$( 'form.checkout' ).on( 'change', 'input[name^="payment_method"]', function() {
$('body').trigger('update_checkout');
});
})(jQuery);
</script>
<?php
}

Related

The additional fee for the COD payment method not visible in the front-end

I'm trying to add an additional fee to the COD payment method.
The below code is working fine but only when I'm logetin as a administrator.
If I logout the fee doesn't show in the front end and I don't understand why.
For some reason the code is working only if I'm logget in as a administrator.
// add addition fee to cod payment method
if ( ICL_LANGUAGE_CODE=='cs' ){
add_action( 'woocommerce_cart_calculate_fees','cod_fee' );
function cod_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// get your payment method
$chosen_gateway = WC()->session->chosen_payment_method;
//echo $chosen_gateway;
$fee = 17;
if ( $chosen_gateway == 'cod' ) { //test with cash on delivery method
WC()->cart->add_fee( 'Delivery fee', $fee, false, '' );
}
}
}
// jQuery - Update checkout on payment method change
add_action( 'woocommerce_checkout_init', 'payment_methods_refresh_checkout' );
function payment_methods_refresh_checkout() {
wc_enqueue_js( "jQuery( function($){
$('form.checkout').on('change', 'input[name=payment_method]', function(){
$(document.body).trigger('update_checkout');
});
});");
}

Update order total price by payment method after order was placed

I've created a specific method of payment to manage approval or decline of orders for specific products.
Once order was approved I set order in status "Waiting for payment" and send an email to customer with link to pay.
The problem is that for some payment method I have to apply a discount.
I'm able to apply discount before order was placed ( I use it for order that doesn't require approval), but I don't know how to recalcultate the total in this moment.
For do that I use this code:
add_action( 'woocommerce_cart_calculate_fees','payment_method_discount', 20, 1 );
function payment_method_discount( $cart_object ) {
if ( is_admin() && !defined( 'DOING_AJAX' ) ) return;
foreach($cart_object->cart_contents as $cart_item_id => $cart_item) {
$payment_method_arr = array('ppcp-gateway');
foreach($payment_method_arr as $payment_method) {
$percent = 25;
$chosen_payment_method = WC()->session->get('chosen_payment_method');
if( $payment_method == $chosen_payment_method ) {
WC()->cart->add_fee( 'PayPal fee', 0 - $discount );
}
}
}
}
To trigger the update I used:
add_action( 'woocommerce_review_order_before_payment', 'refresh_payment_methods', 20, 1 );
function refresh_payment_methods() {
?>
<script type="text/javascript">
(function($){
$( 'form.checkout' ).on( 'change', 'input[name^="payment_method"]', function() {
$('body').trigger('update_checkout');
});
})(jQuery);
</script>
<?php
}
I've tried also to add the function refresh_payment_methods to wp_footer hook.

Extra fee based on user ID, user role and payment method in WooCommerce checkout

I have a piece of code that adds a small fee to the checkout for a certain user role (b2bcustomer). Everything works OK.
Now I would like one particular user ID in this user role (b2bcustomer) not to be charged a fee.
I tried to complete the code below, but the fee for this user ID is still charged. Any advice?
Code in functions.php:
add_action( 'woocommerce_cart_calculate_fees', 'b2b_fee_for_gateway' );
function b2b_fee_for_gateway() {
$user_id = get_current_user_id(); /*added*/
if(is_checkout() && WC()->customer->get_role() != current_user_can( 'b2bcustomer' ) && ($user_id != 1083)) /*added && ($user_id != 1083)*/
return;
global $woocommerce;
$chosen_gateway = $woocommerce->session->chosen_payment_method;
if ( $chosen_gateway != 'cod' && current_user_can( 'b2bcustomer' ) && ($user_ID != 1083))
$surcharge = 10;
$woocommerce->cart->add_fee( 'B2B processing cost', $surcharge, true, '');
}
}
Some comments/suggestions regarding your code attempt/question
The use of global $woocommerce; is not necessary, since $cart is passed to the callback function
You can group the conditions but also list them 1 by 1 for clarity.
It is certainly not necessary to repeat the same conditions several times
But the most important, given the chosen payment method. In WooCommerce checkout when choosing a payment method, checkout totals are not refreshed. So something additional is required to refresh checkout "order review" section
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
// 1. Only for 'b2bcustomer' user role
if ( ! current_user_can( 'b2bcustomer' ) ) return;
// 2. Exclude certain user ID
if ( get_current_user_id() == 1083 ) return;
// 3. Only for 'cod' payment method
if ( WC()->session->get( 'chosen_payment_method' ) != 'cod' ) return;
// Fee
$surcharge = 10;
// Applying
$cart->add_fee( __( 'B2B processing cost', 'woocommerce' ), $surcharge, true, '' );
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
// jQuery - Update checkout on method payment change
function action_wp_footer() {
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?>
<script type="text/javascript">
jQuery( function($){
$( 'form.checkout' ).on( 'change', 'input[name="payment_method"]', function() {
$( document.body ).trigger( 'update_checkout' );
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );

woocommerce_cart_calculate_fees doesn't run after a failed Credit Card payment

I have a custom code in a wordpress website where I add a fee if the payment method is Cash On Delivery. I do it like this through woocommerce_cart_calculate_fees
add_action( 'woocommerce_cart_calculate_fees', 'custom_handling_fee' );
function custom_handling_fee ( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_payment_id = WC()->session->get('chosen_payment_method');
if ( empty( $chosen_payment_id ) )
return;
$subtotal = $cart->subtotal;
// SETTINGS: Here set in the array the (payment Id) / (fee cost) pairs
$targeted_payment_ids = array(
'cod' => 1.5 // Fixed fee
);
// Loop through defined payment Ids array
foreach ( $targeted_payment_ids as $payment_id => $fee_cost ) {
if ( $chosen_payment_id === $payment_id ) {
$cart->add_fee( __('Fee', 'woocommerce'), $fee_cost, false );
}
}
}
However, I have the above code is not triggered at all in case of
User makes an order with payment method 'Credit Card' with a bank redirection
CC payment fails or user clicks on 'Abandon the payment' from Bank platform
User is redirected to a page from the shop informing him the transaction failed, where he get a payment button which redirects him to checkout page
User changes to Cash on Delivery
No added Fees from that page. But when I run the process from the regular checkout page, the fee is added.
You above code is working fine. I have tested and works but in order to add fees based on the payment gateway you have to trigger update_checkout to update checkout on method payment change.
add_action( 'wp_footer', 'custom_script_for_add_fess_based_on_payment_gateway' );
function custom_script_for_add_fess_based_on_payment_gateway() {
if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
return;
?>
<script type="text/javascript">
(function($){
$('form.checkout').on('change', 'input[name="payment_method"]', function(){
$(document.body).trigger('update_checkout');
});
})(jQuery);
</script>
<?php
}
Tested and works

Remove selected checkout fields with woocommerce depending on shipping method

Hello so I'm trying to figure out how to remove some billing fields using woocommerce checkout depending on the shipping method selected. So with this code I'm trying to unset the billing address, billing city, billing state and billing postcode when the customer selects local shipping but this code isn't working. Any help would be appreciated.
add_filter('woocommerce_checkout_fields', 'xa_remove_billing_checkout_fields');
function xa_remove_billing_checkout_fields($fields) {
$shipping_method ='local_pickup:1'; // Set the desired shipping method to hide the checkout field(s).
global $woocommerce;
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if ($chosen_shipping == $shipping_method) {
unset($fields['billing']['billing_address_1']); // Add/change filed name to be hide
unset($fields['billing']['billing_address_2']);
unset($fields['billing']['billing_city']);
unset($fields['billing']['billing_state']);
unset($fields['billing']['billing_postcode']);
}
return $fields;
}
Here's how I would go about solving this problem.
This will involve php, css, and javascript (jQuery).
PHP
add_filter( 'woocommerce_checkout_fields', 'xa_remove_billing_checkout_fields' );
function xa_remove_billing_checkout_fields( $fields ) {
// change below for the method
$shipping_method ='local_pickup:1';
// change below for the list of fields
$hide_fields = array( 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode' );
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
// uncomment below line and reload checkout page to check current $chosen_methods
// print_r($chosen_methods);
$chosen_shipping = $chosen_methods[0];
foreach($hide_fields as $field ) {
if ($chosen_shipping == $shipping_method) {
$fields['billing'][$field]['required'] = false;
$fields['billing'][$field]['class'][] = 'hide';
}
$fields['billing'][$field]['class'][] = 'billing-dynamic';
}
return $fields;
}
Instead of unsetting the fields, we will just alter it's requiredness.
That means, if the chosen method is the one we want to check, we will not make it required. Then we will add a hide class. With this, we can hide these fields using css. And woocommerce will not throw an error that it is required. Using jQuery, we can show/hide these fields. So if we unset it on the first run, there's nothing to show because the fields are not there in the first place and with that the page needs to reload.
So here's the javascript and the css part.
add_action( 'wp_footer', 'cart_update_script', 999 );
function cart_update_script() {
if (is_checkout()) :
?>
<style>
.hide {display: none!important;}
</style>
<script>
jQuery( function( $ ) {
// woocommerce_params is required to continue, ensure the object exists
if ( typeof woocommerce_params === 'undefined' ) {
return false;
}
$(document).on( 'change', '#shipping_method input[type="radio"]', function() {
// change local_pickup:1 accordingly
$('.billing-dynamic').toggleClass('hide', this.value == 'local_pickup:1');
});
});
</script>
<?php
endif;
}

Resources