A client wants all products that are sold out to appear at the end of the product listings and I'm struggling to get it to work at the minute, hence the question. It's worth noting that all the categories in the system are set to only use 'Best Value' positioning for their product ordering and that this repositioning must be done automatically.
Currently I've added an observer to the 'sales_convert_quote_item_to_order_item' event which is the point where the cart items are added to the order itself (seemed like a sensible place to target).
The problem I've found is that obviously the qty available for a product is stored on the products inventory record but the products positioning is stored against the category itself (and then indexed).
I don't really want to resort to using SQL so was hoping someone here would be able to offer some sort of suggestion for a method to use.
My Observer method currently looks like this but it doesn't work because the getUsedProducts method isn't available for some reason. Here it is anyway:
$cart = Mage::getModel('checkout/cart')->getQuote();
foreach($cart->getAllItems() as $key=>$item):
print_r(get_class_methods($item));
echo ">>> ".$item->getProductType();
if($item->getProductType()):
$item = $item->load($item->getId());
//print_r(get_class_methods($item));
$_productCollection = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null,$item);
print_r($_productCollection);
$stockLevel = 0;
foreach($_productCollection as $product):
$childProductData = $product->getData();
$stockLevel+= $childProductData['stock_item']['qty'];
endforeach;
echo "<br />STOCK LEVEL: $stockLevel<br />";
if($stockLevel <= 0):
echo "ZERO";
//return true;
endif;
endif;
echo "<br />";
endforeach;
I recognise that this isn't a great way of doing this and as such would be quite intensive it there were a lot of products in the cart. But as the order isn't created at this point then I can't use that either.
Any pointers or suggestions would be gratefully received.
Thanks.
If I am correctly understood from the Problem:
...A client wants all products that are sold out to appear at the end of the product listings...
If listings = categories then why don't u change rendering logic? Simply extend catalog product list and override get product collection method.
What u need to achieve is that all sold out products are at the end of the list. So you can sort loaded collection of products with one of these functions.
You can also use Bestseller logic for listing the products.With the help of this link http://inchoo.net/ecommerce/magento/bestseller-products-in-magento/ Or http://blog.magikcommerce.com/how-to-display-best-selling-products-on-magento-store-home-page/ you will know how to get the bestseller products and then you need to call this best seller block in product list.Hope this will help you if you are still searching for the solution.
Related
Hello and good day to all the members of this great community. I'm still new in PHP and especially in Magento.
I'm not posting, waiting for answers, and leaving without replying back. This is a learning process. I hope to get a great support from all of you.
I have a product. I did create custom option for the product, that is an attribute named "a_size". The attribute has value of S, M and L. Each of the value has quantity.
In the single product view, I would like to call all the available size. That is the size (S, M, or L) that has quantity more than 0. I just want to show the available size, not how much the size left.
Can anybody guide me? I'm using Magento 1.7.x and as far for this 2 weeks, I did try pretty many of suggested answers from the community thru the search function.
The replies will be much appreciated. Thank you.
There are a few things to try.
Firstly check that when you set up your new attribute in the Magento Admin (Catalog->Attributes->Manage Attribute) that in the Frontend Properties box you have set Visible on Product View Page on Front-end to yes.
To get size values I use this code:
$cabac_sizeAttribute = $_product->getAttributeText("a_size");
but I have other code for getting attribute values that goes like this:
$_product_helper = Mage::helper('catalog/output');
$temp = $_product_helper->productAttribute($_product, $_product->getASize(), 'a_size');
I think it is related to the type of attribute: text, dropdown, multiselect etc so try both and see how you get on. But really the function productAttribute() is just applying formatting. You can read the function in the file app/core/Mage/Catalog/Helper/Output.php
Also, I wonder, if you have set up a configurable product and you are on the product view page then you will be viewing the configurable product. That product won't have an a_size value: you are trying to access the a_size attribute of the simple products that make up the configurable product, yes? Everything I wrote above is (I think) correct but to get the attribute of the simple products that are part of a configured product you should study the code in the function getJsonConfig() of the file app/core/Mage/Catalog/Block/Product/View/Type/Configurable.php
And in particular to these lines:
//file: file app/core/Mage/Catalog/Block/Product/View/Type/Configurable.php
//class: Mage_Catalog_Block_Product_View_Type_Configurable
//function: getJsonConfig()
foreach ($this->getAllowProducts() as $product) {
$productId = $product->getId();
foreach ($this->getAllowAttributes() as $attribute) {
$productAttribute = $attribute->getProductAttribute();
$productAttributeId = $productAttribute->getId();
$attributeValue = $product->getData($productAttribute->getAttributeCode());
Being careful about variable naming: $product is local here, I suggest changing it, and about $this - but if you are in a .phtml of the product view for configurables then I think your $this is already Mage_Catalog_Block_Product_View_Type_Configurable
Welcome to Magento coding. You are doing well; it is a long but rewarding path. (hints: local.xml is your vital friend and so is Alan Storm if you haven't come across his content yet.)
[Additionally, (welcome to Magento) I think you are trying to say eg S and L are out of stock and M is in stock but actually the function getAllowProducts() will disallow a product with zero stock and exclude it from the returned object. You will need to use
$allProducts = $this->getProduct()->getTypeInstance(true)
->getUsedProducts(null, $this->getProduct());
(taken from function getAllowProducts() in file app/core/Mage/Catalog/Block/Product/View/Type/Configurable.php)
and then, if needed, check that each product is allowed to be shown eg status=ENABLED, and then check its stock level...
]
Malachy.
If you want to get the values of your drop down attribute use the following code
$_product->getASize();
and initially load the product object
today I'm fighting with Magento again :) and I found a difference between
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $product_sku);
and
$product = Mage::getModel('catalog/product')->load($product_id);
Can anyone exaplain me a difference between these two approaches? I found that when I'm loading a product by sku then when I 'try to re-save it with changed data then I get error exception 'Varien_Exception' with message 'Invalid method Varien_Object::save in app\code\core\Mage\CatalogInventory\Model\Observer.php(153): Varien_Object->__call('save', Array) that's true because once you try to load by sku then another observer sets product's stock item as Varien_Object, that looks like pitfall or I just dont understand it enough, but
I do daily Magento development from its beginnig so I know a lot about system and this is new for me. Thanks in advance, Jaro.
Interesting. While both methods will net you a single product model instance with fully loaded EAV data (provided the third parameter of loadByAttribute() is not passed or is *), the observers which add stock-related data are different for products vs. product collections, yet both stock information objects are added to the product data key "stock_item". It's debatable, but this feels like a bug. I would think that Mage_CatalogInventory_Model_Observer::saveInventoryData() or Mage_CatalogInventory_Model_Observer::_prepareItemForSave() would handle this.
You could resolve this issue by setting the product stock item fully on your product instance using the stock_item object.
loadByAttribute is a serious misnomer in my opinion because it doesn't actually trigger a load(); rather it uses getResourceCollection():
public function loadByAttribute($attribute, $value, $additionalAttributes = '*')
{
$collection = $this->getResourceCollection()
->addAttributeToSelect($additionalAttributes)
->addAttributeToFilter($attribute, $value)
->setPage(1,1);
Because it doesn't trigger the observer events associated with load() it means the resulting product object doesn't include the full set of product data you might want. In my case I needed the "description" attribute and it wasn't included.
There are several ways to resolve this:
Use a different method to load by SKU:
$product = Mage::getModel("catalog/product");
$product->load($product->getIdBySku("whatever"));
Force the desired attribute data to be included in the default product resource data by visiting Magento Admin > Catalog > Attributes > Edit attribute > "Used in Product Listing" = "Yes" and then reindexing. You should then be able to use the attribute data (in the frontend, at least) using loadByAttribute().
See also https://magento.stackexchange.com/a/197286/18855
So when you do a credit memo in Magento, it sets the stock back to the correct level but does not change the "out of stock" back to "in stock" (if applicable). I came across this post by Wright Creatives (http://wrightcreativelabs.com/blog/55-credit-memo-in-stock.html) and it solves this problem. However, the method is too slow! It takes about 30 seconds per product.
I've ultimately had to remove this as a solution (because of the "speed") and now my boss would like the functionality reimplemented.
I know that the is_in_stock data controls this & I'm wondering if there is already a module out there, an article/tutorial, or someone who can help me get started on a "better/faster" solution.
I know it's old but because this isn't yet fixed not even in 1.7.0.1 I came up with a better solution.
Tested on 1.5.1 and above:
\app\code\core\Mage\CatalogInventory\Model\Observer.php
in
public function refundOrderInventory($observer)
after
Mage::getSingleton('cataloginventory/stock')->revertProductsSale($items);
//add this
foreach ($creditmemo->getAllItems() as $item) {
$productId = $item->getProductId();
$product = Mage::getModel('catalog/product')->load($productId);
if(!$product->isConfigurable()){
$stockItem = $product->getStockItem();
//$stockItem->setQty($item->getQty());
$stockItem->setIsInStock(1);
$stockItem->save();
$product->setStockItem($stockItem);
$product->save();
}
}
Write a module that observes the event for credit memos and sets the in_stock flag on the products stock item object before product save. I cant tell you the event you want to observe but I am positive you can find it :)
If there is none, the uglier way would be to observe the products before save. More logic to pull it off but if you always want products to be in stock if they have qty regardless of anything else, then its not a bad idea.
Stores >> Config >> Inventory >> scroll to bottom
Go to System -> Configuration -> Inventory (under Catalog) -> Product Stock Options -> Automatically Return Credit Memo Item to Stock and make sure it's set to Yes.
Or simply go to your database and in core_config_data where the path is 'cataloginventory/item_options/auto_return' make sure that the value column is set to '1';
I need to know, if any solution how to add in magento success.phtml order's total price?
Because I want after placed order, customer get all info how to make payment including what price need to pay, because customer don't remember in last step what is total price.
You could use something like this in your success.phtml:
$sOrderId = Mage::getSingleton('checkout/session')->getLastOrderId();
$oOrder = Mage::getModel('sales/order')->load($sOrderId);
echo $oOrder->getGrandTotal();
in success.phtml template you can use
$order = Mage::getModel('sales/order')->loadByIncrementId($this->getOrderId());
$total = $order->getGrandTotal();
proper way is to extend the Mage_Checkout_Block_Onepage_Success and add your own method for loading the order again (As in this page quote is inactive already) as it is not nice to load such stuff in templates
We're building a custom Ajax product search and are returning attribute options, from associated simple products for a configurable product, that are available to purchase.
In this case, the attribute is 'gender', so to illustrate, I'm trying to show, in the search, whether we have 'Guys, Girls, Kids' in stock, or just 'Guys'.
It's the EXACT same logic as product options on a product page, but it's global.
I have it working with this code:
$attributeOptions = false;
$jsonConfig = $this->getLayout()->createBlock('Mage_Catalog_Block_Product_View_Type_Configurable')->setProduct($_product)->getJsonConfig();
$jsonConfigDecode = Mage::helper('core')->jsonDecode($jsonConfig);
$genderAttributes = reset($jsonConfigDecode['attributes']);
$attributeOptions = $genderAttributes['options'];
But it's taking up to 1 second per product result so can't be used in our Ajax implementation, which may have dozens of results.
I'm wondering if there's a better/faster way. Perhaps, I'm bypassing flat catalog, which we're using by doing this?
Thanks for your help!
Wilson
Better way.
$product->getTypeInstance()->getConfigurableAttributesAsArray()