Browse Source

Use separate and explicit fields for each NUTS level

pull/518/head
Antonio Espinosa 9 years ago
committed by Jairo Llopis
parent
commit
01ad0bfd8b
  1. 33
      base_location_nuts/README.rst
  2. 4
      base_location_nuts/i18n/es.po
  3. 18
      base_location_nuts/models/res_country.py
  4. 139
      base_location_nuts/models/res_partner.py
  5. 6
      base_location_nuts/models/res_partner_nuts.py
  6. 10
      base_location_nuts/views/res_country_view.xml
  7. 3
      base_location_nuts/views/res_partner_nuts_view.xml
  8. 71
      base_location_nuts/views/res_partner_view.xml
  9. 6
      base_location_nuts/wizard/__init__.py
  10. 11
      base_location_nuts/wizard/nuts_import.py
  11. 3
      base_location_nuts/wizard/nuts_import_view.xml

33
base_location_nuts/README.rst

@ -7,28 +7,22 @@ NUTS Regions
This module allows to import NUTS locations. This module allows to import NUTS locations.
Creates two new fields in Partner object:
Creates four new fields in Partner object, one per NUTS level
* Region (res.partner.region): Classification over state, automatically
calculated when state is selected
* Substate (res.partner.substate): Classification above state, user must select
one from available for selected state
* NUTS L1: Country level
* NUTS L2: Normally state or big region level
* NUTS L3: Normally substate or state level
* NUTS L4: Normally small region or province level
Installation Installation
============ ============
You need to install another addon (one for each country) in order to use
these NUTS, for example:
We recommend to install another addon (one for each country) in order to relate
NUTS with states define by each localization addon, for example:
* l10n_es_location_nuts :
* Spanish Provinces (NUTS level 4) as Partner State
* Spanish Autonomous communities (NUTS level 3) as Partner Substate
* Spanish Regions (NUTS level 2) as Partner Region
* l10n_de_location_nuts :
* German states (NUTS level 2) as Partner State
* German districts (NUTS level 3) as Partner Substate
* German regions (NUTS level 4) as Partner Region
* l10n_es_location_nuts : Spanish Provinces (NUTS level 4) related to Partner State
* l10n_de_location_nuts : German states (NUTS level 2) related to Partner State
Configuration Configuration
@ -44,13 +38,6 @@ l10n_de_location_nuts, ...) will inherit this wizard and
relate each NUTS item with states. So if you install a new localization addon relate each NUTS item with states. So if you install a new localization addon
you must re-build NUTS clicking this wizard again. you must re-build NUTS clicking this wizard again.
To configure lables and levels per country, you should install a l10n module,
but if you want to do it manually, you need to:
* Have *Sales / Responsible permissions*.
* Go to *Sales > Configuration > Address Book > Localization > Countries*.
* Choose one.
* Use the fields under the *NUTS* section.
Usage Usage
===== =====
@ -61,7 +48,7 @@ in order to allow to assign them to partner object.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot :alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/134/{branch}
:target: https://runbot.odoo-community.org/runbot/134/8.0
Bug Tracker Bug Tracker
=========== ===========

4
base_location_nuts/i18n/es.po

@ -262,9 +262,9 @@ msgid ""
" ENTRIES from new downloaded file." " ENTRIES from new downloaded file."
msgstr "" msgstr ""
"Este asistente descargará la última version de\n" "Este asistente descargará la última version de\n"
" NUTS 2013 desde el servicio de matadatos europeo RAMON.\n"
" NUTS 2013 desde el servicio de metadatos europeo RAMON.\n"
" Actualizando o creando nuevas regiones NUTS si no\n" " Actualizando o creando nuevas regiones NUTS si no\n"
" las encuentra en el sistemma, y BORRANDO LAS QUE NO "
" las encuentra en el sistema, y BORRANDO LAS QUE NO "
"ENCUENTRE\n" "ENCUENTRE\n"
" en el nuevo fichero descargado." " en el nuevo fichero descargado."

