private function getAssociatedGroupedProduct() { $associatedProducts = $this->proxyItem->getAssociatedProducts(); $associatedProductId = reset($associatedProducts); $product = $this->productFactory->create()->setStoreId($this->quote->getStoreId())->load($associatedProductId); return $product->getId() ? $product : null; }
/** * {@inheritDoc} */ public function isFreeShipping(\Magento\Quote\Model\Quote $quote, $items) { /** @var \Magento\Quote\Api\Data\CartItemInterface[] $items */ if (!count($items)) { return false; } $addressFreeShipping = true; $store = $this->storeManager->getStore($quote->getStoreId()); $this->calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode()); /** @var \Magento\Quote\Api\Data\CartItemInterface $item */ foreach ($items as $item) { if ($item->getNoDiscount()) { $addressFreeShipping = false; $item->setFreeShipping(false); continue; } /** Child item discount we calculate for parent */ if ($item->getParentItemId()) { continue; } $this->calculator->processFreeShipping($item); $itemFreeShipping = (bool) $item->getFreeShipping(); $addressFreeShipping = $addressFreeShipping && $itemFreeShipping; /** Parent free shipping we apply to all children*/ $this->applyToChildren($item, $itemFreeShipping); } return $addressFreeShipping; }
public function testGetStoreIdNoId() { $storeMock = $this->getMockBuilder('Magento\\Store\\Model\\Store')->disableOriginalConstructor()->getMock(); $storeMock->expects($this->once())->method('getId')->will($this->returnValue(null)); $this->storeManagerMock->expects($this->once())->method('getStore')->will($this->returnValue($storeMock)); $result = $this->quote->getStoreId(); $this->assertNull($result); }
/** * If module is enabled, don't run collect totals for shipping * * Tax calculation for shipping is handled in this class * @see \ClassyLlama\AvaTax\Model\Tax\Sales\Total\Quote\Tax::collect() * Since this extension doesn't support applying discounts *after* tax, we don't need to run a separate collect * process. * * @param \Magento\Tax\Model\Sales\Total\Quote\Shipping $subject * @param \Closure $proceed * @param \Magento\Quote\Model\Quote $quote * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment * @param \Magento\Quote\Model\Quote\Address\Total $total * @return mixed */ public function aroundCollect(\Magento\Tax\Model\Sales\Total\Quote\Shipping $subject, \Closure $proceed, \Magento\Quote\Model\Quote $quote, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, \Magento\Quote\Model\Quote\Address\Total $total) { $storeId = $quote->getStoreId(); // If quote is virtual, getShipping will return billing address, so no need to check if quote is virtual $address = $shippingAssignment->getShipping()->getAddress(); if (!$this->config->isModuleEnabled($storeId) || $this->config->getTaxMode($storeId) == Config::TAX_MODE_NO_ESTIMATE_OR_SUBMIT || !$this->config->isAddressTaxable($address, $storeId)) { return $proceed($quote, $shippingAssignment, $total); } }
/** * @param \Magento\Quote\Model\Quote $quote * @return \Magento\Payment\Model\MethodInterface[] */ public function getAvailableMethods(\Magento\Quote\Model\Quote $quote = null) { $store = $quote ? $quote->getStoreId() : null; $methods = []; $specification = $this->methodSpecificationFactory->create([AbstractMethod::CHECK_ZERO_TOTAL]); foreach ($this->paymentHelper->getStoreMethods($store, $quote) as $method) { if ($this->_canUseMethod($method, $quote) && $specification->isApplicable($method, $quote)) { $method->setInfoInstance($quote->getPayment()); $methods[] = $method; } } return $methods; }
/** * Collect tax totals for shipping. The result can be used to calculate discount on shipping * * @param \Magento\Quote\Model\Quote $quote * @param ShippingAssignmentInterface $shippingAssignment * @param Address\Total $total * @return $this */ public function collect(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, \Magento\Quote\Model\Quote\Address\Total $total) { $storeId = $quote->getStoreId(); $items = $shippingAssignment->getItems(); if (!$items) { return $this; } //Add shipping $shippingDataObject = $this->getShippingDataObject($shippingAssignment, $total, false); $baseShippingDataObject = $this->getShippingDataObject($shippingAssignment, $total, true); if ($shippingDataObject == null || $baseShippingDataObject == null) { return $this; } $quoteDetails = $this->prepareQuoteDetails($shippingAssignment, [$shippingDataObject]); $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails, $storeId); $baseQuoteDetails = $this->prepareQuoteDetails($shippingAssignment, [$baseShippingDataObject]); $baseTaxDetails = $this->taxCalculationService->calculateTax($baseQuoteDetails, $storeId); $this->processShippingTaxInfo($shippingAssignment, $total, $taxDetails->getItems()[self::ITEM_CODE_SHIPPING], $baseTaxDetails->getItems()[self::ITEM_CODE_SHIPPING]); return $this; }
/** * @param \Magento\Quote\Model\Quote $quote * @param array $total * @return array */ public function fetch(\Magento\Quote\Model\Quote $quote, array $total) { $output = []; $total = $this->totalFactory->create('Magento\\Quote\\Model\\Quote\\Address\\Total')->setData($total); /** @var ReaderInterface $reader */ foreach ($this->collectorList->getCollectors($quote->getStoreId()) as $reader) { $data = $reader->fetch($quote, $total); if ($data === null || empty($data)) { continue; } $totalInstance = $this->convert($data); if (is_array($totalInstance)) { foreach ($totalInstance as $item) { $output = $this->merge($item, $output); } } else { $output = $this->merge($totalInstance, $output); } } return $output; }
private function initializeQuoteItems() { foreach ($this->proxyOrder->getItems() as $item) { $this->clearQuoteItemsCache(); /** @var $quoteItemBuilder \Ess\M2ePro\Model\Magento\Quote\Item */ $quoteItemBuilder = $this->modelFactory->getObject('Magento\\Quote\\Item', ['quote' => $this->quote, 'proxyItem' => $item]); $product = $quoteItemBuilder->getProduct(); $request = $quoteItemBuilder->getRequest(); // --------------------------------------- $productOriginalPrice = (double) $product->getPrice(); $price = $item->getBasePrice(); $product->setPrice($price); $product->setSpecialPrice($price); // --------------------------------------- // see Mage_Sales_Model_Observer::substractQtyFromQuotes $this->quote->setItemsCount($this->quote->getItemsCount() + 1); $this->quote->setItemsQty((double) $this->quote->getItemsQty() + $request->getQty()); $result = $this->quote->addProduct($product, $request); if (is_string($result)) { throw new \Ess\M2ePro\Model\Exception($result); } $quoteItem = $this->quote->getItemByProduct($product); if ($quoteItem !== false) { $quoteItem->setStoreId($this->quote->getStoreId()); $quoteItem->setOriginalCustomPrice($item->getPrice()); $quoteItem->setOriginalPrice($productOriginalPrice); $quoteItem->setBaseOriginalPrice($productOriginalPrice); $quoteItem->setNoDiscount(1); $giftMessageId = $quoteItemBuilder->getGiftMessageId(); if (!empty($giftMessageId)) { $quoteItem->setGiftMessageId($giftMessageId); } $quoteItem->setAdditionalData($quoteItemBuilder->getAdditionalData($quoteItem)); } } }
/** * Check whether there are CC types set in configuration * * @param \Magento\Quote\Model\Quote|null $quote * @return bool */ public function isAvailable($quote = null) { return $this->getConfigData('cctypes', $quote ? $quote->getStoreId() : null) && parent::isAvailable($quote); }
/** * Convert quote/order/invoice/creditmemo to the AvaTax object and request tax from the Get Tax API * * @param \Magento\Quote\Model\Quote $quote * @param \Magento\Tax\Api\Data\QuoteDetailsInterface $taxQuoteDetails * @param \Magento\Tax\Api\Data\QuoteDetailsInterface $baseTaxQuoteDetails * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment * @return \Magento\Tax\Api\Data\TaxDetailsInterface[] * @throws \ClassyLlama\AvaTax\Exception\TaxCalculationException * @throws \Exception */ public function getTaxDetailsForQuote(\Magento\Quote\Model\Quote $quote, \Magento\Tax\Api\Data\QuoteDetailsInterface $taxQuoteDetails, \Magento\Tax\Api\Data\QuoteDetailsInterface $baseTaxQuoteDetails, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment) { $storeId = $quote->getStoreId(); $taxService = $this->taxService; try { // Total quantity of an item can be determined by multiplying parent * child quantity, so it's necessary // to calculate total quantities on a list of all items $this->taxCalculation->calculateTotalQuantities($taxQuoteDetails->getItems()); $this->taxCalculation->calculateTotalQuantities($baseTaxQuoteDetails->getItems()); // Taxes need to be calculated on the base prices/amounts, not the current currency prices. As a result of this, // only the $baseTaxQuoteDetails will have taxes calculated for it. The taxes for the current currency will be // calculated by multiplying the base tax rates * currency conversion rate. /** @var $getTaxRequest GetTaxRequest */ $getTaxRequest = $this->interactionTax->getGetTaxRequestForQuote($quote, $baseTaxQuoteDetails, $shippingAssignment); if (is_null($getTaxRequest)) { $message = __('$quote was empty or address was not valid so not running getTax request.'); throw new \ClassyLlama\AvaTax\Exception\TaxCalculationException($message); } $getTaxResult = $taxService->getTax($getTaxRequest, $storeId, true); if ($getTaxResult->getResultCode() == \AvaTax\SeverityLevel::$Success) { $store = $quote->getStore(); $baseTaxDetails = $this->taxCalculation->calculateTaxDetails($baseTaxQuoteDetails, $getTaxResult, true, $store); /** * If quote is using a currency other than the base currency, calculate tax details for both quote * currency and base currency. Otherwise use the same tax details object. */ if ($quote->getBaseCurrencyCode() != $quote->getQuoteCurrencyCode()) { $taxDetails = $this->taxCalculation->calculateTaxDetails($taxQuoteDetails, $getTaxResult, false, $store); } else { $taxDetails = $baseTaxDetails; } return [self::KEY_TAX_DETAILS => $taxDetails, self::KEY_BASE_TAX_DETAILS => $baseTaxDetails]; } else { $message = __('Bad result code: %1', $getTaxResult->getResultCode()); $this->avaTaxLogger->warning($message, ['request' => var_export($getTaxRequest, true), 'result' => var_export($getTaxResult, true)]); throw new \ClassyLlama\AvaTax\Exception\TaxCalculationException($message); } } catch (\SoapFault $exception) { $message = "Exception: \n"; if ($exception) { $message .= $exception->faultstring; } $message .= $taxService->__getLastRequest() . "\n"; $message .= $taxService->__getLastResponse() . "\n"; $this->avaTaxLogger->error("Exception: \n" . $exception ? $exception->faultstring : "", ['request' => var_export($taxService->__getLastRequest(), true), 'result' => var_export($taxService->__getLastResponse(), true)]); throw new \ClassyLlama\AvaTax\Exception\TaxCalculationException($message); } catch (\Exception $exception) { $message = $exception->getMessage(); $this->avaTaxLogger->error($message); throw new \ClassyLlama\AvaTax\Exception\TaxCalculationException($message); } }
/** * Check is allowed Guest Checkout * Use config settings and observer * * @param \Magento\Quote\Model\Quote $quote * @param int|Store $store * @return bool */ public function isAllowedGuestCheckout(\Magento\Quote\Model\Quote $quote, $store = null) { if ($store === null) { $store = $quote->getStoreId(); } $guestCheckout = $this->scopeConfig->isSetFlag(self::XML_PATH_GUEST_CHECKOUT, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $store); if ($guestCheckout == true) { $result = new \Magento\Framework\Object(); $result->setIsAllowed($guestCheckout); $this->_eventManager->dispatch('checkout_allow_guest', ['quote' => $quote, 'store' => $store, 'result' => $result]); $guestCheckout = $result->getIsAllowed(); } return $guestCheckout; }
/** * @param \Magento\Quote\Model\Quote $quote * @param Address $address * @return Address\Total */ public function collectAddressTotals(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address $address) { /** @var \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment */ $shippingAssignment = $this->shippingAssignmentFactory->create(); /** @var \Magento\Quote\Api\Data\ShippingInterface $shipping */ $shipping = $this->shippingFactory->create(); $shipping->setMethod($address->getShippingMethod()); $shipping->setAddress($address); $shippingAssignment->setShipping($shipping); $shippingAssignment->setItems($address->getAllItems()); /** @var \Magento\Quote\Model\Quote\Address\Total $total */ $total = $this->totalFactory->create('Magento\\Quote\\Model\\Quote\\Address\\Total'); $this->eventManager->dispatch('sales_quote_address_collect_totals_before', ['quote' => $quote, 'shipping_assignment' => $shippingAssignment, 'total' => $total]); foreach ($this->collectorList->getCollectors($quote->getStoreId()) as $collector) { /** @var CollectorInterface $collector */ $collector->collect($quote, $shippingAssignment, $total); } $this->eventManager->dispatch('sales_quote_address_collect_totals_after', ['quote' => $quote, 'shipping_assignment' => $shippingAssignment, 'total' => $total]); $address->addData($total->getData()); $address->setAppliedTaxes($total->getAppliedTaxes()); return $total; }
/** * Collect tax totals for quote address * * @param Quote $quote * @param ShippingAssignmentInterface $shippingAssignment * @param Address\Total $total * @return $this * @throws RemoteServiceUnavailableException */ public function collect(Quote $quote, ShippingAssignmentInterface $shippingAssignment, Address\Total $total) { // If quote is virtual, getShipping will return billing address, so no need to check if quote is virtual $address = $shippingAssignment->getShipping()->getAddress(); $storeId = $quote->getStoreId(); // This will allow a merchant to configure default tax settings for their site using Magento's core tax // calculation and AvaTax's calculation will only kick in during cart/checkout. This is useful for countries // where merchants are required to display prices including tax (such as some countries that charge VAT tax). if (!$this->config->isModuleEnabled($storeId) || $this->config->getTaxMode($storeId) == Config::TAX_MODE_NO_ESTIMATE_OR_SUBMIT || !$this->config->isAddressTaxable($address, $storeId)) { return parent::collect($quote, $shippingAssignment, $total); } $postcode = $address->getPostcode(); // If postcode is not present, then collect totals is being run from a context where customer has not submitted // their address, such as on the product listing, product detail, or cart page. Once the user enters their // postcode in the "Estimate Shipping & Tax" form on the cart page, or submits their shipping address in the // checkout, then a postcode will be present. if (!$postcode) { return parent::collect($quote, $shippingAssignment, $total); } $this->clearValues($total); if (!$shippingAssignment->getItems()) { return $this; } $taxQuoteDetails = $this->getTaxQuoteDetails($shippingAssignment, $total, $storeId, false); $baseTaxQuoteDetails = $this->getTaxQuoteDetails($shippingAssignment, $total, $storeId, true); // Get array of tax details try { $taxDetailsList = $this->interactionGetTax->getTaxDetailsForQuote($quote, $taxQuoteDetails, $baseTaxQuoteDetails, $shippingAssignment); } catch (\Exception $e) { switch ($this->config->getErrorAction($quote->getStoreId())) { case Config::ERROR_ACTION_DISABLE_CHECKOUT: $this->coreRegistry->register(self::AVATAX_GET_TAX_REQUEST_ERROR, true, true); return parent::collect($quote, $shippingAssignment, $total); break; case Config::ERROR_ACTION_ALLOW_CHECKOUT_NATIVE_TAX: default: /** * Note: while this should return Magento's tax calculation, the tax calculation may be slightly * off, as these two collect methods will not have run: * @see \Magento\Tax\Model\Sales\Total\Quote\Shipping::collect() * @see \Magento\Tax\Model\Sales\Total\Quote\Subtotal::collect() */ return parent::collect($quote, $shippingAssignment, $total); break; } } $taxDetails = $taxDetailsList[InteractionGet::KEY_TAX_DETAILS]; $baseTaxDetails = $taxDetailsList[InteractionGet::KEY_BASE_TAX_DETAILS]; $itemsByType = $this->organizeItemTaxDetailsByType($taxDetails, $baseTaxDetails); if (isset($itemsByType[self::ITEM_TYPE_PRODUCT])) { $this->processProductItems($shippingAssignment, $itemsByType[self::ITEM_TYPE_PRODUCT], $total); } if (isset($itemsByType[self::ITEM_TYPE_SHIPPING])) { $shippingTaxDetails = $itemsByType[self::ITEM_TYPE_SHIPPING][self::ITEM_CODE_SHIPPING][self::KEY_ITEM]; $baseShippingTaxDetails = $itemsByType[self::ITEM_TYPE_SHIPPING][self::ITEM_CODE_SHIPPING][self::KEY_BASE_ITEM]; $this->processShippingTaxInfo($shippingAssignment, $total, $shippingTaxDetails, $baseShippingTaxDetails); } //Process taxable items that are not product or shipping $this->processExtraTaxables($total, $itemsByType); //Save applied taxes for each item and the quote in aggregation $this->processAppliedTaxes($total, $shippingAssignment, $itemsByType); if ($this->includeExtraTax()) { $total->addTotalAmount('extra_tax', $total->getExtraTaxAmount()); $total->addBaseTotalAmount('extra_tax', $total->getBaseExtraTaxAmount()); } return $this; }
/** * Check whether payment method can be used * * TODO: payment method instance is not supposed to know about quote * * @param \Magento\Quote\Model\Quote|null $quote * @return bool */ public function isAvailable($quote = null) { $checkResult = new \StdClass(); $isActive = (bool) (int) $this->getConfigData('active', $quote ? $quote->getStoreId() : null); $checkResult->isAvailable = $isActive; $checkResult->isDeniedInConfig = !$isActive; // for future use in observers $this->_eventManager->dispatch('payment_method_is_active', ['result' => $checkResult, 'method_instance' => $this, 'quote' => $quote]); return $checkResult->isAvailable; }
/** * Get reserved order id * * @param \Magento\Quote\Model\Quote $quote * @return string */ public function getReservedOrderId($quote) { return $this->sequenceManager->getSequence(\Magento\Sales\Model\Order::ENTITY, (int) $quote->getStoreId())->getNextValue(); }
/** * Declare quote model object * * @param \Magento\Quote\Model\Quote $quote * @return $this */ public function setQuote(\Magento\Quote\Model\Quote $quote) { $this->_quote = $quote; $this->setQuoteId($quote->getId()); $this->setStoreId($quote->getStoreId()); return $this; }
/** * Retrieve store Id (From Quote) * * @return int */ public function getStoreId() { return (int) $this->_quote->getStoreId(); }
/** * Get reserved order id * * @param \Magento\Quote\Model\Quote $quote * @return string */ public function getReservedOrderId($quote) { $storeId = (int) $quote->getStoreId(); return $this->_config->getEntityType(\Magento\Sales\Model\Order::ENTITY)->fetchNewIncrementId($storeId); }