Browse Source

[ADD] NUTS regions as a base addon

pull/107/head
Antonio Espinosa 10 years ago
committed by Antonio Espinosa
parent
commit
573beb096d
  1. 91
      base_location_nuts/README.rst
  2. 7
      base_location_nuts/__init__.py
  3. 42
      base_location_nuts/__openerp__.py
  4. 214
      base_location_nuts/i18n/base_location_nuts.pot
  5. 220
      base_location_nuts/i18n/es.po
  6. 7
      base_location_nuts/models/__init__.py
  7. 61
      base_location_nuts/models/res_partner.py
  8. 30
      base_location_nuts/models/res_partner_nuts.py
  9. 2
      base_location_nuts/security/ir.model.access.csv
  10. BIN
      base_location_nuts/static/description/icon.png
  11. 76
      base_location_nuts/views/res_partner_nuts_view.xml
  12. 78
      base_location_nuts/views/res_partner_view.xml
  13. 6
      base_location_nuts/wizard/__init__.py
  14. 205
      base_location_nuts/wizard/nuts_import.py
  15. 51
      base_location_nuts/wizard/nuts_import_view.xml

91
base_location_nuts/README.rst

@ -0,0 +1,91 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
============
NUTS Regions
============
This module allows to import NUTS locations.
Creates two new fields in Partner object:
* 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
Installation
============
You need to install another addon (one for each country) in order to use
these NUTS, 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
Configuration
=============
After installation, you must click at import wizard to populate NUTS items
in Odoo database in:
Sales > Configuration > Address Book > Import NUTS 2013
This wizard will download from Europe RAMON service the metadata to
build NUTS in Odoo. Each localization addon (l10n_es_location_nuts,
l10n_de_location_nuts, ...) will inherit this wizard and
relate each NUTS item with states. So if you install a new localization addon
you must re-build NUTS clicking this wizard again.
Usage
=====
Only Administrator can manage NUTS list (it is not neccesary because
it is an European convention) but any registered user can read them,
in order to allow to assign them to partner object.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/134/{branch}
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/partner-contact/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/partner-contact/issues/new?body=module:%20base_location_nuts%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Rafael Blasco <rafabn@antiun.com>
* Antonio Espinosa <antonioea@antiun.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

7
base_location_nuts/__init__.py

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from . import models
from . import wizard

42
base_location_nuts/__openerp__.py

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
# Python source code encoding : https://www.python.org/dev/peps/pep-0263/
##############################################################################
#
# OpenERP, Odoo Source Management Solution
# Copyright (c) 2015 Antiun Ingeniería S.L. (http://www.antiun.com)
# Antonio Espinosa <antonioea@antiun.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'NUTS Regions',
'category': 'Localisation/Europe',
'version': '8.0.1.0.0',
'depends': [
'base',
],
'data': [
'views/res_partner_nuts_view.xml',
'views/res_partner_view.xml',
'wizard/nuts_import_view.xml',
'security/ir.model.access.csv',
],
'author': 'Antiun Ingeniería S.L., '
'Odoo Community Association (OCA)',
'website': 'http://www.antiun.com',
'license': 'AGPL-3',
'installable': True,
}

214
base_location_nuts/i18n/base_location_nuts.pot

