From 033bbf1b4b5537fcbaccba253309663813531093 Mon Sep 17 00:00:00 2001 From: kobros-tech Date: Thu, 5 Dec 2024 21:54:01 +0300 Subject: [PATCH] [18.0][MIG] account_avatax_oca: Migration to 18.0 --- account_avatax_oca/README.rst | 302 +++++++------- account_avatax_oca/__manifest__.py | 2 +- account_avatax_oca/demo/avatax_demo.xml | 19 +- account_avatax_oca/models/account_move.py | 18 +- account_avatax_oca/models/account_tax.py | 8 +- account_avatax_oca/models/avalara_salestax.py | 22 +- account_avatax_oca/models/avatax_rest_api.py | 5 +- account_avatax_oca/models/partner.py | 13 +- account_avatax_oca/models/res_company.py | 7 +- account_avatax_oca/readme/CONTRIBUTORS.md | 2 + .../static/description/index.html | 71 ++-- account_avatax_oca/tests/__init__.py | 1 + account_avatax_oca/tests/common.py | 169 ++++++++ .../tests/mocked_invoice_1_response.py | 377 ++++++++++++++++++ account_avatax_oca/tests/test_avatax.py | 7 +- account_avatax_oca/tests/test_avatax_api.py | 124 ++++++ .../views/avalara_salestax_view.xml | 171 ++++---- account_avatax_oca/views/product_view.xml | 10 +- .../wizard/avalara_get_company_code_view.xml | 2 - ...avalara_salestax_address_validate_view.xml | 10 +- requirements.txt | 2 + 21 files changed, 1021 insertions(+), 321 deletions(-) create mode 100644 account_avatax_oca/tests/common.py create mode 100644 account_avatax_oca/tests/mocked_invoice_1_response.py create mode 100644 account_avatax_oca/tests/test_avatax_api.py create mode 100644 requirements.txt diff --git a/account_avatax_oca/README.rst b/account_avatax_oca/README.rst index b68c0492d..88ac5074f 100644 --- a/account_avatax_oca/README.rst +++ b/account_avatax_oca/README.rst @@ -17,13 +17,13 @@ Avalara Avatax Certified Connector :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--fiscal--rule-lightgray.png?logo=github - :target: https://github.com/OCA/account-fiscal-rule/tree/17.0/account_avatax_oca + :target: https://github.com/OCA/account-fiscal-rule/tree/18.0/account_avatax_oca :alt: OCA/account-fiscal-rule .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/account-fiscal-rule-17-0/account-fiscal-rule-17-0-account_avatax_oca + :target: https://translation.odoo-community.org/projects/account-fiscal-rule-18-0/account-fiscal-rule-18-0-account_avatax_oca :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/account-fiscal-rule&target_branch=17.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-fiscal-rule&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -52,10 +52,10 @@ calculations and reporting seamlessly to the AvaTax server. This guide includes instructions for the following elements: -- Activating your organization's AvaTax account and downloading the - product -- Entering the AvaTax credentials into your Odoo database and - configuring it to use AvaTax services and features within Odoo +- Activating your organization's AvaTax account and downloading the + product +- Entering the AvaTax credentials into your Odoo database and + configuring it to use AvaTax services and features within Odoo Note: Test the module before deploying in live environment. All changes to the AvaTax settings must be performed by a user with administrative @@ -115,17 +115,17 @@ In most cases you will want to download and install both modules. To install the Avatax app: -- Download the AvaTax modules -- Extract the downloaded files -- Upload the extracted directories into your Odoo module/addons - directory -- Log into Odoo as an Administrator and enable the Developer Mode, in - 'Settings' -- Navigate to 'Apps', select the 'Update Apps List' menu, to have the - new apps listed. -- In the Apps list, search for 'AvaTax' -- Click on the Install button. If available, the - ``account_avatax_sale`` module will also be installed automatically. +- Download the AvaTax modules +- Extract the downloaded files +- Upload the extracted directories into your Odoo module/addons + directory +- Log into Odoo as an Administrator and enable the Developer Mode, in + 'Settings' +- Navigate to 'Apps', select the 'Update Apps List' menu, to have the + new apps listed. +- In the Apps list, search for 'AvaTax' +- Click on the Install button. If available, the ``account_avatax_sale`` + module will also be installed automatically. Configuration ============= @@ -145,62 +145,61 @@ Configure Avatax API Connection Before you can configure the Odoo Avatax connector, you will need some connection details ready: -- Login to https://home.avalara.com/ -- Navigate to Settings >> All AvaTax Settings. There you will see the - company details. -- Take note of the Account ID and Company Code -- Navigate to Settings >> License and API Keys. In the "Reset License - Key" tab, click on the "Generate License Key" button, and take note - of it. +- Login to https://home.avalara.com/ +- Navigate to Settings >> All AvaTax Settings. There you will see the + company details. +- Take note of the Account ID and Company Code +- Navigate to Settings >> License and API Keys. In the "Reset License + Key" tab, click on the "Generate License Key" button, and take note of + it. To configure AvaTax connector in Odoo: -- Navigate to: Accounting/Invoicing App >> Configuration >> AvaTax >> - AvaTax API -- Click on the Create button -- Fill out the form with the elements collected from the AvaTax - website: +- Navigate to: Accounting/Invoicing App >> Configuration >> AvaTax >> + AvaTax API +- Click on the Create button +- Fill out the form with the elements collected from the AvaTax website: - - Account ID - - License Key - - Service URL: usually Production, or Sandox if you have that - available. - - Company Code + - Account ID + - License Key + - Service URL: usually Production, or Sandox if you have that + available. + - Company Code -- Click the Test Connection button -- Click the Save button +- Click the Test Connection button +- Click the Save button Other Avatax API advanced configurations: -- Tax Calculation tab: +- Tax Calculation tab: - - Disable Document Recording/Commiting: invoices will not be stored - in Avalara - - Enable UPC Taxability: this will transmit Odoo's product ean13 - number instead of its Internal Reference. If there is no ean13 - then the Internal Reference will be sent automatically. - - Hide Exemption & Tax Based on shipping address -- this will give - user ability to hide or show Tax Exemption and Tax Based on - shipping address fields at the invoice level. + - Disable Document Recording/Commiting: invoices will not be stored in + Avalara + - Enable UPC Taxability: this will transmit Odoo's product ean13 + number instead of its Internal Reference. If there is no ean13 then + the Internal Reference will be sent automatically. + - Hide Exemption & Tax Based on shipping address -- this will give + user ability to hide or show Tax Exemption and Tax Based on shipping + address fields at the invoice level. -- Address Validation tab: +- Address Validation tab: - - Automatic Address Validation: automatically attempts to validate - on creation and update of customer record, last validation date - will be visible and stored - - Require Validated Addresses: if validation for customer is - required but not valid, the validation will be forced - - Return validation results in upper case: validation results will - return in upper case form + - Automatic Address Validation: automatically attempts to validate on + creation and update of customer record, last validation date will be + visible and stored + - Require Validated Addresses: if validation for customer is required + but not valid, the validation will be forced + - Return validation results in upper case: validation results will + return in upper case form -- Advanced tab: +- Advanced tab: - - Automatically generate missing customer code: generates a customer - code on creation and update of customer profile - - Log API requests: enables detailed AvaTax transaction logging - within application - - Request Timeout: default is 300ms - - Countries: countries where AvaTax can be used. + - Automatically generate missing customer code: generates a customer + code on creation and update of customer profile + - Log API requests: enables detailed AvaTax transaction logging within + application + - Request Timeout: default is 300ms + - Countries: countries where AvaTax can be used. Configure Company Taxes ----------------------- @@ -211,29 +210,29 @@ transactions. Validate Company Address: -- On the AvTax API configuration form, click on the "Company Address" - link -- On the company address form, click on the "validate" button in the - "AvaTax" tab +- On the AvTax API configuration form, click on the "Company Address" + link +- On the company address form, click on the "validate" button in the + "AvaTax" tab Validate Warehouse Address: -- Navigate to: Inventory >> Configuration >> Warehouse Management >> - Warehouses -- For each warehouse, open the correspoding from view -- On the Warehouse form, click on the "Address" link -- On the warehouse address form, click on the "validate" button in the - "AvaTax" tab +- Navigate to: Inventory >> Configuration >> Warehouse Management >> + Warehouses +- For each warehouse, open the correspoding from view +- On the Warehouse form, click on the "Address" link +- On the warehouse address form, click on the "validate" button in the + "AvaTax" tab Fiscal Positions is what tells the AvaTax connector if the AvaTax service should be used for a particular Sales Order or Invoice. Configure Fiscal Position: -- Navigate to: Accounting/Invoicing App >> Configuration >> Accounting - >> Fiscal Positions -- Ensure there is a Fiscal Position record for the Company, with the - "Use Avatax API" flag checked +- Navigate to: Accounting/Invoicing App >> Configuration >> Accounting + >> Fiscal Positions +- Ensure there is a Fiscal Position record for the Company, with the + "Use Avatax API" flag checked When the appropriate Fiscal Position is being used, and a tax rate is retrieved form AvaTax, then the corresponding Tax is automatically @@ -242,18 +241,17 @@ appropriate accounting configurations. Configure Taxes: -- Navigate to: Accounting/Invoicing App >> Configuration >> Accounting - >> Taxes -- Ensure there is a Tax record for the Company, with the "Is Avatax" - flag checked (visible in the "Advanced Options" tab). This Tax should - have: +- Navigate to: Accounting/Invoicing App >> Configuration >> Accounting + >> Taxes +- Ensure there is a Tax record for the Company, with the "Is Avatax" + flag checked (visible in the "Advanced Options" tab). This Tax should + have: - - Tax Type: Sales - - Tax Computation: Percentage of Price - - Amount: 0.0% - - Distribution for Invoices: ensure correct account configuration - - Distribution for Credit Notes: ensure correct account - configuration + - Tax Type: Sales + - Tax Computation: Percentage of Price + - Amount: 0.0% + - Distribution for Invoices: ensure correct account configuration + - Distribution for Credit Notes: ensure correct account configuration Configure Customers ------------------- @@ -271,22 +269,22 @@ and applied for all transactions. Create New Customer -- Navigate to Contacts -- Click Create button +- Navigate to Contacts +- Click Create button Configure and Validate Customer Address -- Enter Customer Address -- Under AvaTax >> Validation, click Validate button -- AvaTax Module will attempt to match the address you entered with a - valid address in its database. Click the Accept button if the address - is valid. +- Enter Customer Address +- Under AvaTax >> Validation, click Validate button +- AvaTax Module will attempt to match the address you entered with a + valid address in its database. Click the Accept button if the address + is valid. Tax Exemption Status -- If the customer is tax exempt, check the box under AvaTax >> Tax - Exemption >> Is Tax Exempt and -- Select the desired Tax Exempt Code from the dropdown menu. +- If the customer is tax exempt, check the box under AvaTax >> Tax + Exemption >> Is Tax Exempt and +- Select the desired Tax Exempt Code from the dropdown menu. Configure Products ------------------ @@ -301,16 +299,16 @@ Products in Odoo are typically assigned to product categories. AvaTax settings can also be assigned to the product category when a product category is created. -- Create New Product Category +- Create New Product Category - - Navigate to: Inventory >> Configuration >> Products >> Product - Categories - - Click Create button + - Navigate to: Inventory >> Configuration >> Products >> Product + Categories + - Click Create button -- Configure Product Category Tax Code +- Configure Product Category Tax Code - - Under AvaTax Properties >> Tax Code - - Select the desired Tax Code + - Under AvaTax Properties >> Tax Code + - Select the desired Tax Code Usage ===== @@ -338,22 +336,22 @@ sent to AvaTax. Create New Customer Invoice ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Navigate to: Accounting or Invoicing >> Customers >> Invoices. -- Click Create button. +- Navigate to: Accounting or Invoicing >> Customers >> Invoices. +- Click Create button. Validate Invoice ~~~~~~~~~~~~~~~~ -- Ensure that Tax based on shipping address is checked. -- Line items should have AVATAX selected under Taxes for internal - records. -- To complete the invoice, click the Validate button. -- The sale order will now appear in the AvaTax dashboard. +- Ensure that Tax based on shipping address is checked. +- Line items should have AVATAX selected under Taxes for internal + records. +- To complete the invoice, click the Validate button. +- The sale order will now appear in the AvaTax dashboard. Register Payment ~~~~~~~~~~~~~~~~ -- Click the Register Payment button to finalize the invoice. +- Click the Register Payment button to finalize the invoice. Customer Refunds ~~~~~~~~~~~~~~~~ @@ -367,26 +365,26 @@ refunds and is applied to each transaction. Initiate Customer Refund -- Navigate to: Accounting or Invoicing >> Customers >> Invoices -- Select the invoice you wish to refund -- Click Add Credit Note button +- Navigate to: Accounting or Invoicing >> Customers >> Invoices +- Select the invoice you wish to refund +- Click Add Credit Note button Create Credit Note -- Under Credit Method, select Create a draft credit note. -- Enter a reason. -- Click Add Credit Note button. +- Under Credit Method, select Create a draft credit note. +- Enter a reason. +- Click Add Credit Note button. Note: You will be taken to the Credit Notes list view Validate Refund -- Select the Credit Note you wish to validate, review and then click - Validate button. +- Select the Credit Note you wish to validate, review and then click + Validate button. Register Refund Payment -- Click Register Payment button to complete a refund +- Click Register Payment button to complete a refund Sales Orders ------------ @@ -404,22 +402,22 @@ will be reported as a net deduction on the line item cost. Create New Sales Order -- Navigate to: Sales >> Orders >> Orders -- Click Create button +- Navigate to: Sales >> Orders >> Orders +- Click Create button Compute Taxes with AvaTax -- The module will calculate tax when the sales order is confirmed, or - by navigating to Action >> Update taxes with Avatax. At this step, - the sales order will retrieve the tax amount from Avalara but will - not report the transaction to the AvaTax dashboard. Only invoice, - refund, and payment activity are reported to the dashboard. -- The module will check if there is a selected warehouse and will - automatically determine the address of the warehouse and the origin - location. If no address is assigned to the warehouse the module will - automatically use the address of the company as its origin. Location - code will automatically populate with the warehouse code but can be - modified if needed. +- The module will calculate tax when the sales order is confirmed, or by + navigating to Action >> Update taxes with Avatax. At this step, the + sales order will retrieve the tax amount from Avalara but will not + report the transaction to the AvaTax dashboard. Only invoice, refund, + and payment activity are reported to the dashboard. +- The module will check if there is a selected warehouse and will + automatically determine the address of the warehouse and the origin + location. If no address is assigned to the warehouse the module will + automatically use the address of the company as its origin. Location + code will automatically populate with the warehouse code but can be + modified if needed. Known issues / Roadmap ====================== @@ -429,13 +427,13 @@ Sales Tax. However the Avatax service supports more use cases, that could be added: -- Add support to EU VAT -- Add support to US Use Tax on Purchases / vendor Bills +- Add support to EU VAT +- Add support to US Use Tax on Purchases / vendor Bills Other improvements that could be added: -- Detect and warn if customers State is not a nexus available for the - current account +- Detect and warn if customers State is not a nexus available for the + current account Bug Tracker =========== @@ -443,7 +441,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -460,24 +458,28 @@ Authors Contributors ------------ -- Odoo SA +- Odoo SA - - Fabrice Henrion + - Fabrice Henrion -- Open Source Integrators (https://opensourceintegrators.com) +- Open Source Integrators (https://opensourceintegrators.com) - - Daniel Reis - - Bhavesh Odedra - - Sandip Mangukiya - - Nikul Chaudhary + - Daniel Reis + - Bhavesh Odedra + - Sandip Mangukiya + - Nikul Chaudhary -- Serpent CS +- Serpent CS - - Murtuza Saleh + - Murtuza Saleh -- Sodexis +- Sodexis - - Atchuthan Ubendran + - Atchuthan Ubendran + +- Kencove (https://www.kencove.com) + + - Mohamed Alkobrosli Other credits ------------- @@ -522,6 +524,6 @@ Current `maintainer `__: |maintainer-dreispt| -This module is part of the `OCA/account-fiscal-rule `_ project on GitHub. +This module is part of the `OCA/account-fiscal-rule `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_avatax_oca/__manifest__.py b/account_avatax_oca/__manifest__.py index 9a89491d5..b30379759 100644 --- a/account_avatax_oca/__manifest__.py +++ b/account_avatax_oca/__manifest__.py @@ -1,6 +1,6 @@ { "name": "Avalara Avatax Certified Connector", - "version": "17.0.1.3.1", + "version": "18.0.1.0.0", "author": "Open Source Integrators, Fabrice Henrion," "Sodexis, Odoo Community Association (OCA)", "summary": "Compute Sales Tax using the Avalara Avatax Service", diff --git a/account_avatax_oca/demo/avatax_demo.xml b/account_avatax_oca/demo/avatax_demo.xml index 4359bd58a..1890e4cff 100644 --- a/account_avatax_oca/demo/avatax_demo.xml +++ b/account_avatax_oca/demo/avatax_demo.xml @@ -1,4 +1,10 @@ + + + + 123456789 + avatax_key + Washington Customer @@ -24,21 +30,20 @@ Test Item P0000000 - product + consu 100.0 - + Test Item NT - product + consu 100.0 - + Common Carrier FR020100 - service + service 50.0 - + - diff --git a/account_avatax_oca/models/account_move.py b/account_avatax_oca/models/account_move.py index 0b3b1ae27..8ce26672d 100644 --- a/account_avatax_oca/models/account_move.py +++ b/account_avatax_oca/models/account_move.py @@ -1,8 +1,7 @@ import logging -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import UserError -from odoo.tests.common import Form _logger = logging.getLogger(__name__) @@ -268,12 +267,11 @@ def _avatax_compute_tax(self, commit=False): # Set Taxes on lines in a way that properly triggers onchanges # This same approach is also used by the official account_taxcloud connector - with Form(self) as move_form: - for index, taxes in taxes_to_set: - with move_form.invoice_line_ids.edit(index) as line_form: - line_form.tax_ids.clear() - for tax in taxes: - line_form.tax_ids.add(tax) + for index, taxes in taxes_to_set: + # Access the invoice line by index + line = self.invoice_line_ids[index] + # Update the tax_ids field + line.write({"tax_ids": [(6, 0, [tax.id for tax in taxes])]}) return tax_result @@ -316,7 +314,9 @@ def _post(self, soft=True): if not addr.date_validation: # The Validate action will be interrupted # if the address is not validated - raise UserError(_("Avatax address is not validated!")) + raise UserError( + self.env._("Avatax address is not validated!") + ) # We should compute taxes before validating the invoice # to ensure correct account moves # However, we can't save the invoice because it wasn't assigned a diff --git a/account_avatax_oca/models/account_tax.py b/account_avatax_oca/models/account_tax.py index 4b40ea0fc..b43f3f53b 100644 --- a/account_avatax_oca/models/account_tax.py +++ b/account_avatax_oca/models/account_tax.py @@ -1,6 +1,6 @@ from math import copysign -from odoo import _, api, exceptions, fields, models +from odoo import api, exceptions, fields, models from odoo.tools.float_utils import float_compare @@ -25,7 +25,7 @@ def _get_avalara_tax_domain(self, tax_rate, doc_type): @api.model def _get_avalara_tax_name(self, tax_rate, doc_type=None): - return _("{}%*").format(str(tax_rate)) + return self.env._("{}%*").format(str(tax_rate)) @api.model def get_avalara_tax(self, tax_rate, doc_type): @@ -38,7 +38,7 @@ def get_avalara_tax(self, tax_rate, doc_type): tax_template = self.search(domain, limit=1) if not tax_template: raise exceptions.UserError( - _("Please configure Avatax Tax for Company %s:") + self.env._("Please configure Avatax Tax for Company %s:") % self.env.company.name ) # If you get a unique constraint error here, @@ -105,7 +105,7 @@ def compute_all( if avatax_amount is None: avatax_amount = 0.0 raise exceptions.UserError( - _( + self.env._( "Incorrect retrieval of Avatax amount for Invoice " "%(avatax_invoice)s: product %(product.display_name)s, " "price_unit %(-price_unit)f , quantity %(quantity)f" diff --git a/account_avatax_oca/models/avalara_salestax.py b/account_avatax_oca/models/avalara_salestax.py index decbdf1cb..2b8a00105 100644 --- a/account_avatax_oca/models/avalara_salestax.py +++ b/account_avatax_oca/models/avalara_salestax.py @@ -1,6 +1,6 @@ import logging -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import UserError from .avatax_rest_api import AvaTaxRESTService @@ -214,7 +214,7 @@ def create_transaction( if not partner.customer_code: if not avatax_config.auto_generate_customer_code: raise UserError( - _( + self.env._( "Customer Code for customer %(partner.name)s not defined.\n\n " "You can edit the Customer Code in customer profile. " 'You can fix by clicking "Generate Customer Code" ' @@ -226,12 +226,14 @@ def create_transaction( if not shipping_address: raise UserError( - _("There is no source shipping address defined for partner %s.") + self.env._( + "There is no source shipping address defined for partner %s." + ) % partner.name ) if not ship_from_address: - raise UserError(_("There is no Company address defined.")) + raise UserError(self.env._("There is no Company address defined.")) if avatax_config.validation_on_save: for address in [partner, shipping_address, ship_from_address]: @@ -246,7 +248,7 @@ def create_transaction( ): if not shipping_address.date_validation: raise UserError( - _( + self.env._( "Please validate the shipping address for the partner " "%(partner.name)s." ) @@ -254,11 +256,13 @@ def create_transaction( # if not avatax_config.address_validation: if not ship_from_address.date_validation: - raise UserError(_("Please validate the origin warehouse address.")) + raise UserError( + self.env._("Please validate the origin warehouse address.") + ) if avatax_config.disable_tax_calculation: _logger.info( - "Avatax tax calculation is disabled. Skipping %s %s.", + self.env._("Avatax tax calculation is disabled. Skipping %s %s."), doc_code, doc_type, ) @@ -266,7 +270,9 @@ def create_transaction( if commit and avatax_config.disable_tax_reporting: _logger.warning( - _("Avatax commiting document %s, but it tax reporting is disabled."), + self.env._( + "Avatax commiting document %s, but it tax reporting is disabled." + ), doc_code, ) diff --git a/account_avatax_oca/models/avatax_rest_api.py b/account_avatax_oca/models/avatax_rest_api.py index b7ae83999..d791320ef 100644 --- a/account_avatax_oca/models/avatax_rest_api.py +++ b/account_avatax_oca/models/avatax_rest_api.py @@ -4,7 +4,7 @@ import pprint import socket -from odoo import _, fields, tools +from odoo import _, fields from odoo.exceptions import UserError _logger = logging.getLogger(__name__) @@ -26,6 +26,7 @@ def __init__( config=None, ): self.config = config + self.env = config and config.env or None self.timeout = not config and timeout or config.request_timeout self.is_log_enabled = enable_log or config and config.logging # Set elements adapter defaults @@ -250,7 +251,7 @@ def get_tax( lineslist = [ { "number": line["id"].id, - "description": tools.ustr(line.get("description", ""))[:255], + "description": str(line.get("description", ""))[:255], "itemCode": line.get("itemcode"), "quantity": line.get("qty", 1), "amount": line.get("amount", 0.0), diff --git a/account_avatax_oca/models/partner.py b/account_avatax_oca/models/partner.py index 7a1296228..7b7d473a5 100644 --- a/account_avatax_oca/models/partner.py +++ b/account_avatax_oca/models/partner.py @@ -2,7 +2,7 @@ import time from random import random -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import UserError from .avatax_rest_api import AvaTaxRESTService @@ -22,7 +22,7 @@ class ResPartner(models.Model): def _onchange_property_exemption_contry_wide(self): if self.property_exemption_country_wide: message = ( - _( + self.env._( "Enabling the exemption status for all states" " may have tax compliance risks," " and should be carefully considered.\n\n" @@ -31,7 +31,12 @@ def _onchange_property_exemption_contry_wide(self): " for every state this Partner may have transactions." ), ) - return {"warning": {"title": _("Tax Compliance Risk"), "message": message}} + return { + "warning": { + "title": self.env._("Tax Compliance Risk"), + "message": message, + } + } date_validation = fields.Date( "Last Validation Date", @@ -101,7 +106,7 @@ def check_exemption_number(self): partner.property_exemption_code_id or partner.property_exemption_number ): raise UserError( - _( + self.env._( "Please enter either Exemption Number or Exemption Code" " for marking customer as Exempt." ) diff --git a/account_avatax_oca/models/res_company.py b/account_avatax_oca/models/res_company.py index 91b193bfd..9127e3ac8 100644 --- a/account_avatax_oca/models/res_company.py +++ b/account_avatax_oca/models/res_company.py @@ -1,6 +1,6 @@ import logging -from odoo import _, models +from odoo import models _LOGGER = logging.getLogger(__name__) @@ -18,11 +18,12 @@ def get_avatax_config_company(self): ) if len(res) > 1: _LOGGER.warning( - _("Company %s has too many Avatax configurations!"), + self.env._("Company %s has too many Avatax configurations!"), self.display_name, ) if len(res) < 1: _LOGGER.warning( - _("Company %s has no Avatax configuration."), self.display_name + self.env._("Company %s has no Avatax configuration."), + self.display_name, ) return res and res[0] diff --git a/account_avatax_oca/readme/CONTRIBUTORS.md b/account_avatax_oca/readme/CONTRIBUTORS.md index 467df06af..d9f1238c8 100644 --- a/account_avatax_oca/readme/CONTRIBUTORS.md +++ b/account_avatax_oca/readme/CONTRIBUTORS.md @@ -9,3 +9,5 @@ - Murtuza Saleh - Sodexis - Atchuthan Ubendran +- Kencove () + - Mohamed Alkobrosli \<\> diff --git a/account_avatax_oca/static/description/index.html b/account_avatax_oca/static/description/index.html index 12dd3c90e..0c4e0a2ce 100644 --- a/account_avatax_oca/static/description/index.html +++ b/account_avatax_oca/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -368,7 +369,7 @@

