How to make a custom cart fee to be taxable in WooCommerce - php

Found exactly the snippet I was looking for to add a fixed fee amount to each individual cart item regardless of price. This site sells tires. So each tire will be charged 3$.
Here is the code I'm using and works:
add_action('woocommerce_cart_calculate_fees', function() {
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
$feetot = WC()->cart->get_cart_contents_count();
WC()->cart->add_fee(__('Specific Duty on New Tires', 'txtdomain'), 3 * $feetot);
});
I'm not very good with PHP and I'm learning as I go. I did spend 3 hours trying to modify this code so that the $3 fee would be TAXED as well. But I couldn't figure it out.
Below is what I tried as one of the attempts to have the fee taxed as well but it doesn't work:
add_action('woocommerce_cart_calculate_fees', function() {
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
$feetot = WC()->cart->get_cart_contents_count();
WC()->cart->add_fee(__('Specific Duty on New Tires', 'txtdomain', $taxable = true, $tax_class = ''), 3 * $feetot);
});
What I am doing wrong? Any help please.

To make it work, replace in your code the line:
WC()->cart->add_fee(__('Specific Duty on New Tires', 'txtdomain', $taxable = true, $tax_class = ''), 3 * $feetot);
with the following code line (see WC_Cart add_fee() method):
WC()->cart->add_fee( __('Specific Duty on New Tires', 'text_domain'), $feetot * 3, true, '' );
So your correct hooked function code will be:
add_action('woocommerce_cart_calculate_fees', 'custom_cart_items_fee' );
function custom_cart_items_fee( $cart ) {
if ( is_admin() && ! defined('DOING_AJAX') ) {
return;
}
$fee_amount = $cart->get_cart_contents_count() * 3;
$cart->add_fee( __('Specific Duty on New Tires', 'text_domain'), $fee_amount, true, '' );
}
Code goes in functions.php file of the active child theme (or active theme). It should works.

Related

Percentage discount based on user role and payment method in Woocommerce

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:

Custom dynamic shipping rate cost calculation in Woocommerce

I've set up a custom shipping method, i need to calculate shipping cost every time users get to the cart page.
It seems that woocommerce_package_rates action (where I calculate the custom shipping costs) runs only when user does click on a shipping method. This way the cart total is wrong most of the times, the worst is when the custom shipping method is already selected (user doesn't need to click it, so its cost doesn't update).
Is this the normal behavior of woocommerce_package_rates hook?
How to force woocommerce_package_rates to be always executed before displaying the cart totals?
EDIT
Here's some code i'm trying to hack with:
add_action( 'woocommerce_before_cart', 'force_shipping_calc', 1, 0 );
function force_shipping_calc() {
foreach( WC()->session->get('shipping_for_package_0')['rates'] as $rate_id =>$rate) {
// looking for the shipping method to recalc
if($rate->method_id == 'flat_rate') {
// mk1: set_shipping_total won't work, i'm using woocommerce < 3
//WC()->cart->set_shipping_total( MY_calculate_shipping() );
// mk2: doesn't work, "Indirect modification of overloaded property"
WC()->cart->totals['shipping_total'] = wc_format_decimal( MY_calculate_shipping(), wc_get_price_decimals() );
// mk3: cart total nor shipping total affected (?!)
WC()->cart->shipping_total = MY_calculate_shipping();
// mk4: ... ?! work in progress...
}
}
function MY_calculate_shipping() {
return 99.99;
}
add_filter( 'woocommerce_package_rates', 'fty_shipping_flat_rate_cost_calculation', 10, 2 );
function fty_shipping_flat_rate_cost_calculation($rates, $package) {
foreach($rates as $rate_key => $rate_values) {
$method_id = $rate_values->method_id;
$rate_id = $rate_values->id;
if ( 'flat_rate' === $method_id ){
$dist_cost = MY_calculate_shipping();
$price_excl_tax = $rates[$rate_id]->cost + $dist_cost;
$rates[$rate_id]->cost = number_format($price_excl_tax, 2);
$tax_keys = array_keys($rates[$rate_id]->taxes);
$price_excl_tax = $rates[$rate_id]->cost + $dist_cost;
$rates[$rate_id]->cost = number_format($price_excl_tax, 2);
$tax_calculation = $rates[$rate_id]->taxes[$tax_keys[0]] + $dist_cost*(TAX_AMOUNT_IVA-1);
$rates[$rate_id]->taxes[$tax_keys[0]] = number_format($tax_calculation, 2);
$rates[$rate_id]->cost += $dist_cost;
}
}
return $rates;
}
EDIT, again
This (mk. ~17786) seems to be in the right direction.
I changed the hook and force calculate_shipping() from WC_Shipping
add_action( 'woocommerce_cart_totals_before_shipping', 'fty_force_calculate_shipping', 1, 2550 );
function fty_force_calculate_shipping() {
WC()->shipping->calculate_shipping(WC()->shipping->packages);
WC()->cart->calculate_totals();
}
but it's not perfect yet, i think this hook makes a loop in the checkout page...
This needs to be done in woocommerce_package_rates only. In your code there is many errors or mistakes… Try the following:
function custom_calculated_shipping() {
return 99.99;
}
add_filter( 'woocommerce_package_rates', 'custom_shipping_rate_cost_calculation', 10, 2 );
function custom_shipping_rate_cost_calculation( $rates, $package ) {
foreach( $rates as $rate_key => $rate ) {
if ( 'flat_rate' === $rate->method_id ){
// Get rate cost and Custom cost
$initial_cost = $rates[$rate_key]->cost;
$additional_cost = custom_calculated_shipping();
// Calculation
$new_cost = $initial_cost + $additional_cost;
// Set Custom rate cost
$rates[$rate_key]->cost = round($new_cost, 2);
// Taxes rate cost (if enabled)
$new_taxes = array();
$has_taxes = false;
foreach ( $rate->taxes as $key => $tax ){
if( $tax > 0 ){
// Calculating the tax rate unit
$tax_rate = $tax / $initial_cost;
// Calculating the new tax cost
$new_tax_cost = $tax_rate * $new_cost;
// Save the calculated new tax rate cost in the array
$new_taxes[$key] = round( $new_tax_cost, 2 );
$has_taxes = true;
}
}
// Set new tax rates cost (if enabled)
if( $has_taxes )
$rate->taxes = $new_taxes;
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or theme). Tested and works. It will work in all woocommerce versions since 2.6…
You should need to refresh the shipping caches:
1) First this code is already saved on your function.php file.
2) Empty cart.
3) In Shipping settings, enter in a Shipping Zone and disable a Shipping Method and "save". Then re-enable that Shipping Method and "save". You are done.