@ -0,0 +1,214 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_location_nuts
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-11 15:26+0000\n"
"PO-Revision-Date: 2015-06-11 15:26+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: base_location_nuts
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "Cancel"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,children:0
msgid "Children"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,code:0
msgid "Code"
msgstr ""
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
#: field:res.partner.nuts,country_id:0
msgid "Country"
msgstr ""
#. module: base_location_nuts
#: field:nuts.import,create_uid:0
#: field:res.partner.nuts,create_uid:0
msgid "Created by"
msgstr ""
#. module: base_location_nuts
#: field:nuts.import,create_date:0
#: field:res.partner.nuts,create_date:0
msgid "Created on"
msgstr ""
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:149
#, python-format
msgid "Downloaded file is not a valid XML file"
msgstr ""
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:141
#, python-format
msgid "Got an error %d when trying to download the file %s."
msgstr ""
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:137
#, python-format
msgid "Got an error when trying to download the file: %s."
msgstr ""
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
msgid "Group By"
msgstr ""
#. module: base_location_nuts
#: field:nuts.import,id:0
#: field:res.partner.nuts,id:0
msgid "ID"
msgstr ""
#. module: base_location_nuts
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "Import"
msgstr ""
#. module: base_location_nuts
#: model:ir.ui.menu,name:base_location_nuts.nuts_import_menu
msgid "Import NUTS 2013"
msgstr ""
#. module: base_location_nuts
#: model:ir.actions.act_window,name:base_location_nuts.nuts_import_action
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "Import NUTS 2013 from RAMON"
msgstr ""
#. module: base_location_nuts
#: model:ir.model,name:base_location_nuts.model_nuts_import
msgid "Import NUTS items from European RAMON service"
msgstr ""
#. module: base_location_nuts
#: field:nuts.import,write_uid:0
#: field:res.partner.nuts,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: base_location_nuts
#: field:nuts.import,write_date:0
#: field:res.partner.nuts,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
#: field:res.partner.nuts,level:0
msgid "Level"
msgstr ""
#. module: base_location_nuts
#: model:ir.model,name:base_location_nuts.model_res_partner_nuts
#: view:res.partner.nuts:base_location_nuts.res_partner_nuts_form
msgid "NUTS Item"
msgstr ""
#. module: base_location_nuts
#: model:ir.actions.act_window,name:base_location_nuts.res_partner_nuts_action
#: model:ir.ui.menu,name:base_location_nuts.res_partner_nuts_menu
#: view:res.partner.nuts:base_location_nuts.res_partner_nuts_tree
msgid "NUTS Items"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,name:0
msgid "Name"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,parent_left:0
msgid "Parent Left"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,parent_right:0
msgid "Parent Right"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,parent_id:0
msgid "Parent id"
msgstr ""
#. module: base_location_nuts
#: model:ir.model,name:base_location_nuts.model_res_partner
msgid "Partner"
msgstr ""
#. module: base_location_nuts
#: code:addons/base_location_nuts/models/res_partner.py:53
#: view:res.partner:base_location_nuts.view_res_partner_filter_nuts
#: field:res.partner,region:0
#, python-format
msgid "Region"
msgstr ""
#. module: base_location_nuts
#: view:res.partner:base_location_nuts.view_res_partner_filter_nuts
msgid "Salesperson"
msgstr ""
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
msgid "Search NUTS"
msgstr ""
#. module: base_location_nuts
#: field:res.partner.nuts,state_id:0
msgid "State"
msgstr ""
#. module: base_location_nuts
#: code:addons/base_location_nuts/models/res_partner.py:54
#: view:res.partner:base_location_nuts.view_res_partner_filter_nuts
#: field:res.partner,substate:0
#, python-format
msgid "Substate"
msgstr ""
#. module: base_location_nuts
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "This wizard will download the lastest version of\n"
" NUTS 2013 from Europe RAMON metadata service.\n"
" Updating or creating new NUTS entries if not\n"
" found already in the system, and DELETING MISSING\n"
" ENTRIES from new downloaded file."
msgstr ""
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:116
#, python-format
msgid "Value not found for mandatory field %s"
msgstr ""
#. module: base_location_nuts
#: model:ir.actions.todo,note:base_location_nuts.config_wizard_nuts
msgid "You can import NUTS from RAMON european service."
msgstr ""
#. module: base_location_nuts
#: model:ir.actions.act_window,help:base_location_nuts.res_partner_nuts_action
msgid "You must click at import wizard to populate NUTS items\n"
" in Odoo database in:\n"
" Sales > Configuration > Address Book > Localization > Import NUTS 2013"
msgstr ""

220
base_location_nuts/i18n/es.po

