/**
  * Cache validated response
  *
  * @param ValidateRequest $validateRequest
  * @param $storeId
  * @return ValidateResult
  * @throws \SoapFault
  */
 public function validate(ValidateRequest $validateRequest, $storeId)
 {
     $addressCacheKey = $this->getCacheKey($validateRequest->getAddress()) . $storeId;
     $validateResult = @unserialize($this->cache->load($addressCacheKey));
     if ($validateResult instanceof ValidateResult) {
         $this->avaTaxLogger->addDebug('Loaded \\AvaTax\\ValidateResult from cache.', ['request' => var_export($validateRequest, true), 'result' => var_export($validateResult, true), 'cache_key' => $addressCacheKey]);
         return $validateResult;
     }
     try {
         $addressService = $this->interactionAddress->getAddressService($this->type, $storeId);
         $validateResult = $addressService->validate($validateRequest);
         $serializedValidateResult = serialize($validateResult);
         $this->cache->save($serializedValidateResult, $addressCacheKey, [Config::AVATAX_CACHE_TAG]);
         $validAddress = isset($validateResult->getValidAddresses()[0]) ? $validateResult->getValidAddresses()[0] : null;
         $validAddressCacheKey = $this->getCacheKey($validAddress);
         $this->avaTaxLogger->addDebug('Loaded \\AvaTax\\ValidateResult from SOAP.', ['request' => var_export($validateRequest, true), 'result' => var_export($validateResult, true)]);
         $this->cache->save($serializedValidateResult, $validAddressCacheKey, [Config::AVATAX_CACHE_TAG]);
     } catch (LocalizedException $e) {
         $this->avaTaxLogger->addDebug('\\AvaTax\\ValidateResult no valid address found from SOAP.', ['result' => var_export($validateResult, true)]);
     } catch (\SoapFault $e) {
         $this->avaTaxLogger->error("Exception: \n" . $e->getMessage() . "\n" . $e->faultstring, ['request' => var_export($addressService->__getLastRequest(), true), 'result' => var_export($addressService->__getLastResponse(), true)]);
         throw $e;
     }
     return $validateResult;
 }
Example #2
0
 /**
  * Log page
  *
  * @return \Magento\Backend\Model\View\Result\Page
  */
 public function execute()
 {
     // Initiate Log Clearing
     try {
         $this->logTask->clearLogs();
         if ($this->logTask->getDeleteCount() > 0) {
             $message = __('%1 log records were cleared.', $this->logTask->getDeleteCount());
             // Display message on the page
             $this->messageManager->addSuccess($message);
         } else {
             // Display message on the page
             $this->messageManager->addSuccess(__('No logs needed to be cleared.'));
         }
     } catch (\Exception $e) {
         // Build error message
         $message = __('An error occurred while clearing the log.');
         // Display error message on the page
         $this->messageManager->addErrorMessage($message . "\n" . __('Error Message: ') . $e->getMessage());
         // Log the exception
         $this->avaTaxLogger->error($message, ['exception' => sprintf('Exception message: %s%sTrace: %s', $e->getMessage(), "\n", $e->getTraceAsString())]);
     }
     // Redirect browser to log list page
     /** @var Redirect $resultRedirect */
     $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
     $resultRedirect->setPath('*/*/');
     return $resultRedirect;
 }
