1
# -*- coding: utf-8 -*-
2
##############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6
# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU Affero General Public License as
10
# published by the Free Software Foundation, either version 3 of the
11
# License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU Affero General Public License for more details.
18
# You should have received a copy of the GNU Affero General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
##############################################################################
24
from osv import osv, fields
25
from tools.translate import _
26
import decimal_precision as dp
28
from suds_client import AvaTaxService, BaseAddress
30
class res_partner(osv.osv):
31
_inherit = 'res.partner'
33
'exemption_number': fields.char('Exemption Number', size=64, help="Indicates if the customer is exempt or not"),
34
'exemption_code_id': fields.many2one('exemption.code', 'Exemption Code', help="Indicates the type of exemption the customer may have"),
35
'tax_schedule_id': fields.many2one('tax.schedule', 'Tax Schedule', help="Identifies customers using AVATAX. Only customers with AVATAX designation triggers tax calculation from Avatax otherwise it will follow the normal tax calculation that OpenERP provides")
40
class res_partner_address(osv.osv):
41
_inherit = 'res.partner.address'
43
'date_validation': fields.date('Last Validation Date', readonly=True, help="The date the address was last validated by AvaTax and accepted"),
44
'validation_method': fields.selection([('avatax', 'AVATAX'), ('usps', 'USPS'), ('other', 'Other')], 'Address Validation Method', readonly=True, help="It gets populated when the address is validated by the method"),
45
'latitude': fields.char('Latitude', size=32),
46
'longitude': fields.char('Longitude', size=32),
47
'validated_on_save': fields.boolean('Validated On Save', help="Indicates if the address is already validated on save before calling the wizard")
50
def check_avatax_support(self, cr, uid, avatax_config, country_id, context=None):
51
""" Checks if address validation pre-condition meets. """
53
if avatax_config.address_validation:
54
raise osv.except_osv(_('Address Validation is Disabled'), _("The AvaTax Address Validation Service is disabled by the administrator. Please make sure it's enabled for the address validation"))
55
if country_id and country_id not in [x.id for x in avatax_config.country_ids]:
56
raise osv.except_osv(_('Address Validation not Supported for this country'), _("The AvaTax Address Validation Service does not support this country in the configuration, please continue with your normal process."))
59
def get_state_id(self, cr, uid, code, context=None):
60
""" Returns the id of the state from the code. """
62
state_obj = self.pool.get('res.country.state')
63
return state_obj.search(cr, uid, [('code', '=', code)], context=context)[0]
65
def get_country_id(self, cr, uid, code, context=None):
66
""" Returns the id of the country from the code. """
68
country_obj = self.pool.get('res.country')
69
return country_obj.search(cr, uid, [('code', '=', code)], context=context)[0]
71
def get_state_code(self, cr, uid, state_id, context=None):
72
""" Returns the code from the id of the state. """
74
state_obj = self.pool.get('res.country.state')
75
return state_id and state_obj.browse(cr, uid, state_id, context=context).code
77
def get_country_code(self, cr, uid, country_id, context=None):
78
""" Returns the code from the id of the country. """
80
country_obj = self.pool.get('res.country')
81
return country_id and country_obj.browse(cr, uid, country_id, context=context).code
83
def _validate_address(self, cr, uid, address, avatax_config=False, context=None):
84
""" Returns the valid address from the AvaTax Address Validation Service. """
86
avatax_config_obj= self.pool.get('account.salestax.avatax')
91
avatax_config = avatax_config_obj._get_avatax_config_company(cr, uid, context=context)
93
# Create the AvaTax Address service with the configuration parameters set for the instance
94
avapoint = AvaTaxService(avatax_config.account_number, avatax_config.license_key,
95
avatax_config.service_url, avatax_config.request_timeout, avatax_config.logging)
96
addSvc = avapoint.create_address_service().addressSvc
98
# Obtain the state code & country code and create a BaseAddress Object
99
state_code = address.get('state_id') and self.get_state_code(cr, uid, address['state_id'], context=context)
100
country_code = address.get('country_id') and self.get_country_code(cr, uid, address['country_id'], context=context)
101
baseaddress = BaseAddress(addSvc, address.get('street') or None, address.get('street2') or None,
102
address.get('city'), address.get('zip'), state_code, country_code, 0).data
103
result = avapoint.validate_address(baseaddress, avatax_config.result_in_uppercase and 'Upper' or 'Default')
104
valid_address = result.ValidAddresses[0][0]
107
def update_address(self, cr, uid, vals, ids=None, from_write=False, context=None):
108
""" Updates the vals dictionary with the valid address as returned from the AvaTax Address Validation. """
112
if (vals.get('street') or vals.get('street2') or vals.get('zip') or vals.get('city') or \
113
vals.get('country_id') or vals.get('state_id')):
115
address_obj = self.pool.get('res.partner.address')
116
avatax_config_obj= self.pool.get('account.salestax.avatax')
117
avatax_config = avatax_config_obj._get_avatax_config_company(cr, uid, context=context)
119
if avatax_config and avatax_config.validation_on_save:
120
# It implies that there is AvaTax configuration existing for the user company with
121
# option 'Address Validation when a address is saved'
122
# Check if the other conditions are met
123
self.check_avatax_support(cr, uid, avatax_config, address.get('country_id'), context=context)
125
# If this method is called from the 'write' method then we also need to pass
126
# the previous address along with the modifications in the vals dictionary
128
fields_to_read = filter(lambda x: x not in vals, ['street', 'street2', 'city', 'state_id', 'zip', 'country_id'])
129
address = fields_to_read and address_obj.read(cr, uid, ids, fields_to_read, context=context)[0] or {}
130
address['state_id'] = address.get('state_id') and address['state_id'][0]
131
address['country_id'] = address.get('country_id') and address['country_id'][0]
134
valid_address = self._validate_address(cr, uid, address, avatax_config, context=context)
136
'street': valid_address.Line1,
137
'street2': valid_address.Line2,
138
'city': valid_address.City,
139
'state_id': self.get_state_id(cr, uid, valid_address.Region, context=context),
140
'zip': valid_address.PostalCode,
141
'country_id': self.get_country_id(cr, uid, valid_address.Country, context=context),
142
'latitude': valid_address.Latitude,
143
'longitude': valid_address.Longitude,
144
'date_validation': time.strftime('%Y-%m-%d'),
145
'validation_method': 'avatax',
146
'validated_on_save': True
151
def create(self, cr, uid, vals, context=None):
152
vals = self.update_address(cr, uid, vals, context=context)
153
return super(res_partner_address, self).create(cr, uid, vals, context)
155
def write(self, cr, uid, ids, vals, context=None):
159
# Follow the normal write process if it's a write operation from the wizard
160
if context.get('from_validate_button', False):
161
return super(res_partner_address, self).write(cr, uid, ids, vals, context)
163
if context.get('active_id', False):
164
vals = self.update_address(cr, uid, vals, ids, True, context=context)
165
return super(res_partner_address, self).write(cr, uid, ids, vals, context)
167
res_partner_address()
169
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
b'\\ No newline at end of file'