@ -0,0 +1,220 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_location_nuts
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-11 15:26+0000\n"
"PO-Revision-Date: 2015-06-11 15:26+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: base_location_nuts
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "Cancel"
msgstr "Cancelar"
#. module: base_location_nuts
#: field:res.partner.nuts,children:0
msgid "Children"
msgstr "Hijos"
#. module: base_location_nuts
#: field:res.partner.nuts,code:0
msgid "Code"
msgstr "Código"
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
#: field:res.partner.nuts,country_id:0
msgid "Country"
msgstr "País"
#. module: base_location_nuts
#: field:nuts.import,create_uid:0
#: field:res.partner.nuts,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: base_location_nuts
#: field:nuts.import,create_date:0
#: field:res.partner.nuts,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:149
#, python-format
msgid "Downloaded file is not a valid XML file"
msgstr "El fichero descargado no es un fichero XML válido"
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:141
#, python-format
msgid "Got an error %d when trying to download the file %s."
msgstr "Error %d al intentar descargar el fichero %s."
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:137
#, python-format
msgid "Got an error when trying to download the file: %s."
msgstr "Error al intentar descargar el fichero: %s."
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
msgid "Group By"
msgstr "Agrupar por"
#. module: base_location_nuts
#: field:nuts.import,id:0
#: field:res.partner.nuts,id:0
msgid "ID"
msgstr "ID"
#. module: base_location_nuts
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "Import"
msgstr "Importar"
#. module: base_location_nuts
#: model:ir.ui.menu,name:base_location_nuts.nuts_import_menu
msgid "Import NUTS 2013"
msgstr "Importar NUTS 2013"
#. module: base_location_nuts
#: model:ir.actions.act_window,name:base_location_nuts.nuts_import_action
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "Import NUTS 2013 from RAMON"
msgstr "Importar NUTS 2013 desde RAMON"
#. module: base_location_nuts
#: model:ir.model,name:base_location_nuts.model_nuts_import
msgid "Import NUTS items from European RAMON service"
msgstr "Importar regiones NUTS desde el servicio europeo RAMON"
#. module: base_location_nuts
#: field:nuts.import,write_uid:0
#: field:res.partner.nuts,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: base_location_nuts
#: field:nuts.import,write_date:0
#: field:res.partner.nuts,write_date:0
msgid "Last Updated on"
msgstr "Última actualización en"
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
#: field:res.partner.nuts,level:0
msgid "Level"
msgstr "Nivel"
#. module: base_location_nuts
#: model:ir.model,name:base_location_nuts.model_res_partner_nuts
#: view:res.partner.nuts:base_location_nuts.res_partner_nuts_form
msgid "NUTS Item"
msgstr "Región NUTS"
#. module: base_location_nuts
#: model:ir.actions.act_window,name:base_location_nuts.res_partner_nuts_action
#: model:ir.ui.menu,name:base_location_nuts.res_partner_nuts_menu
#: view:res.partner.nuts:base_location_nuts.res_partner_nuts_tree
msgid "NUTS Items"
msgstr "Regiones NUTS"
#. module: base_location_nuts
#: field:res.partner.nuts,name:0
msgid "Name"
msgstr "Nombre"
#. module: base_location_nuts
#: field:res.partner.nuts,parent_left:0
msgid "Parent Left"
msgstr "Padre izquierda"
#. module: base_location_nuts
#: field:res.partner.nuts,parent_right:0
msgid "Parent Right"
msgstr "Padre derecha"
#. module: base_location_nuts
#: field:res.partner.nuts,parent_id:0
msgid "Parent id"
msgstr "ID del padre"
#. module: base_location_nuts
#: model:ir.model,name:base_location_nuts.model_res_partner
msgid "Partner"
msgstr "Empresa"
#. module: base_location_nuts
#: code:addons/base_location_nuts/models/res_partner.py:53
#: view:res.partner:base_location_nuts.view_res_partner_filter_nuts
#: field:res.partner,region:0
#, python-format
msgid "Region"
msgstr "Región"
#. module: base_location_nuts
#: view:res.partner:base_location_nuts.view_res_partner_filter_nuts
msgid "Salesperson"
msgstr "Comercial"
#. module: base_location_nuts
#: view:res.partner.nuts:base_location_nuts.view_res_partner_nuts_filter
msgid "Search NUTS"
msgstr "Buscar NUTS"
#. module: base_location_nuts
#: field:res.partner.nuts,state_id:0
msgid "State"
msgstr "Provincia"
#. module: base_location_nuts
#: code:addons/base_location_nuts/models/res_partner.py:54
#: view:res.partner:base_location_nuts.view_res_partner_filter_nuts
#: field:res.partner,substate:0
#, python-format
msgid "Substate"
msgstr "Estado"
#. module: base_location_nuts
#: view:nuts.import:base_location_nuts.nuts_import_form
msgid "This wizard will download the lastest version of\n"
" NUTS 2013 from Europe RAMON metadata service.\n"
" Updating or creating new NUTS entries if not\n"
" found already in the system, and DELETING MISSING\n"
" ENTRIES from new downloaded file."
msgstr "Este asistente descargará la última version de\n"
" NUTS 2013 desde el servicio de matadatos europeo RAMON.\n"
" Actualizando o creando nuevas regiones NUTS si no\n"
" las encuentra en el sistemma, y BORRANDO LAS QUE NO ENCUENTRE\n"
" en el nuevo fichero descargado."
#. module: base_location_nuts
#: code:addons/base_location_nuts/wizard/nuts_import.py:116
#, python-format
msgid "Value not found for mandatory field %s"
msgstr "El valor no se ha encontrado para el campo obligatorio %s"
#. module: base_location_nuts
#: model:ir.actions.todo,note:base_location_nuts.config_wizard_nuts
msgid "You can import NUTS from RAMON european service."
msgstr "Usted puede importar NUTS desde el servicion europeo RAMON."
#. module: base_location_nuts
#: model:ir.actions.act_window,help:base_location_nuts.res_partner_nuts_action
msgid "You must click at import wizard to populate NUTS items\n"
" in Odoo database in:\n"
" Sales > Configuration > Address Book > Localization > Import NUTS 2013"
msgstr "Debes clicar en el asistente de importación para crear las\n"
" las regiones NUTS en la base de datos de Odoo, en el menú:\n"
" Ventas > Configuración > Libreta de direcciones > Localización > Importar NUTS 2013"

