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