Codeigniter cart - adding item multiple times does not increment qty - codeigniter

Im trying to add some item multiple times to cart, but added item doe's not appear in cart, if its already in it.
Is this normal in CI cart, or I messed up something?
How to workaround this?
I want same item added multiple times, in order to change price on second piece (special offers).
My cart_add function looks like example at codeigniter manual, I think there is no need to include code.
I found in cart class code, that cart row identifier ($rowid) is an md5 checksum generated from id and options. I temporarily added something like this to options array:
'options' => array('rid' => mt_rand(), ...)
but are there better ways? I feel im doing it wrong.

As I know you can't directly add/update the cart multiple times to make it's quantity increased. You need to do cart update by doing loop on cart contents. It's because CI will always create unique row_id on inserted product/item. The reason a unique ID is created is so that identical products with different options can be managed by the cart. For more clear you may refer to this article.
Here you can do to update your cart item:
foreach($this->cart->contents() as $item){
if($item['id'] == 'your_product_id'){
$item['qty'] = 3;
$this->cart->update($item);
}
}

Related

Magento Using Observer To Split Collection Unless Better Method

I am almost done building an Amazon Affiliate extension. In my catalog, the amazon products use the attribute set named AmazonAffiliate, all of the other normal products in the catalog just use whatever set happens to be assigned to them. People can add both regular products to the cart as well as amazon products to the cart.
The separation of the regular products vs. amazon products comes in the cart screen. What I want on the cart page is 2 item tables. One with Amazon products and one with regular.
Through the use of an observer for the event core_collection_abstract_load_before, I was able to filter out the Amazon products from the cart, the totals, everything. I love the way it pulls them out with just one function.
Here is the observer function:
public function excludeAmazonProductsFromMainCart($observer)
{
$collection = $observer->getEvent()->getCollection();
if($collection instanceof Mage_Sales_Model_Resource_Quote_Item_Collection) {
$attributeSetId = Mage::getModel('eav/entity_setup','core_setup')
->getAttributeSetId(Mage_Catalog_Model_Product::ENTITY,CommerceExtensions_AmazonAffiliate_Model_Module::ATTRIBUTE_SET_NAME);
$productTable = Mage::getSingleton('core/resource')->getTableName('catalog/product');
$collection->getSelect()->joinLeft(array('product_table'=>$productTable),'`main_table`.`product_id`=`product_table`.`entity_id`',array('attribute_set_id'));
$collection->getSelect()->where('`product_table`.`attribute_set_id` != '.$attributeSetId);
}
return $collection;
}
Now, the problem is that I want another collection that grabs the items that were excluded in the observer function above. This way, the amazon cart table would have those products and the normal magento product cart table would have my normal catalog products. I just cant seem to split the collection into two.
And in case it can't be split into two, I have the amazon product collection I need created as CommerceExtensions_AmazonAffiliate_Model_Mysql4_Quote_Collection. I just cant seem to set it on my new block.
Here is a screenshot of what I am trying to do. I know it can be done because there are people selling extensions with the same type of functionality.
Thank you in advance for any help!
To be able to get value from your collection
(CommerceExtensions_AmazonAffiliate_Model_Mysql4_Quote_Collection), you have to use your own template and block.
Make own template on checkout, may be commerceextension/checkout.phtml. And Do like $this->amazonItemCollection()
You can pass variable to that template from your block (CommerceExtensions_AmazonAffiliate_Block_Checkout_Cart). Write function - get amazonItemCollection(). Within this function you should be able to instantiate your collection
Add following xml in layout/checkout.xml file which connect your block and template
I have not tested this code. However it should work with few trial/error.

Displaying single product through list.phtml edit