Example #3
0
 /**
  * Log page
  *
  * @return \Magento\Backend\Model\View\Result\Page
  */
 public function execute()
 {
     // Initiate Queue Processing of pending queued entities
     try {
         $this->queueTask->clearQueue();
         if ($this->queueTask->getDeleteCompleteCount() > 0) {
             $message = __('%1 (completed) queued records were cleared. ', $this->queueTask->getDeleteCompleteCount());
             // Display message on the page
             $this->messageManager->addSuccess($message);
         }
         if ($this->queueTask->getDeleteFailedCount() > 0) {
             $message = __('%1 (failed) queued records were cleared. ', $this->queueTask->getDeleteFailedCount());
             // Display message on the page
             $this->messageManager->addSuccess($message);
         }
     } catch (\Exception $e) {
         // Build error message
         $message = __('An error occurred while clearing the queue.');
         // Display error message on the page
         $this->messageManager->addErrorMessage($message . "\n" . __('Error Message: ') . $e->getMessage());
         // Log the exception
         $this->avaTaxLogger->error($message, ['exception' => sprintf('Exception message: %s%sTrace: %s', $e->getMessage(), "\n", $e->getTraceAsString())]);
     }
     // Redirect browser to queue list page
     /** @var Redirect $resultRedirect */
     $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
     $resultRedirect->setPath('*/*/');
     return $resultRedirect;
 }
 /**
  * Get an AvaTax address object with fields as specified in data
  *
  * Note: AvaTax only allows 3 street fields according to the API documentation.  The customer/address/street_lines
  * allows the admin to create fields for 1 to 4 street lines.  This configuration is currently disabled in
  * Magento/CustomerCustomAttributes/etc/adminhtml/system.xml.  As a result not currently doing anything with this.
  * Likely no special consideration since the code is already sending all addresses (up to 3) to AvaTax if present.
  *
  * @param $data \Magento\Customer\Api\Data\AddressInterface|\Magento\Quote\Api\Data\AddressInterface|\Magento\Sales\Api\Data\OrderAddressInterface|array
  * @return \AvaTax\Address
  * @throws LocalizedException
  */
 public function getAddress($data)
 {
     switch (true) {
         case $data instanceof \Magento\Customer\Api\Data\AddressInterface:
             $data = $this->convertCustomerAddressToAvaTaxAddress($data);
             break;
         case $data instanceof \Magento\Quote\Api\Data\AddressInterface:
             $data = $this->convertQuoteAddressToAvaTaxAddress($data);
             break;
         case $data instanceof \Magento\Sales\Api\Data\OrderAddressInterface:
             $data = $this->convertOrderAddressToAvaTaxAddress($data);
             break;
         case !is_array($data):
             throw new LocalizedException(__('Input parameter "$data" was not of a recognized/valid type: "%1".', [gettype($data)]));
     }
     if (isset($data['RegionId'])) {
         $data['Region'] = $this->getRegionCodeById($data['RegionId']);
         unset($data['RegionId']);
     }
     try {
         $data = $this->metaDataObject->validateData($data);
     } catch (MetaData\ValidationException $e) {
         $this->avaTaxLogger->error('Error validating address: ' . $e->getMessage(), ['data' => var_export($data, true)]);
         // Rethrow exception as if internal validation fails, don't send address to AvaTax
         throw $e;
     }
     $address = $this->addressFactory->create();
     return $this->populateAddress($data, $address);
 }
