I found out the problem. I was applying the discount and then subtracting the discount from the array with the rule_id. This was supposed to prevent the discount to apply twice. But it was also setting the discount to zero and thus at checkout page when it seems that the cart rule is getting verified again, it was refreshed and the discount disappeared.
I post here the rule code maybe somebody can get help from it.
<?php
namespace MageDiscount\Discount\Model\SalesRule\Rule\Action\Discount;
use \Magento\SalesRule\Model\Rule\Action\Discount\AbstractDiscount;
/**
* Class GetMostExpensiveDiscount
* @see \Magento\SalesRule\Model\Rule\Action\Discount\BuyXGetY
*/
class GetMostExpensiveDiscount extends AbstractDiscount
{
/**
* @var \MageDiscount\Discount\Helper\Data
*/
protected $helper;
/**
* @var \MageDiscount\Discount\Helper\Rules
*/
protected $rulesHelper;
/**
* GetMostExpensiveDiscount constructor.
* @param \Magento\SalesRule\Model\Validator $validator
* @param \Magento\SalesRule\Model\Rule\Action\Discount\DataFactory $discountDataFactory
* @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
* @param \MageDiscount\Discount\Helper\Data $helper
*/
public function __construct(
\Magento\SalesRule\Model\Validator $validator,
\Magento\SalesRule\Model\Rule\Action\Discount\DataFactory $discountDataFactory,
\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
\MageDiscount\Discount\Helper\Data $helper,
\MageDiscount\Discount\Helper\Rules $rulesHelper
) {
parent::__construct($validator, $discountDataFactory, $priceCurrency);
$this->helper = $helper;
$this->rulesHelper = $rulesHelper;
}
/**
* @param \Magento\SalesRule\Model\Rule $rule
* @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
* @param float $qty
* @return \Magento\SalesRule\Model\Rule\Action\Discount\Data
*/
public function calculate($rule, $item, $qty)
{
/** @var \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData */
$discountData = $this->discountFactory->create();
if (!$this->helper->isAvailable()) {
return $discountData;
}
/** @var \Magento\Quote\Model\Quote $quote */
$quote = $item->getQuote();
/** @var \Magento\Quote\Model\Quote\Address $address */
$address = $item->getAddress();
$difRules = $address->getXgCartGetMostExpensiveDiscountRules();
//\Zend_Debug::dump($difRules, null, true);
if (!(is_array($difRules) && isset($difRules[$rule->getId()]))) {
$difRules[$rule->getId()] = $rule->getDiscountAmount();
}
//\Zend_Debug::dump($difRules, null, true);
if ($difRules[$rule->getId()] > 0) {
$x = $rule->getDiscountStep();
$y = $rule->getDiscountAmount();
$rulePercent = min(100, $y);
//\Zend_Debug::dump($rulePercent);
$cartCategories = array();
$i = 0;
$totalCartQty = 0;
foreach ($quote->getAllVisibleItems() as $vit)
{
$cartCategories[$i]['itemId'] = $vit->getId();
$cartCategories[$i]['qty'] = $vit->getQty();
$totalCartQty += $vit->getQty();
$cartCategories[$i]['itemPrice'] = $this->validator->getItemPrice($vit);
$cartCategories[$i]['baseItemPrice'] = $this->validator->getItemBasePrice($vit);
$cartCategories[$i]['itemOriginalPrice'] = $this->validator->getItemOriginalPrice($vit);
$cartCategories[$i]['baseItemOriginalPrice'] = $this->validator->getItemBaseOriginalPrice($vit);
$i++;
}
// sort array after price from higher to lower
$this->aaVSort($cartCategories, 'itemPrice');
//\Zend_Debug::dump($cartCategories, null, true);
//this is not usable for this rule!
// if(count($cartCategories) === 1)
// {
// return $discountData;
// }
//\Zend_Debug::dump($cartCategories[0]['itemId'], null, true);
//\Zend_Debug::dump($item->getId(), null, true);
if($item->getId() !== $cartCategories[0]['itemId'])
{
return $discountData;
}
$discountQtymin = min($difRules[$rule->getId()], $qty);
//\Zend_Debug::dump($discountQtymin, null, true);
//\Zend_Debug::dump($totalCartQty, null, true);
//only one item to be discounted
$discountQty = 1;
//for thisrule we must have only one item discounted
// if ($x) {
// $discountQty = floor( $totalCartQty / ($x + 1));
// }
// else
// {
// $discountQty = 1;
// }
// this line here is not needed - subtracting the discount form the rule array
//$difRules[$rule->getId()] -= $discountQty * $y;
//$difRules[$rule->getId()] += ($discountQty - 1) * $y;
//\Zend_Debug::dump($discountQty, null, true);
$discountAmount = 0;
$discountAmountBase = 0;
$discountAmountOrig = 0;
$discountAmountBaseOrig = 0;
$_rulePct = $rulePercent / 100;
//\Zend_Debug::dump($_rulePct, null, true);
$itemsToBeDiscounted = array();
//cover cases while $discountQty > 0 and shift most expensive item from array
while( $discountQty > 0)
{
//in order to discount the highest price we remove the first item from the price ordered array
$itemsToBeDiscounted[] = array_shift($cartCategories);
$discKey = count($itemsToBeDiscounted);
$availableQty = $itemsToBeDiscounted[$discKey - 1]['qty'];
if( $discountQty >= $availableQty)
{
$discountAmount += (($itemsToBeDiscounted[$discKey - 1]['itemPrice'] * $availableQty ) * $_rulePct);
$discountAmountBase += (($itemsToBeDiscounted[$discKey - 1]['baseItemPrice'] * $availableQty ) * $_rulePct);
$discountAmountOrig += (($itemsToBeDiscounted[$discKey - 1]['itemOriginalPrice'] * $availableQty ) * $_rulePct);
$discountAmountBaseOrig += (($itemsToBeDiscounted[$discKey - 1]['baseItemOriginalPrice'] * $availableQty ) * $_rulePct);
$discountQty -= $availableQty;
}
else
{
$discountAmount += (($itemsToBeDiscounted[$discKey - 1]['itemPrice'] * $discountQty ) * $_rulePct);
$discountAmountBase += (($itemsToBeDiscounted[$discKey - 1]['baseItemPrice'] * $discountQty ) * $_rulePct);
$discountAmountOrig += (($itemsToBeDiscounted[$discKey - 1]['itemOriginalPrice'] * $discountQty ) * $_rulePct);
$discountAmountBaseOrig += (($itemsToBeDiscounted[$discKey - 1]['baseItemOriginalPrice'] * $discountQty ) * $_rulePct);
$itemsToBeDiscounted[$discKey - 1]['qty'] = $discountQty;
$discountQty = 0;
}
//\Zend_Debug::dump($discountQty, null, true);
if($discountQty === 0)
{
break;
}
}
//\Zend_Debug::dump($discountAmount, null, true);
//\Zend_Debug::dump($itemsToBeDiscounted, null, true);
$discountData->setAmount($discountAmount);
$discountData->setBaseAmount($discountAmountBase);
$discountData->setOriginalAmount($discountAmountOrig);
$discountData->setBaseOriginalAmount($discountAmountBaseOrig);
}
$address->setXgCartGetMostExpensiveDiscountRules($difRules);
//\Zend_Debug::dump($difRules, null, true);
//\Zend_Debug::dump($discountData, null, true);
//\Zend_Debug::dump($item->getId(), null, true);
return $discountData;
}
/**
* Sort Multi Dimension array based on Numerical value + array_values
*
* @author Mohamed Meabed <[email protected]> modified by Andrada Crisan
*
* @param $array
* @param $key
*/
public function aaVSort(&$array, $key)
{
$sorter = array();
$ret = array();
reset($array);
foreach ($array as $ii => $va) {
$sorter[$ii] = $va[$key];
}
arsort($sorter, SORT_NUMERIC);
foreach ($sorter as $ii => $va) {
$ret[$ii] = $array[$ii];
}
$array = array_values($ret);
}
}