This code adds a fee of 29 when PayPal is selected on checkout page for a defined country. However, it's not being taxed. The total tax right now is based on items + shipping.
How would I go about to add tax to the custom fee without double taxing people?
This is my code:
function woocommerce_custom_fee( ) {
global $woocommerce;
$county = array('SE');
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
$chosen_gateway = $woocommerce->session->chosen_payment_method ;
$fee = 29;
if ( $chosen_gateway == 'paypal' and ( in_array( WC()->customer->get_shipping_country(), $county ) ) ) { //test with paypal method
$woocommerce->cart->add_fee( 'Paypal Avgift', $fee, false, '' );
}
}
add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_fee' );
function cart_update_script() {
if (is_checkout()) :
?>
<script>
jQuery( function( $ ) {
// woocommerce_params is required to continue, ensure the object exists
if ( typeof woocommerce_params === 'undefined' ) {
return false;
}
$checkout_form = $( 'form.checkout' );
$checkout_form.on( 'change', 'input[name="payment_method"]', function() {
$checkout_form.trigger( 'update' );
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'cart_update_script', 999 );
Thanks
To enable Tax in WC_Cart add_fee() method, you need to set the third argument to true.
You can remove the last argument as it is already the default value.
In woocommerce_cart_calculate_fees action hook you can use directly the cart object argument $cart_obj that is include in it.
Also global $woocommerce has been replaced by WC() object which include it (so no need anymore to declare global $woocommerce.
Below I have clean and reordered your first hooked function, try it (it will act as yours, and fee will be taxable):
add_action( 'woocommerce_cart_calculate_fees','conditional_payment_mothod_custom_fee', 10, 1 );
function conditional_payment_mothod_custom_fee( $cart_obj ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) || ! is_checkout() )
return;
$fee = 19;
$target_county = 'SE';
$chosen_gateway = WC()->session->chosen_payment_method;
$shipping_country = WC()->customer->get_shipping_country();
// Enabling fee with paypal method (and 'SE' country)
if('paypal' == $chosen_gateway && $shipping_country == $target_county)
$cart_obj->add_fee( __('Paypal Avgift'), $fee, true ); // Tax enabled for the fee
}
Here $cart_obj act just as $woocommerce->cart or WC()->cart
Now in your second function, you can use the jQuery shortcut change() and you can make your code more modern and compact, this way:
add_action( 'wp_footer', 'checkout_update_script', 999 );
function checkout_update_script() {
if ( is_checkout() ) :
?>
<script>
jQuery( function($){
// Checking that the variable "woocommerce_params" is defined to continue
if ( 'undefined' === typeof woocommerce_params )
return false;
$('form.checkout').change('input[name="payment_method"]', function(){
$(this).trigger( 'update' );
});
});
</script>
<?php
endif;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce versions 2.6.x and 3.0+
Related
I'm struggling with applying a fee for an array of user roles if and when a specific payment gateway is selected.
The code I've written works fine if I do not check the user role, but once I try and do that, it does not.
I've removed (commented) the user role if statement in the code and I'm asking for help making it work.
I need to check if the user role match my array and if it does, check the payment gateway. If the payment gateway match too, apply the fee.
This is my code:
add_action( 'woocommerce_cart_calculate_fees', 'custom_fee', 20, 1 );
function custom_fee ($cart){
if (is_admin() && !defined('DOING_AJAX')) return;
if (!is_user_logged_in()) return;
if (!is_checkout() && !is_wc_endpoint_url()) return;
$customer_role = wp_get_current_user();
$roles_to_check = array( 'vendor', 'external' );
$payment_method = WC()->session->get('chosen_payment_method');
// if (!in_array($roles_to_check, $customer_role->roles)) return;
if ('bacs' == $payment_method){
$payment_fee = $cart->subtotal * 0.05;
$cart->add_fee( 'Payment Fee', $payment_fee, true );
}
}
You could use the following, explanation with comments added in the code
Conditions that must be met in this code are:
only for certain user roles
checks on payment method
function custom_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
return; // Only checkout page
if ( ! is_user_logged_in())
return;
// Get current WP_User Object
$user = wp_get_current_user();
// User roles
$roles = ( array ) $user->roles;
// Roles to check
$roles_to_check = array( 'vendor', 'external', 'administrator' );
// Compare
$compare = array_diff( $roles, $roles_to_check );
// Result is empty
if ( empty ( $compare ) ) {
// Payment method
$payment_method = WC()->session->get('chosen_payment_method');
// Condition equal to
if ( $payment_method == 'bacs' ) {
// Calculate
$payment_fee = $cart->subtotal * 0.05;
// Add fee
$cart->add_fee( 'Payment Fee', $payment_fee, true );
}
}
}
add_action( 'woocommerce_cart_calculate_fees', 'custom_fee', 10, 1 );
EDIT
To complete my answer, see the answer from #LoicTheAztec
The answer of #7uc1f3r is good, but something important is missing from it.
In WooCommerce checkout when choosing a payment method, checkout totals are not refreshed. So something additional is required to refresh checkout "order review" section:
// jQuery - Update checkout on payment method change
add_action( 'wp_footer', 'custom_checkout_jquery_script' );
function custom_checkout_jquery_script() {
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;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related: Add fee based on specific payment methods in WooCommerce
In WooCommerce, I need to add a fee when user select specific shipping methods.
I have found "Add a fee based on shipping method and payment method in Woocommerce" answer, that looks like what I need.
I have tried the code and removed the pieces about payment method which I don't need.
The problem is that when I change the shipping method the fee is not added, looks like that I just keep the old value in the session.
This is my code:
// Add a conditional fee
add_action( 'woocommerce_cart_calculate_fees', 'add_cod_fee', 20, 1 );
function add_cod_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0];
var_dump($chosen_shipping_method_id); die;
switch($chosen_shipping_method_id){
case 'flat_rate:3': {
$fee_text = __( "Spese per ritiro", "woocommerce" );
$cart->add_fee( $fee_text, 12, false );
break;
}
case 'flat_rate:4': {
$fee_text = __( "Spese per consegna a domicilio", "woocommerce" );
$cart->add_fee( $fee_text, 24, false );
break;
}
}
}
// Refresh checkout on payment method change
add_action( 'wp_footer', 'refresh_checkout_script' );
function refresh_checkout_script() {
// Only on checkout page
if( is_checkout() && ! is_wc_endpoint_url('order-received') ) :
?>
<script type="text/javascript">
jQuery(function($){
// On payment method change
$('form.woocommerce-checkout').on( 'change', '.shipping_method', function(){
// Refresh checkout
$('body').trigger('update_checkout');
});
})
</script>
<?php
endif;
}
It just keep the old value in $chosen_shipping_method_id
Your code works nicely if you comment var_dump($chosen_shipping_method_id); die;. Also the jQuery script is not needed as it was for payment methods that doesn't update checkout by default.
So there is something else that is making trouble in your case.
Now I have revisited a bit your code (it will work too):
// Add a conditional fee
add_action( 'woocommerce_cart_calculate_fees', 'flat_rate_based_fee', 20, 1 );
function flat_rate_based_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
if( in_array( 'flat_rate:3', $chosen_shipping_methods ) ) {
$fee = array( 'text' => __( "Spese per ritiro", "woocommerce" ), 'amount' => 12 );
} elseif ( in_array( 'flat_rate:4', $chosen_shipping_methods ) ) {
$fee = array( 'text' => __( "Spese per consegna a domicilio", "woocommerce" ), 'amount' => 24 );
}
if( isset($fee) ) {
$cart->add_fee( $fee['text'], $fee['amount'], false );
}
}
Code goes in functions.php file of your active child theme (or active theme).
Tested and work (on Woocommerce 3.5.x and 3.6.x). See it working live on this test server.
I need to add Handling fee in checkout page for some state. For this I am using woocommerce add_fee option. But my problem is on checkout page the handling fee is showing but not add to subtotal. Here is my code
add_action( 'woocommerce_cart_calculate_fees','xa_custom_surcharge' );
function xa_custom_surcharge() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$state= array('MH');
$surcharge = 10;
if ( in_array( WC()->customer->shipping_state, $state ) ) {
$woocommerce->cart->add_fee( 'Additional Charge', $surcharge, true, '' );
}
}
Can anyone please help me.
Your code is outdated since WooCommerce 3:
Properties can't not be accessed anymore on CRUD objects, so you should use instead methods like get_shipping_state() in your case.
global $woocommerce and $woocommerce->cart are outdated & replaced directly by WC()->cart
The WC_Cart Object $cart variable is available in the hooked function as an argument.
The correct code is:
add_action( 'woocommerce_cart_calculate_fees','add_custom_surcharge', 10, 1 );
function add_custom_surcharge( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$state = array('MH');
$surcharge = 10;
if ( in_array( WC()->customer->get_shipping_state(), $state ) ) {
$cart->add_fee( 'Additional Charge', $surcharge, true );
}
}
Now when using the Fee API, the fee amount is displayed as a total and added to gran total at the end, but NOT to the subtotal:
The subtotal in WooCommerce is made only from cart items subtotals…
I was trying to make a code snippet for functions.php which would apply a discount of 2 % for cart totals when the role "subscriber" and the payment method "credit-card" are both selected. My progress so far
function discount_when_role_and_payment(/* magic */) {
global $woocommerce;
if ( /* credit-card selected */ && current_user_can('subscriber') ) {
/* get woocommerce cart totals, apply 2% discount and return*/
}
return /*cart totals after discount*/;
}
add_filter( '/* magic */', 'discount_when_role_and_payment' );
Could anyone help complete this? Or atleast point to the right direction?
The following code will apply a discount of 2% to cart when a targeted payment method has been selected by a subscriber user role only on checkout page:
// Applying conditionally a discount
add_action( 'woocommerce_cart_calculate_fees', 'discount_based_on_user_role_and_payment', 20, 1 );
function discount_based_on_user_role_and_payment( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return; // Exit
// Only on checkout page for 'subscriber' user role
if ( ! ( is_checkout() && current_user_can('subscriber') ) )
return; // Exit
// HERE Below define in the array your targeted payment methods IDs
$targeted_payment_methods = array( 'paypal', 'stripe' );
// HERE define the percentage discount
$percentage = 2;
if( in_array( WC()->session->get('chosen_payment_method'), $targeted_payment_methods ) ){
// Calculation
$discount = $cart->get_subtotal() * $percentage / 100;
// Applying discount
$cart->add_fee( sprintf( __("Discount (%s)", "woocommerce"), $percentage . '%'), -$discount, true );
}
}
// Refreshing totals on choseen payment method change event
add_action( 'woocommerce_review_order_before_payment', 'refresh_payment_methods' );
function refresh_payment_methods(){
// Only on checkout page
if ( ! ( is_checkout() && current_user_can('subscriber') ) ) return;
// jQuery code
?>
<script type="text/javascript">
(function($){
$( 'form.checkout' ).on( 'change', 'input[name^="payment_method"]', function() {
$('body').trigger('update_checkout');
});
})(jQuery);
</script>
<?php
}
This code goes on function.php file of your active child theme (or active theme). tested and works.
To get the correct desired Payment methods IDs, you will have to inspect the html code around the payment methods radio buttons searching with your browser inspector tools:
How can I add a percentage to the total amount when choosing a payment (credit card)?
For example: If the customer pays for cash on delivery, then the base price, and if I chose online payment, then the percentage charged by me is added to the total amount?
Gateway ID for cash payment on delivery is set out: cod
Gateway ID for online payment is set out: tinkoff
add_action( 'woocommerce_after_calculate_totals', 'custom_fee_for_tinkoff' );
function custom_fee_for_tinkoff( $cart ) {
if ( is_checkout() || defined('WOOCOMMERCE_CHECKOUT') ) {
$payment_method = WC()->session->get( 'chosen_payment_method' );
if ($payment_method == 'tinkoff') {
$percentage = 0.025;
$surcharge = ( $cart->cart_contents_total + $cart->tax_total ) * $percentage;
$cart->add_fee( 'Комиссия банка', $surcharge, true, '' );
}
else { return; }
}
}
Image with problem
Try the following revisited code instead that should do the trick:
// Add a custom fee based o cart subtotal
add_action( 'woocommerce_cart_calculate_fees', 'custom_fee_for_tinkoff', 20, 1 );
function custom_fee_for_tinkoff ( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
return; // Only checkout page
$payment_method = WC()->session->get( 'chosen_payment_method' );
if ( 'tinkoff' == $payment_method ) {
$surcharge = $cart->subtotal * 0.025;
$cart->add_fee( 'Комиссия банка', $surcharge, true );
}
}
// jQuery - Update checkout on methode payment change
add_action( 'wp_footer', 'custom_checkout_jqscript' );
function custom_checkout_jqscript() {
if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
return; // Only checkout page
?>
<script type="text/javascript">
jQuery( function($){
$('form.checkout').on('change', 'input[name="payment_method"]', function(){
$(document.body).trigger('update_checkout');
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.