Example #5
0
 /**
  * Clear the queue of complete and failed records
  */
 public function clearQueue()
 {
     $this->avaTaxLogger->debug(__('Starting queue clearing'));
     $this->clearCompleteQueue();
     $this->clearFailedQueue();
     $this->avaTaxLogger->debug(__('Finished queue clearing'), ['delete_complete_count' => $this->deleteCompleteCount, 'delete_failed_count' => $this->deleteFailedCount]);
 }
 /**
  * Cache validated response
  *
  * @param GetTaxRequest $getTaxRequest
  * @param $storeId
  * @param bool $useCache
  * @return GetTaxResult
  * @throws LocalizedException
  */
 public function getTax(GetTaxRequest $getTaxRequest, $storeId, $useCache = false)
 {
     $cacheKey = $this->getCacheKey($getTaxRequest) . $storeId;
     $getTaxResult = @unserialize($this->cache->load($cacheKey));
     if ($getTaxResult instanceof GetTaxResult && $useCache) {
         $this->avaTaxLogger->addDebug('Loaded \\AvaTax\\GetTaxResult from cache.', ['result' => var_export($getTaxResult, true), 'cache_key' => $cacheKey]);
         return $getTaxResult;
     }
     $getTaxResult = $this->taxInteraction->getTaxService($this->type, $storeId)->getTax($getTaxRequest);
     $this->avaTaxLogger->addDebug('Loaded \\AvaTax\\GetTaxResult from SOAP.', ['request' => var_export($getTaxRequest, true), 'result' => var_export($getTaxResult, true)]);
     // Only cache successful requests
     if ($useCache && $getTaxResult->getResultCode() == \AvaTax\SeverityLevel::$Success) {
         $serializedGetTaxResult = serialize($getTaxResult);
         $this->cache->save($serializedGetTaxResult, $cacheKey, [Config::AVATAX_CACHE_TAG], self::CACHE_LIFETIME);
     }
     return $getTaxResult;
 }
 /**
  * Process Queue
  *
  * @return Redirect
  */
 public function execute()
 {
     // Initiate Queue Processing of pending queued entities
     try {
         $this->queueTask->processPendingQueue();
         $message = __('The queue was successfully processed. ') . __('%1 queued records were processed. ', $this->queueTask->getProcessCount());
         $this->messageManager->addSuccess($message);
         if ($this->queueTask->getErrorCount() > 0) {
             $errorMessage = __('Some queue records received errors while processing. ') . __('%1 queued records had errors. ', $this->queueTask->getErrorCount());
             // Include the error messages from the queue task
             foreach ($this->queueTask->getErrorMessages() as $queueErrorMessage) {
                 $errorMessage .= $queueErrorMessage;
             }
             // Display error message on the page
             $this->messageManager->addErrorMessage($errorMessage);
         }
         // Check for any queue records that appear to have been hung and reset them
         $this->queueTask->resetHungQueuedRecords();
         if ($this->queueTask->getResetCount() > 0) {
             $errorMessage = __('Some queue records appeared to have been abandoned while processing. ') . __('%1 queued records were reset to pending so they can be retried. ', $this->queueTask->getResetCount());
             // Display error message on the page
             $this->messageManager->addErrorMessage($errorMessage);
         }
     } catch (\Exception $e) {
         // Build error message
         $message = __('An error occurred while processing the queue. ');
         $partialSuccess = '';
         if ($this->queueTask->getProcessCount() > 0) {
             $partialSuccess = ' ' . __('%1 queued records were processed. ', $this->queueTask->getProcessCount());
         }
         // Display error message on the page
         $this->messageManager->addErrorMessage($message . $partialSuccess . __('Error Message: ') . $e->getMessage());
         // Log the exception
         $this->avaTaxLogger->error($message, ['exception' => sprintf('Exception message: %s%sTrace: %s', $e->getMessage(), "\n", $e->getTraceAsString()), 'process_count' => var_export($this->queueTask->getProcessCount(), true)]);
     }
     // Redirect browser to queue list page
     /** @var Redirect $resultRedirect */
     $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
     $resultRedirect->setPath('*/*/');
     return $resultRedirect;
 }
Example #8
0
 /**
  * Clear the queue of complete and failed records
  */
 public function clearLogs()
 {
     $this->avaTaxLogger->debug(__('Starting queue clearing'));
     /** @var $collection \ClassyLlama\AvaTax\Model\ResourceModel\Log\Collection */
     $collection = $this->logCollectionFactory->create();
     // Get configuration for record lifetime
     $lifetimeDays = $this->avaTaxConfig->getLogDbLifetime();
     // Calculate the number of seconds to adjust the filter
     // 86400 seconds == 60 seconds * 60 minutes * 24 hours == 1 day
     $secondsBeforeNow = $lifetimeDays * 60 * 60 * 24;
     // Add filters
     $collection->addCreatedAtBeforeFilter($secondsBeforeNow);
     // Process each queued entity
     /** @var $log Log */
     foreach ($collection as $log) {
         // Remove the queue record
         $log->delete();
         $this->deleteCount++;
     }
     $this->avaTaxLogger->debug(__('Finished clearing log entries'), ['delete_count' => $this->deleteCount]);
 }
