I have added new rule in Magneto for buying x product and getting y free . I have added a configurable product with multiple simple products . This rule works fine if I buy two of simple products with same sku values. What I want is that if user buys two simple products with different sku they should get second free .
How can i achieve this ?
This cannot be done with the default implementation of cart rules. You need to create new module and add your own type of rule to the list. I have made once such a module, in the following manner:
1) I add my own option to action dropdown. Luckily there is an event adminhtml_block_salesrule_actions_prepareform where you can hook. I used something like this
$form = $observer->getEvent()->getForm();
$options = $form->getElement('simple_action')->getValues();
$options[] = array(
'value' => self::BUY_ANY_X_GET_Y_ACTION,
'label' => Mage::helper('mymodule')->__('Extended Buy X get Y free (search all cart, discount amount is Y)'),
);
$form->getElement('simple_action')->setValues($options);
2) Then I hook into salesrule_validator_process where I checked whether cart items match the rule.
This was a little bit tricky as this validator is run for each cart item so you have to count how many times it was called and which items you have checked. I used conditions tab to prepare rules that says which X items have to be bought in order to get Y items according to conditions in actions tab.
With the first run of the validator you iterate over all cart collection and divides all products in two groups: one contains items that met criteria set by conditions tab, the second one met the criteria set by actions tab. In other words you form two arrays that contains items for X and items for Y.
foreach($quote->getItemsCollection() as $item) {
if (!$item->hasParentItemId()) {
if ($rule->getActions()->validate($item)) {
$ruleItems['y'][] = $item;
}
foreach($rule->getConditions()->getConditions() as $condition) {
foreach($condition->getConditions() as $check) {
if ($check->validate($item)) {
$ruleItems['x'][] = $item;
}
}
}
}
}
You calculate how many X's are there and how many Y's products will get discount. The when the event is called for each item you check if the item is in Y array and if there is enough discounts left for that item. If so you need to set discount amount and base discount amount calculated as item_qty * price and item_qty * base_price respectively. You need to set those values on result object that is in data passed to the observer method like:
$item = $observer->getEvent()->getItem();
$result = $observer->getEvent()->getResult();
$result->setDiscountAmount($item->getQty * $item->getPrice());
$result->setBaseDiscountAmount($item->getQty * $item->getBasePrice());
Related
I just found out that Magento seems to have a bug since 1.8 relating to cart rules.
let's say we have some configurable products and want to add a "discount" for a specific product if the qty is less then 50. In my case it a surcharge not a discount (you can easily add negative discount so it'll get surcharge by changing two files see http://php.quicoto.com/extra-fee-shopping-cart-price-rules-magento/).
so what does magento do?
1) checks if rule is valid for that product
2) if not it checks if it is a configurable product, then takes the first simple product, and check the rule against that.
in this case true cause qty is less then 50 ( cause this simple product is not even in cart.... )
extending the rule by a "less then 50 and more then 1" didn't worked.
$product = $object->getProduct();
if (!($product instanceof Mage_Catalog_Model_Product)) {
$product = Mage::getModel('catalog/product')->load($object->getProductId());
}
// here, everythign correct. $valid is false cause item is less then x times in cart..
$valid = parent::validate($object);
// this part makes no sense, cause he's checking on a child which is not in cart.
/** /
if (!$valid && $product->getTypeId() == Mage_Catalog_Model_Product_Type_Configurable::TYPE_CODE) {
$children = $object->getChildren();
$valid = $children && $this->validate($children[0]);
}/**/
this small snippet is related to it, and in my eyes it doesn't make any sense. why the rule should be checked against the first product of a configurable one? why randomly check the rule against some other product?
does anyone has an idea about that?
my solution for now, just comment this line out ... ;-) and the rule get applied as it should.
greets
felix
here's an image about the rule in magento backend
Looks like $object is instance of Mage_Sales_Quote_Item. If so, it explains why rule is being checked against first child - because it is the only child of configurable product in cart. It can't be more than one child of particular configurable product item in the cart at the same time
I'm using an observer to override the checkout_cart_product_add_after in order to update a unit price of a product. The price comes from a third party system and it tailored for each customer. I can set the price as follows:
$item = $observer->getQuoteItem();
if ($item->getParentItem()) {
$item = $item->getParentItem();
}
$specialPrice = $this->get_price($item->getsku(), $item->getQty());
$item->setCustomPrice($specialPrice);
$item->setOriginalCustomPrice($specialPrice);
$item->getProduct()->setIsSuperMode(true);
The product prices can technically be as many as 6 decimal places. I'm using the ET_Currency manager to set the display to 4 decimal places as that's the maximum it seems to allow. On small quantities it's not a problem but on large quantities it can be 30p - 40p out.
Can anyone advise how I can get this to 6 decimal places so the subtotals are more accurate?
I need to be able to get the discount type applied in the cart.
I can get the discount amount like so:
$cart = Mage::getModel('checkout/cart')->getQuote();
$totals = $cart->getTotals();
$discount = $totals["discount"]->getValue();
How can i check what type of discount it is - whether it is a percentage or fixed amount off?
Take a look at applied_rule_ids in sales_flat_quote and sales_flat_quote_item
You could try something like
//if the item has not had a rule applied to it skip it
if($item->getAppliedRuleIds() == '')continue;
/*
* I cant remember in the database they might be comma separated or space if multiple rules were applied
* the getAppliedRuleIds() function is the one you want
*/
foreach(explode(",",$item->getAppliedRuleIds()) as $ruleID){
//Load the rule object
$rule = Mage::getModel('catalogrule/rule')->load($ruleID);
// Throw out some information like the rule name what product it was applied to
echo "<p>".$item->getSku()." had rule ".$rule->getName()."(".$item->getAppliedRuleIds().") applied </p>";
}
See Magento - get price rules from order
I have several websites using different currencies on each store view. The base currency (default) is set to GBP.
If I add a fixed price to a custom option the currency is converted according to store currency which is fine.
The problem starts when I want to update other values afterwards as it keeps converting the price.
For example, Let’s say I have a product on Store View 1 with a custom option that adds 100 GBP for a blue color option.
The same product will appear on Store View 2 with a custom option that adds 120 EUR for a blue color option, according to the correct currency conversion.
If I change any value on Store View 2, for example, changing the name of the product or adding an image, a change that doesn’t involve the price or the custom options, and than I save the change, it will continue to convert the price of the custom option.
If it was 120 EUR it will refer to it as if it is a new value of 120 GBP and convert it to 143.5 EUR and so on.
If I’ll click save again it will convert it again to 171.5 EUR and so on.
This happens because Magento refers to the custom options added price as a new value that needs to be converted.
Any idea how can I solve this as every time I change a value of a product it changes the custom options price?
I know that this is quite old question, but this bug still occurs (even in Magento 1.9) so maybe my answer will help somebody.
You have to overwrite Mage_Catalog_Model_Resource_Product_Option_Value class.
First add this method:
protected function checkIfPriceHasNotBeenChanged($object, $storeId)
{
$newPrice = (float)sprintf('%F', $object->getPrice());
$priceTable = $this->getTable('catalog/product_option_type_price');
$select = $this->_getReadAdapter()->select()
->from($priceTable, 'price')
->where('option_type_id = ?', (int)$object->getId())
->where('store_id = ?', $storeId);
$oldPrice = $this->_getReadAdapter()->fetchOne($select);
return $newPrice == $oldPrice;
}
Then use it in _saveValuePrices method:
if ($object->getStoreId() != '0' && $scope == Mage_Core_Model_Store::PRICE_SCOPE_WEBSITE
&& !$object->getData('scope', 'price')) {
$baseCurrency = Mage::app()->getBaseCurrencyCode();
$storeIds = Mage::app()->getStore($object->getStoreId())
->getWebsite()
->getStoreIds();
if (is_array($storeIds)) {
foreach ($storeIds as $storeId) {
if ($priceType == 'fixed') {
if ($this->checkIfPriceHasNotBeenChanged($object, $storeId)) {
continue;
}
(...)
I am trying to setup a bundle product within Magento. This product should allow the customer to select 4 free products to include with the bundle. These products can be all different or 4 of the same product.
For example
Free Product 1
Free Product 2
Free Product 3
A customer could select four of Free Product 1, or one of Free Product 1 & 2, with two of Free Product 3.
I am using 4 drop-down input types which each have all three Free products as options. So a customer can choose any of the three products for each Free Gift line item.
Magento is only displaying one of the drop-down select lists, I believe due to the fact that each drop-down contains the same product list.
Where would I need to look to stop Magento from checking if the product options are already listed in a previous selection?
Unless you're doing this programmatically (that is writing the code), there's no way to do this.
When Magento adds a product, it first looks into the quote / shopping cart to see if one already exists. If one does, it pulls that one and adds to the quantity. There is no way to turn this off.
Programmatically, you very manually add an item to a shopping cart. This is how...
$cart = Mage::getSingleton("checkout/cart");
foreach ($products_to_add as $product_id => $custom_options) {
$product = Mage::getModel("catalog/product")->load($product_id);
$options = new Varien_Object(array("options" => $custom_options,
"qty" => 1));
// some products may result in multiple products getting added to cart
// I beleive this pulls them all and sets the custom options accordingly
$add_all = $product->getTypeInstance(true)
->prepareForCartAdvanced($options, $product, Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_FULL);
foreach ($add_all as $add_me) {
$item = Mage::getModel('sales/quote_item');
$item->setStoreId(Mage::app()->getStore()->getId());
$item->setOptions($add_me->getCustomOptions())
->setProduct($add_me);
$item->setQty(1);
$cart->getQuote()->addItem($item);
}
}
// when done adding all the items, finally call save on the cart
$cart->save();