Browse Source

[MIG] base_location

pull/638/head
etobella 7 years ago
committed by Pedro M. Baeza
parent
commit
e5d0e3d40a
  1. 53
      base_location/README.rst
  2. 1
      base_location/__init__.py
  3. 5
      base_location/__openerp__.py
  4. 8
      base_location/demo/better_zip.xml
  5. 1
      base_location/models/__init__.py
  6. 101
      base_location/models/better_zip.py
  7. 64
      base_location/models/company.py
  8. 60
      base_location/models/partner.py
  9. 1
      base_location/models/state.py
  10. 3
      base_location/tests/__init__.py
  11. 270
      base_location/tests/test_base_location.py
  12. 49
      base_location/tests/test_completion.py
  13. 27
      base_location/views/better_zip_view.xml
  14. 10
      base_location/views/company_view.xml
  15. 14
      base_location/views/partner_view.xml
  16. 16
      base_location/views/res_country_view.xml

53
base_location/README.rst

@ -1,5 +1,5 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg .. 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 :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. 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 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 .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot :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 Bug Tracker
=========== ===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/
partner_contact/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 <https://github.com/OCA/
partner_contact/issues/new?body=module:%20
base_location%0Aversion:%20
10.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/partner_contact/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 Credits
======= =======
Images
------
* Icon park: `Icon http://icon-park.com/icon/location-map-pin-orange3/`
Contributors Contributors
------------ ------------
@ -45,17 +70,13 @@ Contributors
* Francesco Apruzzese <f.apruzzese@apuliasoftware.it> * Francesco Apruzzese <f.apruzzese@apuliasoftware.it>
* Dave Lasley <dave@laslabs.com> * Dave Lasley <dave@laslabs.com>
Icon
----
* http://icon-park.com/icon/location-map-pin-orange3/
Maintainer Maintainer
---------- ----------
.. image:: http://odoo-community.org/logo.png
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association :alt: Odoo Community Association
:target: http://odoo-community.org
:target: https://odoo-community.org
This module is maintained by the OCA. 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 mission is to support the collaborative development of Odoo features and
promote its widespread use. 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.

1
base_location/__init__.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

5
base_location/__openerp__.py

@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Location management (aka Better ZIP)', 'name': 'Location management (aka Better ZIP)',
'version': '10.0.1.0.1',
'version': '11.0.1.0.0',
'depends': [ 'depends': [
'base',
'base_address_city'
], ],
'author': "Camptocamp," 'author': "Camptocamp,"
"ACYSOS S.L.," "ACYSOS S.L.,"

8
base_location/demo/better_zip.xml

@ -1,12 +1,8 @@
<?xml version = "1.0" encoding="utf-8"?> <?xml version = "1.0" encoding="utf-8"?>
<openerp>
<data>
<odoo>
<record id="demo_brussels" model="res.better.zip"> <record id="demo_brussels" model="res.better.zip">
<field name="name">1000</field> <field name="name">1000</field>
<field name="city">Brussels</field> <field name="city">Brussels</field>
<field name="country_id" ref="base.be"/> <field name="country_id" ref="base.be"/>
</record> </record>
</data>
</openerp>
</odoo>

1
base_location/models/__init__.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

101
base_location/models/better_zip.py

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # 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): class BetterZip(models.Model):
@ -11,37 +11,90 @@ class BetterZip(models.Model):
_name = "res.better.zip" _name = "res.better.zip"
_description = __doc__ _description = __doc__
_order = "name asc" _order = "name asc"
_rec_name = "display_name"
display_name = fields.Char('Name', compute='_get_display_name', store=True)
name = fields.Char('ZIP') 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) 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') country_id = fields.Many2one('res.country', 'Country')
enforce_cities = fields.Boolean(
related='country_id.enforce_cities',
readonly=True,
)
latitude = fields.Float() latitude = fields.Float()
longitude = 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: 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') @api.onchange('state_id')
def onchange_state_id(self):
def _onchange_state_id(self):
if self.state_id: if self.state_id:
self.country_id = self.state_id.country_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)

64
base_location/models/company.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # 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): class ResCompany(models.Model):
_inherit = 'res.company' _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', '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', 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

60
base_location/models/partner.py

@ -1,18 +1,66 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # 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): class ResPartner(models.Model):
_inherit = 'res.partner' _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') @api.onchange('zip_id')
def onchange_zip_id(self):
def _onchange_zip_id(self):
if self.zip_id: 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.zip = self.zip_id.name
self.city = self.zip_id.city
self.state_id = self.zip_id.state_id 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))

1
base_location/models/state.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Nicolas Bessi, Camptocamp SA # Copyright 2016 Nicolas Bessi, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

3
base_location/tests/__init__.py

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Yannick Vaucher, Camptocamp SA # Copyright 2015 Yannick Vaucher, Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_completion
from . import test_base_location

270
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'),
})

