I am trying to join some existing simple products programmatically to an existing configurable product.
I hardly found any hints / documentation on this. I examined the MAGMI Magento Mass Importer Plugin (in particular the magmi_productimportengine.php-file) with no success.
After that I found this snippet:
function attachProductToConfigurable($childProduct, $configurableProduct)
{
$loader = Mage::getResourceModel('catalog/product_type_configurable')
->load($configurableProduct, $configurableProduct->getId());
$ids = $configurableProduct
->getTypeInstance()
->getUsedProductIds();
$newids = array();
foreach ($ids as $id) {
$newids[$id] = 1;
}
$newids[$childProduct->getId()] = 1;
//$loader->saveProducts( $_configurableProduct->getid(), array_keys( $newids ) );
$loader->saveProducts($configurableProduct, array_keys($newids));
}
But when I am trying to call the function like this:
$sProduct = Mage::getModel('catalog/product')
->loadByAttribute('sku', $v);
$cProduct = Mage::getModel('catalog/product')
->loadByAttribute('sku', $sku);
attachProductToConfigurable($sProduct, $cProduct);
(each simple product SKU gets passed step by step to the configurable product)
Fatal error: Call to a member function getId() on a non-object in ... on line 1018
which is this line from the function itself
$loader = Mage::getResourceModel('catalog/product_type_configurable')
->load($configurableProduct, $configurableProduct
->getId());
Since I do not find anything similar to joining simple SKUs to an existing configurable product, I am stuck looking up what might be wrong upon initializing the function calls, resource models etc..
Any ideas on what to keep an eye on to get this going are highly appreciated.
Give this a try:
Mage::getResourceSingleton('catalog/product_type_configurable')
->saveProducts($mainConfigrableProduct, $simpleProductIds);
Where $mainConfigrableProduct must be an instance of the configurable product, and $simpleProductIds is an array with the ids of the simple products associated to the configurable products.
On a side note, be very careful when doing this. The simple products must be in the same attribute set as the configurable products. Here is what can happen if they are not.
Related
I'm developing a module for my Prestashop website and I'm stuck for hours now on a thing. I use Prestashop 1.7.5.1.
Here is the use case :
Some products are set in the default category "preorder" who have the ID 21. When a customer buy an article who is in this category, I would like to automatically change the order state ID to the preorder ID. The order state ID for the preorder is 18.
Here is the code :
public function hookDisplayOrderConfirmation($params)
{
$objOrder = $params['order'];
$products = $objOrder->getProducts();
foreach ($products as $product)
{
$cat = (int)$product->id_category_default;
if($cat == 21)
{
$history = new OrderHistory();
$history->id_order = $objOrder->id;
$history->changeIdOrderState(18, $objOrder->id);
break;
}
}
}
By the way, where I can find all the class and method of Prestashop ? for example, where I can find all the variable of the $objOrder above ?
Thanks a lot for your support :) and have a nice day !
You can find all the variable of Order object inside [prestashop]/classes/order/Order.php class. Here you can find all the variable and function/ methods related to the Order object.
I've got an observer which changes the prices of products in the product list and the product view. To realize that i'm using the catalogProductLoadAfter and the catalogProductCollectionLoadAfter events.
public function catalogProductLoadAfter( $observer )
{
$product = $observer->getEvent()->getProduct();
$product->setPrice( 123.00 );
}
public function catalogProductCollectionLoadAfter( $observer )
{
$collection = $observer->getEvent()->getCollection();
foreach ($collection as $product)
{
$product->setPrice(123.00); // doesn't work
}
}
The catalogProductLoadAfter $product->setPrice works fine, but in catalogProductCollectionLoadAfter it does nothing... no error, no changing, nothing. What did i wrong Oo ?! Is there any magic i've to use or is that a magento bug ?
I've worked for a company which had such an observer too and there only works the catalogProductLoadAfter setPrice too and not the catalogProductCollectionLoadAfter setPrice.
I'm using the Trego Design and the Simple Configurable Product Plugin which has an AJAX product updater.. Is it possible that there are conflicts, maybe the trego plugins or the SCP Plugin overrides the prices too ?
//Edit: i searched for any setPrice uses, nothing found which can create conflicts.. no extern actions from other modules
Thanks for any help.
Greetings
Try this
public function catalogProductCollectionLoadAfter( $observer )
{
$collection = $observer->getEvent()->getCollection();
foreach ($collection as $product)
{
$product->setData('my_price','123.00');
}
}
You can retrieve the price value like below:
$product->getMyPrice();
OR
$product->getData('my_price');
I'm in the process of developing an extension for Magento 1.5.1.0, which allows me to add catalog price rules to products which quantity in stock is reduced to zero. I have added an attribute to my attribute-set called auto_discount_active. This attribute is my on/off switch which works as condition for my price rule.
I wrote an Observer that reacts on the events sales_order_place_after and catalog_product_save_before. It's task is to check wether to stock quantity of the current product has been changed and set my custom attribute to on or off.
The method which handles the catalog_product_save_before event works fine. After saving an article in the backend, the price rule becomes (in)active like it should. The code looks like following:
class Company_AutoDiscount_Model_Observer
{
public function updateAutoDiscount($observer)
{
/**
* #var Varien_Event
*/
$event = $observer->getEvent();
$product = $event->getProduct();
$data = $product->getStockData();
$discount = $data['qty'] < 1 ? true : false;
$attributes = $product->getAttributes();
$attribute = $attributes["auto_discount_active"];
if ($product->getAutoDiscountAllowed())
{
$product->setAutoDiscountActive($discount);
}
return $this;
}
}
Now I want to do the same thing, if someone places an order in my shop. That for I use the event sales_order_place_after which works so far. But after changing the custom attributes value, the price rules are not updated. My observer method looks like this:
public function updateAutoDiscountAfterOrder($observer)
{
/**
* #var Varien_Event
*/
$event = $observer->getEvent();
$order = $event->getOrder();
foreach ($order->getItemsCollection() as $item)
{
$productId = $item->getProductId();
$productIds[] = $productId;
$product = Mage::getModel('catalog/product')->setStoreId($order->getStoreId())->load($productId);
$data = $product->getStockData();
$discount = $data['qty'] < 1 ? true : false;
if ($product->getAutoDiscountAllowed())
{
$product->setAutoDiscountActive($discount);
$product->save();
}
Mage::getModel('catalogrule/rule')->applyAllRulesToProduct($productId);
}
return $this;
}
After placing an order and saving the bought article manually in the backend without changes, the price rule gets updated. But I have get the update working in my observer method.
What do I have to do to get the catalog price rule being assigned, after changing the custom attribute?
Thx in advance!
Okay, I want to advise you on some fairly major code optimisations.
You can reduce your collection size and remove the conditional logic inside your loop by using:
$order->getItemsCollection()->addFieldToFilter('is_in_stock', 0);
You could also update all the attributes with a much faster method than save(), by using:
Mage::getSingleton('catalog/product_action')
->updateAttributes($order->getItemsCollection()->addFieldToFilter('is_in_stock', 0)->getAllIds(), array('auto_discount_active' => 1), 0);
Also, bear in mind, you'll also need to apply your observer to any product stock level modification, ie. product save, import, credit memo (refund) - so its a fairly expansive area. You would probably be better served rewriting the stock class, as there isn't too many events dispatched that will give you enough scope to cover this.
Finally, to perform the assignation of rules, I would suggest extending the resource model for the rule (Mage/CatalogRule/Model/Mysql4/Rule.php) so that you can pass in your array of product ids (to save it iterating through the entire catalogue).
You could simply extend getRuleProductIds() to take a Mage::registry variable (if set) with your product ids from the collection above. Then after running the code above, you could just execute
Mage::getModel('catalogrule/rule')->load(myruleid)->save();
Which will re-index and apply rules to new products as necessary - for only the products that have changed.
I would imagine this method cutting overheads by an extremely significant amount.
I've been grabbing attribute options from Magento like so:
<?php
if ($attribute->usesSource()) {
$options = $attribute->getSource()->getAllOptions(false);
}
?>
It's been working fine until I tried to get the options for the built in 'color' attribute -- I got the following error:
PHP Fatal error: Call to a member function setAttribute() on a non-object in app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php on line 374
It would appear that the getSource() call fails and causes this error. Does anyone know why this happens and how I can get color options out?
Thanks!
It looks like that you initialize attribute by yourself, instead of using Magento attribute initialization process:
Mage::getSingleton('eav/config')
->getAttribute($entityType, $attributeCode)
Because since 1.4.x Magento has separate attribute models for catalog and customers model and definition of default source model for catalog_product now is moved from EAV attribute model (Mage_Eav_Model_Entity_Attribute) to the catalog one (Mage_Catalog_Model_Resource_Eav_Attribute).
As a result, some catalog attributes won't work with the EAV attribute model. Particularly those that use Mage_Eav_Model_Entity_Attribute_Source_Table but don't explicitly define it (color, manufacturer, etc.).
The following code snippet should work perfectly on your installation:
$attribute = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'color');
if ($attribute->usesSource()) {
$options = $attribute->getSource()->getAllOptions(false);
}
By the way Mage_Eav_Model_Config model has a lot of helpful methods, that can be used in your development, so don't hesitate to look into this model.
The above code does not work if the resource_model is empty. The following snippet does the job:
$attribute = Mage::getModel('eav/entity_attribute')->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'YOUR_ATTRIBUTE_CODE');
/** #var $attribute Mage_Eav_Model_Entity_Attribute */
$valuesCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setAttributeFilter($attribute->getId())
->setStoreFilter(0, false);
$attribute = Mage::getModel('eav/config')->getAttribute('customer','cateinterest');
$options = $attribute->getSource()->getAllOptions();
<?php
//Possible color value
$attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 'color'); //"color" is the attribute_code
$allOptions = $attribute->getSource()->getAllOptions(true, true);
foreach ($allOptions as $instance) {
$id = $instance['value']; //id of the option
$value = $instance['label']; //Label of the option
Sorry for an incomplete answer, but take a look at the database, specifically in the backend_model column. I seem to remember having this same problem until I set this field to match some of the system fields in this respect.
In Magento, if you need to get / fetch the Shopping Cart's Item details, you can do it in any of the two possible ways, which will provide you with all the shopped Items in an array:-
$cartItems1 = $cart->getQuote()->getAllItems();
$cartItems2 = $cart->getItems()->getData();
But before using any one of the above two methods, you need to initialize the shopping cart object as:-
$cart = new Mage_Checkout_Model_Cart();
$cart->init();
Can anyone please describe in details as to what the two options provide & their differences between each other, along with their possible usage.
In any more such option is available in Magento, can anyone please highlight it?
If you look at the code of the Cart and Quote classes everything will become clear.
Here's the code for $cart->getItems():
public function getItems()
{
return $this->getQuote()->getAllVisibleItems();
}
Plain and simple - it just calls a method of the Quote object. So the question now is: What is the difference between getAllVisibleItems() and getAllItems()?
Let's look at the code of both methods:
public function getAllItems()
{
$items = array();
foreach ($this->getItemsCollection() as $item) {
if (!$item->isDeleted()) {
$items[] = $item;
}
}
return $items;
}
public function getAllVisibleItems()
{
$items = array();
foreach ($this->getItemsCollection() as $item) {
if (!$item->isDeleted() && !$item->getParentItemId()) {
$items[] = $item;
}
}
return $items;
}
The only difference: getAllVisibleItems() has an additional check for each item:
!$item->getParentItemId()
which tests if the product has a parent (in other words, it tests if it is a simple product). So this method's return array will be missing simple products, as opposed to getAllItems().
Are there any other ways to retrieve items?
One would be to directly get the product collection from the quote object:
$productCollection = $cart->getQuote()->getItemsCollection();