7
base_location_nuts/models/__init__.py

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from . import res_partner_nuts
from . import res_partner

61
base_location_nuts/models/res_partner.py

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from openerp import models, fields, api
from openerp.tools.translate import _
import collections
def dict_recursive_update(d, u):
for k, v in u.iteritems():
if isinstance(v, collections.Mapping):
r = dict_recursive_update(d.get(k, {}), v)
d[k] = r
else:
d[k] = u[k]
return d
class ResPartner(models.Model):
_inherit = 'res.partner'
region = fields.Many2one(comodel_name='res.partner.nuts',
string="Region")
substate = fields.Many2one(comodel_name='res.partner.nuts',
string="Substate")
lbl_region = fields.Char(compute='_labels_get')
lbl_substate = fields.Char(compute='_labels_get')
@api.one
@api.depends('country_id')
def _labels_get(self):
self.lbl_region = _('Region')
self.lbl_substate = _('Substate')
@api.multi
def onchange_state(self, state_id):
result = super(ResPartner, self).onchange_state(state_id)
if not state_id:
changes = {
'domain': {
'substate': [],
'region': [],
},
'value': {
'substate': False,
'region': False,
}
}
dict_recursive_update(result, changes)
return result
@api.onchange('substate', 'region')
def onchange_substate_or_region(self):
result = {'domain': {}}
if not self.substate:
result['domain']['substate'] = []
if not self.region:
result['domain']['region'] = []
return result

30
base_location_nuts/models/res_partner_nuts.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from openerp import models, fields
class ResPartnerNuts(models.Model):
_name = 'res.partner.nuts'
_order = "parent_left"
_parent_order = "name"
_parent_store = True
_description = "NUTS Item"
# NUTS fields
level = fields.Integer(required=True)
code = fields.Char(required=True)
name = fields.Char(required=True, translate=True)
country_id = fields.Many2one(comodel_name='res.country', string="Country",
required=True)
state_id = fields.Many2one(comodel_name='res.country.state',
string='State')
# Parent hierarchy
parent_id = fields.Many2one(comodel_name='res.partner.nuts',
ondelete='restrict')
children = fields.One2many(comodel_name='res.partner.nuts',
inverse_name='parent_id')
parent_left = fields.Integer('Parent Left', select=True)
parent_right = fields.Integer('Parent Right', select=True)

2
base_location_nuts/security/ir.model.access.csv

@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_res_partner_nuts_user","res_partner_nuts group_user","model_res_partner_nuts","base.group_user",1,0,0,0

BIN
base_location_nuts/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 7.7 KiB