18
base_location_nuts/models/res_country.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Antiun Ingeniería S.L. - Antonio Espinosa
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis # © 2015 Antiun Ingeniería S.L. - Jairo Llopis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
@ -6,24 +7,7 @@ from openerp import models, fields
class ResCountry(models.Model): class ResCountry(models.Model):
"""Add labels corresponding to each country.
These stay empty in this base module, and should be filled by l10n ones.
"""
_inherit = "res.country" _inherit = "res.country"
state_label = fields.Char(
translate=True,
help="Label for the state NUTS category.")
substate_label = fields.Char(
translate=True,
help="Label for the substate NUTS category.")
region_label = fields.Char(
translate=True,
help="Label for the region NUTS category.")
state_level = fields.Integer( state_level = fields.Integer(
help="Level for the state NUTS category.") help="Level for the state NUTS category.")
substate_level = fields.Integer(
help="Level for the substate NUTS category.")
region_level = fields.Integer(
help="Level for the region NUTS category.")

139
base_location_nuts/models/res_partner.py

@ -1,73 +1,122 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
# © 2015 Antiun Ingeniería S.L. - Antonio Espinosa
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields, api from openerp import models, fields, api
from openerp.tools.translate import _
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'
region_id = fields.Many2one(
'res.partner.nuts',
"Region",
oldname="region")
substate_id = fields.Many2one(
'res.partner.nuts',
"Substate",
oldname="substate")
lbl_region = fields.Char(
default=_("Region"),
compute='_labels_get')
lbl_substate = fields.Char(
default=_("Substate"),
compute='_labels_get')
nuts1_id = fields.Many2one(
comodel_name='res.partner.nuts', domain=[('level', '=', 1)],
string="NUTS L1")
nuts2_id = fields.Many2one(
comodel_name='res.partner.nuts', domain=[('level', '=', 2)],
string="NUTS L2", oldname="region")
nuts3_id = fields.Many2one(
comodel_name='res.partner.nuts', domain=[('level', '=', 3)],
string="NUTS L3", oldname="substate")
nuts4_id = fields.Many2one(
comodel_name='res.partner.nuts', domain=[('level', '=', 4)],
string="NUTS L4")
@api.multi @api.multi
@api.depends('country_id')
def _labels_get(self):
for s in self:
s.lbl_region = s.country_id.region_label or _('Region')
s.lbl_substate = s.country_id.substate_label or _('Substate')
def _onchange_nuts(self, field):
country_id = self[field].country_id.id
state_id = self[field].state_id.id
if country_id and self.country_id.id != country_id:
self.country_id = country_id
if state_id and self.state_id.id != state_id:
self.state_id = state_id
level = int(field[:5][-1])
if (level - 1) > 0:
parent_id = self[field].parent_id.id
if parent_id:
parent_field = 'nuts%d_id' % (level - 1)
if self[parent_field].id != parent_id:
self[parent_field] = parent_id
result = dict()
if country_id and level < 4:
result['domain'] = dict()
while level < 4:
parent_field = 'nuts%d_id' % level
domain_field = 'nuts%d_id' % (level + 1)
parent_id = self[parent_field].id
if parent_id:
result['domain'][domain_field] = [
('parent_id', '=', parent_id),
]
level += 1
return result
@api.multi @api.multi
@api.onchange("substate_id")
def _onchange_substate_id(self):
if self.substate_id.country_id:
self.country_id = self.substate_id.country_id
return dict()
@api.onchange('nuts4_id')
def _onchange_nuts4_id(self):
return self._onchange_nuts('nuts4_id')
@api.multi @api.multi
@api.onchange("region_id")
def _onchange_region_id(self):
if self.region_id.country_id:
self.country_id = self.region_id.country_id
return dict()
@api.onchange('nuts3_id')
def _onchange_nuts3_id(self):
return self._onchange_nuts('nuts3_id')
@api.multi @api.multi
@api.onchange("country_id")
@api.onchange('nuts2_id')
def _onchange_nuts2_id(self):
return self._onchange_nuts('nuts2_id')
@api.multi
@api.onchange('nuts1_id')
def _onchange_nuts1_id(self):
return self._onchange_nuts('nuts1_id')
@api.multi
@api.onchange('country_id')
def _onchange_country_id(self): def _onchange_country_id(self):
"""Sensible values and domains for related fields.""" """Sensible values and domains for related fields."""
fields = {"state", "region", "substate"}
country_domain = ([("country_id", "=", self.country_id.id)]
fields = ['state_id', 'nuts1_id', 'nuts2_id', 'nuts3_id', 'nuts4_id']
country_domain = ([('country_id', '=', self.country_id.id)]
if self.country_id else []) if self.country_id else [])
domain = dict() domain = dict()
for field in fields: for field in fields:
field += "_id"
if self.country_id and self[field].country_id != self.country_id: if self.country_id and self[field].country_id != self.country_id:
self[field] = False self[field] = False
domain[field] = list(country_domain) # Using list() to copy domain[field] = list(country_domain) # Using list() to copy
fields.remove("state")
fields.remove('state_id')
for field in fields: for field in fields:
level = self.country_id["%s_level" % field]
field += "_id"
level = int(field[:5][-1])
if level: if level:
domain[field].append(("level", "=", level))
domain[field].append(('level', '=', level))
if self.country_id:
nuts1 = self.env['res.partner.nuts'].search([
('level', '=', 1),
('country_id', '=', self.country_id.id),
], limit=1)
if self.nuts1_id.id != nuts1.id:
self.nuts1_id = nuts1.id
return { return {
"domain": domain,
'domain': domain,
} }
@api.multi
def onchange_state(self, state_id):
result = super(ResPartner, self).onchange_state(state_id)
state = self.env['res.country.state'].browse(state_id)
if state.country_id.state_level:
nuts_state = self.env['res.partner.nuts'].search([
('level', '=', state.country_id.state_level),
('state_id', '=', state.id)
], limit=1)
if nuts_state:
field = 'nuts%d_id' % state.country_id.state_level
result.setdefault("value", dict())
result['value'][field] = nuts_state.id
return result
@api.model
def _address_fields(self):
fields = super(ResPartner, self)._address_fields()
if fields:
fields += ['nuts1_id', 'nuts2_id', 'nuts3_id', 'nuts4_id']
return fields

