Ejemplo n.º 1
0
 public function testCollect()
 {
     $this->shippingAssignment->expects($this->exactly(3))->method('getShipping')->willReturn($this->shipping);
     $this->shipping->expects($this->exactly(2))->method('getAddress')->willReturn($this->address);
     $this->shipping->expects($this->once())->method('getMethod')->willReturn('flatrate');
     $this->shippingAssignment->expects($this->atLeastOnce())->method('getItems')->willReturn([$this->cartItem]);
     $this->freeShipping->expects($this->once())->method('isFreeShipping')->with($this->quote, [$this->cartItem])->willReturn(true);
     $this->address->expects($this->once())->method('setFreeShipping')->with(true);
     $this->total->expects($this->atLeastOnce())->method('setTotalAmount');
     $this->total->expects($this->atLeastOnce())->method('setBaseTotalAmount');
     $this->cartItem->expects($this->atLeastOnce())->method('getProduct')->willReturnSelf();
     $this->cartItem->expects($this->atLeastOnce())->method('isVirtual')->willReturn(false);
     $this->cartItem->expects($this->once())->method('getParentItem')->willReturn(false);
     $this->cartItem->expects($this->once())->method('getHasChildren')->willReturn(false);
     $this->cartItem->expects($this->once())->method('getWeight')->willReturn(2);
     $this->cartItem->expects($this->atLeastOnce())->method('getQty')->willReturn(2);
     $this->address->expects($this->once())->method('getFreeShipping')->willReturn(true);
     $this->cartItem->expects($this->once())->method('setRowWeight')->with(0);
     $this->address->expects($this->once())->method('setItemQty')->with(2);
     $this->address->expects($this->atLeastOnce())->method('setWeight');
     $this->address->expects($this->atLeastOnce())->method('setFreeMethodWeight');
     $this->address->expects($this->once())->method('collectShippingRates');
     $this->address->expects($this->once())->method('getAllShippingRates')->willReturn([$this->rate]);
     $this->rate->expects($this->once())->method('getCode')->willReturn('flatrate');
     $this->quote->expects($this->once())->method('getStore')->willReturn($this->store);
     $this->rate->expects($this->atLeastOnce())->method('getPrice')->willReturn(5);
     $this->priceCurrency->expects($this->once())->method('convert')->with(5, $this->store)->willReturn(5);
     $this->total->expects($this->once())->method('setShippingAmount')->with(5);
     $this->rate->expects($this->once())->method('getCarrierTitle')->willReturn('Carrier title');
     $this->rate->expects($this->once())->method('getMethodTitle')->willReturn('Method title');
     $this->address->expects($this->once())->method('setShippingDescription')->with('Carrier title - Method title');
     $this->address->expects($this->once())->method('getShippingDescription')->willReturn('Carrier title - Method title');
     $this->total->expects($this->once())->method('setShippingDescription')->with('Carrier title - Method title');
     $this->shippingModel->collect($this->quote, $this->shippingAssignment, $this->total);
 }
Ejemplo n.º 2
0
 /**
  * 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 ShippingAssignmentInterface $shippingAssignment
  * @param CartInterface $quote
  * @return void
  * @throws InputException
  */
 public function save(CartInterface $quote, ShippingAssignmentInterface $shippingAssignment)
 {
     /** @var \Magento\Quote\Model\Quote $quote */
     foreach ($shippingAssignment->getItems() as $item) {
         if (!$quote->getItemById($item->getItemId())) {
             $this->cartItemPersister->save($quote, $item);
         }
     }
     $this->shippingProcessor->save($shippingAssignment->getShipping(), $quote);
 }
Ejemplo n.º 4
0
 /**
  * Collect totals process.
  *
  * @param \Magento\Quote\Model\Quote $quote
  * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
  * @param \Magento\Quote\Model\Quote\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)
 {
     $this->_setAddress($shippingAssignment->getShipping()->getAddress());
     $this->_setTotal($total);
     /**
      * Reset amounts
      */
     $this->_setAmount(0);
     $this->_setBaseAmount(0);
     return $this;
 }
 /**
  * Collect address discount amount
  *
  * @param \Magento\Quote\Model\Quote                          $quote
  * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
  * @param \Magento\Quote\Model\Quote\Address\Total            $total
  *
  * @return $this
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  */
 public function collect(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, \Magento\Quote\Model\Quote\Address\Total $total)
 {
     $address = $shippingAssignment->getShipping()->getAddress();
     if ($this->_getDiscountCondition($address, $shippingAssignment)) {
         parent::collect($quote, $shippingAssignment, $total);
         $balance = $this->_getDiscountAmount();
         $address->setDiscountCouponAmount($balance);
         $address->setBaseDiscountCouponAmount($balance);
         $total->setDiscountCouponDescription($this->getCode());
         $total->setDiscountCouponAmount($balance);
         $total->setBaseDiscountCouponAmount($balance);
     }
     $total->addTotalAmount($this->getCode(), $address->getDiscountCouponAmount());
     $total->addBaseTotalAmount($this->getCode(), $address->getBaseDiscountCouponAmount());
     return $this;
 }