76
base_location_nuts/views/res_partner_nuts_view.xml

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="res_partner_nuts_tree" model="ir.ui.view">
<field name="name">NUTS Items tree</field>
<field name="model">res.partner.nuts</field>
<field name="arch" type="xml">
<tree string="NUTS Items">
<field name="level"/>
<field name="code"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="res_partner_nuts_form" model="ir.ui.view">
<field name="name">NUTS Items tree</field>
<field name="model">res.partner.nuts</field>
<field name="arch" type="xml">
<form string="NUTS Item">
<group>
<group>
<field name="level"/>
<field name="code"/>
<field name="parent_id"/>
<field name="name"/>
</group>
<group>
<field name="country_id"/>
<field name="state_id"/>
</group>
</group>
</form>
</field>
</record>
<record id="res_partner_nuts_action" model="ir.actions.act_window">
<field name="name">NUTS Items</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.nuts</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help">You must click at import wizard to populate NUTS items
in Odoo database in:
Sales > Configuration > Address Book > Localization > Import NUTS 2013</field>
</record>
<record model="ir.ui.view" id="view_res_partner_nuts_filter">
<field name="name">NUTS search filters</field>
<field name="model">res.partner.nuts</field>
<field name="arch" type="xml">
<search string="Search NUTS">
<field name="name"/>
<field name="country_id"/>
<field name="state_id"/>
<group expand="0" string="Group By">
<filter string="Country"
domain="[]"
context="{'group_by': 'country_id'}"/>
<filter string="Level"
domain="[]"
context="{'group_by': 'level'}"/>
</group>
</search>
</field>
</record>
<menuitem action="res_partner_nuts_action"
id="res_partner_nuts_menu"
name="NUTS Items"
parent="base.menu_localisation"
sequence="40"/>
</data>
</openerp>

78
base_location_nuts/views/res_partner_view.xml

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_partner_form_nuts">
<field name="name">Partner form with NUTS</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<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"
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"
class="oe_no_button"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('use_parent_address','=',True)]}"/>
</div>
</xpath>
<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"
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"
class="oe_no_button"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('use_parent_address','=',True)]}"/>
</div>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="view_res_partner_filter_nuts">
<field name="name">Partner search with NUTS</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_res_partner_filter"/>
<field name="arch" type="xml">
<field name="category_id" position="after">
<field name="region"/>
<field name="substate"/>
</field>
<filter string="Salesperson" position="after">
<filter string="Region"
domain="[]"
context="{'group_by': 'region'}"/>
<filter string="Substate"
domain="[]"
context="{'group_by': 'substate'}"/>
</filter>
</field>
</record>
</data>
</openerp>

6
base_location_nuts/wizard/__init__.py

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from . import nuts_import

205
base_location_nuts/wizard/nuts_import.py