49
base_location/tests/test_completion.py

@ -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',
})

27
base_location/views/better_zip_view.xml

@ -7,11 +7,20 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="City"> <form string="City">
<group col="4"> <group col="4">
<group>
<field name="name"/> <field name="name"/>
<field name="code"/>
<field name="city"/>
<field name="state_id"/>
<field name="city_id"
attrs="{'invisible': [('enforce_cities', '=', False)],'required': [('enforce_cities', '=', True)]}"/>
<field name="city"
attrs="{'invisible': [('enforce_cities', '=', True)]}"/>
<field name="country_id"/> <field name="country_id"/>
<field name="enforce_cities" invisible="1"/>
</group>
<group>
<field name="code"/>
<field name="state_id"
attrs="{'invisible': [('enforce_cities', '=', True)]}"/>
</group>
</group> </group>
</form> </form>
</field> </field>
@ -42,15 +51,17 @@
<field name="state_id"/> <field name="state_id"/>
<field name="country_id"/> <field name="country_id"/>
<group expand="0" string="Group By"> <group expand="0" string="Group By">
<filter string="State" domain="[]" context="{'group_by':'state_id'}"/>
<filter string="Country" domain="[]" context="{'group_by':'country_id'}"/>
<filter string="State" domain="[]"
context="{'group_by':'state_id'}"/>
<filter string="Country" domain="[]"
context="{'group_by':'country_id'}"/>
</group> </group>
</search> </search>
</field> </field>
</record> </record>
<record id="action_zip_tree" model="ir.actions.act_window"> <record id="action_zip_tree" model="ir.actions.act_window">
<field name="name">Cites/locations</field>
<field name="name">Locations</field>
<field name="res_model">res.better.zip</field> <field name="res_model">res.better.zip</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
@ -59,13 +70,13 @@
</record> </record>
<menuitem <menuitem
name="Cities/Locations Management"
name="Locations Management"
id="locations_root_menu" id="locations_root_menu"
parent="base.menu_custom" parent="base.menu_custom"
/> />
<menuitem <menuitem
name="Cities/Locations"
name="Locations"
id="locations_menu" id="locations_menu"
parent="locations_root_menu" parent="locations_root_menu"
action="action_zip_tree" action="action_zip_tree"

10
base_location/views/company_view.xml

@ -8,11 +8,19 @@
<field name="inherit_id" ref="base.view_company_form" /> <field name="inherit_id" ref="base.view_company_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="street2" position="after"> <field name="street2" position="after">
<field name="better_zip_id"
<field name="zip_id"
options="{'create_name_field': 'city'}" options="{'create_name_field': 'city'}"
colspan="4" colspan="4"
placeholder="City completion" /> placeholder="City completion" />
</field> </field>
<field name="city" position="after">
<field name="country_enforce_cities" invisible="1"/>
<field name='city_id'
attrs="{'invisible': [('country_enforce_cities', '=', False)]}"/>
</field>
<field name="city" position="attributes">
<attribute name="invisible">[('country_enforce_cities', '=', True)]</attribute>
</field>
</field> </field>
</record> </record>

14
base_location/views/partner_view.xml

@ -1,24 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<odoo> <odoo>
<record id="view_partner_form" model="ir.ui.view"> <record id="view_partner_form" model="ir.ui.view">
<field name="name">res.partner.zip_id.2</field> <field name="name">res.partner.zip_id.2</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="city" position="before"> <field name="city" position="before">
<field name="zip_id" <field name="zip_id"
options="{'create_name_field': 'city', 'no_open': True, 'no_create': True}" options="{'create_name_field': 'city', 'no_open': True, 'no_create': True}"
placeholder="City completion"
class="oe_edit_only" />
placeholder="Location completion"
class="oe_edit_only"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"/>
</field> </field>
<xpath expr="//field[@name='child_ids']/form//field[@name='city']" position="before">
<xpath expr="//field[@name='child_ids']/form//field[@name='city']"
position="before">
<field name="zip_id" <field name="zip_id"
options="{'create_name_field': 'city', 'no_open': True, 'no_create': True}" options="{'create_name_field': 'city', 'no_open': True, 'no_create': True}"
placeholder="City completion" placeholder="City completion"
class="oe_edit_only" />
class="oe_edit_only"/>
</xpath> </xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

16
base_location/views/res_country_view.xml

@ -12,4 +12,20 @@
</field> </field>
</record> </record>
<record id="view_res_country_city_better_zip_form" model="ir.ui.view">
<field name="model">res.country</field>
<field name="inherit_id" ref="base.view_country_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button name="%(action_zip_tree)d"
class="oe_stat_button"
icon="fa-globe"
type="action"
context="{'default_country_id': active_id, 'search_default_country_id': active_id}"
string="Locations">
</button>
</xpath>
</field>
</record>
</odoo> </odoo>
Loading…
Cancel
Save