Example #9
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);
     }
 }
Example #10
0
 /**
  * @param int $storeId
  * @param string $entityTypeCode
  * @param int $entityId
  * @param string $incrementId
  * @param string $queueStatus
  * @throws \Exception
  * @throws \Magento\Framework\Exception\LocalizedException
  */
 public function build($storeId, $entityTypeCode, $entityId, $incrementId, $queueStatus)
 {
     // validating $entityTypeCode
     if (!in_array($entityTypeCode, [self::ENTITY_TYPE_CODE_INVOICE, self::ENTITY_TYPE_CODE_CREDITMEMO])) {
         $message = __('When building a queue record an invalid entity_type_code was provided');
         $this->avaTaxLogger->error($message, ['invalid_entity_type_code' => $entityTypeCode]);
         throw new \Exception($message);
     }
     // Get Entity Type Details
     $entityType = $this->eavConfig->getEntityType($entityTypeCode);
     $this->setStoreId($storeId);
     $this->setEntityTypeId($entityType->getEntityTypeId());
     $this->setEntityTypeCode($entityTypeCode);
     $this->setEntityId($entityId);
     $this->setIncrementId($incrementId);
     $this->setQueueStatus($queueStatus);
     $this->setAttempts(0);
 }
 /**
  * @param \Magento\Sales\Api\Data\InvoiceInterface|\Magento\Sales\Api\Data\CreditmemoInterface $entity
  * @param \ClassyLlama\AvaTax\Api\Data\GetTaxResponseInterface $processSalesResponse
  */
 protected function updateAdditionalEntityAttributes($entity, GetTaxResponseInterface $processSalesResponse)
 {
     $entityExtension = $entity->getExtensionAttributes();
     if ($entityExtension == null) {
         $entityExtension = $this->getEntityExtensionInterface($entity);
     }
     // check to see if the AvataxIsUnbalanced is already set on this entity
     $avataxIsUnbalancedToSave = false;
     if ($entityExtension->getAvataxIsUnbalanced() === null) {
         $entityExtension->setAvataxIsUnbalanced($processSalesResponse->getIsUnbalanced());
         $avataxIsUnbalancedToSave = true;
     } else {
         // check to see if any existing value is different from the new value
         if ($processSalesResponse->getIsUnbalanced() != $entityExtension->getAvataxIsUnbalanced()) {
             // Log the warning
             $this->avaTaxLogger->warning(__('When processing an entity in the queue there was an existing AvataxIsUnbalanced and ' . 'the new value was different than the old one. The old value was overwritten.'), ['old_is_unbalanced' => $entityExtension->getAvataxIsUnbalanced(), 'new_is_unbalanced' => $processSalesResponse->getIsUnbalanced()]);
             $entityExtension->setAvataxIsUnbalanced($processSalesResponse->getIsUnbalanced());
             $avataxIsUnbalancedToSave = true;
         }
     }
     // check to see if the BaseAvataxTaxAmount is already set on this entity
     $baseAvataxTaxAmountToSave = false;
     if ($entityExtension->getBaseAvataxTaxAmount() === null) {
         $entityExtension->setBaseAvataxTaxAmount($processSalesResponse->getBaseAvataxTaxAmount());
         $baseAvataxTaxAmountToSave = true;
     } else {
         // check to see if any existing value is different from the new value
         if ($processSalesResponse->getBaseAvataxTaxAmount() != $entityExtension->getBaseAvataxTaxAmount()) {
             // Log the warning
             $this->avaTaxLogger->warning(__('When processing an entity in the queue there was an existing BaseAvataxTaxAmount and ' . 'the new value was different than the old one. The old value was overwritten.'), ['old_base_avatax_tax_amount' => $entityExtension->getBaseAvataxTaxAmount(), 'new_base_avatax_tax_amount' => $processSalesResponse->getBaseAvataxTaxAmount()]);
             $entityExtension->setBaseAvataxTaxAmount($processSalesResponse->getBaseAvataxTaxAmount());
             $baseAvataxTaxAmountToSave = true;
         }
     }
     // save the ExtensionAttributes on the entity object
     if ($avataxIsUnbalancedToSave || $baseAvataxTaxAmountToSave) {
         $entity->setExtensionAttributes($entityExtension);
         // get the repository for this entity type
         $entityRepository = $this->getEntityRepository($entity);
         // save the entity object using the repository
         $entityRepository->save($entity);
     }
 }