Avalara Avatax Certified Connector

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:f10e5df6dbd20f081048703034a1a6a8a23e83abee5e6ba9b174bb90dca4c95e !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Production/Stable License: AGPL-3 OCA/account-fiscal-rule Translate me on Weblate Try me on Runboat

+

Production/Stable License: AGPL-3 OCA/account-fiscal-rule Translate me on Weblate Try me on Runboat

AVALARA CERTIFICATION PENDING!

Odoo provides integration with AvaTax, a tax solution software by Avalara which includes sales tax calculation for all US states and @@ -483,8 +484,8 @@

Installation

  • Navigate to ‘Apps’, select the ‘Update Apps List’ menu, to have the new apps listed.
  • In the Apps list, search for ‘AvaTax’
  • -
  • Click on the Install button. If available, the -account_avatax_sale module will also be installed automatically.
  • +
  • Click on the Install button. If available, the account_avatax_sale +module will also be installed automatically.
  • @@ -508,16 +509,15 @@

    Configure Avatax API Connection
  • Take note of the Account ID and Company Code
  • Navigate to Settings >> License and API Keys. In the “Reset License -Key” tab, click on the “Generate License Key” button, and take note -of it.
  • +Key” tab, click on the “Generate License Key” button, and take note of +it.

    To configure AvaTax connector in Odoo:

    @@ -832,6 +831,10 @@

    Contributors

  • Atchuthan Ubendran
  • +
  • Kencove (https://www.kencove.com) +
  • @@ -854,13 +857,15 @@

    Other credits

    Maintainers

    This module is maintained by the OCA.

    -Odoo Community Association + +Odoo Community Association +

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    Current maintainer:

    dreispt

    -

    This module is part of the OCA/account-fiscal-rule project on GitHub.

    +

    This module is part of the OCA/account-fiscal-rule project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    diff --git a/account_avatax_oca/tests/__init__.py b/account_avatax_oca/tests/__init__.py index b7caa1cac..378899979 100644 --- a/account_avatax_oca/tests/__init__.py +++ b/account_avatax_oca/tests/__init__.py @@ -2,3 +2,4 @@ from . import test_avatax from . import test_parter from . import test_rest_api +from . import test_avatax_api diff --git a/account_avatax_oca/tests/common.py b/account_avatax_oca/tests/common.py new file mode 100644 index 000000000..538f3035b --- /dev/null +++ b/account_avatax_oca/tests/common.py @@ -0,0 +1,169 @@ +import socket +from contextlib import contextmanager +from unittest.mock import Mock, patch + +from avalara import AvataxClient + +from odoo.exceptions import UserError +from odoo.tests.common import TransactionCase + +from .mocked_invoice_1_response import generate_response as generate_response_invoice_1 + +NOTHING = object() + + +class TestAvataxCommon(TransactionCase): + @classmethod + def setUpClass(cls): + res = super().setUpClass() + cls.appname = "Odoo 17 - Open Source Integrators/OCA" + cls.version = "a0o5a000007SPdsAAG" + cls.hostname = socket.gethostname() + url = "" + cls.environment = ( + "sandbox" if "sandbox" in url or "development" in url else "production" + ) + try: + cls.client = AvataxClient( + cls.appname, cls.version, cls.hostname, cls.environment + ) + except NameError as exc: + raise UserError( + cls.env._( + "AvataxClient is not available in your system. " + "Please contact your system administrator " + "to 'pip3 install Avalara'" + ) + ) from exc + + # Update address of company + company = cls.env.user.company_id + company.write( + { + "street": "255 Executive Park Blvd", + "city": "San Francisco", + "state_id": cls.env.ref("base.state_us_5").id, + "country_id": cls.env.ref("base.us").id, + "zip": "94134", + } + ) + + cls.fp_avatax = cls.env["account.fiscal.position"].create( + { + "name": "Avatax", + "is_avatax": True, + } + ) + + # Create partner with correct US address + cls.partner = cls.env["res.partner"].create( + { + "name": "Demo Sale Partner", + "street": "2288 Market St", + "city": "San Francisco", + "state_id": cls.env.ref("base.state_us_5").id, + "country_id": cls.env.ref("base.us").id, + "zip": "94114", + "property_account_position_id": cls.fp_avatax.id, + } + ) + + cls.invoice = cls.env["account.move"].create( + { + "move_type": "out_invoice", + "partner_id": cls.partner.id, + "invoice_line_ids": [ + ( + 0, + 0, + {"name": "Demo Invoice Line", "price_unit": 10, "quantity": 20}, + ) + ], + } + ) + cls.avatax = cls.env.ref("account_avatax_oca.avatax_api_configuraation") + cls.invoice_1_response = dict( + generate_response_invoice_1(cls.invoice.invoice_line_ids) + ) + + return res + + @classmethod + @contextmanager + def _capture_create_or_adjust_transaction( + cls, return_value=NOTHING, return_func=NOTHING, apply_args=False + ): + class Capture: + mock_response = Mock() + val = None + + def _capture_create_or_adjust_transaction(cls, model, include=None): + cls.val = model + if return_value is NOTHING: + cls.mock_response.json.return_value = return_func(model) + else: + cls.mock_response.json.return_value = return_value + if apply_args: + # Apply the real passed args and return them in the mocked response + cls.mock_response.json()["description"] = model[ + "createTransactionModel" + ]["description"] + cls.mock_response.json()["type"] = model["createTransactionModel"][ + "type" + ] + cls.mock_response.json()["code"] = model["createTransactionModel"][ + "code" + ] + cls.mock_response.json()["date"] = model["createTransactionModel"][ + "date" + ] + cls.mock_response.json()["salespersonCode"] = model[ + "createTransactionModel" + ]["salespersonCode"] + cls.mock_response.json()["customerCode"] = model[ + "createTransactionModel" + ]["customerCode"] + cls.mock_response.json()["lines"][0]["itemCode"] = model[ + "createTransactionModel" + ]["lines"][0]["itemCode"] + cls.mock_response.json()["lines"][0]["taxCode"] = model[ + "createTransactionModel" + ]["lines"][0]["taxCode"] + cls.mock_response.json()["lines"][0]["lineNumber"] = model[ + "createTransactionModel" + ]["lines"][0]["number"] + cls.mock_response.json()["lines"][0]["description"] = model[ + "createTransactionModel" + ]["lines"][0]["description"] + cls.mock_response.json()["lines"][0]["quantity"] = model[ + "createTransactionModel" + ]["lines"][0]["quantity"] + cls.mock_response.json()["lines"][0]["lineAmount"] = model[ + "createTransactionModel" + ]["lines"][0]["amount"] + return cls.mock_response + + capture = Capture() + with patch( + "avalara.client_methods.Mixin.create_or_adjust_transaction", + capture._capture_create_or_adjust_transaction, + ): + yield capture + + @classmethod + @contextmanager + def _capture_ping(cls, return_value=NOTHING): + class Capture: + mock_response = Mock() + + def _capture_ping(cls): + if return_value is NOTHING: + default_response = {"key": "value"} + cls.mock_response.json.return_value = default_response + else: + cls.mock_response.json.return_value = return_value + return cls.mock_response + + capture = Capture() + with patch("avalara.client_methods.Mixin.ping", capture._capture_ping): + yield capture diff --git a/account_avatax_oca/tests/mocked_invoice_1_response.py b/account_avatax_oca/tests/mocked_invoice_1_response.py new file mode 100644 index 000000000..69bf5db02 --- /dev/null +++ b/account_avatax_oca/tests/mocked_invoice_1_response.py @@ -0,0 +1,377 @@ +def generate_response(invoice_line_ids=None): + assert len(invoice_line_ids) == 1, "the mocked response is for 1 line" + for i, line in enumerate(response["lines"]): + line["lineNumber"] = f"{invoice_line_ids[i].id}" + return response + + +response = { + "addresses": [ + { + "boundaryLevel": "Address", + "city": "San Francisco", + "country": "US", + "id": 5000304937315, + "latitude": "37.764754", + "line1": "2280 Market St", + "line2": "", + "line3": "", + "longitude": "-122.432634", + "postalCode": "94114-1506", + "region": "CA", + "taxRegionId": 4016940, + "transactionId": 6000182165320, + }, + { + "boundaryLevel": "Address", + "city": "San Francisco", + "country": "US", + "id": 6000304937315, + "latitude": "37.71116", + "line1": "250 Executive Park Blvd", + "line2": "", + "line3": "", + "longitude": "-122.391717", + "postalCode": "94134-3394", + "region": "CA", + "taxRegionId": 4016940, + "transactionId": 6000182165320, + }, + ], + "adjustmentDescription": "", + "adjustmentReason": "NotAdjusted", + "batchCode": "", + "businessIdentificationNo": "", + "code": "Journal Entry 67", + "companyId": 281741, + "country": "US", + "currencyCode": "USD", + "customerCode": "CUST123456", + "customerUsageType": "", + "customerVendorCode": "CUST123456", + "date": "2021-01-01", + "description": "", + "destinationAddressId": 5000304937315, + "email": "", + "entityUseCode": "", + "exchangeRate": 1.0, + "exchangeRateCurrencyCode": "USD", + "exchangeRateEffectiveDate": "2021-01-01", + "exemptNo": "", + "id": 6000182165320, + "lines": [ + { + "boundaryOverrideId": 0, + "businessIdentificationNo": "", + "costInsuranceFreight": 0.0, + "customerUsageType": "", + "description": "Odoo User", + "destinationAddressId": 5000304937315, + "details": [ + { + "addressId": 6000304937315, + "country": "US", + "countyFIPS": "", + "exemptAmount": 0.0, + "exemptReasonId": 4, + "exemptUnits": 0.0, + "id": 9000401706101, + "inState": True, + "isFee": False, + "isNonPassThru": False, + "jurisCode": "06", + "jurisName": "CALIFORNIA", + "jurisType": "STA", + "jurisdictionId": 5000531, + "jurisdictionType": "State", + "liabilityType": "Seller", + "nonTaxableAmount": 0.0, + "nonTaxableRuleId": 0, + "nonTaxableType": "RateRule", + "nonTaxableUnits": 0.0, + "rate": 0.06, + "rateRuleId": 1525706, + "rateSourceId": 3, + "rateType": "General", + "rateTypeCode": "G", + "region": "CA", + "reportingExemptUnits": 0.0, + "reportingNonTaxableUnits": 0.0, + "reportingTax": 2.1, + "reportingTaxCalculated": 2.1, + "reportingTaxableUnits": 35.0, + "serCode": "", + "signatureCode": "AGAM", + "sourcing": "Origin", + "stateAssignedNo": "", + "stateFIPS": "", + "tax": 2.1, + "taxAuthorityTypeId": 45, + "taxCalculated": 2.1, + "taxName": "CA STATE TAX", + "taxOverride": 0.0, + "taxRegionId": 4016940, + "taxSubTypeId": "S", + "taxType": "Sales", + "taxTypeGroupId": "SalesAndUse", + "taxableAmount": 35.0, + "taxableUnits": 35.0, + "transactionId": 6000182165320, + "transactionLineId": 10403927888, + "unitOfBasis": "PerCurrencyUnit", + }, + { + "addressId": 6000304937315, + "country": "US", + "countyFIPS": "", + "exemptAmount": 0.0, + "exemptReasonId": 4, + "exemptUnits": 0.0, + "id": 10000401706103, + "inState": True, + "isFee": False, + "isNonPassThru": False, + "jurisCode": "075", + "jurisName": "SAN FRANCISCO", + "jurisType": "CTY", + "jurisdictionId": 275, + "jurisdictionType": "County", + "liabilityType": "Seller", + "nonTaxableAmount": 0.0, + "nonTaxableRuleId": 0, + "nonTaxableType": "RateRule", + "nonTaxableUnits": 0.0, + "rate": 0.0025, + "rateRuleId": 1525710, + "rateSourceId": 3, + "rateType": "General", + "rateTypeCode": "G", + "region": "CA", + "reportingExemptUnits": 0.0, + "reportingNonTaxableUnits": 0.0, + "reportingTax": 0.09, + "reportingTaxCalculated": 0.09, + "reportingTaxableUnits": 35.0, + "serCode": "", + "signatureCode": "AIUQ", + "sourcing": "Origin", + "stateAssignedNo": "", + "stateFIPS": "", + "tax": 0.09, + "taxAuthorityTypeId": 45, + "taxCalculated": 0.09, + "taxName": "CA COUNTY TAX", + "taxOverride": 0.0, + "taxRegionId": 4016940, + "taxSubTypeId": "S", + "taxType": "Sales", + "taxTypeGroupId": "SalesAndUse", + "taxableAmount": 35.0, + "taxableUnits": 35.0, + "transactionId": 6000182165320, + "transactionLineId": 10403927888, + "unitOfBasis": "PerCurrencyUnit", + }, + { + "addressId": 6000304937315, + "country": "US", + "countyFIPS": "", + "exemptAmount": 0.0, + "exemptReasonId": 4, + "exemptUnits": 0.0, + "id": 11000401706101, + "inState": True, + "isFee": False, + "isNonPassThru": False, + "jurisCode": "EMTV0", + "jurisName": "SAN FRANCISCO CO LOCAL TAX SL", + "jurisType": "STJ", + "jurisdictionId": 2001061792, + "jurisdictionType": "Special", + "liabilityType": "Seller", + "nonTaxableAmount": 0.0, + "nonTaxableRuleId": 0, + "nonTaxableType": "RateRule", + "nonTaxableUnits": 0.0, + "rate": 0.01, + "rateRuleId": 1525730, + "rateSourceId": 3, + "rateType": "General", + "rateTypeCode": "G", + "region": "CA", + "reportingExemptUnits": 0.0, + "reportingNonTaxableUnits": 0.0, + "reportingTax": 0.35, + "reportingTaxCalculated": 0.35, + "reportingTaxableUnits": 35.0, + "serCode": "", + "signatureCode": "EMTV", + "sourcing": "Origin", + "stateAssignedNo": "38", + "stateFIPS": "", + "tax": 0.35, + "taxAuthorityTypeId": 45, + "taxCalculated": 0.35, + "taxName": "CA SPECIAL TAX", + "taxOverride": 0.0, + "taxRegionId": 4016940, + "taxSubTypeId": "S", + "taxType": "Sales", + "taxTypeGroupId": "SalesAndUse", + "taxableAmount": 35.0, + "taxableUnits": 35.0, + "transactionId": 6000182165320, + "transactionLineId": 10403927888, + "unitOfBasis": "PerCurrencyUnit", + }, + ], + "discountAmount": 0.0, + "discountTypeId": 0, + "entityUseCode": "", + "exemptAmount": 0.0, + "exemptCertId": 0, + "exemptNo": "", + "hsCode": "", + "id": 10403927888, + "isItemTaxable": True, + "isSSTP": False, + "itemCode": "false", + "lineAmount": 35.0, + "lineLocationTypes": [ + { + "documentAddressId": 6000304937315, + "documentLineId": 10403927888, + "documentLineLocationTypeId": 11000385345219, + "locationTypeCode": "ShipFrom", + }, + { + "documentAddressId": 5000304937315, + "documentLineId": 10403927888, + "documentLineLocationTypeId": 12000385345218, + "locationTypeCode": "ShipTo", + }, + ], + "lineNumber": "229", + "nonPassthroughDetails": [], + "originAddressId": 6000304937315, + "quantity": 1.0, + "ref1": "", + "ref2": "", + "reportingDate": "2021-01-01", + "revAccount": "", + "sourcing": "Origin", + "tax": 2.54, + "taxCalculated": 2.54, + "taxCode": "DC010000", + "taxCodeId": 8575, + "taxDate": "2021-01-01", + "taxEngine": "", + "taxIncluded": False, + "taxOverrideAmount": 0.0, + "taxOverrideReason": "", + "taxOverrideType": "None", + "taxableAmount": 35.0, + "transactionId": 6000182165320, + "vatCode": "", + "vatNumberTypeId": 0, + }, + ], + "locationCode": "", + "locationTypes": [ + { + "documentAddressId": 6000304937315, + "documentId": 6000182165320, + "documentLocationTypeId": 11254474859, + "locationTypeCode": "ShipFrom", + }, + { + "documentAddressId": 5000304937315, + "documentId": 6000182165320, + "documentLocationTypeId": 5000269681192, + "locationTypeCode": "ShipTo", + }, + ], + "locked": False, + "modifiedDate": "2021-09-24T19:39:27.7013484Z", + "modifiedUserId": 212768, + "originAddressId": 6000304937315, + "purchaseOrderNo": "", + "reconciled": False, + "referenceCode": "INV/2021/01/0001", + "region": "CA", + "reportingLocationCode": "", + "salespersonCode": "", + "softwareVersion": "21.8.1.0", + "status": "Saved", + "summary": [ + { + "country": "US", + "exemption": 0.0, + "jurisCode": "06", + "jurisName": "CALIFORNIA", + "jurisType": "State", + "nonTaxable": 0.0, + "rate": 0.06, + "rateType": "General", + "region": "CA", + "stateAssignedNo": "", + "tax": 5.4, + "taxAuthorityType": 45, + "taxCalculated": 5.4, + "taxName": "CA STATE TAX", + "taxSubType": "S", + "taxType": "Sales", + "taxable": 90.0, + }, + { + "country": "US", + "exemption": 0.0, + "jurisCode": "075", + "jurisName": "SAN FRANCISCO", + "jurisType": "County", + "nonTaxable": 0.0, + "rate": 0.0025, + "rateType": "General", + "region": "CA", + "stateAssignedNo": "", + "tax": 0.24, + "taxAuthorityType": 45, + "taxCalculated": 0.24, + "taxName": "CA COUNTY TAX", + "taxSubType": "S", + "taxType": "Sales", + "taxable": 90.0, + }, + { + "country": "US", + "exemption": 0.0, + "jurisCode": "EMTV0", + "jurisName": "SAN FRANCISCO CO LOCAL TAX SL", + "jurisType": "Special", + "nonTaxable": 0.0, + "rate": 0.01, + "rateType": "General", + "region": "CA", + "stateAssignedNo": "38", + "tax": 0.9, + "taxAuthorityType": 45, + "taxCalculated": 0.9, + "taxName": "CA SPECIAL TAX", + "taxSubType": "S", + "taxType": "Sales", + "taxable": 90.0, + }, + ], + "taxDate": "2021-01-01", + "taxOverrideAmount": 0.0, + "taxOverrideReason": "", + "taxOverrideType": "None", + "totalAmount": 90.0, + "totalDiscount": 0.0, + "totalExempt": 0.0, + "totalTax": 6.54, + "totalTaxCalculated": 6.54, + "totalTaxable": 90.0, + "type": "SalesInvoice", + "version": 1, +} diff --git a/account_avatax_oca/tests/test_avatax.py b/account_avatax_oca/tests/test_avatax.py index 326391109..8ba38bf2b 100644 --- a/account_avatax_oca/tests/test_avatax.py +++ b/account_avatax_oca/tests/test_avatax.py @@ -2,6 +2,8 @@ # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +import logging + from odoo.tests import common @@ -9,6 +11,9 @@ class TestAvatax(common.TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() + logging.getLogger("odoo.addons.account_avatax_oca.models.res_company").setLevel( + logging.ERROR + ) cls.customer = cls.env["res.partner"].create( { "name": "Customer", @@ -16,7 +21,7 @@ def setUpClass(cls): "property_exemption_number": "12321", "property_exemption_code_id": cls.env.ref( "account_avatax_oca.resale_type" - ), + ).id, } ) cls.invoice = cls.env["account.move"].create( diff --git a/account_avatax_oca/tests/test_avatax_api.py b/account_avatax_oca/tests/test_avatax_api.py new file mode 100644 index 000000000..b5ee410dc --- /dev/null +++ b/account_avatax_oca/tests/test_avatax_api.py @@ -0,0 +1,124 @@ +import logging + +from odoo.exceptions import UserError +from odoo.tests.common import tagged + +from .common import TestAvataxCommon +from .mocked_invoice_1_response import response as response_invoice_1 + +_logger = logging.getLogger(__name__) + + +@tagged("-at_install", "post_install") +class TestAccountAvalaraInternal(TestAvataxCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + + def test_mocked_response(self): + # mocking response with actual invoice line ids + self.assertNotEqual(response_invoice_1["lines"][0]["lineNumber"], "229") + first_line_id = self.invoice.invoice_line_ids[:1] + + with self._capture_create_or_adjust_transaction( + return_value=self.invoice_1_response + ) as captured: + mock_response = captured._capture_create_or_adjust_transaction( + model={"key": "value"} + ) + self.assertNotEqual( + self.invoice_1_response["lines"][0]["lineNumber"], + "229", + ) + self.assertEqual( + self.invoice_1_response["lines"][0]["lineNumber"], + first_line_id.id, + ) + self.assertEqual( + mock_response.json()["lines"][0]["lineNumber"], + first_line_id.id, + ) + + def test_ping(self): + # test not authenticated user + with self._capture_ping() as captured: + with self.assertRaises(UserError): + self.env.user.lang = "en_US" + res = self.avatax.ping() + + response = { + "key": "connection to avalara is successful!", + "authenticated": True, + } + # test authenticated user + with self._capture_ping(return_value=response) as captured: + # mocked method is not called and no returned vaules + try: + self.assertDictEqual(response, captured.mock_response.json()) + except AssertionError as e: + _logger.info(f"AssertionError: \n===========> {e}") + # mocked method is called and return value + res = self.avatax.ping() + self.assertTrue(res) + # inserted return value is equal to returned value from mocked method + self.assertDictEqual(response, captured.mock_response.json()) + + def test__avatax_compute_tax(self): + first_line_id = self.invoice.invoice_line_ids[:1] + # test no tax records yet for invoice lines + self.assertFalse(first_line_id.tax_ids) + + # Without applying arguments + with self._capture_create_or_adjust_transaction( + return_value=self.invoice_1_response + ) as captured: + tax_result = self.invoice._avatax_compute_tax() + # test tax record is created for invoice lines + self.assertEqual( + captured.mock_response.json()["lines"][0]["lineNumber"], + f"{self.invoice.invoice_line_ids[:1].id}", + ) + self.assertEqual( + captured.mock_response.json()["lines"][0]["itemCode"], "false" + ) + self.assertEqual(captured.mock_response.json()["description"], "") + self.assertEqual(captured.mock_response.json()["type"], "SalesInvoice") + self.assertTrue( + captured.mock_response.json()["customerCode"] == "CUST123456" + ) + self.assertTrue(first_line_id.tax_ids) + self.assertEqual(tax_result["totalTax"], 6.54) + self.assertEqual(self.invoice_1_response["totalTax"], 6.54) + self.assertEqual(tax_result["totalTaxable"], 90.0) + self.assertEqual(self.invoice_1_response["totalTaxable"], 90.0) + + # With applying arguments + with self._capture_create_or_adjust_transaction( + return_value=self.invoice_1_response, apply_args=True + ) as captured: + tax_result = self.invoice._avatax_compute_tax() + # test tax record is created for invoice lines + self.assertEqual( + captured.mock_response.json()["lines"][0]["lineNumber"], + self.invoice.invoice_line_ids[:1].id, + ) + self.assertEqual( + captured.mock_response.json()["lines"][0]["itemCode"], "ID:0" + ) + self.assertEqual(captured.mock_response.json()["description"], "Draft") + self.assertEqual(captured.mock_response.json()["type"], "SalesOrder") + self.assertTrue( + captured.mock_response.json()["customerCode"] != "CUST123456" + ) + self.assertTrue(first_line_id.tax_ids) + self.assertEqual(tax_result["totalTax"], 6.54) + self.assertEqual(self.invoice_1_response["totalTax"], 6.54) + self.assertEqual(tax_result["totalTaxable"], 90.0) + self.assertEqual(self.invoice_1_response["totalTaxable"], 90.0) + + def test_avatax_compute_taxes(self): + with self._capture_create_or_adjust_transaction( + return_value=self.invoice_1_response + ): + returne_true = self.invoice.avatax_compute_taxes() + self.assertTrue(returne_true) diff --git a/account_avatax_oca/views/avalara_salestax_view.xml b/account_avatax_oca/views/avalara_salestax_view.xml index 7d43f5d96..4545f8bc0 100644 --- a/account_avatax_oca/views/avalara_salestax_view.xml +++ b/account_avatax_oca/views/avalara_salestax_view.xml @@ -24,39 +24,39 @@ - - - - + @@ -65,54 +65,51 @@ name="calculation_page" invisible="disable_tax_calculation == True" > -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - -
    - -
    -
    -
    -
    - -
    - +
    +
    + +
    +
    +
    -
    -
    -
    - -
    - +
    +
    + +
    +
    +
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - +
    +
    + +
    +
    +
    -
    -
    -
    avalara.salestax.tree avalara.salestax - tree + list - + - + AvaTax API avalara.salestax - tree - tree,form + list + list,form Configuration of AvaTax in odoo exemption.code.tree.view exemption.code - tree + list - + - + Exemption Code exemption.code - tree - tree,form + list + list,form product.tax.code.tree product.tax.code - tree + list - + - + @@ -31,8 +31,8 @@ Product Tax Codes ir.actions.act_window product.tax.code - tree - tree,form + list + list,form - avalara.salestax.getcompany @@ -32,5 +31,4 @@ >{'record_id': active_id, 'active_id_view_ref': active_id} new - diff --git a/account_avatax_oca/wizard/avalara_salestax_address_validate_view.xml b/account_avatax_oca/wizard/avalara_salestax_address_validate_view.xml index cc6f63364..290359e6e 100644 --- a/account_avatax_oca/wizard/avalara_salestax_address_validate_view.xml +++ b/account_avatax_oca/wizard/avalara_salestax_address_validate_view.xml @@ -26,11 +26,11 @@ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..f400ceda7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +Avalara