flectra/addons/base_address_extended/models/base_address_extended.py

177 lines
7.8 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
import re
from flectra import api, fields, models, _
from flectra.exceptions import UserError
STREET_FIELDS = ('street_name', 'street_number', 'street_number2')
class ResCountry(models.Model):
_inherit = 'res.country'
street_format = fields.Text(
help="Format to use for streets belonging to this country.\n\n"
"You can use the python-style string pattern with all the fields of the street "
"(for example, use '%(street_name)s, %(street_number)s' if you want to display "
"the street name, followed by a comma and the house number)"
"\n%(street_name)s: the name of the street"
"\n%(street_number)s: the house number"
"\n%(street_number2)s: the door number",
default='%(street_number)s/%(street_number2)s %(street_name)s', required=True)
class Partner(models.Model):
_inherit = ['res.partner']
_name = 'res.partner'
street_name = fields.Char('Street Name', compute='_split_street',
inverse='_set_street', store=True)
street_number = fields.Char('House Number', compute='_split_street',
inverse='_set_street', store=True)
street_number2 = fields.Char('Door Number', compute='_split_street',
inverse='_set_street', store=True)
def get_street_fields(self):
"""Returns the fields that can be used in a street format.
Overwrite this function if you want to add your own fields."""
return STREET_FIELDS
@api.multi
def _set_street(self):
"""Updates the street field.
Writes the `street` field on the partners when one of the sub-fields in STREET_FIELDS
has been touched"""
street_fields = self.get_street_fields()
for partner in self:
street_format = (partner.country_id.street_format or
'%(street_number)s/%(street_number2)s %(street_name)s')
previous_field = None
previous_pos = 0
street_value = ""
separator = ""
# iter on fields in street_format, detected as '%(<field_name>)s'
for re_match in re.finditer(r'%\(\w+\)s', street_format):
# [2:-2] is used to remove the extra chars '%(' and ')s'
field_name = re_match.group()[2:-2]
field_pos = re_match.start()
if field_name not in street_fields:
raise UserError(_("Unrecognized field %s in street format.") % field_name)
if not previous_field:
# first iteration: add heading chars in street_format
if partner[field_name]:
street_value += street_format[0:field_pos] + partner[field_name]
else:
# get the substring between 2 fields, to be used as separator
separator = street_format[previous_pos:field_pos]
if street_value and partner[field_name]:
street_value += separator
if partner[field_name]:
street_value += partner[field_name]
previous_field = field_name
previous_pos = re_match.end()
# add trailing chars in street_format
street_value += street_format[previous_pos:]
# /!\ Note that we must use a sql query to bypass the orm as it would call _split_street()
# that would try to set the fields we just modified.
self._cr.execute('UPDATE res_partner SET street = %s WHERE ID = %s', (street_value, partner.id))
#invalidate the cache for the field we manually set
self.invalidate_cache(['street'], [partner.id])
@api.multi
@api.depends('street')
def _split_street(self):
"""Splits street value into sub-fields.
Recomputes the fields of STREET_FIELDS when `street` of a partner is updated"""
street_fields = self.get_street_fields()
for partner in self:
if not partner.street:
for field in street_fields:
partner[field] = None
continue
street_format = (partner.country_id.street_format or
'%(street_number)s/%(street_number2)s %(street_name)s')
vals = {}
previous_pos = 0
street_raw = partner.street
field_name = None
# iter on fields in street_format, detected as '%(<field_name>)s'
for re_match in re.finditer(r'%\(\w+\)s', street_format):
field_pos = re_match.start()
if not field_name:
#first iteration: remove the heading chars
street_raw = street_raw[field_pos:]
# get the substring between 2 fields, to be used as separator
separator = street_format[previous_pos:field_pos]
field_value = None
if separator and field_name:
#maxsplit set to 1 to unpack only the first element and let the rest untouched
tmp = street_raw.split(separator, 1)
if len(tmp) == 2:
field_value, street_raw = tmp
vals[field_name] = field_value
if field_value or not field_name:
# select next field to find (first pass OR field found)
# [2:-2] is used to remove the extra chars '%(' and ')s'
field_name = re_match.group()[2:-2]
else:
# value not found: keep looking for the same field
pass
if field_name not in street_fields:
raise UserError(_("Unrecognized field %s in street format.") % field_name)
previous_pos = re_match.end()
# last field value is what remains in street_raw minus trailing chars in street_format
trailing_chars = street_format[previous_pos:]
if trailing_chars and street_raw.endswith(trailing_chars):
vals[field_name] = street_raw[:-len(trailing_chars)]
else:
vals[field_name] = street_raw
# assign the values to the fields
# /!\ Note that a write(vals) would cause a recursion since it would bypass the cache
for k, v in vals.items():
partner[k] = v
def write(self, vals):
res = super(Partner, self).write(vals)
if 'country_id' in vals:
self._set_street()
return res
class Company(models.Model):
_inherit = 'res.company'
street_name = fields.Char('Street Name', compute='_compute_address',
inverse='_inverse_street_name')
street_number = fields.Char('House Number', compute='_compute_address',
inverse='_inverse_street_number')
street_number2 = fields.Char('Door Number', compute='_compute_address',
inverse='_inverse_street_number2')
def _get_company_address_fields(self, partner):
address_fields = super(Company, self)._get_company_address_fields(partner)
address_fields.update({
'street_name': partner.street_name,
'street_number': partner.street_number,
'street_number2': partner.street_number2,
})
return address_fields
def _inverse_street_name(self):
for company in self:
company.partner_id.street_name = company.street_name
def _inverse_street_number(self):
for company in self:
company.partner_id.street_number = company.street_number
def _inverse_street_number2(self):
for company in self:
company.partner_id.street_number2 = company.street_number2