Merge lp:~akretion-team/partner-contact-management/base-location-geonames-import into lp:~partner-contact-core-editors/partner-contact-management/7.0

Proposed by Alexis de Lattre on 2014-04-07
Status: Needs review
Proposed branch: lp:~akretion-team/partner-contact-management/base-location-geonames-import
Merge into: lp:~partner-contact-core-editors/partner-contact-management/7.0
Diff against target: 437 lines (+400/-0)
7 files modified
base_location_geonames_import/__init__.py (+23/-0)
base_location_geonames_import/__openerp__.py (+47/-0)
base_location_geonames_import/i18n/base_location_geonames_import.pot (+68/-0)
base_location_geonames_import/i18n/fr.po (+68/-0)
base_location_geonames_import/wizard/__init__.py (+23/-0)
base_location_geonames_import/wizard/geonames_import.py (+127/-0)
base_location_geonames_import/wizard/geonames_import_view.xml (+44/-0)
To merge this branch: bzr merge lp:~akretion-team/partner-contact-management/base-location-geonames-import
Reviewer Review Type Date Requested Status
Lorenzo Battistini - Agile BG (community) Resubmit on 2014-07-23
Nicolas Bessi - Camptocamp (community) 2014-04-07 Needs Fixing on 2014-04-11
Review via email: mp+214564@code.launchpad.net

Description of the change

Add module base_location_geonames_import ; this module adds a wizard to import better zip entries from Geonames (http://download.geonames.org/export/zip/).

Nicolas Bessi suggested on twitter that it should be part of the geospacial addons. But, after thinking about it, my opinion is that this module would be better here, because users of the "base_location" module would have a higher chance of finding this module here than in the geospacial addons.

To post a comment you must log in.
40. By Alexis de Lattre on 2014-04-07

Allow to skip entries in the _prepare method.

Hello thanks for the patch.

Is there a good reason not to merge it here: https://launchpad.net/geospatial-addons ?
Some tests would also be a nice addition.

review: Needs Information
Alexis de Lattre (alexis-via) wrote :

@Nicolas

As I said in my comment, I think that it's better for the module "base_location_geonames_import" to sit right next to the "base_location" module, so that it's easier to find for users of the "base_location" module. We could even imagine that the wizard that is provided by "base_location_geonames_import" could be provided inside "base_location" and not in a separate module.

Oups I missed that.

Actually, I do not agrees with you, but I won't argue too long on this as for me the branch organisation problem is more deep. Let's see what other think about it.

Some comments Belows:
Some PEP8 in manifest:

328 + _("The content of the file doesn't correspond to the "
329 + "selected country."))

I will add row value and country info it will be more easy for support.

A question with :
+ if res_request.status_code != requests.codes.ok:
349 + raise orm.except_orm(
350 + _('Error:'),
351 + _('Got an error %d when trying to download the file %s.')
352 + % (res_request.status_code, url))

It's been a long time since I used geonames, if I'm correct in case of wrong country it returns 404 that right. If it the case I'm ok with this else we may have to treat a 200 with a message

+ if bzip_ids_to_delete:
356 + bzip_obj.unlink(cr, uid, bzip_ids_to_delete, context=context)
357 + logger.info(
358 + '%d better zip entries deleted for country %s'
359 + % (len(bzip_ids_to_delete), wizard.country_id.name))

This is a quite a direct approach, I agree create, update, unactivate is quite not easy to put in place, but as other development can depends on base location model there should at least be a Big warning in manifest.

Also it would be a good idea to add a small lock to ensure atomicity during the import.
A query "for update no wait" a the begining of transaction would be nice.

Tests are also missing. Without depending on the geoname services having a local excrept to base the tests would be great.

Thanks for the contributions, keep up the good work.

Regards

Nicolas

review: Needs Fixing
41. By Alexis de Lattre on 2014-04-11

Insist on the fact that the wizard deletes current better zip entries in the module description and in the wizard itself.
Better error message when the country code inside the file is wrong.

42. By Alexis de Lattre on 2014-04-11

Add a FOR UPDATE NOWAIT at the beginning of the transaction.

Alexis de Lattre (alexis-via) wrote :

@Nicolas:

I confirm that it returns 404 if you try to download a wrong country.