Ejemplo n.º 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;
 }
Ejemplo n.º 7
0
 /**
  * Calculate tax on product items. The result will be used to determine shipping
  * and discount later.
  *
  * @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)
 {
     $items = $shippingAssignment->getItems();
     if (!$items) {
         return $this;
     }
     $store = $quote->getStore();
     $priceIncludesTax = $this->_config->priceIncludesTax($store);
     //Setup taxable items
     $itemDataObjects = $this->mapItems($shippingAssignment, $priceIncludesTax, false);
     $quoteDetails = $this->prepareQuoteDetails($shippingAssignment, $itemDataObjects);
     $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails, $store->getStoreId());
     $itemDataObjects = $this->mapItems($shippingAssignment, $priceIncludesTax, true);
     $baseQuoteDetails = $this->prepareQuoteDetails($shippingAssignment, $itemDataObjects);
     $baseTaxDetails = $this->taxCalculationService->calculateTax($baseQuoteDetails, $store->getStoreId());
     $itemsByType = $this->organizeItemTaxDetailsByType($taxDetails, $baseTaxDetails);
     if (isset($itemsByType[self::ITEM_TYPE_PRODUCT])) {
         $this->processProductItems($shippingAssignment, $itemsByType[self::ITEM_TYPE_PRODUCT], $total);
     }
     return $this;
 }
Ejemplo n.º 8
0
 /**
  * Call tax calculation service to get tax details on the quote and items
  *
  * @param ShippingAssignmentInterface $shippingAssignment
  * @param Address\Total $total
  * @param bool $useBaseCurrency
  * @return \Magento\Tax\Api\Data\TaxDetailsInterface
  */
 protected function getQuoteTaxDetails($shippingAssignment, $total, $useBaseCurrency)
 {
     $address = $shippingAssignment->getShipping()->getAddress();
     //Setup taxable items
     $priceIncludesTax = $this->_config->priceIncludesTax($address->getQuote()->getStore());
     $itemDataObjects = $this->mapItems($shippingAssignment, $priceIncludesTax, $useBaseCurrency);
     //Add shipping
     $shippingDataObject = $this->getShippingDataObject($shippingAssignment, $total, $useBaseCurrency);
     if ($shippingDataObject != null) {
         $itemDataObjects[] = $shippingDataObject;
     }
     //process extra taxable items associated only with quote
     $quoteExtraTaxables = $this->mapQuoteExtraTaxables($this->quoteDetailsItemDataObjectFactory, $address, $useBaseCurrency);
     if (!empty($quoteExtraTaxables)) {
         $itemDataObjects = array_merge($itemDataObjects, $quoteExtraTaxables);
     }
     //Preparation for calling taxCalculationService
     $quoteDetails = $this->prepareQuoteDetails($shippingAssignment, $itemDataObjects);
     $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails, $address->getQuote()->getStore()->getStoreId());
     return $taxDetails;
 }
 /**
  * Update tax related fields for shipping
  *
  * @param ShippingAssignmentInterface $shippingAssignment
  * @param QuoteAddress\Total $total
  * @param TaxDetailsItemInterface $shippingTaxDetails
  * @param TaxDetailsItemInterface $baseShippingTaxDetails
  * @return $this
  */
 protected function processShippingTaxInfo(ShippingAssignmentInterface $shippingAssignment, QuoteAddress\Total $total, $shippingTaxDetails, $baseShippingTaxDetails)
 {
     $total->setTotalAmount('shipping', $shippingTaxDetails->getRowTotal());
     $total->setBaseTotalAmount('shipping', $baseShippingTaxDetails->getRowTotal());
     $total->setTotalAmount('shipping_discount_tax_compensation', $shippingTaxDetails->getDiscountTaxCompensationAmount());
     $total->setBaseTotalAmount('shipping_discount_tax_compensation', $baseShippingTaxDetails->getDiscountTaxCompensationAmount());
     $total->setShippingInclTax($shippingTaxDetails->getRowTotalInclTax());
     $total->setBaseShippingInclTax($baseShippingTaxDetails->getRowTotalInclTax());
     $total->setShippingTaxAmount($shippingTaxDetails->getRowTax());
     $total->setBaseShippingTaxAmount($baseShippingTaxDetails->getRowTax());
     //Add the shipping tax to total tax amount
     $total->addTotalAmount('tax', $shippingTaxDetails->getRowTax());
     $total->addBaseTotalAmount('tax', $baseShippingTaxDetails->getRowTax());
     if ($this->_config->discountTax($shippingAssignment->getShipping()->getAddress()->getQuote()->getStore())) {
         $total->setShippingAmountForDiscount($shippingTaxDetails->getRowTotalInclTax());
         $total->setBaseShippingAmountForDiscount($baseShippingTaxDetails->getRowTotalInclTax());
     }
     return $this;
 }
