I am currently building a module for an ecommerce website (Lemonstand). My shop sells both normal books and ebooks, and charge different rates of for shipping based on the subtotal of all items in the cart ($7 shipping cost for subtotal of less than $20, $14 shipping cost for between $20 and $50..etc). Currently the website just uses the subtotal of all items in the cart to determine which rate should be applied. The problem is, I want only the subtotal of normal books to be used for calculating shipping, because obviously ebooks don't need shipping.
Lemonstand platform has some built_in functions that I'm using to help with this. update_shipping_quote function is called just before shipping cost is calculated. It will be used to change the subtotal of cart items so that shipping cost can be calculated using the subtotal of non-ebooks instead.
Here is the API documentation for the function: https://v1.lemonstand.com/api/event/shop:onupdateshippingquote/
Here is the bit of code that's giving me trouble. I want to know if the value I get at the end ($non_ebook_subtotal) actually contains the value it's supposed to.
If anyone can come up with a better method for doing what I'm trying to do, please share.
//$params is an array containing things like individual item price
//Here I get the cart items and put them into var
public function
update_shipping_quote($shipping_option, $params) {
$cart_items = $params['cart_items'];
//find all products that are ebooks
foreach ($cart_items-> items as $item)
{
$product = $item->product;
if($product->product_type->code == 'ebook') {
$isEbook = true;
}
}
//add price of all ebooks into $ebook_subtotal
foreach ($cart_items as $item) {
$product = $item -> product;
if ($isEbook == true) {
$ebook_subtotal = $ebook_subtotal + total_price($product);
}
}
//Calculating the subtotal of only the non-ebook products
$non_ebook_subtotal = $params['total_price'] - $ebook_subtotal;
//This returns the non_ebook_subtotal to be used for calculating shipping cost
return array('total_price' => $non_ebook_subtotal);
}
Thanks
// get all variables needed
$totalprice = $params['total_price'];
$items = $params['cart_items'];
foreach ($items AS $item) {
// if is ebook
if ($item->product->product_type->code == 'ebook') {
// minus price of the item from total
$totalprice -= total_price($item->product);
}
}
return $totalprice;
Related
I am trying to display the flat rate shipping cost for a product on its single product page.
From searching on Stack Overflow, I did find some solutions, but none worked quite as expected.
Currently, the Geo Location is being used, so I want to base the displayed shipping cost off of that location. Each product may have more than one shipping option, but I only want to display the flat rate fee for the individual product. E.g.
In the US - Product X - Shipping Cost $Y
In the UK - Product X - Shipping Cost £Z
Currently I have the following code:
function shipping_cost_display_1() {
$rates = WC()->session->get("shipping_for_package_0")['rates'];
if (! empty($rates) ) {
foreach ( $rates as $rate_key => $rate ) {
$method_id = $rate->method_id;
$instance_id = $rate->instance_id;
$rate_id = $rate_key;
$label = $rate->label;
$cost = $rate->cost;
$taxes_array = $rate->taxes;
$update_cost = ceil($cost *= (1 + display_tax_rate_on_single_product() / 100));
if ($label == 'Shipping cost') {
//'Shipping cost' is the Flat Rate
echo $label;
echo number_format($update_cost, 2);
}
}
}
}
It is displaying on the product page, but there are some issues. It will display the correct price on one page, but then if I go to another page the same price for the previous product will be displayed. If I add something to the cart then the price displayed on all product pages will change to that, so it seems to be related to the cart somehow.
Is there a way to get the direct flat rate for the individual product rather than have it related to the cart? Since Geo Location is already active, it should be possible to simply pull the flat rate for the product based on the current location.
I assume this current issue is happening somehow due to WC()->session , but any input would be appreciated.
I have a pretty weird issue, I hope someone can help me with this.
Here are the major config settings that influence my problem:
Catalog prices in admin panel are shown including tax
Catalog prices in frontend are shown including tax
Items in shopping cart are shown excluding tax (so it's displayed separately near the subtotal).
Everything is working fine so far. The problem comes in a custom ajax mini cart module. I grab the collection of items from the cart, but, since I'm getting the price from the shopping cart item, I get it without tax.
Here is some code to exemplify what I mean. I will assume a 20% tax and a product that has the admin price (including tax) set to 120$, an option that costs 60$ (also including tax). Excluding tax these would be 100$ and 50$. I want to get the price + option + tax => 180$
$quote = Mage::getSingleton('checkout/session')->getQuote();
$items = $quote->getAllVisibleItems();
foreach ($items as $item) {
echo $item->getPrice(); // 150$ - price excluding tax
echo $item->getPriceInclTax(); // 150$ - price excluding tax
echo $item->getProduct()->getPrice(); // 120$ price including tax, BUT without the customer selected options.
}
PS: The custom option I am talking about is user selected, for example an install checkbox that adds +50$ to the price of the product.
- Get products id, name, price, quantity, etc. present in your cart.
- Get number of items in cart and total quantity in cart.
- Get base total price and grand total price of items in cart.
Get all items information in cart
// $items = Mage::getModel('checkout/cart')->getQuote()->getAllItems();
$items = Mage::getSingleton('checkout/session')->getQuote()->getAllItems();
foreach($items as $item) {
echo 'ID: '.$item->getProductId().'<br />';
echo 'Name: '.$item->getName().'<br />';
echo 'Sku: '.$item->getSku().'<br />';
echo 'Quantity: '.$item->getQty().'<br />';
echo 'Price: '.$item->getPrice().'<br />';
echo "<br />";
}
Get total items and total quantity in cart
$totalItems = Mage::getModel('checkout/cart')->getQuote()->getItemsCount();
$totalQuantity = Mage::getModel('checkout/cart')->getQuote()->getItemsQty();
Get subtotal and grand total price of cart
$subTotal = Mage::getModel('checkout/cart')->getQuote()->getSubtotal();
$grandTotal = Mage::getModel('checkout/cart')->getQuote()->getGrandTotal();
Have you tried:
$product->getFinalPrice();
// or this?
$product->getPriceModel()->getFinalPrice($qty, $product);
what is the ouput of $item->getOptions()?
Have you tried $item->getData('price')?
How do you apply your custom options? What is the ouput of $item->debug()? Maybe you can find what you need there.
Regards
Simon
I didn't find a solution to my exact problem, but I changed the settings to mimic this exact functionality, and the problem I encountered was no longer there.
First of all, I removed all the taxes on the site, and told magento all the prices are excluding tax (even though they are including tax).
The tax reduction is now made through a promotion applied on a custom group, so for
$tax = 20; // percent
I add a reduction of
(1 - (1 / ($tax / 100 + 1)))*100
// for 20% tax => 16.6667% reduction
// for 24% tax => 19.3548% reduction
with 4 decimals (that's as much as magento accepts). It may have an error of 1 cent from time to time - so if this is not an issue, go for it!
Now the prices all over the website will be shown exactly for the product (because the promotion is applied per cart, not per product).
You can try This :
$grandTotal = $this->helper('checkout/cart')->getQuote()->getGrandTotal();
echo $text .= $this->__(' Total: %s', $this->helper('core')->formatPrice($grandTotal, false));
show the quantity of a cart in my header
if ($parentBlock = $this->getParentBlock()) {
$count = $this->helper('checkout/cart')->getSummaryCount();
if( $count == 1 ) {
echo $text = $this->__('My Cart (%s item)', $count);
} elseif( $count > 0 ) {
echo $text = $this->__('My Cart (%s items)', $count);
} else {
echo $text = $this->__('My Cart (0 items)');
}
}
show the total price of a cart in my header
$grandTotal = $this->helper('checkout/cart')->getQuote()->getGrandTotal();
echo $text .= $this->__(' Total: %s', $this->helper('core')->formatPrice($grandTotal, false));
I have this code on my products view.phtml file: I am getting a shipping estimate and basing the lowest cost to a UK address and rendering this on the products page. Rather than having a full blown shipping estimator on the pages.
<?php
if($_product->isSaleable())
{
$quote = Mage::getModel('sales/quote');
$quote->getShippingAddress()->setCountryId('GB');
$quote->addProduct($_product);
$quote->getShippingAddress()->collectTotals();
$quote->getShippingAddress()->setCollectShippingRates(true);
$quote->getShippingAddress()->collectShippingRates();
$rates = $quote->getShippingAddress()->getShippingRatesCollection();
$minPrice = PHP_INT_MAX;
foreach ($rates as $rate) {
$minPrice = min($minPrice, $rate->getPrice());
}
if ($minPrice == 0) {
echo ('This item qualifies for FREE shipping');
}
elseif ($minPrice < PHP_INT_MAX) {
echo ('Shipping to UK from £' . money_format('%i', $rate->getPrice()) . "\n");
}
}
?>
Which works fine for simple products. however on configurable products, it always displays free shipping! How can get around this?
This is just a guess, but a configurable product is just a container to organize a bunch of simple products. When you add a product to the cart (for real), there is a simple product in the cart in addition to the configurable one. I'm guessing that this second product provides the weight and information for shipping, etc.
That would imply that, to get your shipping estimate, you'll need to specify one of the simple products underneath the configurable (either directly, or by passing some options and pretending to have "selected" a product) in order to see your shipping estimates.
I'm setting up a tracking code for an affiliate programs. Now we give different commissions. One for Food related products and one for Non-Food related products. These are also the tax classes we have (Food, Non Food).
I need to display the sub total for food products and a subtotal for non food products.
I use the following code but that doesn't work:
<?php
//Get Order Number & Order Total
$order = Mage::getModel('sales/order')->loadByIncrementId(Mage::getSingleton('checkout/session')->getLastRealOrderId());
$grandamount = number_format($order->getGrandTotal(),2);
$coupon = $order->getCouponCode();
$amountfood = number_format($order->getSubtotal('Food'), 2);
$amountnonfood = number_format($order->getSubtotal('Non_Food'), 2);
$discount = number_format(0.00 - $order->getDiscountAmount(), 2);
?>
If I use $amountfood = number_format($order->getSubtotal(), 2); it does work for the subtotal including both the food and non food values.
Could someone please help me with that.
Thanks,
Daniel
I don't think this information is available directly: magento stores the subtotal and taxes in a global way, only the total, no detailed information.
What you could do, is fetch the ordered products, for each one get his tax class and store in an array the sale value.
Something like this:
$order = Mage::getModel('sales/order')->load($order_id);
$items = $order->getAllItems();
$subtotals = array();
foreach ($items as $_item) {
if (array_key_exists($subtotals[$_item->getTaxClassId()])) {
$subtotals[$_item->getTaxClassId()] += $_item->getRowTotal();
} else {
$subtotals[$_item->getTaxClassId()] = $_item->getRowTotal();
}
}
not sure if the "if" is needed though.
hope that helps
I want to add a product to cart programmatically. Also, I want to change the product price when added to cart.
Suppose, my product's price is $100. I wanted to change it to $90 when added to cart.
I added product to cart. However, I am unable to change the product price.
Is it possible?
Here is the code to add product to cart:-
$cart = Mage::getSingleton('checkout/cart');
try {
$cart->addProduct($product, array('qty' => 1));
$cart->save();
}
catch (Exception $ex) {
echo $ex->getMessage();
}
After digging a bit into Magento's core code, I found that you need to use $item->getProduct()->setIsSuperMode(true) in order to make $item->setCustomPrice() and $item->setOriginalPrice() work.
Here is some sample code you can use within an Observer that listens for the checkout_cart_product_add_after or checkout_cart_update_items_after events. The code is logically the same except checkout_cart_product_add_after is called for only one item and checkout_cart_update_items_after is called for all items in the cart. This code is separated/duplicated into 2 methods only as an example.
Event: checkout_cart_product_add_after
/**
* #param Varien_Event_Observer $observer
*/
public function applyDiscount(Varien_Event_Observer $observer)
{
/* #var $item Mage_Sales_Model_Quote_Item */
$item = $observer->getQuoteItem();
if ($item->getParentItem()) {
$item = $item->getParentItem();
}
// Discounted 25% off
$percentDiscount = 0.25;
// This makes sure the discount isn't applied over and over when refreshing
$specialPrice = $item->getOriginalPrice() - ($item->getOriginalPrice() * $percentDiscount);
// Make sure we don't have a negative
if ($specialPrice > 0) {
$item->setCustomPrice($specialPrice);
$item->setOriginalCustomPrice($specialPrice);
$item->getProduct()->setIsSuperMode(true);
}
}
Event: checkout_cart_update_items_after
/**
* #param Varien_Event_Observer $observer
*/
public function applyDiscounts(Varien_Event_Observer $observer)
{
foreach ($observer->getCart()->getQuote()->getAllVisibleItems() as $item /* #var $item Mage_Sales_Model_Quote_Item */) {
if ($item->getParentItem()) {
$item = $item->getParentItem();
}
// Discounted 25% off
$percentDiscount = 0.25;
// This makes sure the discount isn't applied over and over when refreshing
$specialPrice = $item->getOriginalPrice() - ($item->getOriginalPrice() * $percentDiscount);
// Make sure we don't have a negative
if ($specialPrice > 0) {
$item->setCustomPrice($specialPrice);
$item->setOriginalCustomPrice($specialPrice);
$item->getProduct()->setIsSuperMode(true);
}
}
}
Magento have changed the way the prices are calculated in the cart which makes it very difficult to do this in v1.4 onwards. If you do set the price using an Observer or other device, it will almost certainly be overwritten back to the catalog price.
Effectively, you need to use Shopping Cart rules to implement this.
It is possible to set a customer specific price of a quote item. Hence, something like this should do it:
$quoteItem = $quote->addProduct($product, $qty);
$quoteItem->setCustomPrice($price);
// we need this since Magento 1.4
$quoteItem->setOriginalCustomPrice($price);
$quote->save();
Hope this helps...
Jonathan's answer is likely the best for most situations. But some customers might not like how shopping cart discounts are displayed in the cart. I recently did a project (with Magento 1.3.3) where the customer didn't like how the each line item still showed the full price as well as the subtotal, with a Discount line below the subtotal - he wanted to see the price of each item discounted, and the subtotal show the discounted price as well. He really didn't like having the Discount line after the Subtotal line.
Anyway, if you find yourself in the same boat, one approach is to override the getCalculationPrice() and getBaseCalculationPrice() methods in Mage_Sales_Model_Quote_Address_Item and Mage_Sales_Model_Quote_Item. I know that it isn't always pretty to override, much better to use events, but in this case I couldn't get events to work seamlessly on both the frontend and backend. Not sure if this approach will work in Magento 1.4+.
If I have to share my solution that I made on the base of Simon then I have managed to rewrite model class save function of quote.
public function save()
{
$this->getQuote()->getBillingAddress();
$this->getQuote()->getShippingAddress()->setCollectShippingRates(true);
$this->getQuote()->collectTotals();
//$this->getQuote()->save();
foreach($this->getQuote()->getAllItems() as $item) {
$productId = $item->getProductId();
$product = Mage::getModel('catalog/product')->load($productId);
if($product->getAttributeText('is_dummy') == 'Yes') {
$price = 2;
$item->setCustomPrice($price);
// we need this since Magento 1.4
$item->setOriginalCustomPrice($price);
}
}
$this->getQuote()->save();
$this->getCheckoutSession()->setQuoteId($this->getQuote()->getId());
/**
* Cart save usually called after chenges with cart items.
*/
Mage::dispatchEvent('checkout_cart_save_after', array('cart'=>$this));
return $this;
}
I had the same issue and i am not a developer. What i did was added a new price attribute in magento backend called "site price". On the product page this showed the higher price $100. the actual price of the item was $90. so when the shopper adds it to cart they will see the actual price of the item, but on the product page they see the custom attribute price of $100
if all your prices on the product page are a set % higher then the real price just multiply your product price by the 1+percent. So if you want to add 10% to all your prices do price*1.1
This will display your price as 10% higher but when the shopper adds to cart they will see the real price.