Add fee based on specific payment methods in WooCommerce

In WooCommerce I need to apply a custom handling fee for a specific payment gateway. I have this piece of code from here: How to Add Handling Fee to WooCommerce Checkout.
This is my code:
add_action( 'woocommerce_cart_calculate_fees','endo_handling_fee' );
function endo_handling_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$fee = 5.00;
$woocommerce->cart->add_fee( 'Handling', $fee, true, 'standard' );
}
This function add a fee to all transactions.
Is it possible to tweak this function and make it apply for specific payment method only ?
The other problem is that I want this fee to be applied on cart. Is it possible?
I will welcome any alternative method as well. I know about the similar "Payment Gateway Based Fees" woo plugin, but I can't afford it.
2021 UPDATE
Note: All payment methods are only available on Checkout page.
The following code will add conditionally a specific fee based on the chosen payment method:
// Add a custom fee (fixed or based cart subtotal percentage) by payment
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' => 8, // Fixed fee
'paypal' => 5 * $subtotal / 100, // Percentage 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( __('Handling fee', 'woocommerce'), $fee_cost, true );
}
}
}
You will need the following to refresh checkout on payment method change, to get it work:
// 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');
});
});");
}
Code goes in functions.php file of your active child theme (or active theme). tested and works.
How to find a specific payment method ID in WooCommerce Checkout page?
The following will display on checkout payment methods the payment Id just for admins:
add_filter( 'woocommerce_gateway_title', 'display_payment_method_id_for_admins_on_checkout', 100, 2 );
function display_payment_method_id_for_admins_on_checkout( $title, $payment_id ){
if( is_checkout() && ( current_user_can( 'administrator') || current_user_can( 'shop_manager') ) ) {
$title .= ' <code style="border:solid 1px #ccc;padding:2px 5px;color:red;">' . $payment_id . '</code>';
}
return $title;
}
Code goes in functions.php file of your active child theme (or active theme). Once used, remove it.
Similar answer:
Add a custom fee for a specific payment gateway in Woocommerce
Add a fee based on shipping method and payment method in Woocommerce
Percentage discount based on user role and payment method in Woocommerce
First of all there are some key things we need to understand:
We are going to use the only filter hook which is woocommerce_cart_calculate_fees
In order to get user selected payment method we must retrieve it from user sessions using this method WC()->session->get( 'chosen_payment_method' )
calculate_fees() and calculate_totals() methods are not necessary.
We are going to add the fee using cart method WC()->cart->add_fee() which accepts two parameters – the first one, is the fee description, the second one – fee amount.
And one more thing – we will need a payment method slug, the easiest way to get it described in this tutorial https://rudrastyh.com/woocommerce/add-id-column-to-payment-methods-table.html
Let's go now:
add_action( 'woocommerce_cart_calculate_fees', 'rudr_paypal_fee', 25 );
function rudr_paypal_fee() {
if( 'paypal' == WC()->session->get( 'chosen_payment_method' ) ) {
WC()->cart->add_fee( 'PayPal fee', 2 ); // let's add a fee for paypal
}
}
It would be also great to refresh the checkout every time payment gateway is changed, it is easy to do using this code:
jQuery( function( $ ) {
$( 'form.checkout' ).on( 'change', 'input[name^="payment_method"]', function() {
$( 'body' ).trigger( 'update_checkout' );
});
});
That's it. Everything is described in details here as well: https://rudrastyh.com/woocommerce/charge-additional-fees-based-on-payment-gateway.html
For anyone else looking to do this, I wanted to add a fee for Bank Transfers (BACS), here is the method I used:
//Hook the order creation since it is called during the checkout process:
add_filter('woocommerce_create_order', 'my_handle_bacs', 10, 2);
function my_handle_bacs($order_id, $checkout){
//Get the payment method from the $_POST
$payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : '';
//Make sure it's the right payment method
if($payment_method == "bacs"){
//Use the cart API to add recalculate fees and totals, and hook the action to add our fee
add_action('woocommerce_cart_calculate_fees', 'my_add_bacs_fee');
WC()->cart->calculate_fees();
WC()->cart->calculate_totals();
}
//This filter is for creating your own orders, we don't want to do that so return the $order_id untouched
return $order_id;
}
function my_add_bacs_fee($cart){
//Add the appropriate fee to the cart
$cart->add_fee("Bank Transfer Fee", 40);
}
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 = 5;
if ( $chosen_gateway == 'cod' ) { //test with cash on delivery method
WC()->cart->add_fee( 'delivery fee', $fee, false, '' );
}
}

