From e5d0e3d40a996d268501d4f3225865aee45093f2 Mon Sep 17 00:00:00 2001 From: etobella Date: Wed, 18 Oct 2017 09:39:14 +0200 Subject: [PATCH] [MIG] base_location --- base_location/README.rst | 53 ++-- base_location/__init__.py | 1 - base_location/__openerp__.py | 5 +- base_location/demo/better_zip.xml | 8 +- base_location/models/__init__.py | 1 - base_location/models/better_zip.py | 101 ++++++-- base_location/models/company.py | 64 ++++- base_location/models/partner.py | 60 ++++- base_location/models/state.py | 1 - base_location/security/ir.model.access.csv | 2 +- base_location/tests/__init__.py | 3 +- base_location/tests/test_base_location.py | 270 +++++++++++++++++++++ base_location/tests/test_completion.py | 49 ---- base_location/views/better_zip_view.xml | 35 ++- base_location/views/company_view.xml | 10 +- base_location/views/partner_view.xml | 20 +- base_location/views/res_country_view.xml | 16 ++ 17 files changed, 555 insertions(+), 144 deletions(-) create mode 100644 base_location/tests/test_base_location.py delete mode 100644 base_location/tests/test_completion.py diff --git a/base_location/README.rst b/base_location/README.rst index 5f52c2da8..160dbf7c0 100644 --- a/base_location/README.rst +++ b/base_location/README.rst @@ -1,5 +1,5 @@ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 ======================= @@ -12,27 +12,52 @@ It enables zip, city, state and country auto-completion on partners and companie Also allows different search filters. +Configuration +============= + +#. Activate the developer mode in *Settings*. +#. Go to *Settings / Technical / Locations Management / Locations*. +#. Create a new Location. + +or, with module 'Contacts Directory' installed: +#. Go to *Contacts / Configuration / Localization / Countries*. +#. Locate the desired country. +#. Press on the button 'Locations'. + +or, +#. Go to *Contacts / Configuration / Localization / Fed. States* +#. Locate the desired state. +#. Enter the desired Locations. + Usage ===== +#. Access a partner record +#. Fill the field *Location completion* +#. Information about country, state, city and zip will be filled automatically + + + .. 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/10.0 + :target: https://runbot.odoo-community.org/runbot/134/11.0 Bug Tracker =========== -Bugs are tracked on `GitHub 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 `_. +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. Credits ======= +Images +------ + +* Icon park: `Icon http://icon-park.com/icon/location-map-pin-orange3/` + Contributors ------------ @@ -45,17 +70,13 @@ Contributors * Francesco Apruzzese * Dave Lasley -Icon ----- -* http://icon-park.com/icon/location-map-pin-orange3/ - Maintainer ---------- -.. image:: http://odoo-community.org/logo.png +.. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association - :target: http://odoo-community.org + :target: https://odoo-community.org This module is maintained by the OCA. @@ -63,4 +84,4 @@ 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. +To contribute to this module, please visit https://odoo-community.org. diff --git a/base_location/__init__.py b/base_location/__init__.py index a5fc6a4d0..e2aed6e67 100644 --- a/base_location/__init__.py +++ b/base_location/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/base_location/__openerp__.py b/base_location/__openerp__.py index 91b865f5e..ab99a039d 100644 --- a/base_location/__openerp__.py +++ b/base_location/__openerp__.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': 'Location management (aka Better ZIP)', - 'version': '10.0.1.0.1', + 'version': '11.0.1.0.0', 'depends': [ - 'base', + 'base_address_city' ], 'author': "Camptocamp," "ACYSOS S.L.," diff --git a/base_location/demo/better_zip.xml b/base_location/demo/better_zip.xml index 7ecc6b14b..0c7f3b9ee 100644 --- a/base_location/demo/better_zip.xml +++ b/base_location/demo/better_zip.xml @@ -1,12 +1,8 @@ - - - + 1000 Brussels - - - + diff --git a/base_location/models/__init__.py b/base_location/models/__init__.py index 3d1df1e8d..3f7a893a5 100644 --- a/base_location/models/__init__.py +++ b/base_location/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/base_location/models/better_zip.py b/base_location/models/better_zip.py index 777f736ce..be949fe23 100644 --- a/base_location/models/better_zip.py +++ b/base_location/models/better_zip.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields, api +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError class BetterZip(models.Model): @@ -11,37 +11,90 @@ class BetterZip(models.Model): _name = "res.better.zip" _description = __doc__ _order = "name asc" - _rec_name = "display_name" - display_name = fields.Char('Name', compute='_get_display_name', store=True) name = fields.Char('ZIP') - code = fields.Char('City Code', size=64, - help="The official code for the city") + code = fields.Char( + 'City Code', + size=64, + help="The official code for the city" + ) city = fields.Char('City', required=True) - state_id = fields.Many2one('res.country.state', 'State') + city_id = fields.Many2one( + 'res.city', + 'City', + ) + state_id = fields.Many2one( + 'res.country.state', + 'State', + ) country_id = fields.Many2one('res.country', 'Country') + enforce_cities = fields.Boolean( + related='country_id.enforce_cities', + readonly=True, + ) latitude = fields.Float() longitude = fields.Float() - @api.one - @api.depends( - 'name', - 'city', - 'state_id', - 'country_id', - ) - def _get_display_name(self): - if self.name: - name = [self.name, self.city] - else: - name = [self.city] - if self.state_id: - name.append(self.state_id.name) + @api.multi + @api.depends('name', 'city', 'state_id', 'country_id') + def name_get(self): + result = [] + for rec in self: + name = [] + if rec.name: + name.append('%(name)s' % {'name': rec.name}) + name.append('%(name)s' % {'name': rec.city}) + if rec.state_id: + name.append('%(name)s' % {'name': rec.state_id.name}) + if rec.country_id: + name.append('%(name)s' % {'name': rec.country_id.name}) + result.append((rec.id, ", ".join(name))) + return result + + @api.onchange('country_id') + def _onchange_country_id(self): + if self.state_id.country_id != self.country_id: + self.state_id = False + if self.city_id.country_id != self.country_id: + self.city_id = False if self.country_id: - name.append(self.country_id.name) - self.display_name = ", ".join(name) + domain = [('country_id', '=', self.country_id.id)] + else: + domain = [] + return { + 'domain': { + 'state_id': domain, + 'city_id': domain, + } + } + + @api.onchange('city_id') + def _onchange_city_id(self): + if self.city_id: + self.city = self.city_id.name + self.country_id = self.city_id.country_id + self.state_id = self.city_id.state_id @api.onchange('state_id') - def onchange_state_id(self): + def _onchange_state_id(self): if self.state_id: self.country_id = self.state_id.country_id + + @api.constrains('state_id', 'country_id', 'city_id') + def constrains_country(self): + for rec in self: + if rec.state_id and rec.state_id.country_id != \ + rec.country_id: + raise ValidationError(_( + "The country of the state differs from the country in " + "location %s") % rec.name) + if rec.city_id and rec.city_id.country_id \ + != rec.country_id: + raise ValidationError(_( + "The country of the city differs from the country in " + "location %s") % rec.name) + if rec.city_id and rec.city_id.state_id \ + != rec.state_id: + raise ValidationError(_( + "The state of the city differs from the state in " + "location %s") % rec.name) diff --git a/base_location/models/company.py b/base_location/models/company.py index d1970d2ae..3c0e78560 100644 --- a/base_location/models/company.py +++ b/base_location/models/company.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -6,19 +5,60 @@ from odoo import models, fields, api class ResCompany(models.Model): - _inherit = 'res.company' - @api.onchange('better_zip_id') - def on_change_city(self): - if self.better_zip_id: - self.zip = self.better_zip_id.name - self.city = self.better_zip_id.city - self.state_id = self.better_zip_id.state_id - self.country_id = self.better_zip_id.country_id - - better_zip_id = fields.Many2one( + city_id = fields.Many2one( + 'res.city', + compute='_compute_address', + inverse='_inverse_city_id', + string="City" + ) + zip_id = fields.Many2one( 'res.better.zip', - string='Location', + string='ZIP Location', + compute='_compute_address', + inverse='_inverse_zip_id', + oldname="better_zip_id", help='Use the city name or the zip code to search the location', ) + # In order to keep the same logic used in odoo, fields must be computed + # and inversed, not related. This way, we can ensure that it works + # correctly on changes and inconsistencies cannot happen. + # When you make the fields related, the constrains added in res.partner + # will fail. because when you change the city_id in the company, you are + # effectively changing it in the partner. The constrains on the partner + # are evaluated before the inverse methods update the other fields (city, + # etc..). And we need constrains in the partner to ensure consistency. + # So, as a conclusion, address fields are very related to each other. + # Either you make them all related to the partner in company, or you + # don't for all of them. But mixing methods produces inconsistencies. + + country_enforce_cities = fields.Boolean( + related='country_id.enforce_cities' + ) + + def _get_company_address_fields(self, partner): + res = super(ResCompany, self)._get_company_address_fields(partner) + res['city_id'] = partner.city_id + res['zip_id'] = partner.zip_id + return res + + def _inverse_city_id(self): + for company in self: + company.partner_id.city_id = company.city_id + + def _inverse_zip_id(self): + for company in self: + company.partner_id.zip_id = company.zip_id + + @api.onchange('zip_id') + def _onchange_zip_id(self): + if self.zip_id: + self.zip = self.zip_id.name + self.city_id = self.zip_id.city_id + self.city = self.zip_id.city + self.country_id = self.zip_id.country_id + if self.country_id.enforce_cities: + self.state_id = self.city_id.state_id + else: + self.state_id = self.zip_id.state_id diff --git a/base_location/models/partner.py b/base_location/models/partner.py index 1eaa08cf3..61e172920 100644 --- a/base_location/models/partner.py +++ b/base_location/models/partner.py @@ -1,18 +1,66 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields, api +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError class ResPartner(models.Model): _inherit = 'res.partner' - zip_id = fields.Many2one('res.better.zip', 'City/Location') + zip_id = fields.Many2one('res.better.zip', 'ZIP Location') + + @api.onchange('city_id') + def _onchange_city_id(self): + if not self.zip_id: + super(ResPartner, self)._onchange_city_id() + if self.zip_id and self.city_id != self.zip_id.city_id: + self.zip_id = False + self.zip = False + self.city = False + if self.city_id: + return { + 'domain': { + 'zip_id': [('city_id', '=', self.city_id.id)] + }, + } + return {'domain': {'zip_id': []}} + + @api.onchange('state_id') + def _onchange_state_id(self): + if self.zip_id and self.state_id != self.zip_id.state_id: + self.zip_id = False + self.zip = False + self.city = False + + @api.onchange('country_id') + def _onchange_country_id(self): + res = super(ResPartner, self)._onchange_country_id() + if self.zip_id and self.zip_id.country_id != self.country_id: + self.zip_id = False + return res @api.onchange('zip_id') - def onchange_zip_id(self): + def _onchange_zip_id(self): if self.zip_id: + self.country_id = self.zip_id.country_id + if self.country_id.enforce_cities: + self.city_id = self.zip_id.city_id self.zip = self.zip_id.name - self.city = self.zip_id.city self.state_id = self.zip_id.state_id - self.country_id = self.zip_id.country_id + self.city = self.zip_id.city + + @api.constrains('zip_id', 'country_id', 'city_id', 'state_id') + def _check_zip(self): + for rec in self.filtered('zip_id'): + if rec.zip_id.state_id != rec.state_id: + raise ValidationError(_( + "The state of the partner %s differs from that in " + "location %s") % (rec.name, rec.zip_id.name)) + if rec.zip_id.country_id != rec.country_id: + raise ValidationError(_( + "The country of the partner %s differs from that in " + "location %s") % (rec.name, rec.zip_id.name)) + if rec.zip_id.city_id != rec.city_id: + raise ValidationError(_( + "The city of partner %s differs from that in " + "location %s") % (rec.name, rec.zip_id.name)) diff --git a/base_location/models/state.py b/base_location/models/state.py index 5c3b31f60..5161a34a6 100644 --- a/base_location/models/state.py +++ b/base_location/models/state.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Nicolas Bessi, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/base_location/security/ir.model.access.csv b/base_location/security/ir.model.access.csv index c6562df1b..5ef6c8b46 100644 --- a/base_location/security/ir.model.access.csv +++ b/base_location/security/ir.model.access.csv @@ -1,3 +1,3 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "ir_model_access_betterzip0","res_better_zip group_user_all","model_res_better_zip",base.group_user,1,0,0,0 -"ir_model_access_betterzip1","res_better_zip group_user","model_res_better_zip","base.group_partner_manager",1,1,1,1 \ No newline at end of file +"ir_model_access_betterzip1","res_better_zip group_user","model_res_better_zip","base.group_partner_manager",1,1,1,1 diff --git a/base_location/tests/__init__.py b/base_location/tests/__init__.py index 3c8d5b3d9..372da9775 100644 --- a/base_location/tests/__init__.py +++ b/base_location/tests/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- # Copyright 2015 Yannick Vaucher, Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import test_completion +from . import test_base_location diff --git a/base_location/tests/test_base_location.py b/base_location/tests/test_base_location.py new file mode 100644 index 000000000..b179f3b5d --- /dev/null +++ b/base_location/tests/test_base_location.py @@ -0,0 +1,270 @@ +# Copyright 2015 Yannick Vaucher, Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase +from odoo.exceptions import ValidationError + + +class TestBaseLocation(TransactionCase): + + def test_onchange_better_zip_state_id(self): + """ Test onchange on res.better.zip """ + usa_MA = self.env.ref('base.state_us_34') + better_zip1 = self.env['res.better.zip'].new(self.values_better_zip1()) + better_zip1.state_id = usa_MA + better_zip1._onchange_state_id() + self.assertEqual(better_zip1.country_id, usa_MA.country_id) + + def test_onchange_better_zip_city_id(self): + better_zip2 = self.env['res.better.zip'].new(self.values_better_zip2()) + better_zip2.city_id = self.city_madrid + better_zip2._onchange_city_id() + self.assertEqual(better_zip2.city, self.city_madrid.name) + + def test_onchange_better_zip_country_id(self): + better_zip1 = self.env['res.better.zip'].new(self.values_better_zip1()) + better_zip1.country_id = self.env.ref('base.es') + better_zip1._onchange_country_id() + self.assertFalse(better_zip1.state_id) + + def test_onchange_better_zip_none(self): + better_zip1 = self.env['res.better.zip'].new(self.values_better_zip1()) + better_zip1.country_id = False + better_zip1._onchange_country_id() + self.assertFalse(better_zip1.state_id) + + def test_onchange_partner_city_completion(self): + partner1 = self.env['res.partner'].new({ + 'name': 'Camptocamp', + }) + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + better_zip2.country_id.enforce_cities = True + partner1.zip_id = better_zip2 + partner1._onchange_zip_id() + self.assertEqual(partner1.zip, better_zip2.name) + self.assertEqual(partner1.city, better_zip2.city) + self.assertEqual(partner1.state_id, better_zip2.state_id) + self.assertEqual(partner1.country_id, better_zip2.country_id) + + def test_onchange_company_city_completion(self): + company = self.env['res.company'].new({'name': 'Test'}) + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + company.zip_id = better_zip1 + company._onchange_zip_id() + self.assertEqual(company.zip, better_zip1.name) + self.assertEqual(company.city, better_zip1.city) + self.assertEqual(company.state_id, better_zip1.state_id) + self.assertEqual(company.country_id, better_zip1.country_id) + + def test_company_address_fields(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1() + ) + company = self.env['res.company'].create({ + 'name': 'Test', + }) + self.assertTrue(company.partner_id) + company.partner_id.write({ + 'zip_id': better_zip1.id, + 'state_id': better_zip1.state_id.id, + 'country_id': better_zip1.country_id.id, + 'city_id': better_zip1.city_id.id, + 'city': better_zip1.city, + 'zip': better_zip1.name, + }) + company._compute_address() + self.assertEqual(company.zip_id, company.partner_id.zip_id) + self.assertEqual(company.city_id, company.partner_id.city_id) + + def test_company_address_fields_inverse(self): + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2() + ) + company = self.env['res.company'].new({ + 'name': 'Test', + 'partner_id': self.env['res.partner'].new({}).id + # Partner must be initiated in order to be filled + }) + company.update({ + 'zip_id': better_zip2.id, + }) + company._inverse_city_id() + company._inverse_zip_id() + self.assertEqual(company.zip_id, company.partner_id.zip_id) + self.assertEqual(company.city_id, company.partner_id.city_id) + + def test_onchange_company_city_id_completion(self): + company = self.env['res.company'].new({'name': 'Test'}) + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + company.zip_id = better_zip2 + company._onchange_zip_id() + self.assertEqual(company.city_id, better_zip2.city_id) + + def test_constrains_better_zip_01(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + + better_zip1.city_id = self.city_lausanne + with self.assertRaises(ValidationError): + better_zip2.city_id = better_zip1.city_id + + def test_constrains_better_zip_02(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + + with self.assertRaises(ValidationError): + better_zip2.country_id = better_zip1.country_id + + def test_constrains_better_zip_03(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + + with self.assertRaises(ValidationError): + better_zip2.state_id = better_zip1.state_id + + def test_constrains_better_zip_04(self): + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + + with self.assertRaises(ValidationError): + better_zip2.city_id = self.city_madrid + + def test_constrains_partner_01(self): + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + with self.assertRaises(ValidationError): + self.env['res.partner'].create({ + 'name': 'P1', + 'zip_id': better_zip2.id, + }) + + def test_constrains_partner_02(self): + better_zip2 = self.env['res.better.zip'].create( + self.values_better_zip2()) + partner = self.env['res.partner'].create({ + 'name': 'P1', + 'zip_id': better_zip2.id, + 'country_id': better_zip2.country_id.id, + 'state_id': better_zip2.state_id.id, + 'city_id': better_zip2.city_id.id, + }) + + with self.assertRaises(ValidationError): + partner.country_id = self.ref('base.ch') + + with self.assertRaises(ValidationError): + partner.state_id = self.state_vd.id, + + with self.assertRaises(ValidationError): + partner.city_id = self.city_lausanne + + def values_better_zip1(self): + return { + 'name': 1000, + 'city': 'Lausanne', + 'state_id': self.state_vd.id, + 'country_id': self.ref('base.ch'), + } + + def values_better_zip2(self): + return { + 'city_id': self.city_bcn.id, + 'city': self.city_bcn.name, + 'state_id': self.state_bcn.id, + 'country_id': self.ref('base.es'), + } + + def test_partner_onchange_country(self): + country_es = self.browse_ref('base.es') + country_es.enforce_cities = True + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + partner = self.env['res.partner'].new({ + 'name': 'TEST', + 'zip_id': better_zip1.id + }) + partner.country_id = country_es + partner._onchange_country_id() + self.assertFalse(partner.zip_id) + + def test_partner_onchange_city(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + partner = self.env['res.partner'].new({ + 'name': 'TEST', + 'zip_id': better_zip1.id + }) + self.city_bcn.country_id.enforce_cities = False + partner.city_id = self.city_bcn + partner._onchange_city_id() + self.assertFalse(partner.zip_id) + partner.city_id = False + res = partner._onchange_city_id() + self.assertFalse(res['domain']['zip_id']) + + def test_partner_onchange_state(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + partner = self.env['res.partner'].new({ + 'name': 'TEST', + 'zip_id': better_zip1.id + }) + partner.state_id = self.state_bcn + partner._onchange_state_id() + self.assertFalse(partner.zip_id) + + def test_display_name(self): + better_zip1 = self.env['res.better.zip'].create( + self.values_better_zip1()) + self.assertEqual( + better_zip1.display_name, '1000, Lausanne, Vaud, '+self.browse_ref( + 'base.ch' + ).name + ) + + def setUp(self): + super(TestBaseLocation, self).setUp() + self.state_vd = self.env['res.country.state'].create({ + 'name': 'Vaud', + 'code': 'VD', + 'country_id': self.ref('base.ch'), + }) + self.env['res.country'].browse(self.ref('base.es')).write({ + 'enforce_cities': True + }) + self.company = self.env.ref('base.main_company') + + self.state_bcn = self.env['res.country.state'].create({ + 'name': 'Barcelona', + 'code': '08', + 'country_id': self.ref('base.es'), + }) + self.state_madrid = self.env['res.country.state'].create({ + 'name': 'Madrid', + 'code': '28', + 'country_id': self.ref('base.es'), + }) + self.city_bcn = self.env['res.city'].create({ + 'name': 'Barcelona', + 'state_id': self.state_bcn.id, + 'country_id': self.ref('base.es'), + }) + self.city_madrid = self.env['res.city'].create({ + 'name': 'Madrid', + 'state_id': self.state_madrid.id, + 'country_id': self.ref('base.es'), + }) + self.city_lausanne = self.env['res.city'].create({ + 'name': 'Lausanne', + 'state_id': self.state_vd.id, + 'country_id': self.ref('base.ch'), + }) diff --git a/base_location/tests/test_completion.py b/base_location/tests/test_completion.py deleted file mode 100644 index cf75c05f3..000000000 --- a/base_location/tests/test_completion.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2015 Yannick Vaucher, Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo.tests.common import TransactionCase - - -class TestCompletion(TransactionCase): - - def test_onchange_better_zip_state_id(self): - """ Test onchange on res.better.zip """ - usa_MA = self.env.ref('base.state_us_34') - self.better_zip1.state_id = usa_MA - self.better_zip1.onchange_state_id() - self.assertEqual(self.better_zip1.country_id, usa_MA.country_id) - - def test_onchange_partner_city_completion(self): - self.partner1.zip_id = self.better_zip1 - self.partner1.onchange_zip_id() - self.assertEqual(self.partner1.zip, self.better_zip1.name) - self.assertEqual(self.partner1.city, self.better_zip1.city) - self.assertEqual(self.partner1.state_id, self.better_zip1.state_id) - self.assertEqual(self.partner1.country_id, self.better_zip1.country_id) - - def test_onchange_company_city_completion(self): - self.company.better_zip_id = self.better_zip1 - self.company.on_change_city() - self.assertEqual(self.company.zip, self.better_zip1.name) - self.assertEqual(self.company.city, self.better_zip1.city) - self.assertEqual(self.company.state_id, self.better_zip1.state_id) - self.assertEqual(self.company.country_id, self.better_zip1.country_id) - - def setUp(self): - super(TestCompletion, self).setUp() - state_vd = self.env['res.country.state'].create({ - 'name': 'Vaud', - 'code': 'VD', - 'country_id': self.ref('base.ch'), - }) - self.company = self.env.ref('base.main_company') - self.better_zip1 = self.env['res.better.zip'].create({ - 'name': 1000, - 'city': 'Lausanne', - 'state_id': state_vd.id, - 'country_id': self.ref('base.ch'), - }) - self.partner1 = self.env['res.partner'].create({ - 'name': 'Camptocamp', - }) diff --git a/base_location/views/better_zip_view.xml b/base_location/views/better_zip_view.xml index d384c7d8e..207c88e92 100644 --- a/base_location/views/better_zip_view.xml +++ b/base_location/views/better_zip_view.xml @@ -7,11 +7,20 @@
- - - - - + + + + + + + + + + +
@@ -41,16 +50,18 @@ - - - - + + + + - Cites/locations + Locations res.better.zip form tree,form @@ -59,13 +70,13 @@ - + + + + + + [('country_enforce_cities', '=', True)] + diff --git a/base_location/views/partner_view.xml b/base_location/views/partner_view.xml index cc3499b40..1e8a016e5 100644 --- a/base_location/views/partner_view.xml +++ b/base_location/views/partner_view.xml @@ -1,24 +1,26 @@ - res.partner.zip_id.2 res.partner - + + options="{'create_name_field': 'city', 'no_open': True, 'no_create': True}" + placeholder="Location completion" + class="oe_edit_only" + attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"/> - + + options="{'create_name_field': 'city', 'no_open': True, 'no_create': True}" + placeholder="City completion" + class="oe_edit_only"/> + diff --git a/base_location/views/res_country_view.xml b/base_location/views/res_country_view.xml index d45cd0cb1..cbf0f3ff3 100644 --- a/base_location/views/res_country_view.xml +++ b/base_location/views/res_country_view.xml @@ -12,4 +12,20 @@ + + res.country + + + + + + + +