diff --git a/addons/base_address_city/__init__.py b/addons/base_address_city/__init__.py new file mode 100644 index 00000000000..81fc81d29c9 --- /dev/null +++ b/addons/base_address_city/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import models diff --git a/addons/base_address_city/__manifest__.py b/addons/base_address_city/__manifest__.py new file mode 100644 index 00000000000..f472eb3680e --- /dev/null +++ b/addons/base_address_city/__manifest__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': 'City Addresses', + 'summary': 'Add a many2one field city on addresses', + 'sequence': '19', + 'category': 'Base', + 'complexity': 'easy', + 'description': """ +City Management in Addresses +============================ + +This module allows to enforce users to choose the city of a partner inside a given list instead of a free text field. + """, + 'data': [ + 'security/ir.model.access.csv', + 'views/res_city_view.xml', + 'views/res_country_view.xml', + ], + 'depends': ['base'], +} diff --git a/addons/base_address_city/models/__init__.py b/addons/base_address_city/models/__init__.py new file mode 100644 index 00000000000..e0230d01848 --- /dev/null +++ b/addons/base_address_city/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import res_city +import res_country +import res_partner diff --git a/addons/base_address_city/models/res_city.py b/addons/base_address_city/models/res_city.py new file mode 100644 index 00000000000..c542a1a3a8e --- /dev/null +++ b/addons/base_address_city/models/res_city.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class City(models.Model): + _name = 'res.city' + _description = 'City' + _order = 'name' + + name = fields.Char("Name", required=True, translate=True) + zipcode = fields.Char("Zip") + country_id = fields.Many2one('res.country', string='Country', required=True) + state_id = fields.Many2one( + 'res.country.state', 'State', domain="[('country_id', '=', country_id)]") diff --git a/addons/base_address_city/models/res_country.py b/addons/base_address_city/models/res_country.py new file mode 100644 index 00000000000..a3de7de697a --- /dev/null +++ b/addons/base_address_city/models/res_country.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class Country(models.Model): + _inherit = 'res.country' + + enforce_cities = fields.Boolean( + string='Enforce Cities', + help="Check this box to ensure every address created in that country has a 'City' chosen " + "in the list of the country's cities.") diff --git a/addons/base_address_city/models/res_partner.py b/addons/base_address_city/models/res_partner.py new file mode 100644 index 00000000000..4469730b602 --- /dev/null +++ b/addons/base_address_city/models/res_partner.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from lxml import etree + +from odoo import api, models, fields + +class FormatAddressMixin(models.AbstractModel): + _inherit = "format.address.mixin" + + @api.model + def fields_view_get_address(self, arch): + arch = super(FormatAddressMixin, self).fields_view_get_address(arch) + #render the partner address accordingly to address_view_id + doc = etree.fromstring(arch) + for city_node in doc.xpath("//field[@name='city']"): + replacement_xml = """ +
+ +
+ + +
+
+ """ + city_id_node = etree.fromstring(replacement_xml) + city_node.getparent().replace(city_node, city_id_node) + + arch = etree.tostring(doc) + return arch + + +class Partner(models.Model): + _inherit = 'res.partner' + + country_enforce_cities = fields.Boolean(related='country_id.enforce_cities') + city_id = fields.Many2one('res.city', string='Company') + + @api.onchange('city_id') + def _onchange_city_id(self): + self.city = self.city_id.name + self.zip = self.city_id.zipcode + self.state_id = self.city_id.state_id diff --git a/addons/base_address_city/security/ir.model.access.csv b/addons/base_address_city/security/ir.model.access.csv new file mode 100644 index 00000000000..92da18e7054 --- /dev/null +++ b/addons/base_address_city/security/ir.model.access.csv @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_res_city_group_user","res_city group_user","model_res_city","base.group_partner_manager",1,1,1,1 +"access_res_city_group_all","res_city group_user_all","model_res_city",,1,0,0,0 diff --git a/addons/base_address_city/views/res_city_view.xml b/addons/base_address_city/views/res_city_view.xml new file mode 100644 index 00000000000..b9fd53b735e --- /dev/null +++ b/addons/base_address_city/views/res_city_view.xml @@ -0,0 +1,41 @@ + + + + + res.city + + + + + + + + + + + res.city + + + + + + + + + + + Cities + ir.actions.act_window + res.city + form + tree + + Display and manage the list of all cities that can be assigned to + your partner records. Note that an option can be set on each country separately + to enforce any address of it to have a city in this list. + + + + + diff --git a/addons/base_address_city/views/res_country_view.xml b/addons/base_address_city/views/res_country_view.xml new file mode 100644 index 00000000000..e221e2f9798 --- /dev/null +++ b/addons/base_address_city/views/res_country_view.xml @@ -0,0 +1,23 @@ + + + + + res.country + + + + + + + + + + + +