[ADD] account_taxcloud: Integrate TaxCloud API to get Sales Tax

- add a new checkbox on fiscal position: TaxCloud API
- when computing this fiscal position, it will:
        - return an existing tax if one exists for the same tax
          percentage, state, zip and TIC Category
        - or create and return this tax if it does not exists yet
- Create a data fiscal position: country U.S., tax cloud API
- In l10n_us, add a settings in accounting: compute tax automatically using tax cloud.

NB:
- The signature of map_tax has been modified to optionally specify the product
  and the partner on which the tax is applied
- The avoid the validationerrors that may occur while evaluation the tax with Taxcloud
  when a public user is on the frontend shop (website_sale), we have to execute the
  error silently by logging it.
This commit is contained in:
Mahendra barad
2016-06-28 12:12:30 +02:00
committed by Yannick Tivisse
parent 84b0fb5bbc
commit 6ba6213fa9
13 changed files with 60 additions and 17 deletions
+2 -2
View File
@@ -1179,7 +1179,7 @@ class AccountInvoiceLine(models.Model):
company_id = self.company_id or self.env.user.company_id
taxes = taxes.filtered(lambda r: r.company_id == company_id)
self.invoice_line_tax_ids = fp_taxes = self.invoice_id.fiscal_position_id.map_tax(taxes)
self.invoice_line_tax_ids = fp_taxes = self.invoice_id.fiscal_position_id.map_tax(taxes, self.product_id, self.invoice_id.partner_id)
fix_price = self.env['account.tax']._fix_tax_included_price
if self.invoice_id.type in ('in_invoice', 'in_refund'):
@@ -1250,7 +1250,7 @@ class AccountInvoiceLine(models.Model):
return
if not self.product_id:
fpos = self.invoice_id.fiscal_position_id
self.invoice_line_tax_ids = fpos.map_tax(self.account_id.tax_ids).ids
self.invoice_line_tax_ids = fpos.map_tax(self.account_id.tax_ids, partner=self.partner_id).ids
elif not self.price_unit:
self._set_taxes()
+2 -2
View File
@@ -45,7 +45,7 @@ class AccountFiscalPosition(models.Model):
return True
@api.v7
def map_tax(self, cr, uid, fposition_id, taxes, context=None):
def map_tax(self, cr, uid, fposition_id, taxes, product=None, partner=None, context=None):
if not taxes:
return []
if not fposition_id:
@@ -63,7 +63,7 @@ class AccountFiscalPosition(models.Model):
return list(result)
@api.v8 # noqa
def map_tax(self, taxes):
def map_tax(self, taxes, product=None, partner=None):
result = self.env['account.tax'].browse()
for tax in taxes:
tax_count = 0
+6 -4
View File
@@ -37,13 +37,15 @@
<page name="tax_mapping" string="Tax Mapping">
<group>
<field name="tax_ids" widget="one2many_list" nolabel="1">
<tree string="Tax Mapping" editable="bottom">
<tree name="tax_map_tree" string="Tax Mapping" editable="bottom">
<field name="tax_src_id" domain="[('type_tax_use', '!=', None)]"/>
<field name="tax_dest_id" domain="[('type_tax_use', '!=', None), ('price_include', '=', False)]"/>
</tree>
<form string="Tax Mapping">
<field name="tax_src_id" domain="[('type_tax_use', '!=', None)]"/>
<field name="tax_dest_id" domain="[('type_tax_use', '!=', None), ('price_include', '=', False)]"/>
<form name="tax_map_form" string="Tax Mapping">
<group>
<field name="tax_src_id" domain="[('type_tax_use', '!=', None)]"/>
<field name="tax_dest_id" domain="[('type_tax_use', '!=', None), ('price_include', '=', False)]"/>
</group>
</form>
</field>
</group>
+1 -1
View File
@@ -80,7 +80,7 @@ class SaleOrder(models.Model):
taxes = carrier.product_id.taxes_id.filtered(lambda t: t.company_id.id == self.company_id.id)
taxes_ids = taxes.ids
if self.partner_id and self.fiscal_position_id:
taxes_ids = self.fiscal_position_id.map_tax(taxes).ids
taxes_ids = self.fiscal_position_id.map_tax(taxes, carrier.product_id, self.partner_id).ids
# Create the sale order line
values = {
+2
View File
@@ -1,2 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import models
+1
View File
@@ -11,6 +11,7 @@ United States - Chart of accounts.
'depends': ['l10n_generic_coa', 'report'],
'data': [
'data/res_company.xml',
'views/res_config_view.xml'
],
'demo': [],
'test': [],
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import res_config
+11
View File
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class AccountConfigSettings(models.TransientModel):
_inherit = 'account.config.settings'
module_account_taxcloud = fields.Boolean("Compute sales tax automatically in the United States using TaxCloud.",
help='TaxCloud is an online provider that is committed to making it easy for retailers to collect sales tax online'
'in the United States.')
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_config_settings_inherit_form_view" model="ir.ui.view">
<field name="name">account settings</field>
<field name="model">account.config.settings</field>
<field name="inherit_id" ref="account.view_account_config_settings"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='invoice_taxes']" position="inside">
<div name="taxcloud_tax" class="o_row">
<field name="module_account_taxcloud"/>
<label for="module_account_taxcloud"/>
</div>
</xpath>
</field>
</record>
</odoo>
+4 -4
View File
@@ -22,7 +22,7 @@ class PosOrder(models.Model):
def _amount_line_tax(self, cr, uid, line, fiscal_position_id, context=None):
taxes = line.tax_ids.filtered(lambda t: t.company_id.id == line.order_id.company_id.id)
if fiscal_position_id:
taxes = fiscal_position_id.map_tax(taxes)
taxes = fiscal_position_id.map_tax(taxes, line.product_id, line.order_id.partner_id)
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
taxes = taxes.compute_all(price, line.order_id.pricelist_id.currency_id, line.qty, product=line.product_id, partner=line.order_id.partner_id or False)['taxes']
return sum(tax.get('amount', 0.0) for tax in taxes)
@@ -184,7 +184,7 @@ class PosOrder(models.Model):
invoice_line.invoice_line_tax_ids = invoice_line.invoice_line_tax_ids.filtered(lambda t: t.company_id.id == line.order_id.company_id.id).ids
fiscal_position_id = line.order_id.fiscal_position_id
if fiscal_position_id:
invoice_line.invoice_line_tax_ids = fiscal_position_id.map_tax(invoice_line.invoice_line_tax_ids)
invoice_line.invoice_line_tax_ids = fiscal_position_id.map_tax(invoice_line.invoice_line_tax_ids, line.product_id, line.order_id.partner_id)
invoice_line.invoice_line_tax_ids = invoice_line.invoice_line_tax_ids.ids
# We convert a new id object back to a dictionary to write to
# bridge between old and new api
@@ -739,7 +739,7 @@ class PosOrderLine(models.Model):
taxes = line.tax_ids.filtered(lambda tax: tax.company_id.id == line.order_id.company_id.id)
fiscal_position_id = line.order_id.fiscal_position_id
if fiscal_position_id:
taxes = fiscal_position_id.map_tax(taxes)
taxes = fiscal_position_id.map_tax(taxes, line.product_id, line.order_id.partner_id)
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
line.price_subtotal = line.price_subtotal_incl = price * line.qty
if taxes:
@@ -778,7 +778,7 @@ class PosOrderLine(models.Model):
@api.multi
def _get_tax_ids_after_fiscal_position(self):
for line in self:
line.tax_ids_after_fiscal_position = line.order_id.fiscal_position_id.map_tax(line.tax_ids)
line.tax_ids_after_fiscal_position = line.order_id.fiscal_position_id.map_tax(line.tax_ids, line.product_id, line.order_id.partner_id)
class PosOrderLineLot(models.Model):
+1 -1
View File
@@ -639,7 +639,7 @@ class SaleOrderLine(models.Model):
fpos = line.order_id.fiscal_position_id or line.order_id.partner_id.property_account_position_id
# If company_id is set, always filter taxes by the company
taxes = line.product_id.taxes_id.filtered(lambda r: not line.company_id or r.company_id == line.company_id)
line.tax_id = fpos.map_tax(taxes) if fpos else taxes
line.tax_id = fpos.map_tax(taxes, line.product_id, line.order_id.partner_id) if fpos else taxes
@api.multi
def _prepare_order_line_procurement(self, group_id=False):
+2 -1
View File
@@ -59,7 +59,8 @@ class AccountAnalyticLine(models.Model):
last_sequence = last_so_line.sequence + 1 if last_so_line else 100
fpos = order.fiscal_position_id or order.partner_id.property_account_position_id
taxes = fpos.map_tax(self.product_id.taxes_id)
taxes = fpos.map_tax(self.product_id.taxes_id, self.product_id, order.partner_id)
return {
'order_id': order.id,
'name': self.name,
+6 -2
View File
@@ -5,7 +5,7 @@ import random
from odoo import api, models, fields, tools, _
from odoo.http import request
from odoo.exceptions import UserError
from odoo.exceptions import UserError, ValidationError
_logger = logging.getLogger(__name__)
@@ -92,7 +92,11 @@ class SaleOrder(models.Model):
if not order_line:
values = self._website_product_id_change(self.id, product_id, qty=1)
order_line = SaleOrderLineSudo.create(values)
order_line._compute_tax_id()
try:
order_line._compute_tax_id()
except ValidationError as e:
# The validation may occur in backend (eg: taxcloud) but should fail silently in frontend
_logger.debug("ValidationError occurs during tax compute. %s" % (e))
if add_qty:
add_qty -= 1