diff --git a/CHANGELOG b/CHANGELOG
index 7d72077091..07c0f295e4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,5 @@
+* Add zip
+
Version 3.2.0 - 2014-04-21
* Bug fixes (see mercurial logs for details)
diff --git a/__init__.py b/__init__.py
index 1a180eedca..55eb99c86f 100644
--- a/__init__.py
+++ b/__init__.py
@@ -9,4 +9,5 @@ def register():
Pool.register(
Country,
Subdivision,
+ Zip,
module='country', type_='model')
diff --git a/country.py b/country.py
index d499226059..25eef8c5c1 100644
--- a/country.py
+++ b/country.py
@@ -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'))
diff --git a/country.xml b/country.xml
index 16da48cad2..7a8f267a22 100644
--- a/country.xml
+++ b/country.xml
@@ -46,6 +46,39 @@ this repository contains the full copyright notices and license terms. -->
subdivision_tree
+
+ country.zip
+ form
+ zip_form
+
+
+ country.zip
+ tree
+ zip_list
+
+
+
+ Zip
+ country.zip
+ [('country', 'in', Eval('active_ids'))]
+
+
+
+
+
+
+
+
+
+
+
+
+ form_relate
+ country.country,-1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/index.rst b/doc/index.rst
index e2a71eb272..6a70403d0b 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -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.
diff --git a/scripts/trytond_import_zip b/scripts/trytond_import_zip
new file mode 100755
index 0000000000..1954904da3
--- /dev/null
+++ b/scripts/trytond_import_zip
@@ -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)
diff --git a/setup.py b/setup.py
index a7bb6cf801..fb93f71f47 100644
--- a/setup.py
+++ b/setup.py
@@ -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]
diff --git a/view/zip_form.xml b/view/zip_form.xml
new file mode 100644
index 0000000000..e3819ab805
--- /dev/null
+++ b/view/zip_form.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/view/zip_list.xml b/view/zip_list.xml
new file mode 100644
index 0000000000..9d125b18b2
--- /dev/null
+++ b/view/zip_list.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+