Okay
  Public Ticket #2571019
price hooks
Closed

Comments

  •  4
    Antti-Pekka started the conversation

    Hello, I want to show both original price and discounted price without VAT if there is a discount (which there will always be for B2B users). I am using the following code but it doesn't work with the discounts made by B2BKing. Is there a way to make it work (preferrably with dynamic discount rules as I don't like updating prices for products separately).

    Below is the snippet I'm using and I attached couple pictures of how iI want it to work also with dynamic discounts. Note that this is required only for B2B users. For Logged out / B2C users I want to show only regular or sale price (input in normal woocommerce regular/sale price field, depending if there is a sale ongoing or not).

    I understand that customization is not included in support but I hope you can point me to right direction (I'm still learning modifying instead of adding plugins) or give me a quote of such modification. Thank you!


    //Määrittelee miten myyntihinta näytetään 

    function edit_price_display() {     global $product;     $price = $product->price; $price_excl_tax = round($price / ( 1.24 ), 2);     $price = number_format($price, 2, ",", ".");     $display_price = '<span class="price">';     $display_price .= '<span class="amount"> Myyntierä ' . $price .'<small class="woocommerce-price-suffix">€ Sis ALV</small></span>';     $display_price .= '<br>';     echo $display_price;

    } add_filter( 'woocommerce_get_price_html', 'edit_price_display', 10, 2 );


    //Määrittelee hinta ja alv 0% arvon ja näyttää molemmat 

    function ts_custom_price() {

    global $product;

    $price = $product->price;

    $price_excl_tax = round($price / ( 1.24 ), 2);

    if ($product->is_on_sale())

    {

    if( $product->is_type('simple') || $product->is_type('external') || $product->is_type('grouped') ) {

    $regular_price = get_post_meta( $product->get_id(), '_regular_price', true );

    $sale_price = get_post_meta( $product->get_id(), '_sale_price', true );

    if( !empty($sale_price) ) {

    print '<p class="custom_text"><b>OVH:</b> €'.$regular_price.'</p><p class="custom_text"><b>ALV 0%:</b> €'.$price_excl_tax.'</p>';

    }

    }

    }

    }

    add_filter( 'woocommerce_get_price_html', 'ts_custom_price', 10, 2 );


  •  4
    Antti-Pekka replied

    I found some quides and rewrote the snippet, and it is working almost as I want it (for now when there is no registered B2C users, only B2B):


    add_filter('woocommerce_get_price_html','members_only_price');
    function members_only_price($price){
    if(is_user_logged_in() ){
    global $product;
        $price = $product->price;
    $price_excl_tax = round($price / ( 1.24 ), 2);
        $price = number_format($price, 2, ",", ".");
    $regular_price = get_post_meta( $product->get_id(), '_regular_price', true );
        $display_price = '<span class="price">';
        $display_price .= '<span class="amount"> ME ' . $price .'<small class="woocommerce-price-suffix">€ Sis ALV</small></span>';
    print '<p class="hinnat"><b>OVH:</b> €'.$regular_price.'</p><p class="hinnat"><b>ALV 0%:</b> €'.$price_excl_tax.'</p>';

        echo $display_price;

    ;
    }
    else return $price;
    }


    It works correctly if i put fixed B2B price, but if I add dynamic discount the plugin adds its own fields and "ME" (=sale lot) is not updated doesn't work like I want it. Please help! Also for future, the rule "if logged in" should be if member of b2b group but I don't know what to put there. :)


  •  1,903
    WebWizards replied

    Hi Antti-Pekka,

    I'll do my best to help,

    1)

    To make some code work only for b2b users, here is how you can do it:

    if (get_user_meta(get_current_user_id(),'b2bking_b2buser', true) === 'yes'){
        // YOUR CODE FOR ONLY B2B HERE
    }


    2) 

    If you want to overwrite the plugin's display for price, you can increase priority.

    Replace this line of code

    add_filter('woocommerce_get_price_html','members_only_price');
    

    with

    add_filter('woocommerce_get_price_html','members_only_price', 99999, 1);
    

    99999 is the priority

    1 is the number of arguments in the function

    3) By overwriting priority above, I think you will only see your function and the plugin will no longer add anything, but I am not sure if that would set the display as you want it or if you need to show the sale price.

    If you need to show the sale price, you can use this to get it:

    wc_get_price_to_display(  $product, array( 'price' => $product->get_sale_price() ) )
    


    I will copy paste the code the plugin uses inside the woocommerce_get_price_html normally, in case it helps you:

    $price_html = wc_format_sale_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ), wc_get_price_to_display(  $product, array( 'price' => $product->get_sale_price() ) ) ) . $product->get_price_suffix();
    
  •  4
    Antti-Pekka replied

    Thank you Stefan, I got bit further;

    1) & 2) I got working but I can't get the sale price to show in place of regular price (=ME) if there is a dynamic discount. I don't know where to use the "wc_get_price_to_display". Moreover, if/when the sale price is shown in place of "ME" also the tax calculation should use the sale price instead of regular price and show VAT 0% in place of "ALV 0%".

    I think this is "if-else" case but I really don't have enough experience in writing .php to make this work:

    If user is a member of b2b group:

    -> Show RRP (from woocommerce regular_price field, prices are inputted including VAT) 

    -> Show VAT 0% (calculated from b2b price)

    -> Show B2B price including VAT


    and if there is a dynamic discount:

    -> Show RRP (same as above)

    -> Show VAT 0% (calculated from discounted b2b price)

    -> Show discounted B2B price Including VAT


    and else (user not member of b2b group)

    -> Show only RRP (including VAT)


    My goal is to reduce the manual labor in updating prices -> I want that a shop manager need only update the RRP (=OVH in my language) and pricing for B2B is managed through dynamic discounts (basically by creating price groups with % discount applied to a member of B2B group). I think this would be a really useful feature in your plugin as well as it is important to show all three prices for B2B customers (B2B price incl & excl VAT + RRP including VAT).

  •  1,903
    WebWizards replied

    Hi,

     1)

     I can't get the sale price to show in place of regular price (=ME) if there is a dynamic discount. I don't know where to use the "wc_get_price_to_display".

    I think you would simply test if the product is on sale (the dynamic discount sets the product as on sale).

    Code would look somewhat like this:

    if( $product->is_on_sale() ){
        // show sale price
        $sale_price_number = $product->get_sale_price();
        $sale_price_string = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) );
    } else {
        // show regular price (RRP)
        $regular_price_number = $product->get_regular_price();
        $regular_price_string = wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) );
    }
    

    I wish I could give you the exact code for your setup but truth is this is one of the most complex woocommerce aspects and I couldn't without many hours (or days) of testing.


    2)

    For the VAT, if you have 1 single country and 1 number (eg 24%) (I didn't understand what VAT 0% means) you can calculate it directly. If you have multiple countries/tax classes/possible VAT percentages, it gets a lot more complex.

    This may help as a starting point:

    if ($product->is_taxable()){
         $tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
         $tax_vat = 0;
         if (!empty($tax_rates)) {
            $tax_rate = reset($tax_rates);
            $tax_vat += ($productprice * $tax_rate['rate'] * $item['quantity'])/100;
        }
    }
    



  •  4
    Antti-Pekka replied

    Thank you Stefan and sorry for late reply. I had to do other things before coming back to this. Unfotunately I cannot get the sale price set by B2BKing dynamic discount shown. When trying, "Get_sale_price" returns only the value from Woocommerce sale price field, not the discounted regular price set to B2B customers by B2BKing Dynamic rules (The code you posted returns a critical error, but maybe it was not supposed to use as is). I'm only copy pasting and trying to rename correct fields since I have zero education for coding anything, but this case is clearly too challenging. i'm using snippets -plugin if this matters.

    VAT 0% I'm referring is simply the price excluding tax. We input prices including VAT which is the normal view for B2C customers -> this is what I refer when talking about RRP (recommended retail price), and this is the normal price shown in every case and only price the B2C customers see.

    However, for B2B customers we need to show three different prices in product loops and in singel product page;

    RRP for example 12,40€ inc.tax

    ME (Price for B2B user inc.tax) -> ME is simply a term for "Sales batch", with dynamic discount of 40% this would be 7,44€ inc.tax

    ME VAT 0% (Price for B2B users excluding tax) In the example this would be ME / 1,24 = 6€  VAT 0%

    Now, I was able to accomplish this if we input the ME price to corresponding regular price field of the B2B group, but what I'd want to do is to set only the RRP price for each product and use B2BKing Dynamic Rules to calculate the ME price, and then display also that ME price excluding tax for B2B users.

    Edit: I finally got it working with this simple line of code!! :D

    if (get_user_meta(get_current_user_id(),'b2bking_b2buser', true) === 'yes'){  
        
        add_filter('woocommerce_get_price_html','members_only_price', 99999, 1);
        function members_only_price($price){
        
        global $product;
        $price = $product->price;
        $price = number_format($price, 2, ",", ".");
        $regular_price = get_post_meta( $product->get_id(), '_regular_price', true );
        $sale_price = $product->get_sale_price();
        $price_excl_tax = round($sale_price / ( 1.24 ), 2);
        $display_price = '<span class="price">';
        $display_price .= '<span class="amount"> ME ' . $sale_price .'<small class="woocommerce-price-suffix">€ Sis ALV</small></span>';
        print '<p class="hinnat"><b>OVH:</b> €'.$regular_price.'</p><p class="hinnat"><b>ALV 0%:</b> €'.$price_excl_tax.'</p>';
        
        echo $display_price;
    }
    }
    
  •  1,903
    WebWizards replied

    Hi Antti-Pekka,

    I'm happy to hear you got it working! Pricing and price display is one of the most challenging WooCommerce areas.


    Let me know if I can help,

    Stefan


  •  4
    Antti-Pekka replied

    Hi I have one problem I need help with. I have now added if-else conditions to show prices correctly whether the product has discount or not (and it is working as supposed) but when I add also table rate price for the product, the unit price is shown incorrectly in the cart (I have dynamic price active for the product). 

    In the attached picture you can see that I have 5 products which have unit price of 6€ -> incorrect

    Correct unit price would be 10€ which is set to be the table rate. However, the cart total is calculated correctly.

    So, how do I override or hide the unit price from the cart if the table rate can be applied (=customer has added enough products to cart to achieve the table rate price).

    Thank you in advance!


    Here is the code so far in case someone needs similar setup:

    if (get_user_meta(get_current_user_id(),'b2bking_b2buser', true) === 'yes'){
    add_filter( 'woocommerce_get_price_html', 'hinnat', 99999, 3 );
    function hinnat() {
    global $product;
        //jos tuotteella on alennus
    if($product->is_on_sale())
    {
        ($price = $product->price);
        ($price = number_format($price, 2, ",", "."));
        
        //hakee woocommercen Normaali hinta kentässä olevan hinnan
        ($regular_price = get_post_meta( $product->get_id(), '_regular_price', true ));
        
        //hakee alennushinnan
        ($sale_price = $product->get_sale_price());
        
        //laskee alv 0 hinnan alennushinnasta
        ($price_excl_tax = round($sale_price / ( 1.24 ), 2));
        
        //tulostaa määritetyt hinnan ja määrittää muotoilu-luokat
        ($display_price = '<span class="price">');
        ($display_price .= '<span class="amount"> ME ' . $sale_price .'<small class="woocommerce-price-suffix"> € (Sis.Alv 24%)</small></span>');
        (print '<p class="hinnat"><b>OVH:</b> €'.$regular_price.'</p><p class="hinnat"><b>ALV 0%:</b> €'.$price_excl_tax.'</p>');
    }
        
        //jos tuotteella ei ole alennusta
    else
    {
        ($price = $product->price);
        ($price = number_format($price, 2, ",", "."));
        
        //hakee woocommercen Normaali hinta kentässä olevan hinnan
        ($regular_price = get_post_meta( $product->get_id(), '_regular_price', true ));
        
        //laskee alv 0 hinnan alennushinnasta
        ($price_excl_tax = round($price / ( 1.24 ), 2));
        
        //tulostaa määritetyt hinnan ja määrittää muotoilu-luokat
        ($display_price = '<span class="price">');
        ($display_price .= '<span class="amount"> ME ' . $price .'<small class="woocommerce-price-suffix"> € (Sis.Alv 24%)</small></span>');
        (print '<p class="hinnat"><b>OVH:</b> €'.$regular_price.'</p><p class="hinnat"><b>ALV 0%:</b> €'.$price_excl_tax.'</p>');
    }
        echo $display_price;
    }
    }
    
  •  1,903
    WebWizards replied

    Hi,

    I am trying to understand.

    So everything is correct, but your code also modifies the price in cart, and you don't need that?


    Your code does not need to change price, only change how prices are displayed, correct? In that case, if your code only changes display, not actual prices:


    Can you simply not run your code in the cart/checkout pages?


    If you wrap your code inside

    if (!is_cart() && !is_checkout()){
    // your code here
    }

    does that help?



  •  4
    Antti-Pekka replied

    Hi,

    I don't think the code I injected modifies the price, it only prints 3 different prices (depending on conditions discussed earlier) to single product page and product loop.

    The problem is with B2BKing "Dynamic Rules" enabled together with B2BKing table rate price -> Dynamic discount seems to be applied (and printed) in product loop, single product and cart page, except that is not calculated in the total price (so the price is not really affected by it). The total price follows the table rate pricing correctly as I expect it to do, but the prices are not displayed correctly. I think this is a bug in the plugin because it does the same with my code deactivated.

    However, I found out that if I leave the first price field of table rate empty, and start adding bulk price levels from second field -> the price is displayed correctly in the product page and loop, but not in cart: total price follows table rate price and is therefore correct, but the unit price x amount doesn't equal because "unit price" is printed with Dynamic Rule discount applied. Also, I noticed that if I add enough products for enabling a table rate price to cart and return to single product page, the displayed normal price of product is changed -> I'd found this a bit confusing if I'd be a buyer in the webshop.

    You can try to reproduce the problem by creating a product, giving it a regular price (in woocommerce regular price field), leave other fields empty except give the product some table rate prices (5+ costs X, 10+ cost Y etc.). Then create a Dynamic Rule (for exmple 50% discount) for the product with "show discount everywhere" option enabled, and see what happens when you first add one, and then 5 or 10pc of that product to cart, depending on how you set up the table rates. Moreover, try leaving the first table rate price field empty and start from second.

    ps. I will study the code you suggested, but as explained above, the core problem is in how the plugin is coded and if it is working as intended, then I need to at least alter how the price is displayed in the cart page (and use the workaround of leaving the first row of table rate prices empty).

    Thank you once again!


  •  1,903
    WebWizards replied

    Hi,

    Sorry for the delay in getting back to you, it's a very busy period.

    I actually tested this, but it seems to work semi ok for me:

    I have set tiered prices + 50% discount rule

    9706753300.png

    Price is also correct in cart: 

    2149463338.png

    This is my config in the product backend:

    5874530343.png


    However setting a regular price for the group may create an issue indeed. Is that what you meant by leaving the first row empty?



    Ultimately however, the "Final Price" function for the group is supposed to be the definitive price, not to be used together with other discounts. Not all functions of the plugin can be used at the same time: final price + discounts creates some conflicts.


    If you must have a discount, my suggestion is: Don't check the "Show discount everywhere box". That adds the discount in cart, and since it's added when prices are already set, that will work without issues.



  •  4
    Antti-Pekka replied

    Hi,

    Your testing made me dig deeper and I found that some of the oddities (like the: "leaving first row empty fix") were caused by an object cache of my server, which resulted that I didn't see the changes correctly in front-end.

    but, actually you had almost the same problem I want to avoid. I try to explain what I want to achieve using your example:

    - you have set tiered price to 33$ if more than 20pc

    - in cart you have 30pc which  in my case should then equal to 30x33$ = 990$ (as tiered prices should be the lowest prices in my case, and no discount should be applied to tiered price anymore)

    - the unit price you have in cart is 16.50$ (because of the discount) and total calculated based on that (which is the normal way as you stated, but what I actually want to disable).

    My snippet enabled and "show price everywhere" applied, the total price is calculated using the tiered price which, in my case is exactly what I want to achieve, but then the unit price shown in cart (and on single-product page after adding enough products to cart) should not be "16,50$" but "33$" instead.

    So what is the best way to either hide the discounted unit price from cart, single-product page (and checkout?) or show the tiered price in place of the discounted price or ignore dynamic rule if tiered price is achieved when adding enough products to cart?

    I'd appreciate if you could show me a way to achieve this. Unfortunately I have to keep the "show discount everywhere" enabled, because we want to show all three prices discussed earlier.

    Below is the snippet I'm using now:

    if (get_user_meta(get_current_user_id(),'b2bking_b2buser', true) === 'yes'){
    add_filter( 'woocommerce_get_price_html', 'hinnat', 99999, 3 );
    function hinnat() {
    global $product;
        //jos tuotteella on alennus
    if($product->is_on_sale())
    {
        ($price = $product->price);
        ($price = number_format($price, 2, ",", "."));
        
        //hakee woocommercen Normaali hinta kentässä olevan hinnan
        ($regular_price = get_post_meta( $product->get_id(), '_regular_price', true ));
        
        //hakee alennushinnan
        ($sale_price = $product->get_sale_price());
        
        //laskee alv 0 hinnan alennushinnasta
        ($price_excl_tax = round($sale_price / ( 1.24 ), 2));
        
        //tulostaa määritetyt hinnan ja määrittää muotoilu-luokat
        ($display_price .='<span class="hinnat-bold">'.$price_excl_tax.' € (alv 0%)</span>
        <div>
        <span class="hinnat">'.$sale_price.' € (sis.alv) </span>
        <div>
        <spann class="hinnat"><b>OVH:</b> '.$regular_price.'€ ');    
    }
        
        //jos tuotteella ei ole alennusta
    else
    {
        ($price = $product->price);
        ($price = number_format($price, 2, ",", "."));
        
        //hakee woocommercen Normaali hinta kentässä olevan hinnan
        ($regular_price = get_post_meta( $product->get_id(), '_regular_price', true ));
        
        //laskee alv 0 hinnan alennushinnasta
        ($price_excl_tax = round($price / ( 1.24 ), 2));
        
        //tulostaa määritetyt hinnan ja määrittää muotoilu-luokat
        ($display_price .='<span class="hinnat-bold">'.$price_excl_tax.' € (alv 0%)</span>
        <div>
        <span class="hinnat">'.$price.' € (sis.alv) </span>
        <div>
        <span class="hinnat"><b>OVH:</b> '.$regular_price.'€ </span>');
    }
        echo $display_price;
    }
    }
    
  •  1,903
    WebWizards replied

    Hi,

    I have some code that perhaps can help, just not sure if we're fully there yet.

    The code is:


    $have_tiered_price = 'no';
    // Search price tiers
    $price_tiers = get_post_meta($product->get_id(), 'b2bking_product_pricetiers_group_'.$currentusergroupidnr, true );
    // if no tiers, get regular
    if (empty($price_tiers)){
        $price_tiers = get_post_meta($product->get_id(), 'b2bking_product_pricetiers_group_b2c', true );
    }
    if (!empty($price_tiers)){
        // if there are price tiers, check product quantity in cart and set price accordingly
        // find product quantity in cart
        $product_id = $product->get_id();
        $quantity = 0;
        if (is_object( WC()->cart )){
            foreach( WC()->cart->get_cart() as $cart_item ){
                if ( $product_id === $cart_item['product_id'] || $product_id === $cart_item['variation_id']){
                    $quantity = $cart_item['quantity'];
                    break;
                }
            }
        }
        if ($quantity !== 0){
            $price_tiers = explode(';', $price_tiers);
            $quantities_array = array();
            $prices_array = array();
            // first eliminate all quantities larger than the quantity in cart
            foreach($price_tiers as $tier){
                $tier_values = explode(':', $tier);
                if ($tier_values[0] <= $quantity && !empty($tier_values[0])){
                    array_push($quantities_array, $tier_values[0]);
                    $prices_array[$tier_values[0]] = $tier_values[1];
                }
            }
            // if any number remains
            if(count($quantities_array) !== 0){
                // get the largest number
                $largest = max($quantities_array);
                $tiered_price = $prices_array[$largest];
                $have_tiered_price = 'yes';
            }
        }
    }
    

    The code needs 1 variable: $product 

    When the code finishes, we have 2 variables we can use:

    $have_tiered_price - yes or no, depending on whether tiered price is achieved

    $tiered_price - the calculated tiered price based on quantity in cart


    Now, is it possible to use these variables to modify your custom code?

    Or must there be a change in how the plugin works? 

    I ask because for example "ignore dynamic rule if tiered price is achieved when adding enough products to cart?" I can do this, but it requires a lot of plugin modifications to the dynamic rule. And how about future plugin updates?


    If we can modify your code somehow, it is much simpler than modifying the plugin.

  •  4
    Antti-Pekka replied

    Hi Stefan,

    Sorry for late reply. I have postponed working with tiered pricing compatibility, I will update when I get back to testing what you suggested.

    To answer your question: I'd rather modify my code than how the plugin is coded. I don't want to be updating the code every time the plugin is updated. Therefore, best way would be merely to modify what is displayed or hide some fields entirely.

    Thank you.

  •  1,903
    WebWizards replied

    All right, let me know when you have an update, Thank you.