6
base_location_nuts/models/res_partner_nuts.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
# © 2015 Antiun Ingeniería S.L. - Antonio Espinosa
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields from openerp import models, fields

10
base_location_nuts/views/res_country_view.xml

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 Antiun Ingeniería S.L. - Jairo Llopis <!-- © 2015 Antiun Ingeniería S.L. - Jairo Llopis
© 2015 Antiun Ingeniería S.L. - Antonio Espinosa
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp> <openerp>
@ -13,17 +14,8 @@
<xpath expr="/form"> <xpath expr="/form">
<group name="nuts" string="NUTS"> <group name="nuts" string="NUTS">
<group> <group>
<field name="state_label"/>
<field name="state_level"/> <field name="state_level"/>
</group> </group>
<group>
<field name="substate_label"/>
<field name="substate_level"/>
</group>
<group>
<field name="region_label"/>
<field name="region_level"/>
</group>
</group> </group>
</xpath> </xpath>
</field> </field>

3
base_location_nuts/views/res_partner_nuts_view.xml

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 Antiun Ingeniería S.L. - Jairo Llopis
© 2015 Antiun Ingeniería S.L. - Antonio Espinosa
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp> <openerp>
<data> <data>

71
base_location_nuts/views/res_partner_view.xml

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 Antiun Ingeniería S.L. - Jairo Llopis
© 2015 Antiun Ingeniería S.L. - Antonio Espinosa
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp> <openerp>
<data> <data>
@ -8,48 +11,16 @@
<field name="inherit_id" ref="base.view_partner_form"/> <field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//sheet/group//field[@name='country_id']/.." position="after"> <xpath expr="//sheet/group//field[@name='country_id']/.." position="after">
<div width="1%" cell-class="oe_form_group_cell_label"
attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="lbl_substate" class="oe_inline"/>
</div>
<div attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="substate_id"
class="oe_no_button"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('use_parent_address','=',True)]}"/>
</div>
<div width="1%" cell-class="oe_form_group_cell_label"
attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="lbl_region" class="oe_inline"/>
</div>
<div attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="region_id"
class="oe_no_button"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('use_parent_address','=',True)]}"/>
</div>
<field name="nuts1_id"/>
<field name="nuts2_id"/>
<field name="nuts3_id"/>
<field name="nuts4_id"/>
</xpath> </xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='country_id']/.." position="after"> <xpath expr="//field[@name='child_ids']/form//field[@name='country_id']/.." position="after">
<div width="1%" cell-class="oe_form_group_cell_label"
attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="lbl_substate" class="oe_inline"/>
</div>
<div attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="substate_id"
class="oe_no_button"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('use_parent_address','=',True)]}"/>
</div>
<div width="1%" cell-class="oe_form_group_cell_label"
attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="lbl_region" class="oe_inline"/>
</div>
<div attrs="{'invisible': [('use_parent_address','=',True)]}">
<field name="region_id"
class="oe_no_button"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('use_parent_address','=',True)]}"/>
</div>
<field name="nuts1_id"/>
<field name="nuts2_id"/>
<field name="nuts3_id"/>
<field name="nuts4_id"/>
</xpath> </xpath>
</field> </field>
</record> </record>
@ -60,16 +31,24 @@
<field name="inherit_id" ref="base.view_res_partner_filter"/> <field name="inherit_id" ref="base.view_res_partner_filter"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="category_id" position="after"> <field name="category_id" position="after">
<field name="region_id"/>
<field name="substate_id"/>
<field name="nuts1_id"/>
<field name="nuts2_id"/>
<field name="nuts3_id"/>
<field name="nuts4_id"/>
</field> </field>
<filter string="Salesperson" position="after"> <filter string="Salesperson" position="after">
<filter string="Region"
<filter string="NUTS L1"
domain="[]" domain="[]"
context="{'group_by': 'region_id'}"/>
<filter string="Substate"
context="{'group_by': 'nuts1_id'}"/>
<filter string="NUTS L2"
domain="[]" domain="[]"
context="{'group_by': 'substate_id'}"/>
context="{'group_by': 'nuts2_id'}"/>
<filter string="NUTS L3"
domain="[]"
context="{'group_by': 'nuts3_id'}"/>
<filter string="NUTS L4"
domain="[]"
context="{'group_by': 'nuts4_id'}"/>
</filter> </filter>
</field> </field>
</record> </record>