Example #12
0
 /**
  * Accepts an invoice or creditmemo and returns an \AvaTax\Line object
  *
  * @param \Magento\Sales\Api\Data\InvoiceInterface|\Magento\Sales\Api\Data\CreditmemoInterface $data
  * @return \AvaTax\Line|bool
  */
 public function getNegativeAdjustmentLine($data)
 {
     $amount = $data->getBaseAdjustmentNegative();
     if ($amount == 0) {
         return false;
     }
     $storeId = $data->getStoreId();
     $itemCode = $this->config->getSkuAdjustmentNegative($storeId);
     $data = ['No' => $this->getLineNumber(), 'ItemCode' => $itemCode, 'Description' => self::ADJUSTMENT_NEGATIVE_LINE_DESCRIPTION, 'Qty' => 1, 'Amount' => $amount, 'Discounted' => false, 'TaxIncluded' => true];
     try {
         $data = $this->metaDataObject->validateData($data);
     } catch (ValidationException $e) {
         $this->avaTaxLogger->error('Error validating line: ' . $e->getMessage(), ['data' => var_export($data, true)]);
     }
     /** @var $line \AvaTax\Line */
     $line = $this->lineFactory->create();
     $this->populateLine($data, $line);
     return $line;
 }
 /**
  * @param \Magento\Sales\Model\Spi\InvoiceResourceInterface $subject
  * @param \Closure $proceed
  *
  *        I include both the extended AbstractModel and implemented Interface here for the IDE's benefit
  * @param \Magento\Framework\Model\AbstractModel|\Magento\Sales\Api\Data\InvoiceInterface $entity
  * @return \Magento\Sales\Model\Spi\InvoiceResourceInterface
  * @throws \Magento\Framework\Exception\CouldNotSaveException
  */
 public function aroundSave(InvoiceResourceInterface $subject, \Closure $proceed, AbstractModel $entity)
 {
     // Check to see if this is a newly created entity and store the determination for later evaluation after
     // the entity is saved via plugin closure. After the entity is saved it will not be listed as new any longer.
     $isObjectNew = $entity->isObjectNew();
     // Save AvaTax extension attributes
     if ($this->avaTaxConfig->isModuleEnabled($entity->getStoreId())) {
         // check to see if any extension attributes exist and set them on the model for saving to the db
         $extensionAttributes = $entity->getExtensionAttributes();
         if ($extensionAttributes && $extensionAttributes->getAvataxIsUnbalanced() !== null) {
             $entity->setData('avatax_is_unbalanced', $extensionAttributes->getAvataxIsUnbalanced());
         }
         if ($extensionAttributes && $extensionAttributes->getBaseAvataxTaxAmount() !== null) {
             $entity->setData('base_avatax_tax_amount', $extensionAttributes->getBaseAvataxTaxAmount());
         }
         // Updating a field to trigger a change to the record when avatax_is_unbalanced and base_avatax_tax_amount
         // are both false or 0 which evaluate the same as null in the isModified check
         if ($extensionAttributes && ($extensionAttributes->getAvataxIsUnbalanced() !== null && ($entity->getOrigData('avatax_is_unbalanced') === null || $extensionAttributes->getAvataxIsUnbalanced() != $entity->getOrigData('avatax_is_unbalanced')) || $extensionAttributes->getBaseAvataxTaxAmount() !== null && ($entity->getOrigData('base_avatax_tax_amount') === null || $extensionAttributes->getBaseAvataxTaxAmount() != $entity->getOrigData('base_avatax_tax_amount')))) {
             $entity->setUpdatedAt($this->dateTime->gmtDate());
         }
     }
     /** @var \Magento\Sales\Model\Spi\InvoiceResourceInterface $resultEntity */
     $resultEntity = $proceed($entity);
     /** @var \Magento\Sales\Model\Order $order */
     $order = $entity->getOrder();
     $isVirtual = $order->getIsVirtual();
     $address = $isVirtual ? $entity->getBillingAddress() : $entity->getShippingAddress();
     $storeId = $entity->getStoreId();
     // Queue the entity to be sent to AvaTax
     if ($this->avaTaxConfig->isModuleEnabled($entity->getStoreId()) && $this->avaTaxConfig->getTaxMode($entity->getStoreId()) == Config::TAX_MODE_ESTIMATE_AND_SUBMIT && $this->avaTaxConfig->isAddressTaxable($address, $storeId)) {
         // Add this entity to the avatax processing queue if this is a new entity
         if ($isObjectNew) {
             /** @var Queue $queue */
             $queue = $this->queueFactory->create();
             $queue->build($entity->getStoreId(), Queue::ENTITY_TYPE_CODE_INVOICE, $entity->getEntityId(), $entity->getIncrementId(), Queue::QUEUE_STATUS_PENDING);
             $queue->save();
             $this->avaTaxLogger->debug(__('Added entity to the queue'), ['queue_id' => $queue->getId(), 'entity_type_code' => Queue::ENTITY_TYPE_CODE_INVOICE, 'entity_id' => $entity->getEntityId()]);
         }
     }
     return $resultEntity;
 }
 public function aroundSaveAddressInformation(\Magento\Checkout\Model\ShippingInformationManagement $subject, \Closure $proceed, $cartId, ShippingInformationInterface $addressInformation)
 {
     // Only validate address if module is enabled
     $quote = $this->quoteRepository->getActive($cartId);
     $storeId = $quote->getStoreId();
     if (!$this->config->isModuleEnabled($storeId)) {
         $paymentDetails = $proceed($cartId, $addressInformation);
         $this->ensureTaxCalculationSuccess($storeId);
         return $paymentDetails;
     }
     // Only validate address if address validation is enabled
     if (!$this->config->isAddressValidationEnabled($storeId)) {
         $paymentDetails = $proceed($cartId, $addressInformation);
         $this->ensureTaxCalculationSuccess($storeId);
         return $paymentDetails;
     }
     // If quote is virtual, getShippingAddress will return billing address, so no need to check if quote is virtual
     $shippingAddress = $addressInformation->getShippingAddress();
     $shippingInformationExtension = $addressInformation->getExtensionAttributes();
     $errorMessage = null;
     $validAddress = null;
     $customerAddress = null;
     $quoteAddress = null;
     $shouldValidateAddress = true;
     if (!is_null($shippingInformationExtension)) {
         $shouldValidateAddress = $shippingInformationExtension->getShouldValidateAddress();
     }
     $customerAddressId = $shippingAddress->getCustomerAddressId();
     $enabledAddressValidationCountries = explode(',', $this->config->getAddressValidationCountriesEnabled($storeId));
     if (!in_array($shippingAddress->getCountryId(), $enabledAddressValidationCountries)) {
         $shouldValidateAddress = false;
     }
     if ($shouldValidateAddress) {
         try {
             $validAddress = $this->validationInteraction->validateAddress($shippingAddress, $storeId);
         } catch (AddressValidateException $e) {
             $errorMessage = $e->getMessage();
         } catch (\SoapFault $e) {
             // If there is a SoapFault, it will have already been logged, so just disable address validation, as we
             // don't want to display SoapFault error message to user
             $shouldValidateAddress = false;
         } catch (\Exception $e) {
             $this->avaTaxLogger->error('Error in validating address in aroundSaveAddressInformation: ' . $e->getMessage());
             // Continue without address validation
             $shouldValidateAddress = false;
         }
     }
     // Determine which address to save to the customer or shipping addresses
     if (!is_null($validAddress)) {
         $quoteAddress = $validAddress;
     } else {
         $quoteAddress = $shippingAddress;
     }
     try {
         /*
          * Regardless of whether address was validated by AvaTax, if the address is a customer address then we need
          * to save that address on the customer record. The reason for this is that when a user is on the "Review
          * & Payments" step and they are selecting between "Valid" and "Original" address options, the selected
          * address information is submitted to this API so that the customer address is updated and tax
          * calculation is affected accordingly.
          */
         if ($customerAddressId) {
             // Update the customer address
             $customerAddress = $this->customerAddressRepository->getById($customerAddressId);
             $mergedCustomerAddress = $this->addressInteraction->copyQuoteAddressToCustomerAddress($quoteAddress, $customerAddress);
             $this->customerAddressRepository->save($mergedCustomerAddress);
         } else {
             // Update the shipping address
             $addressInformation->setShippingAddress($quoteAddress);
         }
     } catch (\Exception $e) {
         // There may be scenarios in which the above address updating may fail, in which case we should just do
         // nothing
         $this->avaTaxLogger->error('Error in saving address: ' . $e->getMessage());
         // Continue without address validation
         $shouldValidateAddress = false;
     }
     $returnValue = $proceed($cartId, $addressInformation);
     $this->ensureTaxCalculationSuccess($storeId);
     if (!$shouldValidateAddress) {
         return $returnValue;
     }
     $paymentDetailsExtension = $returnValue->getExtensionAttributes();
     if (is_null($paymentDetailsExtension)) {
         $paymentDetailsExtension = $this->paymentDetailsExtensionFactory->create();
     }
     if (!is_null($validAddress)) {
         $paymentDetailsExtension->setValidAddress($validAddress);
     } else {
         $paymentDetailsExtension->setErrorMessage($errorMessage);
     }
     $paymentDetailsExtension->setOriginalAddress($shippingAddress);
     $returnValue->setExtensionAttributes($paymentDetailsExtension);
     return $returnValue;
 }
Example #15
0
 /**
  * Creates and returns a populated getTaxRequest for a invoice
  *
  * @param \Magento\Sales\Api\Data\InvoiceInterface|\Magento\Sales\Api\Data\CreditmemoInterface $object
  * @return GetTaxRequest
  */
 public function getGetTaxRequestForSalesObject($object)
 {
     $order = $this->orderRepository->get($object->getOrderId());
     $lines = [];
     $items = $object->getItems();
     $this->taxClassHelper->populateCorrectTaxClasses($items, $object->getStoreId());
     /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $item */
     foreach ($items as $item) {
         $line = $this->interactionLine->getLine($item);
         if ($line) {
             $lines[] = $line;
         }
     }
     $objectIsCreditMemo = $object instanceof \Magento\Sales\Api\Data\CreditmemoInterface;
     $credit = $objectIsCreditMemo;
     $line = $this->interactionLine->getShippingLine($object, $credit);
     if ($line) {
         $lines[] = $line;
     }
     $line = $this->interactionLine->getGiftWrapItemsLine($object, $credit);
     if ($line) {
         $lines[] = $line;
     }
     $line = $this->interactionLine->getGiftWrapOrderLine($object, $credit);
     if ($line) {
         $lines[] = $line;
     }
     $line = $this->interactionLine->getGiftWrapCardLine($object, $credit);
     if ($line) {
         $lines[] = $line;
     }
     if ($objectIsCreditMemo) {
         $line = $this->interactionLine->getPositiveAdjustmentLine($object);
         if ($line) {
             $lines[] = $line;
         }
         $line = $this->interactionLine->getNegativeAdjustmentLine($object);
         if ($line) {
             $lines[] = $line;
         }
     }
     /** @var \Magento\Sales\Api\Data\OrderAddressInterface $address */
     if (!$order->getIsVirtual()) {
         $address = $order->getShippingAddress();
     } else {
         $address = $order->getBillingAddress();
     }
     $avaTaxAddress = $this->address->getAddress($address);
     $store = $this->storeRepository->getById($object->getStoreId());
     $currentDate = $this->getFormattedDate($store, $object->getCreatedAt());
     $taxOverride = null;
     if ($object instanceof \Magento\Sales\Api\Data\InvoiceInterface) {
         $docType = DocumentType::$SalesInvoice;
         if ($this->areTimesDifferentDays($order->getCreatedAt(), $object->getCreatedAt(), $object->getStoreId())) {
             $taxCalculationDate = $this->getFormattedDate($store, $order->getCreatedAt());
             // Set the tax date for calculation
             $taxOverride = $this->taxOverrideFactory->create();
             $taxOverride->setTaxDate($taxCalculationDate);
             $taxOverride->setTaxOverrideType(\AvaTax\TaxOverrideType::$TaxDate);
             $taxOverride->setTaxAmount(0.0);
             $taxOverride->setReason(self::AVATAX_INVOICE_OVERRIDE_REASON);
         }
     } else {
         $docType = DocumentType::$ReturnInvoice;
         $invoice = $this->getInvoice($object->getInvoiceId());
         // If a Creditmemo was generated for an invoice, use the created_at value from the invoice
         if ($invoice) {
             $taxCalculationDate = $this->getFormattedDate($store, $invoice->getCreatedAt());
         } else {
             $taxCalculationDate = $this->getFormattedDate($store, $order->getCreatedAt());
         }
         // Set the tax date for calculation
         $taxOverride = $this->taxOverrideFactory->create();
         $taxOverride->setTaxDate($taxCalculationDate);
         $taxOverride->setTaxOverrideType(\AvaTax\TaxOverrideType::$TaxDate);
         $taxOverride->setTaxAmount(0.0);
         $taxOverride->setReason(self::AVATAX_CREDITMEMO_OVERRIDE_REASON);
     }
     $customer = $this->getCustomerById($order->getCustomerId());
     $customerUsageType = $customer ? $this->taxClassHelper->getAvataxTaxCodeForCustomer($customer) : null;
     $data = ['StoreId' => $store->getId(), 'Commit' => $this->config->getCommitSubmittedTransactions($store), 'TaxOverride' => $taxOverride, 'CurrencyCode' => $order->getOrderCurrencyCode(), 'CustomerCode' => $this->getCustomerCode($order), 'CustomerUsageType' => $customerUsageType, 'DestinationAddress' => $avaTaxAddress, 'DocCode' => $object->getIncrementId() . '123-' . rand(10000000, 90000000000), 'DocDate' => $currentDate, 'DocType' => $docType, 'ExchangeRate' => $this->getExchangeRate($store, $order->getBaseCurrencyCode(), $order->getOrderCurrencyCode()), 'ExchangeRateEffDate' => $currentDate, 'Lines' => $lines, 'DetailLevel' => DetailLevel::$Document, 'PaymentDate' => $currentDate, 'PurchaseOrderNo' => $object->getIncrementId()];
     $data = array_merge($this->retrieveGetTaxRequestFields($store, $address, $object), $data);
     try {
         $data = $this->metaDataObject->validateData($data);
     } catch (ValidationException $e) {
         $this->avaTaxLogger->error('Error validating data: ' . $e->getMessage(), ['data' => var_export($data, true)]);
     }
     /** @var $getTaxRequest GetTaxRequest */
     $getTaxRequest = $this->getTaxRequestFactory->create();
     $this->populateGetTaxRequest($data, $getTaxRequest);
     return $getTaxRequest;
 }