├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── Api ├── Data │ ├── GetTaxResponseInterface.php │ ├── GrandTotalDetailsInterface.php │ └── GrandTotalRatesInterface.php └── ValidAddressManagementInterface.php ├── Block ├── Adminhtml │ ├── Customer │ │ └── Edit │ │ │ └── Region.php │ ├── Log │ │ ├── ClearButton.php │ │ ├── Summary.php │ │ └── View.php │ ├── Queue │ │ ├── ClearButton.php │ │ └── Summary.php │ └── Tax │ │ └── Classes │ │ ├── Base │ │ ├── Edit.php │ │ ├── Edit │ │ │ └── Form.php │ │ ├── NewClass.php │ │ └── NewClass │ │ │ └── Form.php │ │ ├── Customer │ │ ├── Edit.php │ │ ├── Edit │ │ │ └── Form.php │ │ ├── NewClass.php │ │ └── NewClass │ │ │ └── Form.php │ │ └── Product │ │ ├── Edit.php │ │ ├── Edit │ │ └── Form.php │ │ ├── NewClass.php │ │ └── NewClass │ │ └── Form.php ├── Checkout │ └── LayoutProcessor.php ├── CustomerAddress.php └── Tax │ └── Adminhtml │ └── Rule │ └── Edit │ └── Form.php ├── CHANGELOG.md ├── Controller └── Adminhtml │ ├── Address │ ├── Region.php │ └── Validation.php │ ├── Log.php │ ├── Log │ ├── Clear.php │ ├── Index.php │ └── View.php │ ├── Queue.php │ ├── Queue │ ├── Clear.php │ ├── Index.php │ └── Process.php │ └── Tax │ ├── Classes.php │ ├── Classes │ ├── Base │ │ ├── Delete.php │ │ ├── Edit.php │ │ ├── Index.php │ │ ├── Newclass.php │ │ └── Save.php │ ├── Customer │ │ ├── Delete.php │ │ ├── Edit.php │ │ ├── Index.php │ │ ├── Newclass.php │ │ └── Save.php │ └── Product │ │ ├── Delete.php │ │ ├── Edit.php │ │ ├── Index.php │ │ ├── Newclass.php │ │ └── Save.php │ └── IgnoreTaxRuleNotification.php ├── Exception ├── AddressValidateException.php └── TaxCalculationException.php ├── Framework ├── AppInterface.php └── Interaction │ ├── Address.php │ ├── Address │ └── Validation.php │ ├── Cacheable │ ├── AddressService.php │ └── TaxService.php │ ├── Line.php │ ├── MetaData │ ├── ArrayType.php │ ├── BooleanType.php │ ├── DoubleType.php │ ├── IntegerType.php │ ├── MetaDataAbstract.php │ ├── MetaDataObject.php │ ├── MetaDataObjectFactory.php │ ├── ObjectType.php │ ├── StringType.php │ └── ValidationException.php │ ├── Tax.php │ ├── Tax │ ├── Get.php │ └── Get │ │ └── Response.php │ └── TaxCalculation.php ├── Helper ├── Config.php ├── ModuleChecks.php └── TaxClass.php ├── LICENSE.txt ├── Model ├── Config │ └── Source │ │ ├── AddressValidationCountries.php │ │ ├── AvaTaxCustomerUsageType.php │ │ ├── CustomerCode.php │ │ ├── ErrorAction.php │ │ ├── LogDetail.php │ │ ├── LogFileMode.php │ │ ├── LogLevel.php │ │ ├── Mode.php │ │ ├── Product │ │ └── Attributes.php │ │ ├── RegionFilterList.php │ │ ├── TaxCalculationCountries.php │ │ └── TaxMode.php ├── CreditMemo.php ├── Invoice.php ├── Log.php ├── Log │ └── Task.php ├── Logger │ ├── AvaTaxLogger.php │ ├── AvaTaxProcessor.php │ ├── DbHandler.php │ ├── FileFormatter.php │ └── FileHandler.php ├── Message │ ├── ConfigNotification.php │ ├── QueueDisabledNotification.php │ ├── QueueFailureNotification.php │ └── QueueNotification.php ├── Queue.php ├── Queue │ ├── Processing.php │ └── Task.php ├── Quote │ └── GrandTotalDetailsPlugin.php ├── ResourceModel │ ├── CreditMemo.php │ ├── Invoice.php │ ├── Log.php │ ├── Log │ │ └── Collection.php │ ├── Queue.php │ ├── Queue │ │ └── Collection.php │ └── Tax │ │ └── Classes │ │ ├── Customer.php │ │ ├── Customer │ │ └── Collection.php │ │ ├── Product.php │ │ └── Product │ │ └── Collection.php ├── Tax │ ├── Calculation │ │ └── GrandTotalRates.php │ └── Sales │ │ └── Total │ │ └── Quote │ │ └── Tax.php └── ValidAddressManagement.php ├── Observer ├── CalculateVirtualOrder.php ├── ConfigSaveObserver.php └── PreventOrderPlaceObserver.php ├── Plugin ├── Checkout │ └── Model │ │ └── ShippingInformationManagement.php ├── Quote │ └── Model │ │ └── Quote │ │ └── Config.php ├── Sales │ ├── Admin │ │ └── Order │ │ │ └── Create │ │ │ └── Form │ │ │ └── Account.php │ ├── Model │ │ └── Spi │ │ │ ├── CreditmemoResource.php │ │ │ └── InvoiceResource.php │ └── Total │ │ └── Quote │ │ └── CommonTaxCollector.php └── Tax │ └── Model │ └── Sales │ └── Total │ └── Quote │ ├── Shipping.php │ └── Subtotal.php ├── README.md ├── Setup ├── InstallSchema.php ├── UpgradeData.php └── UpgradeSchema.php ├── Tests ├── Integration │ ├── Model │ │ └── Tax │ │ │ └── Sales │ │ │ └── Total │ │ │ └── Quote │ │ │ ├── SetupUtil.php │ │ │ └── TaxTest.php │ ├── _files │ │ ├── scenarios │ │ │ ├── applied_taxes_multiple_rates.php │ │ │ ├── applied_taxes_one_rate.php │ │ │ ├── bundled_product_dynamic_pricing.php │ │ │ ├── bundled_product_fixed_pricing.php │ │ │ ├── configurable_product.php │ │ │ ├── currency_conversion_rounding.php │ │ │ ├── customer_tax_class.php │ │ │ ├── product_tax_classes.php │ │ │ ├── tax_before_discount_applies_to_partial_taxable_amount.php │ │ │ └── tax_before_discount_only_applies_to_taxable_amount.php │ │ └── tax_calculation_data_aggregated.php │ ├── credentials.php.dist │ └── phpunit.xml └── README.md ├── Ui └── Component │ ├── Form │ └── Element │ │ └── ValidateAddress.php │ └── Listing │ └── Columns │ ├── LogActions.php │ ├── QueueActions.php │ ├── TaxClassesCustomerActions.php │ └── TaxClassesProductActions.php ├── composer.json ├── docs ├── address-validation.md ├── customs-duty-import-tax.md ├── document-management.md ├── files │ └── env.php ├── getting-started.md ├── images │ ├── 2017-08-01_130753__Taxes__Stores__Magento_Admin_2017-09-03_20-52-04.png_1423792_2017-09-03_20-58-22.png │ ├── 2017-08-01_130753__Taxes__Stores__Magento_Admin_2017-09-03_21-01-04.png │ ├── AvaTax_Logs__Taxes__Stores__Magento_Admin_2017-09-03_20-48-18.png │ ├── Configuration__Settings__Stores__Magento_Admin_2017-09-03_20-45-22.png │ ├── Veronica_Costello__Customers__Customers__Magento_Admin_2017-04-26_10-08-51.png │ ├── address_validation_admin_order_creation.png │ ├── address_validation_backend_edit_address.png │ ├── address_validation_customer_edit_address.png │ ├── address_validation_unable_to_validate.png │ ├── address_validation_with_choice.png │ ├── address_validation_without_choice.png │ ├── avatax_queue.png │ ├── avatax_sales_invoice.png │ ├── avatax_sales_numbers.png │ ├── configuration_screenshot_2.0.0-rc1.png │ ├── document-management-backend.jpg │ ├── document-management-features.jpg │ ├── screenshot_tax_requests_customer.jpg │ └── screenshot_tax_requests_guest.jpg └── sales-tax.md ├── etc ├── acl.xml ├── adminhtml │ ├── di.xml │ ├── events.xml │ ├── menu.xml │ ├── routes.xml │ └── system.xml ├── config.xml ├── cron_groups.xml ├── crontab.xml ├── di.xml ├── events.xml ├── extension_attributes.xml ├── frontend │ └── di.xml ├── module.xml └── webapi.xml ├── registration.php └── view ├── adminhtml ├── layout │ ├── avatax_log_index.xml │ ├── avatax_log_view.xml │ ├── avatax_order_create_billing_address.xml │ ├── avatax_order_create_shipping_address.xml │ ├── avatax_queue_index.xml │ ├── avatax_tax_classes_customer_edit.xml │ ├── avatax_tax_classes_customer_index.xml │ ├── avatax_tax_classes_customer_newclass.xml │ ├── avatax_tax_classes_product_edit.xml │ ├── avatax_tax_classes_product_index.xml │ ├── avatax_tax_classes_product_newclass.xml │ ├── customer_index_edit.xml │ ├── sales_order_create_index.xml │ ├── sales_order_create_load_block_billing_address.xml │ ├── sales_order_create_load_block_data.xml │ └── sales_order_create_load_block_shipping_address.xml ├── templates │ ├── customer │ │ └── edit │ │ │ └── region.phtml │ ├── log │ │ ├── summary.phtml │ │ └── view.phtml │ ├── order │ │ └── create │ │ │ ├── address_validation_modal.phtml │ │ │ └── form │ │ │ └── address.phtml │ └── queue │ │ └── summary.phtml ├── ui_component │ ├── avatax_log_listing.xml │ ├── avatax_queue_listing.xml │ ├── avatax_tax_classes_customer_listing.xml │ ├── avatax_tax_classes_product_listing.xml │ └── customer_form.xml └── web │ ├── css │ └── source │ │ └── _module.less │ ├── js │ ├── action │ │ └── validate-address-request.js │ ├── form │ │ └── element │ │ │ ├── button.js │ │ │ └── validationForm.js │ ├── lib │ │ └── event.simulate.js │ ├── model │ │ └── region-model.js │ └── view │ │ ├── address-validation-form-admin.js │ │ ├── address-validation-modal.js │ │ └── validation-response-handler.js │ └── template │ └── form │ └── element │ ├── adminValidateAddress.html │ └── button.html ├── base ├── requirejs-config.js └── web │ ├── css │ └── source │ │ └── _address-validation.less │ ├── js │ ├── lib │ │ └── serialize-form.js │ ├── model │ │ └── address-model.js │ └── view │ │ └── address-validation-form.js │ └── template │ └── baseValidateAddress.html └── frontend ├── layout └── customer_address_form.xml ├── requirejs-config.js ├── templates └── init_validation_modal.phtml └── web ├── css └── source │ └── _module.less ├── js ├── action │ ├── set-customer-address.js │ └── set-shipping-address.js ├── addressValidation.js ├── model │ ├── address-converter.js │ ├── shipping-save-processor │ │ ├── default.js │ │ └── gift-registry.js │ └── url-builder.js └── view │ ├── ReviewPayment.js │ ├── address-validation-modal.js │ ├── checkout-validation-handler.js │ └── update-address.js └── template ├── ReviewPayment.html ├── checkout ├── cart │ └── totals │ │ └── tax.html └── summary │ └── tax.html └── checkoutValidateAddress.html /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Avalara has shifted how they are handling support for this extension and are no longer providing support via Github issues. For support, please contact support@avalara.com 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Tests/Integration/credentials.php 2 | -------------------------------------------------------------------------------- /Api/Data/GetTaxResponseInterface.php: -------------------------------------------------------------------------------- 1 | backendUrl = $backendUrl; 33 | $this->configHelper = $configHelper; 34 | parent::__construct($context); 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | public function getRegionUrl() 41 | { 42 | return $url = $this->backendUrl->getUrl('avatax/address/region'); 43 | } 44 | 45 | /** 46 | * @return mixed 47 | */ 48 | public function isAddressValidationEnabled() 49 | { 50 | return $this->configHelper->isAddressValidationEnabled($this->_storeManager->getStore()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Block/Adminhtml/Log/ClearButton.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $context->getUrlBuilder(); 41 | } 42 | 43 | /** 44 | * Get button data 45 | * 46 | * @return array 47 | */ 48 | public function getButtonData() 49 | { 50 | $message = __( 51 | 'This will clear any logs that are older than the lifetime set in configuration. ' . 52 | 'Do you want to continue?' 53 | ); 54 | return [ 55 | 'label' => __('Clear Logs Now'), 56 | 'on_click' => "confirmSetLocation('{$message}', '{$this->getButtonUrl()}')" 57 | ]; 58 | } 59 | 60 | /** 61 | * Get URL for back (reset) button 62 | * 63 | * @return string 64 | */ 65 | protected function getButtonUrl() 66 | { 67 | return $this->urlBuilder->getUrl('*/*/clear'); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Block/Adminhtml/Log/Summary.php: -------------------------------------------------------------------------------- 1 | logCollectionFactory = $logCollectionFactory; 55 | parent::__construct($context, $data); 56 | } 57 | 58 | /** 59 | * @return Collection 60 | */ 61 | protected function getLogCollection() 62 | { 63 | // Initialize the log collection 64 | if ($this->logCollection == null) { 65 | $this->logCollection = $this->logCollectionFactory->create(); 66 | } 67 | return $this->logCollection; 68 | } 69 | 70 | /** 71 | * @return array 72 | */ 73 | public function getSummaryData() 74 | { 75 | // Initialize the summary data 76 | if ($this->summaryData == null) { 77 | $this->summaryData = $this->getLogCollection()->getLevelSummaryCount(); 78 | } 79 | return $this->summaryData; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Block/Adminhtml/Log/View.php: -------------------------------------------------------------------------------- 1 | coreRegistry = $coreRegistry; 48 | parent::__construct($context, $data); 49 | } 50 | 51 | /** 52 | * Add back button 53 | * 54 | * @return void 55 | */ 56 | protected function _construct() 57 | { 58 | parent::_construct(); 59 | $this->buttonList->add( 60 | 'back', 61 | [ 62 | 'label' => __('Back'), 63 | 'onclick' => "setLocation('" . $this->_urlBuilder->getUrl('avatax/log') . "')", 64 | 'class' => 'back' 65 | ] 66 | ); 67 | } 68 | 69 | /** 70 | * Get log model 71 | * 72 | * @return \ClassyLlama\AvaTax\Model\Log 73 | */ 74 | public function getLog() 75 | { 76 | if (null === $this->currentLog) { 77 | $this->currentLog = $this->coreRegistry->registry('current_log'); 78 | } 79 | return $this->currentLog; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Block/Adminhtml/Queue/ClearButton.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $context->getUrlBuilder(); 41 | } 42 | 43 | /** 44 | * Get button data 45 | * 46 | * @return array 47 | */ 48 | public function getButtonData() 49 | { 50 | $message = __( 51 | 'This will clear any completed queued transmissions that have already been sent to AvaTax. ' . 52 | 'This will also clear any failed transmissions that are older than the lifetime set in configuration. ' . 53 | 'Any failed transmissions will need to be manually adjusted and entered into AvaTax directly. ' . 54 | 'Do you want to continue?' 55 | ); 56 | return [ 57 | 'label' => __('Clear Queue Now'), 58 | 'on_click' => "confirmSetLocation('{$message}', '{$this->getButtonUrl()}')" 59 | ]; 60 | } 61 | 62 | /** 63 | * Get URL for back (reset) button 64 | * 65 | * @return string 66 | */ 67 | protected function getButtonUrl() 68 | { 69 | return $this->urlBuilder->getUrl('*/*/clear'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Block/Adminhtml/Tax/Classes/Base/Edit.php: -------------------------------------------------------------------------------- 1 | _mode = 'edit'; 39 | } 40 | 41 | /** 42 | * Retrieve text for header element depending on loaded page 43 | * 44 | * @return \Magento\Framework\Phrase 45 | */ 46 | public function getHeaderText() 47 | { 48 | return __('Edit Tax Class'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Block/Adminhtml/Tax/Classes/Base/Edit/Form.php: -------------------------------------------------------------------------------- 1 | getForm(); 34 | $form->getElement('base_fieldset')->removeField('is_new'); 35 | $form->setAction( 36 | $this->getUrl('avatax/tax_classes_' . \strtolower($this->classType) . '/save', ['id' => $this->getRequest()->getParam('id')]) 37 | ); 38 | return $this; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Block/Adminhtml/Tax/Classes/Base/NewClass.php: -------------------------------------------------------------------------------- 1 | _objectId = 'id'; 38 | $this->_controller = 'adminhtml_tax_classes_' . \strtolower($this->classType); 39 | $this->_blockGroup = 'ClassyLlama_AvaTax'; 40 | $this->_mode = 'newClass'; 41 | 42 | parent::_construct(); 43 | $this->buttonList->update('save', 'label', __('Save Tax Class')); 44 | } 45 | 46 | /** 47 | * Retrieve text for header element depending on loaded page 48 | * 49 | * @return \Magento\Framework\Phrase 50 | */ 51 | public function getHeaderText() 52 | { 53 | return __('New Tax Class'); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Block/Adminhtml/Tax/Classes/Customer/Edit.php: -------------------------------------------------------------------------------- 1 | addField( 38 | 'avatax_code', 39 | 'select', 40 | [ 41 | 'name' => 'avatax_code', 42 | 'label' => __('AvaTax Customer Usage Type'), 43 | 'note' => __('Optional. The AvaTax Customer Usage Type (or Entity Use Code). Refer to the AvaTax documentation for more information.', 'https://help.avalara.com/kb/001/What_are_the_exemption_reasons_for_each_Entity_Use_Code_used_for_Avalara_AvaTax%3F'), 44 | 'values' => $this->avaTaxCustomerUsageType->toOptionArray() 45 | ] 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Block/Adminhtml/Tax/Classes/Product/Edit.php: -------------------------------------------------------------------------------- 1 | addField( 38 | 'avatax_code', 39 | 'text', 40 | [ 41 | 'name' => 'avatax_code', 42 | 'label' => __('AvaTax Tax Code'), 43 | 'note' => __('Optional. AvaTax system Tax Code or custom Tax Code. See AvaTax documentation for more details.', \ClassyLlama\AvaTax\Helper\Config::AVATAX_DOCUMENTATION_TAX_CODE_LINK), 44 | 'class' => 'validate-length maximum-length-25', 45 | ] 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Block/Tax/Adminhtml/Rule/Edit/Form.php: -------------------------------------------------------------------------------- 1 | getForm()->getElement('base_fieldset')->getContainer(); 32 | $fieldset->getElement('tax_customer_class')->setNote( 33 | __( 34 | 'Go to Customer Tax Classes to add AvaTax Customer Usage Types to tax classes.', 35 | $this->_urlBuilder->getUrl('avatax/tax_classes_customer') 36 | ) 37 | ); 38 | $fieldset->getElement('tax_product_class')->setNote( 39 | __( 40 | 'Go to Product Tax Classes to add AvaTax Tax Codes to tax classes.', 41 | $this->_urlBuilder->getUrl('avatax/tax_classes_product') 42 | ) 43 | ); 44 | return $return; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Address/Region.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 52 | $this->escaper = $escaper; 53 | $this->directoryHelper = $directoryHelper; 54 | } 55 | 56 | /** 57 | * @return \Magento\Framework\Controller\Result\Json 58 | */ 59 | public function execute() 60 | { 61 | /** @var \Magento\Framework\Controller\Result\Json $resultJson */ 62 | $resultJson = $this->resultJsonFactory->create(); 63 | $resultJson->setHeader('Cache-Control', 'max-age=0, must-revalidate, no-cache, no-store'); 64 | $resultJson->setHeader('Pragma', 'no-cache'); 65 | if (!$this->regions) { 66 | try { 67 | $this->regions = $this->directoryHelper->getRegionData(); 68 | } catch (\Exception $e) { 69 | $resultJson->setStatusHeader( 70 | \Zend\Http\Response::STATUS_CODE_400, 71 | \Zend\Http\AbstractMessage::VERSION_11, 72 | 'Bad Request' 73 | ); 74 | $this->regions = ['message' => $this->escaper->escapeHtml($e->getMessage())]; 75 | } 76 | } 77 | 78 | return $resultJson->setData($this->regions); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Log.php: -------------------------------------------------------------------------------- 1 | _authorization->isAllowed('ClassyLlama_AvaTax::manage_avatax'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Log/Index.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 33 | $pageResult->setActiveMenu('ClassyLlama_AvaTax::avatax_log'); 34 | $pageResult->getConfig()->getTitle()->prepend(__('AvaTax Logs')); 35 | return $pageResult; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Queue.php: -------------------------------------------------------------------------------- 1 | _authorization->isAllowed('ClassyLlama_AvaTax::manage_avatax'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Queue/Index.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 33 | $pageResult->setActiveMenu('ClassyLlama_AvaTax::avatax_queue'); 34 | $pageResult->getConfig()->getTitle()->prepend(__('AvaTax Queue')); 35 | return $pageResult; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Tax/Classes.php: -------------------------------------------------------------------------------- 1 | _authorization->isAllowed('ClassyLlama_AvaTax::manage_avatax'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Tax/Classes/Base/Delete.php: -------------------------------------------------------------------------------- 1 | getRequest()->getParam('id'); 38 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ 39 | $resultRedirect = $this->resultRedirectFactory->create(); 40 | if ($taxClassId) { 41 | try { 42 | $this->taxClassRepository->deleteById($taxClassId); 43 | $this->messageManager->addSuccess(__('Deleted tax class.')); 44 | return $resultRedirect->setPath('*/*/'); 45 | } catch (\Magento\Framework\Exception\LocalizedException $e) { 46 | $this->messageManager->addError($e->getMessage()); 47 | } catch (\Exception $e) { 48 | $this->messageManager->addException( 49 | $e, 50 | __('We can\'t delete the tax class right now.') 51 | ); 52 | } 53 | return $resultRedirect->setPath('*/*/edit', ['id' => $this->getRequest()->getParam('id')]); 54 | } 55 | return $resultRedirect->setPath('*/*/'); 56 | } 57 | 58 | /** 59 | * Check for is allowed 60 | * 61 | * @return boolean 62 | */ 63 | protected function _isAllowed() 64 | { 65 | return $this->_authorization->isAllowed('ClassyLlama_AvaTax::manage_avatax'); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Tax/Classes/Base/Index.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 44 | $pageResult->setActiveMenu('ClassyLlama_AvaTax::avatax_tax_classes_' . \strtolower($this->classType)); 45 | $pageResult->getConfig()->getTitle()->prepend(__(\ucfirst(\strtolower($this->classType)) . ' Tax Classes')); 46 | return $pageResult; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Tax/Classes/Base/Newclass.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 44 | $pageResult->setActiveMenu('ClassyLlama_AvaTax::avatax_tax_classes_' . \strtolower($this->classType)); 45 | $pageResult->getConfig()->getTitle()->prepend(__('New ' . \ucfirst(\strtolower($this->classType)) . ' Tax Class')); 46 | return $pageResult; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Tax/Classes/Customer/Delete.php: -------------------------------------------------------------------------------- 1 | cacheTypeList = $cacheTypeList; 40 | parent::__construct($context); 41 | } 42 | 43 | /** 44 | * Set tax ignore notification flag and redirect back 45 | * 46 | * @return \Magento\Backend\Model\View\Result\Redirect 47 | */ 48 | public function execute() 49 | { 50 | try { 51 | $path = \ClassyLlama\AvaTax\Helper\Config::XML_PATH_AVATAX_ADMIN_NOTIFICATION_IGNORE_NATIVE_TAX_RULES; 52 | $this->_objectManager->get('Magento\Config\Model\ResourceModel\Config') 53 | ->saveConfig($path, 1, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0); 54 | $this->messageManager->addSuccess('Notification successfully ignored'); 55 | } catch (\Exception $e) { 56 | $this->messageManager->addError($e->getMessage()); 57 | } 58 | 59 | // clear the block html cache 60 | $this->cacheTypeList->cleanType('config'); 61 | $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'block_html']); 62 | 63 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ 64 | $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); 65 | return $resultRedirect->setRefererUrl(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Exception/AddressValidateException.php: -------------------------------------------------------------------------------- 1 | validateSimpleType($value); 54 | 55 | return $value; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Framework/Interaction/MetaData/DoubleType.php: -------------------------------------------------------------------------------- 1 | validateSimpleType($value); 41 | $value = $this->validateOptions($value); 42 | 43 | return $value; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Framework/Interaction/MetaData/IntegerType.php: -------------------------------------------------------------------------------- 1 | validateSimpleType($value); 41 | $value = $this->validateOptions($value); 42 | 43 | return $value; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Framework/Interaction/MetaData/MetaDataObjectFactory.php: -------------------------------------------------------------------------------- 1 | _objectManager = $objectManager; 51 | $this->_instanceName = $instanceName; 52 | } 53 | 54 | /** 55 | * Create class instance with specified parameters 56 | * 57 | * @param array $data 58 | * @return \ClassyLlama\AvaTax\Framework\Interaction\MetaData\MetaDataObject 59 | */ 60 | public function create(array $data = array()) 61 | { 62 | foreach (self::$instantiatedObjects as $objectData) { 63 | if ($objectData['data'] == $data) { 64 | return $objectData['object']; 65 | } 66 | } 67 | 68 | $object = $this->_objectManager->create($this->_instanceName, $data); 69 | self::$instantiatedObjects[] = ['data' => $data, 'object' => $object]; 70 | return $object; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Framework/Interaction/MetaData/ValidationException.php: -------------------------------------------------------------------------------- 1 | getData(self::IS_UNBALANCED); 28 | } 29 | 30 | /** 31 | * {@inheritDoc} 32 | */ 33 | public function setIsUnbalanced($unbalanced) 34 | { 35 | $this->setData(self::IS_UNBALANCED, $unbalanced); 36 | return $this; 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | public function getBaseAvataxTaxAmount() { 43 | return $this->getData(self::BASE_AVATAX_TAX_AMOUNT); 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | public function setBaseAvataxTaxAmount($amount) { 50 | $this->setData(self::BASE_AVATAX_TAX_AMOUNT, $amount); 51 | return $this; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Config/Source/AddressValidationCountries.php: -------------------------------------------------------------------------------- 1 | 'US', 'label' => __('United States')], 32 | ['value' => 'CA', 'label' => __('Canada')] 33 | ]; 34 | 35 | return $options; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Config/Source/AvaTaxCustomerUsageType.php: -------------------------------------------------------------------------------- 1 | '', 'label' => ' '], 32 | ['value' => 'A', 'label' => __('A - Federal Government')], 33 | ['value' => 'B', 'label' => __('B - State/Local Govt.')], 34 | ['value' => 'C', 'label' => __('C - Tribal Government')], 35 | ['value' => 'D', 'label' => __('D - Foreign Diplomat')], 36 | ['value' => 'E', 'label' => __('E - Charitable Organization')], 37 | ['value' => 'F', 'label' => __('F - Religious Organization')], 38 | ['value' => 'G', 'label' => __('G - Resale')], 39 | ['value' => 'H', 'label' => __('H - Agricultural Production')], 40 | ['value' => 'I', 'label' => __('I - Industrial Prod/Mfg.')], 41 | ['value' => 'J', 'label' => __('J - Direct Pay Permit')], 42 | ['value' => 'K', 'label' => __('K - Direct Mail')], 43 | ['value' => 'L', 'label' => __('L - Other')], 44 | ['value' => 'M', 'label' => __('M - Education Organization')], 45 | ['value' => 'N', 'label' => __('N - Local Government')], 46 | ['value' => 'P', 'label' => __('P - Commercial Aquaculture (Canada)')], 47 | ['value' => 'Q', 'label' => __('Q - Commercial Fishery (Canada)')], 48 | ['value' => 'R', 'label' => __('R - Non-resident (Canada)')], 49 | ['value' => 'MED1', 'label' => __('MED1 - US MDET with exempt sales tax')], 50 | ['value' => 'MED2', 'label' => __('MED2 - US MDET with taxable sales tax')], 51 | ]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Config/Source/ErrorAction.php: -------------------------------------------------------------------------------- 1 | Config::ERROR_ACTION_DISABLE_CHECKOUT, 'label' => __('Disable checkout & show error message')], 29 | ['value' => Config::ERROR_ACTION_ALLOW_CHECKOUT_NATIVE_TAX, 'label' => __('Allow checkout & fall back to native Magento tax calculation (no error message)')], 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Model/Config/Source/LogDetail.php: -------------------------------------------------------------------------------- 1 | self::MINIMAL, 'label' => __('Minimal')], 33 | ['value' => self::NORMAL, 'label' => __('Normal')], 34 | ['value' => self::EXTRA, 'label' => __('Extra')], 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Config/Source/LogFileMode.php: -------------------------------------------------------------------------------- 1 | self::COMBINED, 'label' => __('Combined With Magento Log Files')], 32 | ['value' => self::SEPARATE, 'label' => __('Separate AvaTax Log File')], 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Model/Config/Source/LogLevel.php: -------------------------------------------------------------------------------- 1 | Logger::DEBUG, 'label' => __('Debug')], 32 | 33 | // Info - Any normal interesting activity to be aware of having occurred 34 | // Detailed informational logging expected for production monitoring 35 | ['value' => Logger::INFO, 'label' => __('Info')], 36 | 37 | // Notice - Significant normal informational messages 38 | // Lighter informational logging expected for production monitoring 39 | ['value' => Logger::NOTICE, 'label' => __('Notice')], 40 | 41 | // Warning - Any event that is not optimal, but is handled or worked around and should not require intervention by a human 42 | // Something that could degrade site functionality or a customer's experience 43 | ['value' => Logger::WARNING, 'label' => __('Warning')], 44 | 45 | // Error - Something unexpected happened and a human should be made aware of the problem 46 | // Something that likely impacts the site's important functionality or would seriously affect customers 47 | ['value' => Logger::ERROR, 'label' => __('Error')], 48 | 49 | // Critical - Serious errors that require human intervention 50 | // Unhandled code exceptions needing the attention of a developer/admin 51 | ['value' => Logger::CRITICAL, 'label' => __('Critical')], 52 | 53 | //['value' => Logger::ALERT, 'label' => __('Alert')], 54 | //['value' => Logger::EMERGENCY, 'label' => __('Emergency')], 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Model/Config/Source/Mode.php: -------------------------------------------------------------------------------- 1 | 1, 'label' => __('Production')], ['value' => 0, 'label' => __('Development')]]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Model/Config/Source/Product/Attributes.php: -------------------------------------------------------------------------------- 1 | productAttributeRepository = $productAttributeRepository; 42 | $this->searchCriteria = $searchCriteria; 43 | } 44 | 45 | /** 46 | * @return array 47 | */ 48 | public function toOptionArray() 49 | { 50 | $options = [ 51 | ['value' => '', 'label' => __('No Attribute')], 52 | ]; 53 | $attributes = $this->getAttributes(); 54 | 55 | foreach ($attributes as $attribute) { 56 | if (in_array($attribute->getBackendType(), ['static', 'varchar', 'text']) && $attribute->getDefaultFrontendLabel()) { 57 | $options = array_merge($options, [['value' => $attribute->getAttributeCode(), 'label' => $attribute->getDefaultFrontendLabel()]]); 58 | } 59 | } 60 | 61 | return $options; 62 | } 63 | 64 | /** 65 | * Returns attributes 66 | * 67 | * @return \Magento\Catalog\Api\Data\ProductAttributeInterface[] 68 | */ 69 | protected function getAttributes() 70 | { 71 | return $this->productAttributeRepository->getList($this->searchCriteria)->getItems(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Model/Config/Source/TaxCalculationCountries.php: -------------------------------------------------------------------------------- 1 | Config::TAX_MODE_NO_ESTIMATE_OR_SUBMIT, 'label' => __('Disabled')], 29 | ['value' => Config::TAX_MODE_ESTIMATE_ONLY, 'label' => __('Estimate Tax')], 30 | ['value' => Config::TAX_MODE_ESTIMATE_AND_SUBMIT, 'label' => __('Estimate Tax & Submit Transactions to AvaTax (default)')], 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Model/CreditMemo.php: -------------------------------------------------------------------------------- 1 | _init('ClassyLlama\AvaTax\Model\ResourceModel\CreditMemo'); 28 | } 29 | 30 | /** 31 | * @return array 32 | */ 33 | public function getIdentities() 34 | { 35 | return [self::CACHE_TAG . '_' . $this->getId()]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Invoice.php: -------------------------------------------------------------------------------- 1 | _init('ClassyLlama\AvaTax\Model\ResourceModel\Invoice'); 28 | } 29 | 30 | /** 31 | * @return array 32 | */ 33 | public function getIdentities() 34 | { 35 | return [self::CACHE_TAG . '_' . $this->getId()]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Log.php: -------------------------------------------------------------------------------- 1 | _init('ClassyLlama\AvaTax\Model\ResourceModel\Log'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Model/Logger/AvaTaxLogger.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 37 | } 38 | 39 | /** 40 | * Retrieves the current Store ID from Magento and adds it to the record 41 | * 42 | * @param array $record 43 | * @return array 44 | */ 45 | public function __invoke(array $record) 46 | { 47 | // get the store_id and add it to the record 48 | $store = $this->storeManager->getStore(); 49 | $record['extra']['store_id'] = $store->getId(); 50 | 51 | return $record; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Logger/FileFormatter.php: -------------------------------------------------------------------------------- 1 | normalizerFormatter = new NormalizerFormatter; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function format(array $record) 44 | { 45 | $vars = $this->normalizerFormatter->format($record); 46 | 47 | $output = $this->format; 48 | 49 | foreach ($vars['extra'] as $var => $val) { 50 | if (false !== strpos($output, '%extra.'.$var.'%')) { 51 | $output = str_replace('%extra.' . $var . '%', var_export($val, true), $output); 52 | unset($vars['extra'][$var]); 53 | } 54 | } 55 | 56 | foreach ($vars as $var => $val) { 57 | if (false !== strpos($output, '%'.$var.'%')) { 58 | $val_output = ''; 59 | if ((is_array($val) && count($val) > 0) || is_array($val) === false) { 60 | $val_output = var_export($val, true); 61 | } 62 | $output = str_replace('%' . $var . '%', $val_output, $output); 63 | } 64 | } 65 | 66 | return $output; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Model/ResourceModel/CreditMemo.php: -------------------------------------------------------------------------------- 1 | _init('avatax_sales_creditmemo', 'entity_id'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Model/ResourceModel/Invoice.php: -------------------------------------------------------------------------------- 1 | _init('avatax_sales_invoice', 'entity_id'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Model/ResourceModel/Log.php: -------------------------------------------------------------------------------- 1 | _init('avatax_log', 'log_id'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Model/ResourceModel/Tax/Classes/Customer.php: -------------------------------------------------------------------------------- 1 | _init('tax_class', 'class_id'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Model/ResourceModel/Tax/Classes/Customer/Collection.php: -------------------------------------------------------------------------------- 1 | addFieldToFilter('class_type', \Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_CUSTOMER); 34 | return $this; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Model/ResourceModel/Tax/Classes/Product.php: -------------------------------------------------------------------------------- 1 | _init('tax_class', 'class_id'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Model/ResourceModel/Tax/Classes/Product/Collection.php: -------------------------------------------------------------------------------- 1 | addFieldToFilter('class_type', \Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_PRODUCT); 34 | return $this; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Model/Tax/Calculation/GrandTotalRates.php: -------------------------------------------------------------------------------- 1 | _get(ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY); 23 | } 24 | 25 | /** 26 | * {@inheritdoc} 27 | * 28 | * @param \ClassyLlama\AvaTax\Api\Data\GrandTotalRatesExtensionInterface $extensionAttributes 29 | * @return $this 30 | */ 31 | public function setExtensionAttributes( 32 | \ClassyLlama\AvaTax\Api\Data\GrandTotalRatesExtensionInterface $extensionAttributes 33 | ) { 34 | $this->_data[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY] = $extensionAttributes; 35 | return $this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/ValidAddressManagement.php: -------------------------------------------------------------------------------- 1 | validationInteraction = $validationInteraction; 50 | $this->storeManager = $storeManager; 51 | } 52 | 53 | /** 54 | * {@inheritDoc} 55 | */ 56 | public function saveValidAddress(AddressInterface $address, $storeId = null) { 57 | if ($storeId === null) { 58 | $storeId = $this->storeManager->getStore()->getId(); 59 | } 60 | 61 | try { 62 | return $this->validationInteraction->validateAddress($address, $storeId); 63 | } catch (\SoapFault $e) { 64 | return 'Connection Error: ' . $e->getMessage(); 65 | } catch (\Exception $e) { 66 | return $e->getMessage(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Observer/PreventOrderPlaceObserver.php: -------------------------------------------------------------------------------- 1 | coreRegistry = $coreRegistry; 49 | $this->config = $config; 50 | } 51 | 52 | /** 53 | * If AvaTax GetTaxRequest failed and if configuration is set to prevent checkout, throw exception 54 | * 55 | * @param \Magento\Framework\Event\Observer $observer 56 | * @return $this 57 | * @throws LocalizedException 58 | */ 59 | public function execute(\Magento\Framework\Event\Observer $observer) 60 | { 61 | /** @var \Magento\Sales\Api\Data\OrderInterface $order */ 62 | $order = $observer->getOrder(); 63 | if ($this->coreRegistry->registry(Tax::AVATAX_GET_TAX_REQUEST_ERROR)) { 64 | $errorMessage = $this->config->getErrorActionDisableCheckoutMessage($order->getStoreId()); 65 | throw new LocalizedException($errorMessage); 66 | } 67 | return $this; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Plugin/Quote/Model/Quote/Config.php: -------------------------------------------------------------------------------- 1 | config = $config; 36 | } 37 | 38 | /** 39 | * Append attributes to the list of attributes loaded on the quote_items collection 40 | * 41 | * @param QuoteConfig $config 42 | * @param $attributes 43 | * @return array 44 | */ 45 | public function afterGetProductAttributes(QuoteConfig $config, $attributes) 46 | { 47 | if ($this->config->getRef1Attribute()) { 48 | $attributes[] = $this->config->getRef1Attribute(); 49 | } 50 | if ($this->config->getRef2Attribute()) { 51 | $attributes[] = $this->config->getRef2Attribute(); 52 | } 53 | if ($this->config->getUpcAttribute()) { 54 | $attributes[] = $this->config->getUpcAttribute(); 55 | } 56 | return array_unique($attributes); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Plugin/Sales/Admin/Order/Create/Form/Account.php: -------------------------------------------------------------------------------- 1 | avaTaxConfigHelper = $avaTaxConfigHelper; 30 | } 31 | 32 | public function afterToHtml(\Magento\Sales\Block\Adminhtml\Order\Create\Form\Account $subject, $result) 33 | { 34 | if ($this->avaTaxConfigHelper->isModuleEnabled()) { 35 | $html = '
'; 36 | $html .= __('If you are changing a customer group that affects tax calculation, please see this readme for how to ensure the appropriate taxes are calculated.'); 37 | $html .= '
'; 38 | 39 | $result .= $html; 40 | } 41 | 42 | return $result; 43 | } 44 | } -------------------------------------------------------------------------------- /Plugin/Sales/Total/Quote/CommonTaxCollector.php: -------------------------------------------------------------------------------- 1 | $appliedTax) { 33 | $baseAppliedTax = $baseAppliedTaxes[$taxId]; 34 | $rateDataObjects = $appliedTax->getRates(); 35 | 36 | $rates = []; 37 | foreach ($rateDataObjects as $rateDataObject) { 38 | // BEGIN EDIT 39 | // Determine whether or not tax has been set as an extension attribute 40 | if ($rateDataObject->getExtensionAttributes() && $rateDataObject->getExtensionAttributes()->getTax()) { 41 | $tax = $rateDataObject->getExtensionAttributes()->getTax(); 42 | } else { 43 | $tax = 0; 44 | } 45 | $rates[] = [ 46 | 'percent' => $rateDataObject->getPercent(), 47 | 'code' => $rateDataObject->getCode(), 48 | 'title' => $rateDataObject->getTitle(), 49 | // Add extension attributes array to rates array and set tax amount 50 | 'extension_attributes' => ['tax' => $tax] 51 | // END EDIT 52 | ]; 53 | } 54 | 55 | $appliedTaxArray = [ 56 | 'amount' => $appliedTax->getAmount(), 57 | 'base_amount' => $baseAppliedTax->getAmount(), 58 | 'percent' => $appliedTax->getPercent(), 59 | 'id' => $appliedTax->getTaxRateKey(), 60 | 'rates' => $rates, 61 | ]; 62 | if (!empty($extraInfo)) { 63 | $appliedTaxArray = array_merge($appliedTaxArray, $extraInfo); 64 | } 65 | 66 | $appliedTaxesArray[] = $appliedTaxArray; 67 | } 68 | 69 | return $appliedTaxesArray; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Plugin/Tax/Model/Sales/Total/Quote/Subtotal.php: -------------------------------------------------------------------------------- 1 | config = $config; 34 | } 35 | 36 | /** 37 | * If module is enabled, don't run collect totals for subtotal 38 | * 39 | * Tax calculation for shipping is handled in this class 40 | * @see \ClassyLlama\AvaTax\Model\Tax\Sales\Total\Quote\Tax::collect() 41 | * Since this extension doesn't support applying discounts or shipping to the post-tax amount, there is no need to 42 | * run this collect method. 43 | * 44 | * @param \Magento\Tax\Model\Sales\Total\Quote\Subtotal $subject 45 | * @param \Closure $proceed 46 | * @param \Magento\Quote\Model\Quote $quote 47 | * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment 48 | * @param \Magento\Quote\Model\Quote\Address\Total $total 49 | * @return mixed 50 | */ 51 | public function aroundCollect( 52 | \Magento\Tax\Model\Sales\Total\Quote\Subtotal $subject, 53 | \Closure $proceed, 54 | \Magento\Quote\Model\Quote $quote, 55 | \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, 56 | \Magento\Quote\Model\Quote\Address\Total $total 57 | ) { 58 | $storeId = $quote->getStoreId(); 59 | // If quote is virtual, getShipping will return billing address, so no need to check if quote is virtual 60 | $address = $shippingAssignment->getShipping()->getAddress(); 61 | if (!$this->config->isModuleEnabled($storeId) 62 | || $this->config->getTaxMode($storeId) == Config::TAX_MODE_NO_ESTIMATE_OR_SUBMIT 63 | || !$this->config->isAddressTaxable($address, $storeId) 64 | ) { 65 | return $proceed($quote, $shippingAssignment, $total); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Tests/Integration/_files/scenarios/customer_tax_class.php: -------------------------------------------------------------------------------- 1 | [ 21 | SetupUtil::CONFIG_OVERRIDES => $credentialsConfig, 22 | ], 23 | 'quote_data' => [ 24 | 'customer_data' => [ 25 | 'tax_class_name' => SetupUtil::CUSTOMER_TAX_CLASS_2_NON_PROFIT 26 | ], 27 | 'billing_address' => [ 28 | 'region_id' => SetupUtil::REGION_MI, 29 | ], 30 | 'shipping_address' => [ 31 | 'region_id' => SetupUtil::REGION_MI, 32 | ], 33 | 'items' => [ 34 | [ 35 | 'type' => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 36 | 'sku' => 'simple1', 37 | 'price' => 10, 38 | 'qty' => 1, 39 | ], 40 | ], 41 | ], 42 | 'expected_results' => [ 43 | // Not comparing with native Magento since we'd have to setup associated tax rules in Magento 44 | 'compare_with_native_tax_calculation' => false, 45 | 'address_data' => [ 46 | 'subtotal' => 10, 47 | 'subtotal_incl_tax' => 10, 48 | 'tax_amount' => 0, 49 | 'grand_total' => 10, 50 | ], 51 | 'items_data' => [ 52 | 'simple1' => [ 53 | 'row_total' => 10, 54 | 'tax_percent' => 6, 55 | 'price' => 10, 56 | 'price_incl_tax' => 10, 57 | 'row_total_incl_tax' => 10, 58 | 'tax_amount' => 0, 59 | ], 60 | ], 61 | ], 62 | ]; 63 | -------------------------------------------------------------------------------- /Tests/Integration/_files/scenarios/product_tax_classes.php: -------------------------------------------------------------------------------- 1 | [ 21 | SetupUtil::CONFIG_OVERRIDES => $credentialsConfig, 22 | ], 23 | 'quote_data' => [ 24 | 'billing_address' => [ 25 | 'region_id' => SetupUtil::REGION_MI, 26 | ], 27 | 'shipping_address' => [ 28 | 'region_id' => SetupUtil::REGION_MI, 29 | ], 30 | 'items' => [ 31 | [ 32 | 'type' => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 33 | 'sku' => 'simple1', 34 | 'price' => 10, 35 | 'qty' => 1, 36 | ], 37 | [ 38 | 'type' => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 39 | 'sku' => 'simple2_digital_good', 40 | 'price' => 10, 41 | 'qty' => 1, 42 | 'tax_class_name' => SetupUtil::PRODUCT_TAX_CLASS_3_DIGITAL_GOODS 43 | ], 44 | ], 45 | ], 46 | 'expected_results' => [ 47 | // Not comparing with native Magento since we'd have to setup associated tax rules in Magento 48 | 'compare_with_native_tax_calculation' => false, 49 | 'address_data' => [ 50 | 'subtotal' => 20, 51 | 'subtotal_incl_tax' => 20.6, 52 | 'tax_amount' => 0.6, 53 | 'grand_total' => 20.60, 54 | ], 55 | 'items_data' => [ 56 | 'simple1' => [ 57 | 'row_total' => 10, 58 | 'tax_percent' => 6.0, 59 | 'price' => 10, 60 | 'price_incl_tax' => 10.6, 61 | 'row_total_incl_tax' => 10.6, 62 | 'tax_amount' => 0.6, 63 | ], 64 | 'simple2_digital_good' => [ 65 | 'row_total' => 10, 66 | 'tax_percent' => 6.0, 67 | 'price' => 10, 68 | 'price_incl_tax' => 10, 69 | 'row_total_incl_tax' => 10, 70 | 'tax_amount' => 0, 71 | ], 72 | ], 73 | ], 74 | ]; 75 | -------------------------------------------------------------------------------- /Tests/Integration/_files/scenarios/tax_before_discount_only_applies_to_taxable_amount.php: -------------------------------------------------------------------------------- 1 | [ 21 | SetupUtil::CONFIG_OVERRIDES => $credentialsConfig, 22 | ], 23 | 'quote_data' => [ 24 | 'customer_data' => [ 25 | 'tax_class_name' => SetupUtil::CUSTOMER_TAX_CLASS_2_NON_PROFIT 26 | ], 27 | 'billing_address' => [ 28 | 'region_id' => SetupUtil::REGION_MI, 29 | ], 30 | 'shipping_address' => [ 31 | 'region_id' => SetupUtil::REGION_MI, 32 | ], 33 | 'shopping_cart_rules' => [ 34 | [ 35 | 'discount_amount' => 20, 36 | ], 37 | ], 38 | 'items' => [ 39 | [ 40 | 'type' => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 41 | 'sku' => 'simple1', 42 | 'price' => 10, 43 | 'qty' => 1, 44 | ], 45 | ], 46 | ], 47 | 'expected_results' => [ 48 | 'compare_with_native_tax_calculation' => false, 49 | 'address_data' => [ 50 | 'subtotal' => 10, 51 | 'subtotal_incl_tax' => 10, 52 | 'tax_amount' => 0, 53 | 'grand_total' => 8, 54 | ], 55 | 'items_data' => [ 56 | 'simple1' => [ 57 | 'row_total' => 10, 58 | 'tax_percent' => 6, 59 | 'price' => 10, 60 | 'price_incl_tax' => 10, 61 | 'row_total_incl_tax' => 10, 62 | 'tax_amount' => 0, 63 | 64 | 'discount_amount' => 2, 65 | 'tax_before_discount' => 0, 66 | ], 67 | ], 68 | ], 69 | ]; 70 | -------------------------------------------------------------------------------- /Tests/Integration/_files/tax_calculation_data_aggregated.php: -------------------------------------------------------------------------------- 1 | 1, 20 | Config::XML_PATH_AVATAX_LIVE_MODE => 0, 21 | Config::XML_PATH_AVATAX_DEVELOPMENT_COMPANY_CODE => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 22 | Config::XML_PATH_AVATAX_DEVELOPMENT_ACCOUNT_NUMBER => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 23 | Config::XML_PATH_AVATAX_DEVELOPMENT_LICENSE_KEY => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 24 | ]; 25 | -------------------------------------------------------------------------------- /Ui/Component/Listing/Columns/LogActions.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $urlBuilder; 51 | parent::__construct($context, $uiComponentFactory, $components, $data); 52 | } 53 | 54 | /** 55 | * Prepare Data Source 56 | * 57 | * @param array $dataSource 58 | * @return array 59 | */ 60 | public function prepareDataSource(array $dataSource) 61 | { 62 | if (isset($dataSource['data']['items'])) { 63 | foreach ($dataSource['data']['items'] as &$item) { 64 | $item[$this->getData('name')]['view'] = [ 65 | 66 | 'href' => $this->urlBuilder->getUrl(self::LOG_URL_PATH_VIEW, ['id' => $item['log_id']]), 67 | 'label' => __('View') 68 | ]; 69 | } 70 | } 71 | 72 | return $dataSource; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Ui/Component/Listing/Columns/TaxClassesCustomerActions.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $urlBuilder; 51 | parent::__construct($context, $uiComponentFactory, $components, $data); 52 | } 53 | 54 | /** 55 | * Prepare Data Source 56 | * 57 | * @param array $dataSource 58 | * @return array 59 | */ 60 | public function prepareDataSource(array $dataSource) 61 | { 62 | if (isset($dataSource['data']['items'])) { 63 | foreach ($dataSource['data']['items'] as &$item) { 64 | $item[$this->getData('name')]['view'] = [ 65 | 66 | 'href' => $this->urlBuilder->getUrl(self::QUEUE_URL_PATH_VIEW, ['id' => $item['class_id']]), 67 | 'label' => __('Edit') 68 | ]; 69 | } 70 | } 71 | 72 | return $dataSource; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Ui/Component/Listing/Columns/TaxClassesProductActions.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $urlBuilder; 51 | parent::__construct($context, $uiComponentFactory, $components, $data); 52 | } 53 | 54 | /** 55 | * Prepare Data Source 56 | * 57 | * @param array $dataSource 58 | * @return array 59 | */ 60 | public function prepareDataSource(array $dataSource) 61 | { 62 | if (isset($dataSource['data']['items'])) { 63 | foreach ($dataSource['data']['items'] as &$item) { 64 | $item[$this->getData('name')]['view'] = [ 65 | 66 | 'href' => $this->urlBuilder->getUrl(self::QUEUE_URL_PATH_VIEW, ['id' => $item['class_id']]), 67 | 'label' => __('Edit') 68 | ]; 69 | } 70 | } 71 | 72 | return $dataSource; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "classyllama/module-avatax", 3 | "type": "magento2-module", 4 | "version": "1.5.3", 5 | "license": "OSL-3.0", 6 | "require": { 7 | "magento/framework": "^100.1.0|101.0.*|^102.0.0", 8 | "avalara/avatax": "^15.5.2.0" 9 | }, 10 | "autoload": { 11 | "files": [ "registration.php" ], 12 | "psr-4": { 13 | "ClassyLlama\\AvaTax\\": "" 14 | } 15 | }, 16 | "abandoned": "avalara/avatax-magento" 17 | } 18 | -------------------------------------------------------------------------------- /docs/files/env.php: -------------------------------------------------------------------------------- 1 | 4 | array ( 5 | 'frontName' => 'backend', 6 | ), 7 | 'cert-capture' => 8 | array ( 9 | 'url' => 'https://sbx-api.certcapture.com/v2/auth/get-token', 10 | 'sdk-url' => 'https://sbx.certcapture.com/gencert2/js', 11 | 'auth' => 12 | array ( 13 | 'username' => 'example@example.com', 14 | 'password' => 'Xd9Tm0yxd0GHirbm', 15 | ), 16 | 'client-id' => '40306', 17 | ), 18 | 'db' => 19 | array ( 20 | 'connection' => 21 | array ( 22 | 'indexer' => 23 | array ( 24 | 'host' => '127.0.0.1', 25 | 'dbname' => 'magento', 26 | 'username' => 'root', 27 | 'password' => 'root', 28 | 'model' => 'mysql4', 29 | 'engine' => 'innodb', 30 | 'initStatements' => 'SET NAMES utf8;', 31 | 'active' => '1', 32 | 'persistent' => NULL, 33 | ), 34 | 'default' => 35 | array ( 36 | 'host' => '127.0.0.1', 37 | 'dbname' => 'magento', 38 | 'username' => 'root', 39 | 'password' => 'root', 40 | 'model' => 'mysql4', 41 | 'engine' => 'innodb', 42 | 'initStatements' => 'SET NAMES utf8;', 43 | 'active' => '1', 44 | ), 45 | ), 46 | 'table_prefix' => '', 47 | ), 48 | 'crypt' => 49 | array ( 50 | 'key' => 'ecc7b7bdf458531890dd688f00es233c', 51 | ), 52 | 'resource' => 53 | array ( 54 | 'default_setup' => 55 | array ( 56 | 'connection' => 'default', 57 | ), 58 | ), 59 | 'x-frame-options' => 'SAMEORIGIN', 60 | 'MAGE_MODE' => 'developer', 61 | 'session' => 62 | array ( 63 | 'save' => 'files', 64 | ), 65 | 'cache' => 66 | array ( 67 | 'frontend' => 68 | array ( 69 | 'default' => 70 | array ( 71 | 'backend' => 'Cm_Cache_Backend_Redis', 72 | 'backend_options' => 73 | array ( 74 | 'server' => 'localhost', 75 | 'database' => '0', 76 | 'port' => '6379', 77 | ), 78 | ), 79 | ), 80 | ), 81 | 'cache_types' => 82 | array ( 83 | 'config' => 1, 84 | 'layout' => 1, 85 | 'block_html' => 1, 86 | 'collections' => 1, 87 | 'reflection' => 1, 88 | 'db_ddl' => 1, 89 | 'eav' => 1, 90 | 'customer_notification' => 1, 91 | 'config_integration' => 1, 92 | 'config_integration_api' => 1, 93 | 'target_rule' => 1, 94 | 'full_page' => 1, 95 | 'translate' => 1, 96 | 'config_webservice' => 1, 97 | 'compiled_config' => 1, 98 | ), 99 | 'install' => 100 | array ( 101 | 'date' => 'Wed, 23 May 2018 21:09:30 +0000', 102 | ), 103 | ); 104 | -------------------------------------------------------------------------------- /docs/images/2017-08-01_130753__Taxes__Stores__Magento_Admin_2017-09-03_20-52-04.png_1423792_2017-09-03_20-58-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/2017-08-01_130753__Taxes__Stores__Magento_Admin_2017-09-03_20-52-04.png_1423792_2017-09-03_20-58-22.png -------------------------------------------------------------------------------- /docs/images/2017-08-01_130753__Taxes__Stores__Magento_Admin_2017-09-03_21-01-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/2017-08-01_130753__Taxes__Stores__Magento_Admin_2017-09-03_21-01-04.png -------------------------------------------------------------------------------- /docs/images/AvaTax_Logs__Taxes__Stores__Magento_Admin_2017-09-03_20-48-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/AvaTax_Logs__Taxes__Stores__Magento_Admin_2017-09-03_20-48-18.png -------------------------------------------------------------------------------- /docs/images/Configuration__Settings__Stores__Magento_Admin_2017-09-03_20-45-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/Configuration__Settings__Stores__Magento_Admin_2017-09-03_20-45-22.png -------------------------------------------------------------------------------- /docs/images/Veronica_Costello__Customers__Customers__Magento_Admin_2017-04-26_10-08-51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/Veronica_Costello__Customers__Customers__Magento_Admin_2017-04-26_10-08-51.png -------------------------------------------------------------------------------- /docs/images/address_validation_admin_order_creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/address_validation_admin_order_creation.png -------------------------------------------------------------------------------- /docs/images/address_validation_backend_edit_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/address_validation_backend_edit_address.png -------------------------------------------------------------------------------- /docs/images/address_validation_customer_edit_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/address_validation_customer_edit_address.png -------------------------------------------------------------------------------- /docs/images/address_validation_unable_to_validate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/address_validation_unable_to_validate.png -------------------------------------------------------------------------------- /docs/images/address_validation_with_choice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/address_validation_with_choice.png -------------------------------------------------------------------------------- /docs/images/address_validation_without_choice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/address_validation_without_choice.png -------------------------------------------------------------------------------- /docs/images/avatax_queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/avatax_queue.png -------------------------------------------------------------------------------- /docs/images/avatax_sales_invoice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/avatax_sales_invoice.png -------------------------------------------------------------------------------- /docs/images/avatax_sales_numbers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/avatax_sales_numbers.png -------------------------------------------------------------------------------- /docs/images/configuration_screenshot_2.0.0-rc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/configuration_screenshot_2.0.0-rc1.png -------------------------------------------------------------------------------- /docs/images/document-management-backend.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/document-management-backend.jpg -------------------------------------------------------------------------------- /docs/images/document-management-features.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/document-management-features.jpg -------------------------------------------------------------------------------- /docs/images/screenshot_tax_requests_customer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/screenshot_tax_requests_customer.jpg -------------------------------------------------------------------------------- /docs/images/screenshot_tax_requests_guest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classyllama/ClassyLlama_AvaTax/5ee22c26c178b1012becba448e6bd8edd153f99e/docs/images/screenshot_tax_requests_guest.jpg -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /etc/adminhtml/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | ClassyLlama\AvaTax\Model\Message\QueueNotification 22 | ClassyLlama\AvaTax\Model\Message\QueueFailureNotification 23 | ClassyLlama\AvaTax\Model\Message\QueueDisabledNotification 24 | ClassyLlama\AvaTax\Model\Message\ConfigNotification 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /etc/adminhtml/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /etc/cron_groups.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 5 20 | 20 21 | 20 22 | 10 23 | 60 24 | 600 25 | 0 26 | 27 | 28 | -------------------------------------------------------------------------------- /etc/crontab.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | */5 * * * * 21 | 22 | 23 | 2 0 */1 * * 24 | 25 | 26 | 2 0 */1 * * 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /etc/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /etc/frontend/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 21 | 22 | ClassyLlama\AvaTax\Block\Checkout\LayoutProcessor 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /etc/webapi.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_log_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_order_create_billing_address.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | ClassyLlama_AvaTax::order/create/form/address.phtml 22 | 23 | 24 | billing 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_order_create_shipping_address.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | ClassyLlama_AvaTax::order/create/form/address.phtml 22 | 23 | 24 | shipping 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_queue_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_tax_classes_customer_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_tax_classes_customer_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_tax_classes_customer_newclass.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_tax_classes_product_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_tax_classes_product_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/avatax_tax_classes_product_newclass.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /view/adminhtml/layout/customer_index_edit.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /view/adminhtml/layout/sales_order_create_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /view/adminhtml/layout/sales_order_create_load_block_billing_address.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /view/adminhtml/layout/sales_order_create_load_block_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /view/adminhtml/layout/sales_order_create_load_block_shipping_address.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /view/adminhtml/templates/customer/edit/region.phtml: -------------------------------------------------------------------------------- 1 | 16 | isAddressValidationEnabled()): ?> 17 | 24 | 25 | -------------------------------------------------------------------------------- /view/adminhtml/templates/log/summary.phtml: -------------------------------------------------------------------------------- 1 | getSummaryData(); 18 | ?> 19 |
20 | Summary 21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /view/adminhtml/templates/order/create/address_validation_modal.phtml: -------------------------------------------------------------------------------- 1 | 16 | isValidationEnabled()): ?> 17 | 30 | 31 | -------------------------------------------------------------------------------- /view/adminhtml/templates/queue/summary.phtml: -------------------------------------------------------------------------------- 1 | getQueueSummaryLastUpdatedAt(); 18 | $count = $block->getQueueSummaryCount(); 19 | ?> 20 |
21 |
22 | to avoid race conditions during order processing.', (\ClassyLlama\AvaTax\Model\Queue\Task::QUEUE_PROCESSING_DELAY / 60), 'https://github.com/classyllama/ClassyLlama_AvaTax/issues/170') ?> 23 |
24 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/customer_form.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 |
18 |
19 | 23 | 24 | 25 | 26 | ClassyLlama_AvaTax/js/form/element/button 27 | 28 | 10000 29 | 30 | 31 | 32 | 33 | 34 | 35 | ClassyLlama_AvaTax/js/form/element/validationForm 36 | 37 | 10001 38 | 39 | 40 | 41 |
42 |
43 | -------------------------------------------------------------------------------- /view/adminhtml/web/css/source/_module.less: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | @import '_address-validation.less'; 15 | 16 | 17 | .admin__avatax-log-summary { 18 | span { 19 | float: left; 20 | } 21 | .avatax-summary-list { 22 | float: left; 23 | } 24 | .avatax-log-summary-level { 25 | float: left; 26 | margin: 0 0 0 2em; 27 | padding: 0; 28 | } 29 | .avatax-log-summary-level-label { 30 | margin: 0; 31 | padding-right: 0.5em; 32 | text-align: right; 33 | border-right-color: @color-black; 34 | border-right-style: solid; 35 | border-right-width: thin; 36 | } 37 | .avatax-log-summary-count { 38 | padding-left: 0.5em; 39 | margin: 0; 40 | } 41 | } 42 | 43 | pre.admin__avatax-log-text { 44 | white-space: pre-wrap; 45 | } 46 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/action/validate-address-request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | define( 15 | [ 16 | 'jquery', 17 | 'ClassyLlama_AvaTax/js/model/address-model' 18 | ], 19 | function ( 20 | $, 21 | addressModel 22 | ) { 23 | 'use strict'; 24 | return function(url) { 25 | var payload = { 26 | address: addressModel.originalAddress() 27 | }; 28 | return $.ajax({ 29 | url: url, 30 | type: 'post', 31 | dataType: 'json', 32 | data: payload 33 | }); 34 | } 35 | } 36 | ); 37 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/form/element/validationForm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | define([ 15 | 'jquery', 16 | 'Magento_Ui/js/form/element/abstract' 17 | ], function ( 18 | $, 19 | Abstract 20 | ) { 21 | 'use strict'; 22 | 23 | return Abstract.extend({ 24 | defaults: { 25 | links: { 26 | value: '' 27 | }, 28 | template: 'ClassyLlama_AvaTax/form/element/adminValidateAddress' 29 | }, 30 | baseTemplate: 'ClassyLlama_AvaTax/baseValidateAddress', 31 | choice: 1, 32 | 33 | initialize: function () { 34 | this._super() 35 | .initFormId(); 36 | $(document).on('click', '.validateAddressForm .instructions[data-uid="' + this.uid + '"] .edit-address', function () { 37 | $('html, body').animate({scrollTop: $("#container").offset().top}, 1000); 38 | }); 39 | 40 | return this; 41 | }, 42 | 43 | initFormId: function () { 44 | var namespace; 45 | 46 | if (this.formId) { 47 | return this; 48 | } 49 | 50 | namespace = this.name.split('.'); 51 | this.formId = namespace[0]; 52 | 53 | return this; 54 | }, 55 | 56 | getBaseValidateAddressTemplate: function () { 57 | return this.baseTemplate; 58 | } 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/lib/event.simulate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Event.simulate(@element, eventName[, options]) -> Element 3 | * 4 | * - @element: element to fire event on 5 | * - eventName: name of event to fire (only MouseEvents and HTMLEvents interfaces are supported) 6 | * - options: optional object to fine-tune event properties - pointerX, pointerY, ctrlKey, etc. 7 | * 8 | * $('foo').simulate('click'); // => fires "click" event on an element with id=foo 9 | * 10 | **/ 11 | (function(){ 12 | 13 | var eventMatchers = { 14 | 'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/, 15 | 'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/ 16 | } 17 | var defaultOptions = { 18 | pointerX: 0, 19 | pointerY: 0, 20 | button: 0, 21 | ctrlKey: false, 22 | altKey: false, 23 | shiftKey: false, 24 | metaKey: false, 25 | bubbles: true, 26 | cancelable: true 27 | } 28 | 29 | Event.simulate = function(element, eventName) { 30 | var options = Object.extend(defaultOptions, arguments[2] || { }); 31 | var oEvent, eventType = null; 32 | 33 | element = $(element); 34 | 35 | for (var name in eventMatchers) { 36 | if (eventMatchers[name].test(eventName)) { eventType = name; break; } 37 | } 38 | 39 | if (!eventType) 40 | throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported'); 41 | 42 | if (document.createEvent) { 43 | oEvent = document.createEvent(eventType); 44 | if (eventType == 'HTMLEvents') { 45 | oEvent.initEvent(eventName, options.bubbles, options.cancelable); 46 | } 47 | else { 48 | oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView, 49 | options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 50 | options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element); 51 | } 52 | element.dispatchEvent(oEvent); 53 | } 54 | else { 55 | options.clientX = options.pointerX; 56 | options.clientY = options.pointerY; 57 | oEvent = Object.extend(document.createEventObject(), options); 58 | element.fireEvent('on' + eventName, oEvent); 59 | } 60 | return element; 61 | } 62 | 63 | Element.addMethods({ simulate: Event.simulate }); 64 | })() 65 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/model/region-model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @category ClassyLlama 3 | * @copyright Copyright (c) 2018 Classy Llama Studios, LLC 4 | */ 5 | define( 6 | [ 7 | 'jquery' 8 | ], 9 | function( 10 | $ 11 | ) { 12 | 'use strict'; 13 | 14 | return { 15 | /** 16 | * Get list of regions 17 | * @returns {Object} 18 | */ 19 | regions: null, 20 | setRegions: function(url) { 21 | this.regions = $.ajax({ 22 | showLoader: false, 23 | url: url, 24 | type: "POST", 25 | dataType: 'json', 26 | success: function (response) { 27 | return response; 28 | } 29 | }); 30 | } 31 | }; 32 | } 33 | ); 34 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/view/address-validation-form-admin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2018 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | define( 15 | [ 16 | 'underscore', 17 | 'ClassyLlama_AvaTax/js/view/address-validation-form', 18 | 'ClassyLlama_AvaTax/js/model/region-model' 19 | ], 20 | function ( 21 | _, 22 | addressValidationForm, 23 | regionModel 24 | ) { 25 | 'use strict'; 26 | 27 | return _.extend({}, addressValidationForm, { 28 | 29 | // Override the base function to add the additional region data that is missing in the backend 30 | buildOriginalAddress: function (originalAddress) { 31 | try { 32 | // Get country data JSON from region model 33 | var countryData = regionModel.regions.responseJSON; 34 | 35 | if (originalAddress.region_id && countryData[originalAddress.country_id]) { 36 | // A region ID was provided and the provided country ID has region data set 37 | var region = countryData[originalAddress.country_id][originalAddress.region_id]; 38 | if (region) { 39 | // Found a matching region 40 | originalAddress.region = region['name']; 41 | } 42 | } 43 | } catch (error) { 44 | // Don't need to do anything here 45 | } 46 | 47 | // Call through to the parent to proceed normally 48 | return addressValidationForm.buildOriginalAddress.call(this, originalAddress); 49 | 50 | } 51 | }); 52 | } 53 | ); 54 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/view/validation-response-handler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | define( 15 | [ 16 | 'jquery', 17 | 'Magento_Ui/js/modal/alert', 18 | 'ClassyLlama_AvaTax/js/model/address-model', 19 | 'ClassyLlama_AvaTax/js/view/address-validation-form-admin' 20 | ], 21 | function ( 22 | $, 23 | alert, 24 | addressModel, 25 | addressValidationForm 26 | ) { 27 | 'use strict'; 28 | 29 | return { 30 | validationResponseHandler: function (response, settings, form) { 31 | addressModel.error(null); 32 | if (typeof response !== 'undefined') { 33 | if (typeof response === 'string') { 34 | addressModel.error(response); 35 | } else { 36 | addressModel.validAddress(response); 37 | } 38 | addressValidationForm.fillValidateForm(form, settings); 39 | if (addressModel.error() == null && !addressModel.isDifferent()) { 40 | alert({ 41 | title: $.mage.__('Success'), 42 | content: $.mage.__('This address is already valid.') 43 | }); 44 | } 45 | } 46 | } 47 | }; 48 | } 49 | ); 50 | -------------------------------------------------------------------------------- /view/adminhtml/web/template/form/element/adminValidateAddress.html: -------------------------------------------------------------------------------- 1 | 16 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /view/adminhtml/web/template/form/element/button.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /view/base/requirejs-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | var config = { 15 | map: { 16 | '*': { 17 | addressValidationModal: 'ClassyLlama_AvaTax/js/view/address-validation-modal' 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /view/base/web/css/source/_address-validation.less: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | @color-changed: #93EE9E; 15 | 16 | .validateAddressForm, 17 | .validateBinding, 18 | .checkout-validate-address { 19 | .form.validate { 20 | display: flex; 21 | flex-wrap: wrap; 22 | .addressOption { 23 | display: flex; 24 | margin: 20px 10px 0 10px; 25 | flex: 1 0 auto; 26 | .addressLabel { 27 | flex: 1; 28 | cursor: pointer; 29 | display: block; 30 | padding: 10px 10px 10px 30px; 31 | left: -10px; 32 | position: relative; 33 | .optionTitle { 34 | font-weight: bold; 35 | font-size: 14px; 36 | margin-bottom: 5px; 37 | } 38 | } 39 | .addressRadio { 40 | flex: 0; 41 | right: -10px; 42 | top: 10px; 43 | display: table; 44 | position: relative; 45 | } 46 | &.selected { 47 | outline: 1px solid @color-gray80; 48 | background: @color-white-smoke; 49 | } 50 | } 51 | } 52 | .validatedAddress { 53 | margin-top: 10px; 54 | padding:10px; 55 | outline: 1px solid @color-gray80; 56 | background: @color-white-smoke; 57 | } 58 | .address-field-changed { 59 | text-decoration: none; 60 | background-color: @color-changed; 61 | } 62 | .errorMessageContainer { 63 | .instructions p, 64 | .originalAddressText { 65 | margin-top: 10px; 66 | padding: 10px; 67 | outline: 1px solid @color-gray80; 68 | background: @color-white-smoke; 69 | } 70 | } 71 | .instructions { 72 | margin-top: 10px; 73 | a:hover { 74 | cursor: pointer; 75 | } 76 | } 77 | } 78 | 79 | .validateAddressForm, 80 | .validateBinding { 81 | display: none; 82 | } 83 | -------------------------------------------------------------------------------- /view/base/web/js/lib/serialize-form.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery serializeObject 3 | * @copyright 2014, macek 4 | * @link https://github.com/macek/jquery-serialize-object 5 | * @license BSD 6 | * @version 2.5.0 7 | */ 8 | !function(e,i){if("function"==typeof define&&define.amd)define(["exports","jquery"],function(e,r){return i(e,r)});else if("undefined"!=typeof exports){var r=require("jquery");i(exports,r)}else i(e,e.jQuery||e.Zepto||e.ender||e.$)}(this,function(e,i){function r(e,r){function n(e,i,r){return e[i]=r,e}function a(e,i){for(var r,a=e.match(t.key);void 0!==(r=a.pop());)if(t.push.test(r)){var u=s(e.replace(/\[\]$/,""));i=n([],u,i)}else t.fixed.test(r)?i=n([],r,i):t.named.test(r)&&(i=n({},r,i));return i}function s(e){return void 0===h[e]&&(h[e]=0),h[e]++}function u(e){switch(i('[name="'+e.name+'"]',r).attr("type")){case"checkbox":return"on"===e.value?!0:e.value;default:return e.value}}function f(i){if(!t.validate.test(i.name))return this;var r=a(i.name,u(i));return l=e.extend(!0,l,r),this}function d(i){if(!e.isArray(i))throw new Error("formSerializer.addPairs expects an Array");for(var r=0,t=i.length;t>r;r++)this.addPair(i[r]);return this}function o(){return l}function c(){return JSON.stringify(o())}var l={},h={};this.addPair=f,this.addPairs=d,this.serialize=o,this.serializeJSON=c}var t={validate:/^[a-z_][a-z0-9_]*(?:\[(?:\d*|[a-z0-9_]+)\])*$/i,key:/[a-z0-9_]+|(?=\[\])/gi,push:/^$/,fixed:/^\d+$/,named:/^[a-z0-9_]+$/i};return r.patterns=t,r.serializeObject=function(){return new r(i,this).addPairs(this.serializeArray()).serialize()},r.serializeJSON=function(){return new r(i,this).addPairs(this.serializeArray()).serializeJSON()},"undefined"!=typeof i.fn&&(i.fn.serializeObject=r.serializeObject,i.fn.serializeJSON=r.serializeJSON),e.FormSerializer=r,r}); 9 | -------------------------------------------------------------------------------- /view/base/web/js/model/address-model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ClassyLlama_AvaTax 3 | * 4 | * NOTICE OF LICENSE 5 | * 6 | * This source file is subject to the Open Software License (OSL 3.0) 7 | * that is bundled with this package in the file LICENSE.txt. 8 | * It is also available through the world-wide-web at this URL: 9 | * http://opensource.org/licenses/osl-3.0.php 10 | * 11 | * @copyright Copyright (c) 2016 Avalara, Inc. 12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 13 | */ 14 | define( 15 | ['ko'], 16 | function (ko) { 17 | 'use strict'; 18 | var originalAddress = ko.observable(null); 19 | var validAddress = ko.observable(null); 20 | var selectedAddress = ko.observable(null); 21 | var error = ko.observable(null); 22 | var isDifferent = ko.observable(null); 23 | return { 24 | originalAddress: originalAddress, 25 | validAddress: validAddress, 26 | selectedAddress: selectedAddress, 27 | error: error, 28 | isDifferent: isDifferent, 29 | resetValues: function () { 30 | this.originalAddress(null); 31 | this.validAddress(null); 32 | this.selectedAddress(null); 33 | this.error(null); 34 | this.isDifferent(null); 35 | } 36 | }; 37 | } 38 | ); 39 | -------------------------------------------------------------------------------- /view/base/web/template/baseValidateAddress.html: -------------------------------------------------------------------------------- 1 | 16 |
17 | 18 |
19 |
20 |
21 | 22 |
23 |