Add Zip
issue4004 review9441002
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
* Add zip
|
||||
|
||||
Version 3.2.0 - 2014-04-21
|
||||
* Bug fixes (see mercurial logs for details)
|
||||
|
||||
|
||||
@@ -9,4 +9,5 @@ def register():
|
||||
Pool.register(
|
||||
Country,
|
||||
Subdivision,
|
||||
Zip,
|
||||
module='country', type_='model')
|
||||
|
||||
+21
-1
@@ -1,8 +1,9 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.pyson import Eval
|
||||
|
||||
__all__ = ['Country', 'Subdivision']
|
||||
__all__ = ['Country', 'Subdivision', 'Zip']
|
||||
|
||||
|
||||
class Country(ModelSQL, ModelView):
|
||||
@@ -194,3 +195,22 @@ class Subdivision(ModelSQL, ModelView):
|
||||
values['code'] = values['code'].upper()
|
||||
args.extend((subdivisions, values))
|
||||
super(Subdivision, cls).write(*args)
|
||||
|
||||
|
||||
class Zip(ModelSQL, ModelView):
|
||||
"Zip"
|
||||
__name__ = 'country.zip'
|
||||
country = fields.Many2One('country.country', 'Country', required=True,
|
||||
select=True, ondelete='CASCADE')
|
||||
subdivision = fields.Many2One('country.subdivision', 'Subdivision',
|
||||
select=True, ondelete='CASCADE',
|
||||
domain=[('country', '=', Eval('country', -1))],
|
||||
depends=['country'])
|
||||
zip = fields.Char('Zip')
|
||||
city = fields.Char('City')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(Zip, cls).__setup__()
|
||||
cls._order.insert(0, ('country', 'ASC'))
|
||||
cls._order.insert(0, ('zip', 'ASC'))
|
||||
|
||||
+49
@@ -46,6 +46,39 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="name">subdivision_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="zip_view_form">
|
||||
<field name="model">country.zip</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">zip_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="zip_view_list">
|
||||
<field name="model">country.zip</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">zip_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_zip_form">
|
||||
<field name="name">Zip</field>
|
||||
<field name="res_model">country.zip</field>
|
||||
<field name="domain">[('country', 'in', Eval('active_ids'))]</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_zip_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="zip_view_list"/>
|
||||
<field name="act_window" ref="act_zip_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_zip_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="zip_view_form"/>
|
||||
<field name="act_window" ref="act_zip_form"/>
|
||||
</record>
|
||||
<record model="ir.action.keyword"
|
||||
id="act_zip_form_keyword1">
|
||||
<field name="keyword">form_relate</field>
|
||||
<field name="model">country.country,-1</field>
|
||||
<field name="action" ref="act_zip_form"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
<!--
|
||||
@@ -36345,5 +36378,21 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_country_zip">
|
||||
<field name="model" search="[('model', '=', 'country.zip')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_country_zip_admin">
|
||||
<field name="model" search="[('model', '=', 'country.zip')]"/>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
|
||||
@@ -20,3 +20,9 @@ Subdivision
|
||||
|
||||
A subdivision is defined by a name, a code and a type (e.g, Capital
|
||||
City, Province, Emirate, etc)
|
||||
|
||||
|
||||
Zip
|
||||
***
|
||||
|
||||
A zip links a zip code of a country to a city.
|
||||
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
import urllib2
|
||||
import zipfile
|
||||
import csv
|
||||
import sys
|
||||
from io import BytesIO
|
||||
from argparse import ArgumentParser
|
||||
|
||||
try:
|
||||
from progressbar import ProgressBar, Bar, ETA, SimpleProgress
|
||||
except ImportError:
|
||||
ProgressBar = None
|
||||
|
||||
from proteus import Model, config
|
||||
|
||||
|
||||
def clean(code):
|
||||
sys.stderr.write('Cleaning')
|
||||
Zip = Model.get('country.zip')
|
||||
Zip._proxy.delete(
|
||||
[z.id for z in Zip.find([('country.code', '=', code)])], {})
|
||||
print >> sys.stderr, '.'
|
||||
|
||||
|
||||
def fetch(code):
|
||||
sys.stderr.write('Fetching')
|
||||
url = 'http://download.geonames.org/export/zip/%s.zip' % code
|
||||
responce = urllib2.urlopen(url)
|
||||
data = responce.read()
|
||||
with zipfile.ZipFile(BytesIO(data)) as zf:
|
||||
data = zf.read('%s.txt' % code)
|
||||
print >> sys.stderr, '.'
|
||||
return data
|
||||
|
||||
|
||||
def import_(data):
|
||||
Zip = Model.get('country.zip')
|
||||
Country = Model.get('country.country')
|
||||
Subdivision = Model.get('country.subdivision')
|
||||
print >> sys.stderr, 'Importing'
|
||||
|
||||
def get_country(code):
|
||||
country = countries.get(code)
|
||||
if not country:
|
||||
country, = Country.find([('code', '=', code)])
|
||||
countries[code] = country
|
||||
return country
|
||||
countries = {}
|
||||
|
||||
def get_subdivision(country, code):
|
||||
code = '%s-%s' % (country, code)
|
||||
subdivision = subdivisions.get(code)
|
||||
if not subdivision:
|
||||
try:
|
||||
subdivision, = Subdivision.find([('code', '=', code)])
|
||||
except ValueError:
|
||||
return
|
||||
subdivisions[code] = subdivision
|
||||
return subdivision
|
||||
subdivisions = {}
|
||||
|
||||
if ProgressBar:
|
||||
pbar = ProgressBar(
|
||||
widgets=[SimpleProgress(), Bar(), ETA()])
|
||||
else:
|
||||
pbar = iter
|
||||
for row in pbar(list(csv.DictReader(BytesIO(data),
|
||||
fieldnames=_fieldnames, delimiter='\t'))):
|
||||
country = get_country(row['country'])
|
||||
subdivision = get_subdivision(row['country'], row['code1'])
|
||||
Zip(country=country, subdivision=subdivision, zip=row['postal'],
|
||||
city=row['place']).save()
|
||||
|
||||
_fieldnames = ['country', 'postal', 'place', 'name1', 'code1',
|
||||
'name2', 'code2', 'name3', 'code3', 'latitude', 'longitude', 'accuracy']
|
||||
|
||||
|
||||
def main(database, password, codes, config_file=None):
|
||||
config.set_trytond(database, password=password, config_file=config_file)
|
||||
|
||||
for code in codes:
|
||||
print >> sys.stderr, code
|
||||
code = code.upper()
|
||||
clean(code)
|
||||
import_(fetch(code))
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('-p', '--password', dest='password', default='admin',
|
||||
help='admin password (default: %(default)s)')
|
||||
parser.add_argument('-d', '--database', dest='database')
|
||||
parser.add_argument('-c', '--config', dest='config_file',
|
||||
help='the trytond config file')
|
||||
parser.add_argument('codes', nargs='+')
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.database:
|
||||
parser.error('Missing database')
|
||||
main(args.database, args.password, args.codes, args.config_file)
|
||||
@@ -65,6 +65,7 @@ setup(name=name,
|
||||
'trytond.modules.country': (info.get('xml', [])
|
||||
+ ['tryton.cfg', 'view/*.xml', 'locale/*.po']),
|
||||
},
|
||||
scripts=['scripts/trytond_import_zip'],
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -90,6 +91,9 @@ setup(name=name,
|
||||
],
|
||||
license='GPL-3',
|
||||
install_requires=requires,
|
||||
extras_require={
|
||||
'GeoNames': [get_require_version('proteus')],
|
||||
},
|
||||
zip_safe=False,
|
||||
entry_points="""
|
||||
[trytond.modules]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<form string="Zip">
|
||||
<label name="country"/>
|
||||
<field name="country"/>
|
||||
<label name="subdivision"/>
|
||||
<field name="subdivision"/>
|
||||
<label name="zip"/>
|
||||
<field name="zip"/>
|
||||
<label name="city"/>
|
||||
<field name="city"/>
|
||||
</form>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tree string="Zip">
|
||||
<field name="country"/>
|
||||
<field name="subdivision"/>
|
||||
<field name="zip"/>
|
||||
<field name="city"/>
|
||||
</tree>
|
||||
Reference in New Issue
Block a user