Commit d5a2507f by halweg

Merge branch 'developer' of http://47.99.244.21:9999/root/joshine into developer

parents ddba8c77 b339ecf5
...@@ -7,47 +7,99 @@ declare(strict_types=1); ...@@ -7,47 +7,99 @@ declare(strict_types=1);
namespace Magento\SalesRule\Model\Rule\Action\Discount; namespace Magento\SalesRule\Model\Rule\Action\Discount;
use Magento\Quote\Model\Quote\Item\AbstractItem; use Magento\SalesRule\Model\Rule\Action\Discount\AbstractDiscount;
use Magento\SalesRule\Model\Rule; use Magento\Framework\App\ObjectManager;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\SalesRule\Model\DeltaPriceRound;
use Magento\SalesRule\Model\Rule\Action\Discount\DataFactory;
use Magento\SalesRule\Model\Validator;
class BuyXGetY extends AbstractDiscount class BuyXGetY extends AbstractDiscount
{ {
/** /**
* Calculate discount data for BuyXGetY action. * @var DeltaPriceRound
* */
* @param Rule $rule private $deltaPriceRound;
* @param AbstractItem $item private static $discountType = 'BuyXGetY';
/**
* @param Validator $validator
* @param DataFactory $discountDataFactory
* @param PriceCurrencyInterface $priceCurrency
* @param DeltaPriceRound $deltaPriceRound
*/
public function __construct(
Validator $validator,
DataFactory $discountDataFactory,
PriceCurrencyInterface $priceCurrency,
DeltaPriceRound $deltaPriceRound = null
) {
$this->deltaPriceRound = $deltaPriceRound ?: ObjectManager::getInstance()->get(DeltaPriceRound::class);
parent::__construct($validator, $discountDataFactory, $priceCurrency);
}
/**
* @param \Magento\SalesRule\Model\Rule $rule
* @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
* @param float $qty * @param float $qty
* @return Data * @return \Magento\SalesRule\Model\Rule\Action\Discount\Data
*/ */
public function calculate($rule, $item, $qty): Data public function calculate($rule, $item, $qty)
{ {
/** @var \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData */
$discountData = $this->discountFactory->create(); $discountData = $this->discountFactory->create();
$ruleId = $rule->getId();
$ruleTotals = $this->validator->getRuleItemTotalsInfo($ruleId);
$quote = $item->getQuote();
$address = $item->getAddress();
$itemPrice = $this->validator->getItemPrice($item); $itemPrice = $this->validator->getItemPrice($item);
$baseItemPrice = $this->validator->getItemBasePrice($item); $baseItemPrice = $this->validator->getItemBasePrice($item);
$itemOriginalPrice = $this->validator->getItemOriginalPrice($item); $itemOriginalPrice = $this->validator->getItemOriginalPrice($item);
$baseItemOriginalPrice = $this->validator->getItemBaseOriginalPrice($item); $baseItemOriginalPrice = $this->validator->getItemBaseOriginalPrice($item);
$x = $rule->getDiscountStep(); $cartRules = $address->getBuyXGetYRules();
$y = $rule->getDiscountAmount(); if (!isset($cartRules[$ruleId])) {
if (!$x || $y > $x) {
return $discountData; return $discountData;
} }
$buyAndDiscountQty = $x + $y; $availableDiscountAmount = (float)$cartRules[$ruleId]['amount'];
$ruldDiscountAmount = (float)$cartRules[$ruleId]['discount_amount'];
$discountType = self::$discountType . $ruleId;
$fullRuleQtyPeriod = floor($qty / $buyAndDiscountQty); if ($availableDiscountAmount > 0) {
$freeQty = $qty - $fullRuleQtyPeriod * $buyAndDiscountQty; $store = $quote->getStore();
if ($ruleTotals['items_count'] <= 1) {
$quoteAmount = $this->priceCurrency->convert($availableDiscountAmount, $store);
$baseDiscountAmount = min($baseItemPrice * $qty, $availableDiscountAmount);
$this->deltaPriceRound->reset($discountType);
} else {
$ratio = $baseItemPrice * $qty / $ruleTotals['base_items_price'];
$maximumItemDiscount = $this->deltaPriceRound->round(
$ruldDiscountAmount * $ratio,
$discountType
);
$discountQty = $fullRuleQtyPeriod * $y; $quoteAmount = $this->priceCurrency->convert($maximumItemDiscount, $store);
if ($freeQty > $x) {
$discountQty += $freeQty - $x; $baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount);
} $this->validator->decrementRuleItemTotalsCount($ruleId);
}
$discountData->setAmount($discountQty * $itemPrice); $baseDiscountAmount = $this->priceCurrency->round($baseDiscountAmount);
$discountData->setBaseAmount($discountQty * $baseItemPrice);
$discountData->setOriginalAmount($discountQty * $itemOriginalPrice); $availableDiscountAmount -= $baseDiscountAmount;
$discountData->setBaseOriginalAmount($discountQty * $baseItemOriginalPrice); $cartRules[$ruleId]['amount'] = $availableDiscountAmount;
if ($availableDiscountAmount <= 0) {
$this->deltaPriceRound->reset($discountType);
}
$discountData->setAmount($this->priceCurrency->round(min($itemPrice * $qty, $quoteAmount)));
$discountData->setBaseAmount($baseDiscountAmount);
$discountData->setOriginalAmount(min($itemOriginalPrice * $qty, $quoteAmount));
$discountData->setBaseOriginalAmount($this->priceCurrency->round($baseItemOriginalPrice));
}
$address->setBuyXGetYRules($cartRules);
return $discountData; return $discountData;
} }
......
...@@ -432,7 +432,7 @@ class Validator extends \Magento\Framework\Model\AbstractModel ...@@ -432,7 +432,7 @@ class Validator extends \Magento\Framework\Model\AbstractModel
* @throws \Zend_Validate_Exception * @throws \Zend_Validate_Exception
* @throws \Zend_Db_Select_Exception * @throws \Zend_Db_Select_Exception
*/ */
public function initTotals($items, Address $address) public function initTotals_bak($items, Address $address)
{ {
$address->setCartFixedRules([]); $address->setCartFixedRules([]);
...@@ -470,6 +470,97 @@ class Validator extends \Magento\Framework\Model\AbstractModel ...@@ -470,6 +470,97 @@ class Validator extends \Magento\Framework\Model\AbstractModel
return $this; return $this;
} }
public function initTotals($items, Address $address)
{
$address->setCartFixedRules([]);
$address->setBuyXGetYRules([]);
$address->setBuyXPayYRules([]);
if (!$items) {
return $this;
}
/** @var \Magento\SalesRule\Model\Rule $rule */
foreach ($this->_getRules($address) as $rule) {
$ruleId = $rule->getId();
$simpleAction = $rule->getSimpleAction();
if (in_array($simpleAction, [\Magento\SalesRule\Model\Rule::CART_FIXED_ACTION, \Magento\SalesRule\Model\Rule::BUY_X_GET_Y_ACTION])
&& $this->validatorUtility->canProcessRule($rule, $address)
) {
$ruleTotalItemsPrice = 0;
$ruleTotalBaseItemsPrice = 0;
$validItemsCount = 0;
$totalQty = 0;
$buyXGetYItems = [];
//$buyXPayYItems = [];
foreach ($items as $item) {
//Skipping child items to avoid double calculations
if ($item->getParentItemId()) {
continue;
}
if (!$rule->getActions()->validate($item)) {
continue;
}
if (!$this->canApplyDiscount($item)) {
continue;
}
if ($simpleAction == \Magento\SalesRule\Model\Rule::CART_FIXED_ACTION) {
$qty = $this->validatorUtility->getItemQty($item, $rule);
} else {
$qty = $item->getTotalQty();
}
$totalQty += $qty;
$basePrice = $this->getItemBasePrice($item);
$ruleTotalItemsPrice += $this->getItemPrice($item) * $qty;
$ruleTotalBaseItemsPrice += $basePrice * $qty;
$validItemsCount++;
if ($simpleAction == \Magento\SalesRule\Model\Rule::BUY_X_GET_Y_ACTION) {
$buyXGetYItems[] = ['price' => $basePrice, 'qty' => $qty];
}
// if ($simpleAction == self::BUY_X_PAY_Y_ACTION) {
// $buyXPayYItems[] = ['price' => $basePrice, 'qty' => $qty];
// }
}
if (!empty($buyXGetYItems)) {
$x = $rule->getDiscountStep();
$y = $rule->getDiscountAmount();
$buy = ceil($x + $y);
$discountQty = $rule->getDiscountQty();
$maxQty = floor($totalQty / $buy) * $y;
if ($discountQty > 0) {
$maxQty = min($maxQty, $discountQty);
}
$sortCol = array_column($buyXGetYItems, 'price');
array_multisort($sortCol, SORT_ASC, $buyXGetYItems);
$amount = 0;
foreach ($buyXGetYItems as $item) {
if ($item['qty'] > $maxQty) {
$amount += $item['price'] * $maxQty;
$maxQty = 0;
} else {
$amount += $item['price'] * $item['qty'];
$maxQty -= $item['qty'];
}
if ($maxQty <= 0) {
break;
}
}
$address->setBuyXGetYRules([$ruleId => ['amount' => $amount, 'discount_amount' => $amount]]);
}
$this->_rulesItemTotals[$ruleId] = [
'items_price' => $ruleTotalItemsPrice,
'base_items_price' => $ruleTotalBaseItemsPrice,
'items_count' => $validItemsCount,
];
}
}
return $this;
}
/** /**
* Determine if quote item is valid for a given sales rule * Determine if quote item is valid for a given sales rule
...@@ -625,10 +716,12 @@ class Validator extends \Magento\Framework\Model\AbstractModel ...@@ -625,10 +716,12 @@ class Validator extends \Magento\Framework\Model\AbstractModel
if (!empty($itemsSorted)) { if (!empty($itemsSorted)) {
$items = array_merge($itemsSorted, $items); $items = array_merge($itemsSorted, $items);
} }
usort($items, array('self', 'sortByPrice'));
return $items; return $items;
} }
static function sortByPrice($a,$b){
return ($a->getPrice() < $b->getPrice()) ? -1 : 1;
}
/** /**
* Rule total items getter. * Rule total items getter.
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment