Antonio Espinosa
10 years ago
committed by
Andrii Skrypka
14 changed files with 876 additions and 0 deletions
-
91base_location_nuts/README.rst
-
7base_location_nuts/__init__.py
-
42base_location_nuts/__openerp__.py
-
220base_location_nuts/i18n/es.po
-
7base_location_nuts/models/__init__.py
-
61base_location_nuts/models/res_partner.py
-
30base_location_nuts/models/res_partner_nuts.py
-
2base_location_nuts/security/ir.model.access.csv
-
BINbase_location_nuts/static/description/icon.png
-
76base_location_nuts/views/res_partner_nuts_view.xml
-
78base_location_nuts/views/res_partner_view.xml
-
6base_location_nuts/wizard/__init__.py
-
205base_location_nuts/wizard/nuts_import.py
-
51base_location_nuts/wizard/nuts_import_view.xml
@ -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. |
@ -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 |
@ -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, |
||||
|
} |
@ -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" |
||||
|
|
@ -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 |
@ -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 |
@ -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) |
@ -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 |
After Width: 128 | Height: 128 | Size: 7.7 KiB |
@ -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> |
@ -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> |
@ -0,0 +1,6 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# For copyright and license notices, see __openerp__.py file in root directory |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import nuts_import |
@ -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 |
@ -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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue