From b7f2f3c0dc83ef399b3577dc4f458a6ff5d4c754 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Sat, 7 Dec 2019 09:40:12 -0800 Subject: [PATCH] NEW `account_us_ca_salestax` Fiscal position for using the CA state sales tax API to create new taxes for Odoo 12 --- account_us_ca_salestax/__init__.py | 1 + account_us_ca_salestax/__manifest__.py | 13 + account_us_ca_salestax/models/__init__.py | 1 + .../models/account_fiscal_position.py | 76 ++++++ account_us_ca_salestax/models/ca_rates.wsdl | 227 ++++++++++++++++++ .../models/ca_tax_request.py | 29 +++ .../views/account_fiscal_position_view.xml | 28 +++ 7 files changed, 375 insertions(+) create mode 100644 account_us_ca_salestax/__init__.py create mode 100644 account_us_ca_salestax/__manifest__.py create mode 100644 account_us_ca_salestax/models/__init__.py create mode 100644 account_us_ca_salestax/models/account_fiscal_position.py create mode 100644 account_us_ca_salestax/models/ca_rates.wsdl create mode 100644 account_us_ca_salestax/models/ca_tax_request.py create mode 100644 account_us_ca_salestax/views/account_fiscal_position_view.xml diff --git a/account_us_ca_salestax/__init__.py b/account_us_ca_salestax/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/account_us_ca_salestax/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_us_ca_salestax/__manifest__.py b/account_us_ca_salestax/__manifest__.py new file mode 100644 index 00000000..2ce76a86 --- /dev/null +++ b/account_us_ca_salestax/__manifest__.py @@ -0,0 +1,13 @@ +{'name': 'US CA California State SalesTax API', + 'version': '12.0.1.0.0', + 'category': 'Tools', + 'depends': ['account', + ], + 'author': 'Hibou Corp.', + 'license': 'AGPL-3', + 'website': 'https://hibou.io/', + 'data': ['views/account_fiscal_position_view.xml', + ], + 'installable': True, + 'application': False, + } diff --git a/account_us_ca_salestax/models/__init__.py b/account_us_ca_salestax/models/__init__.py new file mode 100644 index 00000000..2637a061 --- /dev/null +++ b/account_us_ca_salestax/models/__init__.py @@ -0,0 +1 @@ +from . import account_fiscal_position diff --git a/account_us_ca_salestax/models/account_fiscal_position.py b/account_us_ca_salestax/models/account_fiscal_position.py new file mode 100644 index 00000000..11e32d67 --- /dev/null +++ b/account_us_ca_salestax/models/account_fiscal_position.py @@ -0,0 +1,76 @@ +from odoo import api, fields, models +from .ca_tax_request import CATaxRequest + + +class AccountFiscalPosition(models.Model): + _inherit = 'account.fiscal.position' + + is_us_ca = fields.Boolean(string='Use CA State API') + ca_base_tax_id = fields.Many2one('account.tax', string='CA Base/Error Tax', company_dependent=True) + + @api.multi + def map_tax(self, taxes, product=None, partner=None): + + if not taxes or not self.is_us_ca or partner is None: + return super(AccountFiscalPosition, self).map_tax(taxes) + + AccountTax = self.env['account.tax'].sudo() + result = AccountTax.browse() + + for tax in taxes: + ca_tax = None + request = CATaxRequest() + try: + res = request.get_rate(partner) + ca_tax = AccountTax.search([ + ('company_id', '=', self.ca_base_tax_id.company_id.id), + ('ca_county', '=', res['county']), + ('amount', '=', res['rate']), + ('amount_type', '=', 'percent'), + ('type_tax_use', '=', 'sale')], limit=1) + if not ca_tax: + ca_tax = AccountTax.create({ + 'name': '%s - Tax %0.2f%%' % (res['county'], res['rate']), + 'ca_county': res['county'], + 'amount': res['rate'], + 'amount_type': 'percent', + 'type_tax_use': 'sale', + 'account_id': self.ca_base_tax_id.account_id.id, + 'refund_account_id': self.ca_base_tax_id.refund_account_id.id, + 'company_id': self.ca_base_tax_id.company_id.id, + 'ca_location_zips': partner.zip, + }) + except: + ca_tax = AccountTax.search([ + ('ca_location_zips', 'like', '%' + partner.zip + '%'), + ('amount_type', '=', 'percent'), + ('type_tax_use', '=', 'sale')], limit=1) + if not ca_tax: + result |= self.ca_base_tax_id + continue + + if not ca_tax.ca_location_zips: + ca_tax.write({'ca_location_zips': partner.zip}) + elif not ca_tax.ca_location_zips.find(str(partner.zip)) >= 0: + zips = ca_tax.ca_location_zips.split(',') + zips.append(str(partner.zip)) + ca_tax.write({'ca_location_zips': ','.join(zips)}) + + # step 3: Find or create mapping + tax_line = self.tax_ids.filtered(lambda x: x.tax_src_id.id == tax.id and x.tax_dest_id.id == ca_tax.id) + if not tax_line: + tax_line = self.env['account.fiscal.position.tax'].sudo().create({ + 'position_id': self.id, + 'tax_src_id': tax.id, + 'tax_dest_id': ca_tax.id, + }) + + result |= tax_line.tax_dest_id + return result + + +class AccountTax(models.Model): + _inherit = 'account.tax' + + ca_county = fields.Char('CA County') + ca_location_zips = fields.Char('CA Location ZIPs', default='') diff --git a/account_us_ca_salestax/models/ca_rates.wsdl b/account_us_ca_salestax/models/ca_rates.wsdl new file mode 100644 index 00000000..3ba42502 --- /dev/null +++ b/account_us_ca_salestax/models/ca_rates.wsdl @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/account_us_ca_salestax/models/ca_tax_request.py b/account_us_ca_salestax/models/ca_tax_request.py new file mode 100644 index 00000000..71a313c7 --- /dev/null +++ b/account_us_ca_salestax/models/ca_tax_request.py @@ -0,0 +1,29 @@ +import os +import logging +from suds.client import Client + +_logger = logging.getLogger(__name__) + + +class CATaxRequest: + def __init__(self): + wsdl_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), './ca_rates.wsdl') + self.client = Client('file:///%s' % wsdl_path.lstrip('/')) + + def get_rate(self, partner): + request = self.client.factory.create('CARateRequest') + request.StreetAddress = partner.street + request.State = partner.state_id.code + request.City = partner.city + zip_ = partner.zip + if zip_ and len(zip_) > 5: + zip_ = zip_[:5] + request.ZipCode = zip_ + + _logger.debug('CA Request: ' + str(request)) + response = self.client.service.GetRate(request) + _logger.debug('CA Response: ' + str(response)) + return { + 'rate': response.CARateResponses[0][0].Responses[0][0].Rate * 100.0, + 'county': response.CARateResponses[0][0].Responses[0][0].Details.County, + } diff --git a/account_us_ca_salestax/views/account_fiscal_position_view.xml b/account_us_ca_salestax/views/account_fiscal_position_view.xml new file mode 100644 index 00000000..30972681 --- /dev/null +++ b/account_us_ca_salestax/views/account_fiscal_position_view.xml @@ -0,0 +1,28 @@ + + + + + account.fiscal.position.form.inherit + account.fiscal.position + + + + + + + + + + + account.tax.form.inherit + account.tax + + + + + + + + + +