6
base_location_nuts/wizard/__init__.py

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
# © 2015 Antiun Ingeniería S.L. - Antonio Espinosa
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import nuts_import from . import nuts_import

11
base_location_nuts/wizard/nuts_import.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
# © 2015 Antiun Ingeniería S.L. - Antonio Espinosa
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, api, _ from openerp import models, api, _
from openerp.exceptions import Warning from openerp.exceptions import Warning
@ -140,7 +140,6 @@ class NutsImport(models.TransientModel):
# UK => GB (United Kingdom) # UK => GB (United Kingdom)
self._countries['EL'] = self._countries['GR'] self._countries['EL'] = self._countries['GR']
self._countries['UK'] = self._countries['GB'] self._countries['UK'] = self._countries['GB']
logger.info('_load_countries = %s' % pformat(self._countries))
@api.model @api.model
def state_mapping(self, data, node): def state_mapping(self, data, node):
@ -184,11 +183,11 @@ class NutsImport(models.TransientModel):
nuts_to_delete = nuts_model.search( nuts_to_delete = nuts_model.search(
[('country_id', 'in', [x.id for x in self._countries.values()])]) [('country_id', 'in', [x.id for x in self._countries.values()])])
# Download NUTS in english, create or update # Download NUTS in english, create or update
logger.info('Import NUTS 2013 English')
logger.info('Importing NUTS 2013 English')
xmlcontent = self._download_nuts() xmlcontent = self._download_nuts()
dom = etree.fromstring(xmlcontent) dom = etree.fromstring(xmlcontent)
for node in dom.iter('Item'): for node in dom.iter('Item'):
logger.info('Reading level=%s, id=%s' %
logger.debug('Reading level=%s, id=%s' %
(node.get('idLevel', 'N/A'), (node.get('idLevel', 'N/A'),
node.get('id', 'N/A'))) node.get('id', 'N/A')))
nuts = self.create_or_update_nuts(node) nuts = self.create_or_update_nuts(node)

3
base_location_nuts/wizard/nuts_import_view.xml

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 Antiun Ingeniería S.L. - Jairo Llopis
© 2015 Antiun Ingeniería S.L. - Antonio Espinosa
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp> <openerp>
<data> <data>

Loading…
Cancel
Save