So what i'm trying to achieve is that the product with the attribute 'promotion' set to 'yes' is displayed on the frontpage of the website. This is working, but the .phtml file i'am using with this is the regular list.phtml. This is currently showing all the items I have set to promotion but I only want to show 1.
So in short: How do I edit the list.phtml to only show 1 product instead of everything?
Change how you are pulling your collection. Clone/Rename your list.phtml, for example promotion.phtml. Then change this line, from this:
$_productCollection=$this->getLoadedProductCollection();
To this:
$_productCollection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('promotion', 1)
->addAttributeToSort('updated_at', 'DESC')
->clear()->setPageSize(1)->load();
And it should load only one item with promotion set to yes. Make sure you set the new template in either your CMS Page Content or XML, depending on which method this is added.
Explanation
Mage::getModel('catalog/product')->getCollection(): Gets the Product Collection. You can get other collections by changing the model, such as "catalog/category" and "cms/page".
->addAttributeToSelect('*'): Adds All Product Columns. This can be exchanged for things like ('name', 'url'). I'm assuming it's faster than loading all but I haven't benchmarked it. Since you're using the full template it's probably best to leave this set to all.
->addFieldToFilter('promotion', 1): Filters out products by attributes. Here we have the products filtered for all those with the 'promotion' attribute set to 1(yes/true). Products use this one, while categories use ->addAttributeToFilter() oddly enough. Definitely give Alan Storm's Collection Explanation(link below) a read through to know what all you can do with this one. You can add multiple filters to your collection, either by adding another ->addFieldToFilter(), or storing your filters in nested arrays.
->addAttributeToSort('updated_at', 'DESC'): Sorts the product collection by specific attribute and direction. Here I have the "updated_at" date set to descending order, "ASC" is ascending. You can add multiple sorting attributes, pay attention to the order you add them in, of course.
->clear()->setPageSize(1)->load(): These three are needed to make adjustments to how much the collection pulls. ->clear() must be called before it will allow changing how many products are pulled. The ->setPageSize() bit is where you specify how many products you would like to return, and ->load() of course loads the collection. Note that if you do not limit the size of the collection returned, you do not need this entire line, the products will iterate without having to call ->load().
Resources
Alan Storm said it best, give this a read and you should be a pro at manipulating collections: http://alanstorm.com/magento_collections

Update All Product Attributes programmatically

How can I set the value of a given attribute to the same value for all products (efficiently)?
By efficient I mean in one transaction, not having to loop through the entire product collection.
In the past I've used Mage_Catalog_Model_Product_Action for bulk updates on products, and it runs pretty fast
Mage::getSingleton('catalog/product_action')
->updateAttributes($productIds, array('some_attribute' => 'some_value'), 0)
But it requires you specify which product ids you're updating, creating a huge WHERE entity_id IN(...) clause in the MySQL statement. Is there a way to do this for everything?
I had same problem before, when I added 11096 product(downloadable products) in my store then client told me to add new attributes in product so i create 1 attribute (Type is Yes/No) and set to attribute set. Now my problem is how can iIedit all product and set that attribute yes or not. If I don't set then value is null so I wrote few line code.
Please check this code may be it'll helpful to you.
$ProductId = Mage::getResourceModel('catalog/product_collection') -
addAttributeToFilter('type_id', Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE) -
getAllIds(); //Now create an array of attribute_code => values
$attributeData = array("my_attribute_code" =>"my_attribute_value");
//Set the store to affect. I used admin to change all default values
$storeId = 0;
//Now Update the attribute for the given products.
Mage::getSingleton('catalog/product_action') ->updateAttributes($ProductId, $attributeData, $storeId);
It was work for me.I hope it'll work for you
Amasty "Mass Product Actions" will allow you to edit product attributes in a variety of ways. This is what we use and it's going to be a life saver once we get the Configurable Products pricing tier working properly.
http://amasty.com/mass-product-actions.html

Magento: Add a "fake" product to cart/quote