What is wrong with this PHP function for Woocommerce Cart?

I created a function for adding a fee to the Woocommerce cart. It works partially, but displays the lowest fee. It just ignores the condition of <= 550 and the highest fee. Does anyone have an idea how to fix this?
function verzendkosten( $cart_object ) {
global $woocommerce;
$laag = 37.50;
$hoog = 57.50;
$vala = 550.00;
$prijs = $woocommerce->cart->total;
if($prijs <= $vala) {
$woocommerce->cart->add_fee( 'Verzendkosten', $hoog, true, 'standard' );
}
if($prijs > $vala) {
$woocommerce->cart->add_fee( 'Verzendkosten', $laag, true, 'standard' );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'verzendkosten' );

Wordpress: Add extra fee in cart

I've created a webshop in Woocommerce (wordpress). It's a wine shop and I need to add an extra cost: 0,08 euro per bottle (product).
I've found this and adjusted it, but I cannot get the number of products (bottles) to multiply with 0.08 euro.
In the cart I do get an extra line but the value is 0.
Can anyone explain me what I'm doing wrong?
function get_cart_contents_count() {
return apply_filters( 'woocommerce_cart_contents_count', $this->cart_contents_count );
}
function woo_add_cart_fee() {
global $woocommerce;
$woocommerce->cart->add_fee( __('Custom', 'woocommerce'), $get_cart_contents_count * 0.08 );
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
Try this code in your functions.php but it will be applied on over all cart
// Hook before adding fees
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
function add_custom_fees( WC_Cart $cart ){
$fees = 0.08;
$cart->add_fee( 'Handling fee', $fees);
}
EDIT:
To multiply it with each product do something like
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
function add_custom_fees( WC_Cart $cart ){
$fees = 0;
foreach( $cart->get_cart() as $item ){
$fees += $item[ 'quantity' ] * 0.08;
}
if( $fees != 0 ){
$cart->add_fee( 'Handling fee', $fees);
}
}
You are talking about adding surcharge to the cart. You can get all the related information from the Woocommerce Doc in here.

Categories