When a new simple product is added (via CSV or manually) we need to check if the appropriate configurable product has been added (where SKU = "item_number-item_colour_code" e.g. BLEA2606B-BK001). If the configurable product exists then associate the simple product. If the configurable product does not exist then create using the data in the simple product AND then associate the simple product.
I found some help from HERE but don't know how check if configurable product already exists, and if not how to create one.
Here is the script file that I downloaded. Can anybody advice if this will work with my scenario?
EDITED
I have scraped the idea of creating configurable product in import. I am doing it by capturing the catalog_product_save_after event now. Hopefully that will get me somewhere.
EDITED 2
OK, Finally, I have it working. I'm doing it in the observer. I know it slows down the product save process but couldn't think of any other way. Thats what I'm doing:
public function productSave($observer)
{
$p = $observer->getProduct();
$pr = Mage::getModel('catalog/product')->load($p->getId());
$attributeValue = Mage::getResourceModel('catalog/product')->getAttributeRawValue($pr->getId(), 'size'); //loads attribute option value
$qtyStock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($pr)->getQty();
Mage::log('Qty: '.$qtyStock.$pr->getId(), null, 'test.txt');
if ($pr->getTaxClassId() == '0' || !isset($pr->getTaxClassId)) {
$taxClass = 'None';
} elseif ($pr->getTaxClassId() == '2') {
$taxClass = 'Taxable Goods';
} elseif ($pr->getTaxClassId() == '4') {
$taxClass = 'Shipping (not used by AvaTax)';
} elseif ($pr->getTaxClassId() == '5') {
$taxClass = 'General';
}
$_configSku = $pr->getItemNumber().'-'.$pr->getItemColourCode();
$category = array();
$categoryCollection = $pr->getCategoryCollection();
foreach ($categoryCollection as $cat) {
$category[] = $cat->getId();
}
$_configExist = Mage::getModel('catalog/product')->loadByAttribute('sku',$_configSku);
if($_configExist && $_configSku != '-') {
//Mage::log($_configExist, null, 'test.txt');
//Mage::log($_configSku, null, 'test.txt');
$new_ids = array();
$current_ids = $_configExist->getTypeInstance()->getUsedProductIds();
foreach($current_ids as $temp_id)
{
$new_ids[] = $temp_id;
}
}
if(!$_configExist && $_configSku != '-') {
$att_size = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_product','size');
$att_sizes = $this->__getAttList('size');
$confProduct = Mage::getModel('catalog/product');
$confProduct->setAttributeSetId('10');
$confProduct->setSku($_configSku);
$confProduct->setTypeId('configurable');
$confProduct->setName($pr->getName());
$confProduct->setDescription($pr->getDescription());
$confProduct->setShortDescription($pr->getShortDescription());
$confProduct->setCreatedAt(strtotime('now'));
$confProduct->setPrice($pr->getPrice());
$confProduct->setStatus(1);
$confProduct->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);
$confProduct->setWebsiteIDs(array(1));
$confProduct->setStockData(array(
'is_in_stock' => 1,
'qty' => 9999
));
$confProduct->setTaxClassId( $taxClass );
$confProduct->setCategoryIds( $category );
/* Set Configurable Attributes */
$confProduct->setConfigurableAttributesData($tmp = array(
array_merge($att_size->getData(), array('label' => '', 'values' => $size_values))
));
$simpleProducts = array(
$pr->getId()=>array( 'attribute_id'=>'145', 'label'=>'size', 'value_index'=>$attributeValue, 'is_percent'=>0, 'pricing_value'=>'' )
);
/* Set Associated Products */
$confProduct->setConfigurableProductsData( $simpleProducts );
//print_r( get_class_methods( $confProduct ) );
$confProduct->save();
}
elseif ($_configExist && !in_array($pr->getId(), $new_ids)) {
$new_ids = array();
$current_ids = $_configExist->getTypeInstance()->getUsedProductIds();
$current_ids[] = $pr->getId();
$current_ids = array_unique($current_ids);
foreach($current_ids as $temp_id)
{
parse_str("position=", $new_ids[$temp_id]);
}
Mage::log('inside', null, 'test.txt');
Mage::log($current_ids, null, 'test.txt');
$_configExist->setConfigurableProductsData($new_ids)->save();
}
All works fine with manual product save/update and import csv (it is slow but works). The only thing is, in configurable product, the Attribute Name field is empty. How to set attribute name there?
with magmi you can easily create configurable products, and more awesome stuff
I have found the way. See EDITED 2 section in the question for the solution.
Related
I want to hide configurable options that doesn't have any image associated. I tried to rewrite the configurable product block but it doesn't work. anyone has any idea about this ?
I think a good solution is to set all simple products that don't have any pictures as out of stock and set the config system->catalog->inventory->stock options->Display Out of Stock Products to no.
If you have an product import logic you can integrate that code into that.
I got solution.
What I noticed, the configurable product options are coming from function $this->getJsonConfig(); located at Mage_Catalog_Block_Product_View_Type_Configurable block. what I did is, I rewrite this block in my module and alter the function by putting the below code in it.
public function getJsonConfig()
{
$attributes = array();
$options = array();
$store = $this->getCurrentStore();
$taxHelper = Mage::helper('tax');
$currentProduct = $this->getProduct();
$preconfiguredFlag = $currentProduct->hasPreconfiguredValues();
if ($preconfiguredFlag) {
$preconfiguredValues = $currentProduct->getPreconfiguredValues();
$defaultValues = array();
}
foreach ($this->getAllowProducts() as $product) {
if($product->getImage() && $product->getImage() != 'no_selection'){
$productId = $product->getId();
foreach ($this->getAllowAttributes() as $attribute) {
$productAttribute = $attribute->getProductAttribute();
$productAttributeId = $productAttribute->getId();
$attributeValue = $product->getData($productAttribute->getAttributeCode());
if (!isset($options[$productAttributeId])) {
$options[$productAttributeId] = array();
}
if (!isset($options[$productAttributeId][$attributeValue])) {
$options[$productAttributeId][$attributeValue] = array();
}
$options[$productAttributeId][$attributeValue][] = $productId;
}
}
}
I just added if($product->getImage() && $product->getImage() != 'no_selection'){ in allowed products foreach loop. This will only filter image items to configurable options json object array.
I need to count how many products of a specific type are in the checkout. But only(!) the products which are of a specific type. The type is defined in a drop down attribute.
This is a code counting the weight and works perfectly.
\template\checkout\cart.phtml
<?php $items = Mage::getSingleton('checkout/session')->getQuote()->getAllItems();
$weight = 0;
foreach($items as $item) {
$weight += ($item->getWeight() * $item->getQty()) ;
}
echo $weight;
?>
But how to count only the products which have a specific attribute value?
Like
=> "count only products which have Attribute color = green"
I found lot about collection and filter but it seems not to work for the shopping cart items.
Hope you can help me.
You have to load the product model as you're looping ( Expensive ) and then you're able to call attributes on it like so:
foreach( $oItems as $oItem )
{
$oProduct = $oItem->getProduct();
$oProductModel = Mage::getModel( 'catalog/product' )->load( $oProduct->getId() );
// For code...
$sColor = $oProductModel->getData( 'color' );
var_dump( $sColor );
// For text...
$sFormat = $oProductModel->getAttributeText( 'color' );
var_dump( $sFormat );
}
This is how you can get the attribute value (after loading your product):
$product = $item->getProduct();
$value = $product->getAttributeText($yourAttributeCode);
But notice for this in order to work you need to set: 'Show in Product Listing' or 'Used in Product Listing' to yes in the attribute editor from admin panel.
And for the grouping part, one possible way could be doing something like this (it makes sense only if you have a small number of values for your specific attribute):
$weights = array ('redWeight' => 0, 'blueWeight' => 0, 'yellowWeight' => 0, ..);
$groupRed = array();
$groupGreen = array();
...
foreach($items as $item) {
$product = $item->getProduct();
$value = $product->getAttributeText('yourAttributeCode');
$weight = ($item->getWeight() * $item->getQty());
if($value){ //Do all products have this attribute?
Switch($value){
case "red":
$Weights['redWeight'] += $weight;
$groupRed[] = $item;
break;
case "green":
....
}
} else {
continue;
}
}
....
HERE YOU HAVE GROUPS OF YOUR ITEMS ACCORDING TO THEIR SPECIFIC ATTRIBUTE VALUES
i am not sure why the sorting of a product attribute on compare page is not working same as on product page. Like on product page the atribute sort is
on product page
1 name
2 new attribute
3 new attribute1
4 color
but on comapre page when i am comp[aring the 2 products has same attributes the attribute sort order becomes
on compare page
1 name
2 color
3 new attribute
4 new attribute1
I have googled a lot to find answer but unable to find. Please help me to fix this issue.
Below are the functions which i find
public function getComparableAttributes()
{
if (is_null($this->_comparableAttributes)) {
$this->_comparableAttributes = array();
$setIds = $this->_getAttributeSetIds();
if ($setIds) {
$attributeIds = $this->_getAttributeIdsBySetIds($setIds);
$select = $this->getConnection()->select()
->from(array('main_table' => $this->getTable('eav/attribute')))
->join(
array('additional_table' => $this->getTable('catalog/eav_attribute')),
'additional_table.attribute_id=main_table.attribute_id'
)
->joinLeft(
array('al' => $this->getTable('eav/attribute_label')),
'al.attribute_id = main_table.attribute_id AND al.store_id = ' . (int) $this->getStoreId(),
array('store_label' => $this->getConnection()->getCheckSql('al.value IS NULL', 'main_table.frontend_label', 'al.value'))
)
->where('additional_table.is_comparable=?', 1)
->where('main_table.attribute_id IN(?)', $attributeIds);
$attributesData = $this->getConnection()->fetchAll($select);
if ($attributesData) {
$entityType = Mage_Catalog_Model_Product::ENTITY;
Mage::getSingleton('eav/config')
->importAttributesData($entityType, $attributesData);
foreach ($attributesData as $data) {
$attribute = Mage::getSingleton('eav/config')
->getAttribute($entityType, $data['attribute_code']);
$this->_comparableAttributes[$attribute->getAttributeCode()] = $attribute;
}
unset($attributesData);
}
}
}
return $this->_comparableAttributes;
}
/**
* Load Comparable attributes
*
* #return Mage_Catalog_Model_Resource_Product_Compare_Item_Collection
*/
public function loadComparableAttributes()
{
$comparableAttributes = $this->getComparableAttributes();
$attributes = array();
foreach ($comparableAttributes as $attribute) {
$attributes[] = $attribute->getAttributeCode();
}
$this->addAttributeToSelect($attributes);
return $this;
}
bUt i cant understand how to filter it by sort order .Please suggest
check the modifications in function below:
the file used is vendor/magento/module-catalog/Model/ResourceModel/Product/Compare/Item/Collection.php
But this is not the best way to do it. you need to override it as per Magento Standards.
I am working on it, will update shortly.
public function getComparableAttributes()
{
if ($this->_comparableAttributes === null) {
$this->_comparableAttributes = [];
$setIds = $this->_getAttributeSetIds();
if ($setIds) {
$attributeIds = $this->_getAttributeIdsBySetIds($setIds);
$select = $this->getConnection()->select()->from(
['main_table' => $this->getTable('eav_attribute')]
)->join(
['additional_table' => $this->getTable('catalog_eav_attribute')],
'additional_table.attribute_id=main_table.attribute_id'
)->joinLeft(
['al' => $this->getTable('eav_attribute_label')],
'al.attribute_id = main_table.attribute_id AND al.store_id = ' . (int)$this->getStoreId(),
[
'store_label' => $this->getConnection()->getCheckSql(
'al.value IS NULL',
'main_table.frontend_label',
'al.value'
)
]
)
->joinLeft( //add sort order to sort the attributes as per backend sort. -- Abid
['as' => $this->getTable('eav_entity_attribute')],
'as.attribute_id = main_table.attribute_id'
)
->where(
'additional_table.is_comparable=?',
1
)->where(
'main_table.attribute_id IN(?)',
$attributeIds
)
->order('as.sort_order') //sort by sort_order -- Abid
;
$attributesData = $this->getConnection()->fetchAll($select);
if ($attributesData) {
$entityType = \Magento\Catalog\Model\Product::ENTITY;
$this->_eavConfig->importAttributesData($entityType, $attributesData);
foreach ($attributesData as $data) {
$attribute = $this->_eavConfig->getAttribute($entityType, $data['attribute_code']);
$this->_comparableAttributes[$attribute->getAttributeCode()] = $attribute;
}
unset($attributesData);
}
}
}
return $this->_comparableAttributes;
}
On product page attributes are sorted like in attribute set.
On compare page attributes are not sorted at all.
You can rewrite function getComparableAttributes in class Mage_Catalog_Model_Resource_Product_Compare_Item_Collection and implement your own sort logic.
But note, that this function differs in different Magento versions. You can try to use free extension ET Advanced Compare or take part of code from this extension (code is available on bitbucket.org. link i on extension page)
i m developping an extension for custom price and i wanna know how to get the unit price from cart i've tried this :
$itemProduct = $this->getProduct();
$cart = Mage::getModel('checkout/cart')->getQuote();
foreach ($cart->getAllItems() as $item) {
$productId = $item->getProduct()->getProductId();
$productPrice = $item->getProduct()->getPrice();
if($productId == $itemProduct->getId()){
/*
* do our check for 'same product' here.
* Returns true if attribute is the same thus it is hte same product
*/
if ($productPrice == $itemProduct->getPrice()) {
return true; //same product
} else {
return false; //different product
}
}
but it returns always false i guess i didn't get the unit price
how to do that ?
try direct to database like :
if you want to looking for quote unit price check ( table name : sales_flat_quote then column subtotal )
if you are looking for sales uni price take a look under ( table name : sales_flat_order then column subtotal )
this help you to improve your extension speed ( only to get content not add )
Thanks
Solved change this :
$productId = $item->getProduct()->getProductId();
$productPrice = $item->getProduct()->getPrice();
to this :
$productId = $item->getProductId();
$productPrice = $item->getPrice();
I have an bundle product as array like this: (take from params when add product to cart)
Array
(
[product] => 165
[bundle_option] => Array
(
[17] => 47
[22] => 60
[16] => 46
[15] => 42
[14] => Array
(
[0] => 39
)
)
)
How could I get price for this bundle product?
Something like this should also work:
public function getDisplayPrice($product) {
if($product->getFinalPrice()) {
return $product->getFormatedPrice();
} else if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) {
$optionCol= $product->getTypeInstance(true)
->getOptionsCollection($product);
$selectionCol= $product->getTypeInstance(true)
->getSelectionsCollection(
$product->getTypeInstance(true)->getOptionsIds($product),
$product
);
$optionCol->appendSelections($selectionCol);
$price = $product->getPrice();
foreach ($optionCol as $option) {
if($option->required) {
$selections = $option->getSelections();
$minPrice = min(array_map(function ($s) {
return $s->price;
}, $selections));
if($product->getSpecialPrice() > 0) {
$minPrice *= $product->getSpecialPrice()/100;
}
$price += round($minPrice,2);
}
}
return Mage::app()->getStore()->formatPrice($price);
} else {
return "";
}
}
You can use the built-in static method calculatePrice of Mage_Bundle_Model_Product_Price like so:
if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE){
$pricemodel = Mage::getModel('bundle/product_price');
$price = $pricemodel::calculatePrice(
$product->getData('price'),
$product->getSpecialPrice(),
$product->getSpecialPriceFrom(),
$product->getSpecialPriceTo(),
false,
Mage::app()->getStore()->getWebsite()->getId(),
Mage::getSingleton('customer/session')->getCustomer()->getGroupId(),
$product->getId()
);
$finalprice = $this->helper('core')->currencyByStore(Mage::helper('tax')->getPrice($product, $price));
}
You can use the getMinimalPrice() and getMaximalPrice() functions in the Mage_Bundle_Product_Price class, which are written specifically for bundle products.
// load product
$product = new Mage_Catalog_Model_Product();
$product->load(165);
$priceModel = $product->getPriceModel();
// get options
$block = Mage::getSingleton('core/layout')->createBlock('bundle/catalog_product_view_type_bundle');
$options = $block->setProduct($product)->getOptions();
$price = 0;
foreach ($options as $option) {
$selection = $option->getDefaultSelection();
if ($selection === null) {
continue;
}
$price += $priceModel->getSelectionPreFinalPrice($product, $selection, $selection->getSelectionQty());
}
or, you can use my magento module: https://github.com/head82/KH_ExtendedBundlePrice tested with magento 1.7
#Kevin, great work. I personally needed a slight modification. In Magento 1.7.0.2, the function getSelectionPreFinalPrice() actually calls upon getSelectionPrice() which calls upon getSelectionFinalTotalPrice() - but in that last part the price is calculated with the final price (so including tier-pricing and special prices) and not the original price.
I applied the following snippet to get that original price (without tier-pricing and without special prices):
$_normalPrice = 0;
$_options = $_priceModel->getOptions($_product);
foreach($_options as $_option) {
$_selection = $_option->getDefaultSelection();
if ($_selection === null) continue;
$_normalPrice = $_normalPrice + $_selection->getPrice();
}
Here is the magento way:
$_product = $this->getProduct();
$_priceModel = $_product->getPriceModel();
list($_minimalPriceTax, $_maximalPriceTax) = $_priceModel->getTotalPrices($_product, null, null, false);
list($_minimalPriceInclTax, $_maximalPriceInclTax) = $_priceModel->getTotalPrices($_product, null, true, false);
Assuming that $this->getProduct() returns Catalog/Product Model.
Works both with fixed and dynamic price types even compatible with Configurable Bundle extention. Taken from design/base/default/template/bundle/catalog/product/price.phtml
I solved it by own method, not sure its acceptable or not.send the post values and product id, the model will return the price.
$bundle_option = Mage::app ()->getRequest ()->getParam('bundle_option');
$bundle_option_array = call_user_func_array('array_merge', $bundle_option);
$price = Mage::Helper('airhotels/bundle')->getBundlePrice($productid,$bundle_option_array);
my helper file is
public function getBundlePrice($productId,$bundle_option_array) {
$product = new Mage_Catalog_Model_Product();
$product->load($productId);
$price=0;
$selectionCollection = $product->getTypeInstance(true)->getSelectionsCollection($product->getTypeInstance(true)->getOptionsIds($product), $product);
foreach($selectionCollection as $option)
{
if (in_array($option->getSelectionId(), $bundle_option_array)){
$price += $option->price;
}
}
return $price;
}
Concept: I built a 1-D array from the 2-D array(the question). from the function in helper we can get all the selection id of a bundle product . By matching (using in_array) we can calculate the price for our custom selected products.
Although I'm sure you have figured out what you needed several year ago I'm not quite sure where in the accepted answer you would put your params.
What I found was that you can get the price for a bundle product with getFinalPrice() just like any other product, but you can set the selected options using the catalog/product helper.
$_product = Mage::getModel('catalog/product')->load($this->getRequest()->getPost()['product'];
$productHelper = $this->helper('catalog/product');
//getpost() contains the array you mentioned when you click add to cart
$_configuredProducts = $_product->getTypeInstance(true)->processConfiguration(new Varien_Object($this->getRequest()->getPost()), $_product,Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_FULL );
echo $_product->getFinalPrice();