@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from openerp import models, api, _
from openerp.exceptions import Warning
import requests
import re
import logging
from lxml import etree
from collections import OrderedDict
from pprint import pformat
logger = logging.getLogger(__name__)
class NutsImport(models.TransientModel):
_name = 'nuts.import'
_description = 'Import NUTS items from European RAMON service'
_parents = [False, False, False, False]
_countries = {
"BE": False,
"BG": False,
"CZ": False,
"DK": False,
"DE": False,
"EE": False,
"IE": False,
"GR": False, # EL
"ES": False,
"FR": False,
"HR": False,
"IT": False,
"CY": False,
"LV": False,
"LT": False,
"LU": False,
"HU": False,
"MT": False,
"NL": False,
"AT": False,
"PL": False,
"PT": False,
"RO": False,
"SI": False,
"SK": False,
"FI": False,
"SE": False,
"GB": False, # UK
}
_current_country = False
_map = OrderedDict([
('level', {
'xpath': '', 'attrib': 'idLevel',
'type': 'integer', 'required': True}),
('code', {
'xpath': './Label/LabelText[@language="ALL"]',
'type': 'string', 'required': True}),
('name', {
'xpath': './Label/LabelText[@language="EN"]',
'type': 'string', 'required': True}),
])
def _check_node(self, node):
if node.get('id') and node.get('idLevel'):
return True
return False
def _mapping(self, node):
item = {}
for k, v in self._map.iteritems():
field_xpath = v.get('xpath', '')
field_attrib = v.get('attrib', False)
field_type = v.get('type', 'string')
field_required = v.get('required', False)
value = ''
if field_xpath:
n = node.find(field_xpath)
else:
n = node
if n is not None:
if field_attrib:
value = n.get(field_attrib, '')
else:
value = n.text
if field_type == 'integer':
try:
value = int(value)
except:
value = 0
else:
logger.debug("xpath = '%s', not found" % field_xpath)
if field_required and not value:
raise Warning(
_('Value not found for mandatory field %s' % k))
item[k] = value
return item
def _download_nuts(self):
url_base = 'http://ec.europa.eu'
url_path = '/eurostat/ramon/nomenclatures/index.cfm'
url_params = {
'TargetUrl': 'ACT_OTH_CLS_DLD',
'StrNom': 'NUTS_2013',
'StrFormat': 'XML',
'StrLanguageCode': 'EN',
'StrLayoutCode': 'HIERARCHIC'
}
url = url_base + url_path + '?'
url += '&'.join([k + '=' + v for k, v in url_params.iteritems()])
logger.info('Starting to download %s' % url)
try:
res_request = requests.get(url)
except Exception, e:
raise Warning(
_('Got an error when trying to download the file: %s.') %
str(e))
if res_request.status_code != requests.codes.ok:
raise Warning(
_('Got an error %d when trying to download the file %s.')
% (res_request.status_code, url))
logger.info('Download successfully %d bytes' %
len(res_request.content))
# Workaround XML: Remove all characters before <?xml
pattern = re.compile(r'^.*<\?xml', re.DOTALL)
content_fixed = re.sub(pattern, '<?xml', res_request.content)
if not re.match(r'<\?xml', content_fixed):
raise Warning(_('Downloaded file is not a valid XML file'))
return content_fixed
@api.model
def _load_countries(self):
for k in self._countries.keys():
self._countries[k] = self.env['res.country'].search(
[('code', '=', k)])
# Workaround to translate some country codes:
# EL => GR (Greece)
# UK => GB (United Kingdom)
self._countries['EL'] = self._countries['GR']
self._countries['UK'] = self._countries['GB']
logger.info('_load_countries = %s' % pformat(self._countries))
@api.model
def state_mapping(self, data, node):
# Method to inherit and add state_id relation depending on country
level = data.get('level', 0)
code = data.get('code', '')
if level == 1:
self._current_country = self._countries[code]
return {
'country_id': self._current_country.id,
}
@api.model
def create_or_update_nuts(self, node):
if not self._check_node(node):
return False
nuts_model = self.env['res.partner.nuts']
data = self._mapping(node)
data.update(self.state_mapping(data, node))
level = data.get('level', 0)
if level >= 2 and level <= 5:
data['parent_id'] = self._parents[level - 2]
nuts = nuts_model.search([('level', '=', data['level']),
('code', '=', data['code'])])
if nuts:
nuts.write(data)
else:
nuts = nuts_model.create(data)
if level >= 1 and level <= 4:
self._parents[level - 1] = nuts.id
return nuts
@api.one
def run_import(self):
nuts_model = self.env['res.partner.nuts'].\
with_context(defer_parent_store_computation=True)
self._load_countries()
# All current NUTS (for available countries),
# delete if not found above
nuts_to_delete = nuts_model.search(
[('country_id', 'in', [x.id for x in self._countries.values()])])
# Download NUTS in english, create or update
logger.info('Import NUTS 2013 English')
xmlcontent = self._download_nuts()
dom = etree.fromstring(xmlcontent)
for node in dom.iter('Item'):
logger.info('Reading level=%s, id=%s' %
(node.get('idLevel', 'N/A'),
node.get('id', 'N/A')))
nuts = self.create_or_update_nuts(node)
if nuts and nuts in nuts_to_delete:
nuts_to_delete -= nuts
# Delete obsolete NUTS
if nuts_to_delete:
logger.info('%d NUTS entries deleted' % len(nuts_to_delete))
nuts_to_delete.unlink()
logger.info(
'The wizard to create NUTS entries from RAMON '
'has been successfully completed.')
return True

51
base_location_nuts/wizard/nuts_import_view.xml

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="nuts_import_form" model="ir.ui.view">
<field name="name">NUTS import</field>
<field name="model">nuts.import</field>
<field name="arch" type="xml">
<form string="Import NUTS 2013 from RAMON">
<div>
This wizard will download the lastest version of
NUTS 2013 from Europe RAMON metadata service.
Updating or creating new NUTS entries if not
found already in the system, and DELETING MISSING
ENTRIES from new downloaded file.
</div>
<footer>
<button name="run_import" type="object"
class="oe_highlight" string="Import"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<record id="nuts_import_action" model="ir.actions.act_window">
<field name="name">Import NUTS 2013 from RAMON</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">nuts.import</field>
<field name="view_id" ref="nuts_import_form"/>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem action="nuts_import_action"
id="nuts_import_menu"
name="Import NUTS 2013"
parent="base.menu_localisation"
sequence="45"/>
<record id="config_wizard_nuts" model="ir.actions.todo">
<field name="name">Import NUTS 2013 from RAMON</field>
<field name="note">You can import NUTS from RAMON european service.</field>
<field name="action_id" ref="nuts_import_action"/>
<field name="sequence">20</field>
<field name="type">automatic</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save