_rateResultFactory = $rateResultFactory; $this->_rateMethodFactory = $rateMethodFactory; $this->itemPriceCalculator = $itemPriceCalculator; parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data); } /** * @param RateRequest $request * @return Result|bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ public function collectRates(RateRequest $request) { if (!$this->getConfigFlag('active')) { return false; } $freeBoxes = $this->getFreeBoxesCount($request); $this->setFreeBoxes($freeBoxes); /** @var Result $result */ $result = $this->_rateResultFactory->create(); $shippingPrice = $this->getShippingPrice($request, $freeBoxes); if ($shippingPrice !== false) { $method = $this->createResultMethod($shippingPrice); $result->append($method); } return $result; } /** * @param RateRequest $request * @return int */ private function getFreeBoxesCount(RateRequest $request) { $freeBoxes = 0; if ($request->getAllItems()) { foreach ($request->getAllItems() as $item) { if ($item->getProduct()->isVirtual() || $item->getParentItem()) { continue; } if ($item->getHasChildren() && $item->isShipSeparately()) { $freeBoxes += $this->getFreeBoxesCountFromChildren($item); } elseif ($item->getFreeShipping()) { $freeBoxes += $item->getQty(); } } } return $freeBoxes; } /** * @return array */ public function getAllowedMethods() { return ['flatrate' => $this->getConfigData('name')]; } /** * @param RateRequest $request * @param int $freeBoxes * @return bool|float */ private function getShippingPrice(RateRequest $request, $freeBoxes) { $shippingPrice = false; $configPrice = $this->getConfigData('price'); if ($this->getConfigData('type') === 'O') { // per order $shippingPrice = $this->itemPriceCalculator->getShippingPricePerOrder($request, $configPrice, $freeBoxes); } elseif ($this->getConfigData('type') === 'I') { // per item $shippingPrice = $this->itemPriceCalculator->getShippingPricePerItem($request, $configPrice, $freeBoxes); } $shippingPrice = $this->getFinalPriceWithHandlingFee($shippingPrice); if ($shippingPrice !== false && $request->getPackageQty() == $freeBoxes) { $shippingPrice = '0.00'; } return $shippingPrice; } /** * @param int|float $shippingPrice * @return \Magento\Quote\Model\Quote\Address\RateResult\Method */ private function createResultMethod($shippingPrice) { /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */ $method = $this->_rateMethodFactory->create(); $method->setCarrier('flatrate'); $method->setCarrierTitle($this->getConfigData('title')); $method->setMethod('flatrate'); $method->setMethodTitle($this->getConfigData('name')); $method->setPrice($shippingPrice); $method->setCost($shippingPrice); return $method; } /** * @param mixed $item * @return mixed */ private function getFreeBoxesCountFromChildren($item) { $freeBoxes = 0; foreach ($item->getChildren() as $child) { if ($child->getFreeShipping() && !$child->getProduct()->isVirtual()) { $freeBoxes += $item->getQty() * $child->getQty(); } } return $freeBoxes; } }