Browse Source

[FIX] base_location_geonames_import: Handle duplicated city names

If there are several cities with the same name in different states, previous code doesn't
handle correctly this situation.

We amend this storing in the cached dictionary both city name and state.

Includes a test for checking this specific condition, got from real data in US.

Fixes #749
14.0
Pedro M. Baeza 5 years ago
parent
commit
799b54896a
  1. 2
      base_location_geonames_import/__manifest__.py
  2. 35
      base_location_geonames_import/tests/test_base_location_geonames_import.py
  3. 30
      base_location_geonames_import/wizard/geonames_import.py

2
base_location_geonames_import/__manifest__.py

@ -8,7 +8,7 @@
{ {
'name': 'Base Location Geonames Import', 'name': 'Base Location Geonames Import',
'version': '12.0.1.0.0',
'version': '12.0.1.0.1',
'category': 'Partner Management', 'category': 'Partner Management',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Import zip entries from Geonames', 'summary': 'Import zip entries from Geonames',

35
base_location_geonames_import/tests/test_base_location_geonames_import.py

@ -1,4 +1,4 @@
# Copyright 2016 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2019 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.tests import common from odoo.tests import common
@ -109,3 +109,36 @@ class TestBaseLocationGeonamesImport(common.SavepointCase):
with a wrong country code""" with a wrong country code"""
with self.assertRaises(UserError): with self.assertRaises(UserError):
self.wrong_wizard.run_import() self.wrong_wizard.run_import()
def test_import_duplicated_city_name(self):
country = self.env.ref('base.us')
self.wizard.country_id = country.id
parsed_csv = [
['US', '95602', 'Auburn', ' California', 'CA', 'Placer', '61',
'38.9829', '-121.0944', '4'],
['US', '95603', 'Auburn', ' California', 'CA', 'Placer', '61',
'38.9115', '-121.08', '4'],
['US', '30011', 'Auburn', ' Georgia', 'GA', 'Barrow', '13',
'34.0191', '-83.8261', '4'],
]
self.wizard._process_csv(parsed_csv)
cities = self.env['res.city'].search([('name', '=', 'Auburn')])
self.assertEqual(len(cities), 2)
mapping = [
['California', '95602'],
['California', '95603'],
['Georgia', '30011'],
]
for state_name, zip_code in mapping:
zip_entry = self.env['res.city.zip'].search([
('city_id.country_id', '=', country.id),
('name', '=', zip_code),
])
state = self.env['res.country.state'].search([
('country_id', '=', country.id),
('name', '=', state_name),
])
self.assertEqual(
zip_entry.city_id.state_id, state,
"Incorrect state for %s %s" % (state_name, zip_code),
)

30
base_location_geonames_import/wizard/geonames_import.py

@ -1,10 +1,10 @@
# Copyright 2014-2016 Akretion (Alexis de Lattre # Copyright 2014-2016 Akretion (Alexis de Lattre
# <alexis.delattre@akretion.com>) # <alexis.delattre@akretion.com>)
# Copyright 2014 Lorenzo Battistini <lorenzo.battistini@agilebg.com> # Copyright 2014 Lorenzo Battistini <lorenzo.battistini@agilebg.com>
# Copyright 2016 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2017 Eficent Business and IT Consulting Services, S.L. # Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# <contact@eficent.com> # <contact@eficent.com>
# Copyright 2018 Aitor Bouzas <aitor.bouzas@adaptivecity.com> # Copyright 2018 Aitor Bouzas <aitor.bouzas@adaptivecity.com>
# Copyright 2016-2019 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models from odoo import _, api, fields, models
@ -168,26 +168,28 @@ class CityZipGeonamesImport(models.TransientModel):
for i, row in enumerate(parsed_csv): for i, row in enumerate(parsed_csv):
if max_import and i == max_import: if max_import and i == max_import:
break break
state_id = state_dict[row[self.code_row_index or 4]]
city = self.select_city( city = self.select_city(
row, self.country_id) if search_cities else False row, self.country_id) if search_cities else False
if not city: if not city:
state_id = state_dict[
row[self.code_row_index or 4]]
city_vals = self.prepare_city( city_vals = self.prepare_city(
row, self.country_id, state_id) row, self.country_id, state_id)
if city_vals not in city_vals_list: if city_vals not in city_vals_list:
city_vals_list.append(city_vals) city_vals_list.append(city_vals)
else: else:
city_dict[city.name] = city.id
city_dict[(city.name, state_id)] = city.id
created_cities = self.env['res.city'].create(city_vals_list) created_cities = self.env['res.city'].create(city_vals_list)
for i, vals in enumerate(city_vals_list): for i, vals in enumerate(city_vals_list):
city_dict[vals['name']] = created_cities[i].id
city_dict[(vals['name'], vals['state_id'])] = created_cities[i].id
return city_dict return city_dict
@api.multi @api.multi
def run_import(self): def run_import(self):
self.ensure_one() self.ensure_one()
parsed_csv = self.get_and_parse_csv()
return self._process_csv(parsed_csv)
def _process_csv(self, parsed_csv):
state_model = self.env['res.country.state'] state_model = self.env['res.country.state']
zip_model = self.env['res.city.zip'] zip_model = self.env['res.city.zip']
res_city_model = self.env['res.city'] res_city_model = self.env['res.city']
@ -203,7 +205,6 @@ class CityZipGeonamesImport(models.TransientModel):
[('country_id', '=', self.country_id.id)]) [('country_id', '=', self.country_id.id)])
search_states = True and len(current_states) > 0 or False search_states = True and len(current_states) > 0 or False
parsed_csv = self.get_and_parse_csv()
max_import = self.env.context.get('max_import', 0) max_import = self.env.context.get('max_import', 0)
logger.info('Starting to create the cities and/or city zip entries') logger.info('Starting to create the cities and/or city zip entries')
@ -218,12 +219,15 @@ class CityZipGeonamesImport(models.TransientModel):
if max_import and i == max_import: if max_import and i == max_import:
break break
# Don't search if there aren't any records # Don't search if there aren't any records
zip = False
zip_code = False
if search_zips: if search_zips:
zip = self.select_zip(row, self.country_id)
if not zip:
city_id = city_dict[
self.transform_city_name(row[2], self.country_id)]
zip_code = self.select_zip(row, self.country_id)
if not zip_code:
state_id = state_dict[row[self.code_row_index or 4]]
city_id = city_dict[(
self.transform_city_name(row[2], self.country_id),
state_id,
)]
zip_vals = self.prepare_zip(row, city_id) zip_vals = self.prepare_zip(row, city_id)
if zip_vals not in zip_vals_list: if zip_vals not in zip_vals_list:
zip_vals_list.append(zip_vals) zip_vals_list.append(zip_vals)
@ -243,7 +247,7 @@ class CityZipGeonamesImport(models.TransientModel):
# we can delete the old ones # we can delete the old ones
created_cities = res_city_model.search( created_cities = res_city_model.search(
[('country_id', '=', self.country_id.id), [('country_id', '=', self.country_id.id),
('id', 'in', [value for key, value in city_dict.items()])]
('id', 'in', list(city_dict.values()))]
) )
current_cities -= created_cities current_cities -= created_cities
current_cities.unlink() current_cities.unlink()

Loading…
Cancel
Save