I have taken into account your other remarks in my last commits (unless the tests ; I don't have experience in this). I am not sure I fully understand the benefit of the FOR UPDATE NOWAIT in this particular case... at least I hope I implemented it as you wanted.

Hello,

Thank for the fixes.
The "UPDATE NO WAIT" will lock the selected rows at postgres database level.
It will avoid a process using the base_location data to alter flushed entries.
It will also avoiding having many concurrent instance of the wizard running on the same rows.
In this case I wonder if we may not want to put a lock on the whole table has we add new entries.

For the test I will see ifI can provide some but I'm in holiday next week, so it have to wait a little.

Regards

Nicolas

43. By Alexis de Lattre on 2014-06-02

Remove France-specific code ; moved to new module l10n_fr_base_location_geonames_import on lp:openerp-french-localization

44. By Alexis de Lattre on 2014-06-11

[MERGE] merge with trunk revno 40.

Hello Alexis, many thanks for the module.

What do you think about creating the res.country.state records if they don't exist, before mapping them in the 'states' dictionary?

The current version is supposed to correctly work with states if you first create states data by modules like l10n_fr_state.
But if base_location_geonames_import also imported states data from geonames (creating records if they don't exist yet) we would not need an extra module just to create states data.

This project is now hosted on https://github.com/OCA/partner-contact. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

review: Resubmit

Unmerged revisions

44. By Alexis de Lattre on 2014-06-11

[MERGE] merge with trunk revno 40.

43. By Alexis de Lattre on 2014-06-02

Remove France-specific code ; moved to new module l10n_fr_base_location_geonames_import on lp:openerp-french-localization

42. By Alexis de Lattre on 2014-04-11

Add a FOR UPDATE NOWAIT at the beginning of the transaction.

41. By Alexis de Lattre on 2014-04-11

Insist on the fact that the wizard deletes current better zip entries in the module description and in the wizard itself.
Better error message when the country code inside the file is wrong.

40. By Alexis de Lattre on 2014-04-07

Allow to skip entries in the _prepare method.

39. By Alexis de Lattre on 2014-04-07

Add support for states (if states are already present in res.country.state).
Add POT file and FR translation.

38. By Alexis de Lattre on 2014-03-30

Add module base_location_geonames_import

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'base_location_geonames_import'
2=== added file 'base_location_geonames_import/__init__.py'
3--- base_location_geonames_import/__init__.py 1970-01-01 00:00:00 +0000
4+++ base_location_geonames_import/__init__.py 2014-06-11 06:33:26 +0000
5@@ -0,0 +1,23 @@
6+# -*- encoding: utf-8 -*-
7+##############################################################################
8+#
9+# Base Location Geonames Import module for OpenERP
10+# Copyright (C) 2014 Akretion (http://www.akretion.com)
11+# @author Alexis de Lattre <alexis.delattre@akretion.com>
12+#
13+# This program is free software: you can redistribute it and/or modify
14+# it under the terms of the GNU Affero General Public License as
15+# published by the Free Software Foundation, either version 3 of the
16+# License, or (at your option) any later version.
17+#
18+# This program is distributed in the hope that it will be useful,
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU Affero General Public License for more details.
22+#
23+# You should have received a copy of the GNU Affero General Public License
24+# along with this program. If not, see <http://www.gnu.org/licenses/>.
25+#
26+##############################################################################
27+
28+from . import wizard
29
30=== added file 'base_location_geonames_import/__openerp__.py'
31--- base_location_geonames_import/__openerp__.py 1970-01-01 00:00:00 +0000
32+++ base_location_geonames_import/__openerp__.py 2014-06-11 06:33:26 +0000
33@@ -0,0 +1,47 @@
34+# -*- encoding: utf-8 -*-
35+##############################################################################
36+#
37+# Base Location Geonames Import module for OpenERP
38+# Copyright (C) 2014 Akretion (http://www.akretion.com)
39+# @author Alexis de Lattre <alexis.delattre@akretion.com>
40+#
41+# This program is free software: you can redistribute it and/or modify
42+# it under the terms of the GNU Affero General Public License as
43+# published by the Free Software Foundation, either version 3 of the
44+# License, or (at your option) any later version.
45+#
46+# This program is distributed in the hope that it will be useful,
47+# but WITHOUT ANY WARRANTY; without even the implied warranty of
48+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49+# GNU Affero General Public License for more details.
50+#
51+# You should have received a copy of the GNU Affero General Public License
52+# along with this program. If not, see <http://www.gnu.org/licenses/>.
53+#
54+##############################################################################
55+
56+
57+{
58+ 'name': 'Base Location Geonames Import',
59+ 'version': '0.1',
60+ 'category': 'Extra Tools',
61+ 'license': 'AGPL-3',
62+ 'summary': 'Import better zip entries from Geonames',
63+ 'description': """
64+Base Location Geonames Import
65+=============================
66+
67+This module adds a wizard to import better zip entries from Geonames (http://download.geonames.org/export/zip/). When you start the wizard, it will ask you to select a country ; then, for the selected country, it will delete all the current better zip entries, download the latest version of the list of cities from geonames.org and create new better zip entries.
68+
69+Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for any help or question about this module.
70+ """,
71+ 'author': 'Akretion',
72+ 'website': 'http://www.akretion.com',
73+ 'depends': ['base_location'],
74+ 'external_dependencies': {'python': ['requests', 'unicodecsv']},
75+ 'data': [
76+ 'wizard/geonames_import_view.xml',
77+ ],
78+ 'installable': True,
79+ 'active': False,
80+}
81
82=== added directory 'base_location_geonames_import/i18n'
83=== added file 'base_location_geonames_import/i18n/base_location_geonames_import.pot'
84--- base_location_geonames_import/i18n/base_location_geonames_import.pot 1970-01-01 00:00:00 +0000
85+++ base_location_geonames_import/i18n/base_location_geonames_import.pot 2014-06-11 06:33:26 +0000
86@@ -0,0 +1,68 @@
87+# Translation of OpenERP Server.
88+# This file contains the translation of the following modules:
89+# * base_location_geonames_import
90+#
91+msgid ""
92+msgstr ""
93+"Project-Id-Version: OpenERP Server 7.0\n"
94+"Report-Msgid-Bugs-To: \n"
95+"POT-Creation-Date: 2014-04-11 20:55+0000\n"
96+"PO-Revision-Date: 2014-04-11 20:55+0000\n"
97+"Last-Translator: <>\n"
98+"Language-Team: \n"
99+"MIME-Version: 1.0\n"
100+"Content-Type: text/plain; charset=UTF-8\n"
101+"Content-Transfer-Encoding: \n"
102+"Plural-Forms: \n"
103+
104+#. module: base_location_geonames_import
105+#: view:better.zip.geonames.import:0
106+msgid "Cancel"
107+msgstr ""
108+
109+#. module: base_location_geonames_import
110+#: field:better.zip.geonames.import,country_id:0
111+msgid "Country"
112+msgstr ""
113+
114+#. module: base_location_geonames_import
115+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:66
116+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:90
117+#, python-format
118+msgid "Error:"
119+msgstr ""
120+
121+#. module: base_location_geonames_import
122+#: view:better.zip.geonames.import:0
123+msgid "For the country selected above, this wizard will DELETE ALL THE CURRENT BETTER ZIP ENTRIES, download the latest version of the list of cities from geonames.org and create new better zip entries."
124+msgstr ""
125+
126+#. module: base_location_geonames_import
127+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:91
128+#, python-format
129+msgid "Got an error %d when trying to download the file %s."
130+msgstr ""
131+
132+#. module: base_location_geonames_import
133+#: view:better.zip.geonames.import:0
134+msgid "Import"
135+msgstr ""
136+
137+#. module: base_location_geonames_import
138+#: model:ir.model,name:base_location_geonames_import.model_better_zip_geonames_import
139+msgid "Import Better Zip from Geonames"
140+msgstr ""
141+
142+#. module: base_location_geonames_import
143+#: view:better.zip.geonames.import:0
144+#: model:ir.actions.act_window,name:base_location_geonames_import.better_zip_geonames_import_action
145+#: model:ir.ui.menu,name:base_location_geonames_import.better_zip_geonames_import_menu
146+msgid "Import Geonames"
147+msgstr ""
148+
149+#. module: base_location_geonames_import
150+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:67
151+#, python-format
152+msgid "The country code inside the file (%s) doesn't correspond to the selected country (%s)."
153+msgstr ""
154+
155
156=== added file 'base_location_geonames_import/i18n/fr.po'
157--- base_location_geonames_import/i18n/fr.po 1970-01-01 00:00:00 +0000
158+++ base_location_geonames_import/i18n/fr.po 2014-06-11 06:33:26 +0000
159@@ -0,0 +1,68 @@
160+# Translation of OpenERP Server.
161+# This file contains the translation of the following modules:
162+# * base_location_geonames_import
163+#
164+msgid ""
165+msgstr ""
166+"Project-Id-Version: OpenERP Server 7.0\n"
167+"Report-Msgid-Bugs-To: \n"
168+"POT-Creation-Date: 2014-04-11 20:56+0000\n"
169+"PO-Revision-Date: 2014-04-11 20:56+0000\n"
170+"Last-Translator: <>\n"
171+"Language-Team: \n"
172+"MIME-Version: 1.0\n"
173+"Content-Type: text/plain; charset=UTF-8\n"
174+"Content-Transfer-Encoding: \n"
175+"Plural-Forms: \n"
176+
177+#. module: base_location_geonames_import
178+#: view:better.zip.geonames.import:0
179+msgid "Cancel"
180+msgstr "Annuler"
181+
182+#. module: base_location_geonames_import
183+#: field:better.zip.geonames.import,country_id:0
184+msgid "Country"
185+msgstr "Pays"
186+
187+#. module: base_location_geonames_import
188+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:66
189+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:90
190+#, python-format
191+msgid "Error:"
192+msgstr "Erreur :"
193+
194+#. module: base_location_geonames_import
195+#: view:better.zip.geonames.import:0
196+msgid "For the country selected above, this wizard will DELETE ALL THE CURRENT BETTER ZIP ENTRIES, download the latest version of the list of cities from geonames.org and create new better zip entries."
197+msgstr "Pour le pays sélectionné ci-dessus, cet assistant va SUPPRIMER TOUTES LES ENTREES BETTER ZIP, télécharger la dernière version de la liste des villes depuis geonames.org et créer de nouveaux enregistrements better zip."
198+
199+#. module: base_location_geonames_import
200+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:91
201+#, python-format
202+msgid "Got an error %d when trying to download the file %s."
203+msgstr "Erreur %d reçue suite à la tentative de téléchargement du fichier %s."
204+
205+#. module: base_location_geonames_import
206+#: view:better.zip.geonames.import:0
207+msgid "Import"
208+msgstr "Importer"
209+
210+#. module: base_location_geonames_import
211+#: model:ir.model,name:base_location_geonames_import.model_better_zip_geonames_import
212+msgid "Import Better Zip from Geonames"
213+msgstr "Import Better Zip from Geonames"
214+
215+#. module: base_location_geonames_import
216+#: view:better.zip.geonames.import:0
217+#: model:ir.actions.act_window,name:base_location_geonames_import.better_zip_geonames_import_action
218+#: model:ir.ui.menu,name:base_location_geonames_import.better_zip_geonames_import_menu
219+msgid "Import Geonames"
220+msgstr "Importer Geonames"
221+
222+#. module: base_location_geonames_import
223+#: code:addons/base_location_geonames_import/wizard/geonames_import.py:67
224+#, python-format
225+msgid "The country code inside the file (%s) doesn't correspond to the selected country (%s)."
226+msgstr "Le code pays utilisé à l'intérieur du fichier (%s) ne correspond pas au pays sélectionné (%s)."
227+
228
229=== added directory 'base_location_geonames_import/wizard'
230=== added file 'base_location_geonames_import/wizard/__init__.py'
231--- base_location_geonames_import/wizard/__init__.py 1970-01-01 00:00:00 +0000
232+++ base_location_geonames_import/wizard/__init__.py 2014-06-11 06:33:26 +0000
233@@ -0,0 +1,23 @@
234+# -*- encoding: utf-8 -*-
235+##############################################################################
236+#
237+# Base Location Geonames Import module for OpenERP
238+# Copyright (C) 2014 Akretion (http://www.akretion.com)
239+# @author Alexis de Lattre <alexis.delattre@akretion.com>
240+#
241+# This program is free software: you can redistribute it and/or modify
242+# it under the terms of the GNU Affero General Public License as
243+# published by the Free Software Foundation, either version 3 of the
244+# License, or (at your option) any later version.
245+#
246+# This program is distributed in the hope that it will be useful,
247+# but WITHOUT ANY WARRANTY; without even the implied warranty of
248+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
249+# GNU Affero General Public License for more details.
250+#
251+# You should have received a copy of the GNU Affero General Public License
252+# along with this program. If not, see <http://www.gnu.org/licenses/>.
253+#
254+##############################################################################
255+
256+from . import geonames_import
257
258=== added file 'base_location_geonames_import/wizard/geonames_import.py'
259--- base_location_geonames_import/wizard/geonames_import.py 1970-01-01 00:00:00 +0000
260+++ base_location_geonames_import/wizard/geonames_import.py 2014-06-11 06:33:26 +0000
261@@ -0,0 +1,127 @@
262+# -*- encoding: utf-8 -*-
263+##############################################################################
264+#
265+# Base Location Geonames Import module for OpenERP
266+# Copyright (C) 2014 Akretion (http://www.akretion.com)
267+# @author Alexis de Lattre <alexis.delattre@akretion.com>
268+#
269+# This program is free software: you can redistribute it and/or modify
270+# it under the terms of the GNU Affero General Public License as
271+# published by the Free Software Foundation, either version 3 of the
272+# License, or (at your option) any later version.
273+#
274+# This program is distributed in the hope that it will be useful,
275+# but WITHOUT ANY WARRANTY; without even the implied warranty of
276+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
277+# GNU Affero General Public License for more details.
278+#
279+# You should have received a copy of the GNU Affero General Public License
280+# along with this program. If not, see <http://www.gnu.org/licenses/>.
281+#
282+##############################################################################
283+
284+from openerp.osv import orm, fields
285+from openerp.tools.translate import _
286+import requests
287+import tempfile
288+import StringIO
289+import unicodecsv
290+import zipfile
291+import os
292+import logging
293+
294+logger = logging.getLogger(__name__)
295+
296+
297+class better_zip_geonames_import(orm.TransientModel):
298+ _name = 'better.zip.geonames.import'
299+ _description = 'Import Better Zip from Geonames'
300+
301+ _columns = {
302+ 'country_id': fields.many2one('res.country', 'Country', required=True),
303+ }
304+
305+ def _prepare_better_zip(
306+ self, cr, uid, row, country_id, states, context=None):
307+ '''This function is designed to be inherited'''
308+ state_id = False
309+ if states and row[4] and row[4] in states:
310+ state_id = states[row[4].upper()]
311+ vals = {
312+ 'name': row[1],
313+ 'city': row[2],
314+ 'state_id': state_id,
315+ 'country_id': country_id,
316+ }
317+ return vals
318+
319+ def create_better_zip(
320+ self, cr, uid, row, country_id, country_code, states,
321+ context=None):
322+ bzip_id = False
323+ if row[0] != country_code:
324+ raise orm.except_orm(
325+ _('Error:'),
326+ _("The country code inside the file (%s) doesn't "
327+ "correspond to the selected country (%s).")
328+ % (row[0], country_code))
329+ logger.debug('ZIP = %s - City = %s' % (row[1], row[2]))
330+ if row[1] and row[2]:
331+ vals = self._prepare_better_zip(
332+ cr, uid, row, country_id, states, context=context)
333+ if vals:
334+ bzip_id = self.pool['res.better.zip'].create(
335+ cr, uid, vals, context=context)
336+ return bzip_id
337+
338+ def run_import(self, cr, uid, ids, context=None):
339+ assert len(ids) == 1, 'Only one ID for the better zip import wizard'
340+ bzip_obj = self.pool['res.better.zip']
341+ wizard = self.browse(cr, uid, ids[0], context=context)
342+ country_id = wizard.country_id.id
343+ country_code = wizard.country_id.code.upper()
344+ url = 'http://download.geonames.org/export/zip/%s.zip' % country_code
345+ logger.info('Starting to download %s' % url)
346+ res_request = requests.get(url)
347+ if res_request.status_code != requests.codes.ok:
348+ raise orm.except_orm(
349+ _('Error:'),
350+ _('Got an error %d when trying to download the file %s.')
351+ % (res_request.status_code, url))
352+ bzip_ids_to_delete = bzip_obj.search(
353+ cr, uid, [('country_id', '=', country_id)], context=context)
354+ if bzip_ids_to_delete:
355+ cr.execute('SELECT id FROM res_better_zip WHERE id in %s '
356+ 'FOR UPDATE NOWAIT', (tuple(bzip_ids_to_delete), ))
357+ bzip_obj.unlink(cr, uid, bzip_ids_to_delete, context=context)
358+ logger.info(
359+ '%d better zip entries deleted for country %s'
360+ % (len(bzip_ids_to_delete), wizard.country_id.name))
361+ state_ids = self.pool['res.country.state'].search(
362+ cr, uid, [('country_id', '=', country_id)], context=context)
363+ states = {}
364+ # key = code of the state ; value = ID of the state in OpenERP
365+ if state_ids:
366+ states_r = self.pool['res.country.state'].read(
367+ cr, uid, state_ids, ['code', 'country_id'], context=context)
368+ for state in states_r:
369+ states[state['code'].upper()] = state['id']
370+ f_geonames = zipfile.ZipFile(StringIO.StringIO(res_request.content))
371+ tempdir = tempfile.mkdtemp(prefix='openerp')
372+ f_geonames.extract('%s.txt' % country_code, tempdir)
373+ logger.info('The geonames zipfile has been decompressed')
374+ data_file = open(os.path.join(tempdir, '%s.txt' % country_code), 'r')
375+ data_file.seek(0)
376+ logger.info(
377+ 'Starting to create the better zip entries %s state information'
378+ % (states and 'with' or 'without'))
379+ for row in unicodecsv.reader(
380+ data_file, encoding='utf-8', delimiter=' '):
381+ self.create_better_zip(
382+ cr, uid, row, country_id, country_code, states,
383+ context=context)
384+ data_file.close()
385+ logger.info(
386+ 'The wizard to create better zip entries from geonames '
387+ 'has been successfully completed.')
388+ return True
389
390=== added file 'base_location_geonames_import/wizard/geonames_import_view.xml'
391--- base_location_geonames_import/wizard/geonames_import_view.xml 1970-01-01 00:00:00 +0000
392+++ base_location_geonames_import/wizard/geonames_import_view.xml 2014-06-11 06:33:26 +0000
393@@ -0,0 +1,44 @@
394+<?xml version="1.0" encoding="utf-8"?>
395+<!--
396+ Copyright (C) 2014 Akretion (http://www.akretion.com/)
397+ @author: Alexis de Lattre <alexis.delattre@akretion.com>
398+ The licence is in the file __openerp__.py
399+-->
400+
401+<openerp>
402+<data>
403+
404+<record id="better_zip_geonames_import_form" model="ir.ui.view">
405+ <field name="name">asterisk.server.company</field>
406+ <field name="model">better.zip.geonames.import</field>
407+ <field name="arch" type="xml">
408+ <form string="Import Geonames" version="7.0">
409+ <group name="main">
410+ <field name="country_id"/>
411+ <label string="For the country selected above, this wizard will DELETE ALL THE CURRENT BETTER ZIP ENTRIES, download the latest version of the list of cities from geonames.org and create new better zip entries."
412+ colspan="2" name="import-help"/>
413+ </group>
414+ <footer>
415+ <button name="run_import" type="object"
416+ class="oe_highlight" string="Import"/>
417+ <button special="cancel" string="Cancel" class="oe_link"/>
418+ </footer>
419+ </form>
420+ </field>
421+</record>
422+
423+<record id="better_zip_geonames_import_action" model="ir.actions.act_window">
424+ <field name="name">Import Geonames</field>
425+ <field name="res_model">better.zip.geonames.import</field>
426+ <field name="view_type">form</field>
427+ <field name="view_mode">form</field>
428+ <field name="target">new</field>
429+</record>
430+
431+<menuitem id="better_zip_geonames_import_menu"
432+ action="better_zip_geonames_import_action"
433+ parent="base.menu_localisation"
434+ sequence="50"/>
435+
436+</data>
437+</openerp>