I understand how to programmatically create a product and also add to cart. I know this might sound dumb but is it is possible to generate a product on the fly and add that to the cart/quote but never actually save it in the database.
We want to create a made to order interface and I was thinking at the end it could add a bundle product with all the selections but that bundle product wouldn't actually exist in the backend.
I figured as long as you can make sure the quote and order has what it needs in terms of the product it would be ok, but obviously there is probably a lot that is tied to looking up stuff in the db on a specific sku or ID. I know that if you delete a product and then look at an order in the admin that causes issues, at least it did for this one scenario I was dealing with.
I was thinking of creating a giant bundle product that had like 6 different bundle items and each item could potentially have like 500 products and then based on what the user selects I programmatically add the bundle to cart. But then I wasn't sure if there would be a negative affect with having a gigantic bundle product like that as well.
UPDATE:
I don't think this will work, obviously there are a lot of information tied to the product in the database and we setup a test and right away we get an error for $item->getProduct(). We are moving forward with creating a giant bundle product and also the generic product with adding custom options on the fly, which Anda pointed out below. Any other suggestions will be greatly appreciated.
I'm not sure that clockworkgeek's approach is going to work. On every page load, Magento loads the items from the cart to make sure that they are still valid (in-stock, prices correct, etc), and amends the cart to reflect those values. My understanding of the system in the past has been that a product in the cart needs to have a corresponding database value to survive this process.
The "giant bundle product" approach is a pain, but in the past has been the best approach I have found. Attempting to change the values of the product (such as price or attributes) will be overridden by the cart checks, so you need a product w/ maximal flexibility, such as an overly-customized bundle product or configurable product.
Hope that helps!
Thanks,
Joe
Why not create a generic product in db and then set the product customization as custom options (additional_options) on the fly depending on the user selection. You can add custom options to the product (actually to the quote item) without having to save them in the database. I did this once for a website that sells glasses with prescription. The prescription was added as an option.
You can programmatically create Mage_Sales_Model_Quote_Items and add them to the cart. You've noticed it needs a product to match it's product ID but it needn't be a useful one. It could be a blank, disabled product, also created in code. All that's needed is a stub.
The necessary stuff for the cart is stored in the quote item - fields like name, value and quantity. Those fields are then copied directly to the order without using a product.
Mage::getModel('catalog/product')
creates a new product. you can add it to a cart, by doing something like this:
$cart = Mage::getSingleton('checkout/cart');
$product = Mage::getModel('catalog/product')
->setStoreId($storeid)
->setTypeId($type_id)
->setQty($quantyty)
->setWhatAttributYouWant($attribute);
$cart->addProduct($product);
product attributes you can find in the DB in tables that start like catalog_product_... or take an already created product, and see what attributes it has in the _data array (with debugger or just print_r($product->getData))

What is the conceptual difference between a Product and a Quote Item

Involved classes : Mage_Sales_Model_Quote_Item and Mage_Catalog_Model_Product.
I get both of them as a result of listening an event ( on cart add ). I am trying to update the quantity information for a product from an external source.
So far I based my code only on the product information and I am not sure if this is correct.
What is the purpose of Quote Items?
How about an bundled of configurable product? Do you have any recommendation on how to get the individual items from a bundle product?
Thanks
I want to thank both responders so far for their effort but their responses are pretty far from my question. I'll try to respond myself based on the things that I've learned.
A quote is a concept related to the order, only that is previous to that in terms of work flow in Magento. A real world concept is something like a preorder, like a postIt on which you place your asked dishes in a restaurant without being an order or a bill.
I was monitoring an event (checkout_cart_product_add_after) that is sending me the $product and the $orderItem. I understand now that is sending both in order to get information about the product and information about billing and the representation of that product in the future order.
In the case of the grouped products for example where the $product is Tshirt with various associated sizes, the $product will contain the SKU of the main grouped product and the $orderItem will contain the instance of the Tshirt that was selected ( medium size SKU ).
FYI: So in order to update the information of a product at cart update you have is better to get the product info from the $item if is a complex type ( bundle, configurable or grouped )
Magento drops quote items into the cart, specifically. Those quote items are retrieved by using $product->prepareForCart. These items also include different information, such as quantity and configurable product options (on a quote item).
From a backend perspective, data for products are stored in: catalog_product_entity_*, whereas quote items are stored in sales_flat_quote_item (at least in Enterprise. someone else might want to verify this on community).
EDIT: Attaching some code that we wrote to import product inventories a while back.
$product = Mage::getModel("catalog/product")->load($productId);
$product->seStockData(array(
"qty" => (int)$yourQuantity,
"is_in_stock" => ((int)$isTheProductInStock),
"manage_stock" => $manageStock,
"is_qty_decimal" => $isQtyDecimal,
"use_config_manage_stock" => $useConfigManageStock,
));
Mage::getModel('catalog/product_api')->update($sku,$product->getData());
For your purposes you may just need to call $product->save();, but I'm including the whole snippet as written because it works.
Hope that helps. Thanks,
Joe
My first answer would be that a product and a quote for a product are two separate entities and therefore should not be modelled in a unified entity.
An example of why would be from the company I work for, and why we model these things separately:
In our e-procurement system you might have a "contract" between a specific buyer and a seller. The "quote" item models this when it comes to invoice entries. If there isn't a contract use the normal product price to create a Quote Item else adjust the price using the "contract" between supplier and buyer.

Resources