Beispiel #1
0
 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;
 }
Beispiel #3
0
 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;
 }
Beispiel #6
0
 /**
  * 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;
 }
Beispiel #8
0
 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));
         }
     }
 }
Beispiel #9
0
 /**
  * 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);
 }
Beispiel #10
0
 /**
  * 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);
     }
 }
Beispiel #11
0
 /**
  * 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;
 }
Beispiel #13
0
 /**
  * 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;
 }
Beispiel #15
0
 /**
  * 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();
 }
Beispiel #16
0
 /**
  * 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();
 }
Beispiel #18
0
 /**
  * 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);
 }