Reputation: 2790
I've had a few people ask me about this recently, and I don't have much of an answer for them, and can't find much info on this elsewhere.
By default, on the product page, the price displayed gets updated dynamically based on custom options. Is it going to be a major pain to have that price updated dynamically based on the tiered pricing structure as well? Basically, so that if a user goes to a product with tiered pricing, and they enter a quantity that qualifies for tiered pricing, the price gets updated based on the tier pricing and quantity selected.
I would think some jQuery voodoo shouldn't be that difficult to build so the price is recalculated based on the values, but I'm curious if anyone else has done this previously and if they are aware of any potential pitfalls with doing this.
Is there a very good reason why not to do this... or in other words, is there a very good reason why this wasn't built as part of the Magento Core?
Upvotes: 2
Views: 13606
Reputation: 1
this version takes product options and first tier price to consideration:
<script type="text/javascript">
jQuery(function($){
// probably you want a custom method in your block for getting a better and safer tierPrices array here
// for example with formatted prices
var tierPrices = <?php
$_tier_json = json_encode($_product->getTierPrice());
$_tier_json = substr($_tier_json,0,1) . '{"price":"'.$_product->getFinalPrice().'","price_qty":"1"},' . substr($_tier_json,1);
echo $_tier_json;
?>;
var getPrice = function(qty){
qty = Number(qty);
var i = tierPrices.length;
while(i--)
{
if(qty >= tierPrices[i]['price_qty']){
return tierPrices[i]['price'];
}
}
return null;
};
var formatPrice = function(price) {
return '$' + parseFloat(price).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
};
var updatePrice = function(price){
// if product has options, use optionsPrice functionality
if ( typeof optionsPrice != 'undefined' && typeof optionsPrice.productPrice != 'undefined' ) {
optionsPrice.productPrice = price;
optionsPrice.reload();
} else {
// or if it is a simple product, change price directly in the html
$(".price-box .price").html( formatPrice(price) );
}
};
var updatePriceEvent = function() {
var price = getPrice( $('#qty').val() );
if(price !== null){
updatePrice(price);
}
};
$('#qty').change( updatePriceEvent );
$('div.qty-changer .qty_inc, div.qty-changer .qty_dec').click( updatePriceEvent );
});
</script>
if it is a configurable product, or product with custom options, it will adjust price according currently selected option. plus, $_product->getTierPrice() returns prices starting second tier, which will display wrong price on lower quantities
Upvotes: 0
Reputation: 111
I found a simple solution, i retrieve the currency rate and it works fine. The Code as follow
<script type="text/javascript">
jQuery(function($$){
var inst_price_format = <?php echo Mage::helper('core')->jsonEncode( Mage::app()->getLocale()->getJsPriceFormat() ); ?>;
var rate = <?php echo Mage::app()->getStore()->getCurrentCurrencyRate(); ?>;
var tierPrices = <?php echo json_encode($_product->getTierPrice()) ?>;
var getPrice = function(qty){
qty = Number(qty);
var i = tierPrices.length;
while(i--)
{
if(qty >= tierPrices[i]['price_qty']){
return tierPrices[i]['price'];
}
}
return null;
};
var updatePrice = function(price) {
$$('.price-box .price').html( formatCurrency( (price*rate), inst_price_format) );
};
var updateTotalPrice = function(price, qty) {
$$('.total-price').html( formatCurrency( ((price*rate) * qty), inst_price_format) );
};
$$('#qty').change( function(){
var price = getPrice(this.value);
var qty = this.value;
if(price !== null) {
updatePrice(price);
updateTotalPrice(price, qty);
} else {
updatePrice(<?php echo $_product->getPrice(); ?>);
updateTotalPrice(<?php echo $_product->getPrice(); ?>, qty);
}
});
});
Upvotes: 2
Reputation: 111
This doesn't work for multistore. The currency is changed but the price is show in default currency.
Upvotes: 0
Reputation: 880
I have done the exact same thing for our multistore system now.
I also added a fallback if you have just a single price set and I am formatting the output for a better user experience.
Feel free to use this code:
<script type="text/javascript">
jQuery(function($){
// This was built using https://stackoverflow.com/questions/12647770/ and https://himansuboity.wordpress.com/2014/09/30/magento-tip-how-to-get-the-store-price-format-by-javascript/
var inst_price_format = <?php echo Mage::helper('core')->jsonEncode( Mage::app()->getLocale()->getJsPriceFormat() ); ?>
var tierPrices = <?php echo json_encode($_product->getTierPrice()) ?>;
var getPrice = function(qty){
qty = Number(qty);
var i = tierPrices.length;
while(i--)
{
if(qty >= tierPrices[i]['price_qty']) { return tierPrices[i]['price']; }
}
return null;
};
var updatePrice = function(price, qty) { $('.price').html( formatCurrency( (price * qty), inst_price_format) ); };
$('#qty').change( function() {
var price = getPrice(this.value);
var qty = this.value;
if(price !== null) { updatePrice(price, qty); }
// no tier prices set, use base price
else { updatePrice(<?php echo $product->getPrice(); ?>, qty); }
});
});
</script>
Upvotes: 0
Reputation: 2790
I spent some time over the weekend and managed to get this working, but I didn't like that I was modifying the tierprices.phtml template so that I could grab 'price_qty' via a class. I swapped that out and used $_product->getTierPrice() instead as you suggested. The code I've ended up with is below:
----edit---- I rewrote some things to also support special pricing.
<script type="text/javascript">
var $j = jQuery;
var $p = {};
var prices = {};
//dom elements being used
$p["old"] = $j(".price-box .old-price .price");
$p["special"] = $j(".price-box .special-price .price");
$p["regular"] = $j(".price-box .regular-price .price");
//save original price to reset back if quantity is reset
//Checking for special price
if ($p["special"].html()) {
var specialPrice = $p["special"].html();
var oldPrice = $p["old"].html();
} else {
var originalPrice = $p["regular"].html();
}
//lets get to work.
$j(function(){
var tiers = <?php echo json_encode($_product->getTierPrice()) ?>;
var h = tiers.length;
while (h--) {
var key = h;
var line = {};
//just build the prices object for use later
line["qty"] = parseInt(tiers[h]["price_qty"]);
line["price"] = parseFloat(tiers[h]["price"]).toFixed(2);
prices[key] = line;
}
//keyup event works nicely here
$j("#qty").on("keyup",function(){
var quantity = $j(this).val();
for (var i in prices) {
var z = i;
//save lowest tier for reset back to original price
var lowest = prices[0]["qty"];
//set the range
var bottom = prices[i]["qty"];
var top = prices[z++]["qty"];
//format to currency -- should probably switch to magento's helper method.
var price = "<?php echo Mage::app()->getLocale()->currency(Mage::app()->getStore()->
getCurrentCurrencyCode())->getSymbol() ?>"+prices[i]["price"];
//check if the price needs to be reset after quantity is reset < lowest
if (quantity < lowest) {
if (specialPrice) {
$p["special"].html(specialPrice);
$p["old"].html(oldPrice);
} else {
$p["regular"].html(originalPrice);
}
break;
}
//check the ranges, set the price accordingly.
if (quantity >= bottom) {
if (quantity >= top) {
if (specialPrice) {
$p["special"].html(price);
} else {
$p["regular"].html(price);
}
continue;
} else {
break;
}
}
}
})
})
</script>
I used $j("#qty").on("keyup",function(){}) instead for the live feedback. I could probably clean this up to use whiles instead of the if structure I set up, but it works so at least it's an alternative method.
Thanks for the assist.
Upvotes: 0
Reputation: 4833
Yes, you could do this with javascript, you only need to put the tier data into some var inside <script>
in your template, something like this could work (if you want to use jQuery):
Template: catalog\product\view.phtml
<script type="text/javascript">
jQuery(function($){
// probably you want a custom method in your block for getting a better and safer tierPrices array here
// for example with formatted prices
var tierPrices = <?php echo json_encode($_product->getTierPrice()) ?>;
var getPrice = function(qty){
qty = Number(qty);
var i = tierPrices.length;
while(i--)
{
if(qty >= tierPrices[i]['price_qty']){
return tierPrices[i]['price'];
}
}
return null;
};
var updatePrice = function(price){
$('.price').html(price);
};
// you can use more events here if you want a live response while the user is typing
$('#qty').change(function(){
var price = getPrice(this.value);
if(price !== null){
updatePrice(price);
}
});
});
</script>
Upvotes: 5