Ejemplo n.º 10
0
 /**
  * Generate \Magento\Tax\Model\Sales\Quote\QuoteDetails object based on shipping assignment
  *
  * Base closely on this method, with the exception of the tax calculation call to calculate taxes:
  * @see \Magento\Tax\Model\Sales\Total\Quote\Tax::getQuoteTaxDetails()
  *
  * @param ShippingAssignmentInterface $shippingAssignment
  * @param Address\Total $total
  * @param bool $useBaseCurrency
  * @param string $storeId
  * @return \Magento\Tax\Api\Data\QuoteDetailsInterface
  */
 protected function getTaxQuoteDetails($shippingAssignment, $total, $storeId, $useBaseCurrency)
 {
     // If quote is virtual, getShipping will return billing address, so no need to check if quote is virtual
     $address = $shippingAssignment->getShipping()->getAddress();
     //Setup taxable items
     $priceIncludesTax = $this->_config->priceIncludesTax($address->getQuote()->getStore());
     $itemDataObjects = $this->mapItems($shippingAssignment, $priceIncludesTax, $useBaseCurrency);
     //Add shipping
     $shippingDataObject = $this->getShippingDataObject($shippingAssignment, $total, $useBaseCurrency);
     if ($shippingDataObject != null) {
         $this->addInfoToQuoteDetailsItemForShipping($shippingDataObject, $storeId);
         $itemDataObjects[] = $shippingDataObject;
     }
     //process extra taxable items associated only with quote
     $quoteExtraTaxables = $this->mapQuoteExtraTaxables($this->quoteDetailsItemDataObjectFactory, $address, $useBaseCurrency);
     if (!empty($quoteExtraTaxables)) {
         $itemDataObjects = array_merge($itemDataObjects, $quoteExtraTaxables);
     }
     //Preparation for calling taxCalculationService
     $quoteDetails = $this->prepareQuoteDetails($shippingAssignment, $itemDataObjects);
     return $quoteDetails;
 }
Ejemplo n.º 11
0
 /**
  * Convert Tax Quote Details into data to be converted to a GetTax Request
  *
  * @param \Magento\Tax\Api\Data\QuoteDetailsInterface $taxQuoteDetails
  * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
  * @param \Magento\Quote\Api\Data\CartInterface $quote
  * @return array|null
  */
 protected function convertTaxQuoteDetailsToData(\Magento\Tax\Api\Data\QuoteDetailsInterface $taxQuoteDetails, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, \Magento\Quote\Api\Data\CartInterface $quote)
 {
     $lines = [];
     $items = $taxQuoteDetails->getItems();
     $keyedItems = $this->taxCalculation->getKeyedItems($items);
     $childrenItems = $this->taxCalculation->getChildrenItems($items);
     /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $item */
     foreach ($keyedItems as $item) {
         /**
          * If a quote has children and they are calculated (e.g., Bundled products with dynamic pricing)
          * @see \Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector::mapItems
          * then we only need to pass child items to AvaTax. Due to the logic in
          * @see \ClassyLlama\AvaTax\Framework\Interaction\TaxCalculation::calculateTaxDetails
          * the parent tax gets calculated based on children items
          */
         //
         if (isset($childrenItems[$item->getCode()])) {
             /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $childItem */
             foreach ($childrenItems[$item->getCode()] as $childItem) {
                 $line = $this->interactionLine->getLine($childItem);
                 if ($line) {
                     $lines[] = $line;
                 }
             }
         } else {
             $line = $this->interactionLine->getLine($item);
             if ($line) {
                 $lines[] = $line;
             }
         }
     }
     // Shipping Address not documented in the interface for some reason
     // they do have a constant for it but not a method in the interface
     //
     // If quote is virtual, getShipping will return billing address, so no need to check if quote is virtual
     $shippingAddress = $shippingAssignment->getShipping()->getAddress();
     $address = $this->address->getAddress($shippingAddress);
     $store = $this->storeRepository->getById($quote->getStoreId());
     $currentDate = $this->getFormattedDate($store);
     // Quote created/updated date is not relevant, so just pass the current date
     $docDate = $currentDate;
     $customerUsageType = $quote->getCustomer() ? $this->taxClassHelper->getAvataxTaxCodeForCustomer($quote->getCustomer()) : null;
     return ['StoreId' => $store->getId(), 'Commit' => false, 'CurrencyCode' => $quote->getCurrency()->getQuoteCurrencyCode(), 'CustomerCode' => $this->getCustomerCode($quote), 'CustomerUsageType' => $customerUsageType, 'DestinationAddress' => $address, 'DocCode' => self::AVATAX_DOC_CODE_PREFIX . $quote->getId(), 'DocDate' => $docDate, 'DocType' => DocumentType::$SalesOrder, 'ExchangeRate' => $this->getExchangeRate($store, $quote->getCurrency()->getBaseCurrencyCode(), $quote->getCurrency()->getQuoteCurrencyCode()), 'ExchangeRateEffDate' => $currentDate, 'Lines' => $lines, 'DetailLevel' => DetailLevel::$Line, 'PurchaseOrderNo' => $quote->getReservedOrderId()];
 }