Browse Source
[MIG] base_location: Migration to 12.0
[MIG] base_location: Migration to 12.0
This module has now been refactored to be more consistent with what base_address_city offers to the location management. Added dependency to contacts so that I could change the menu location for cities / zip management. Now, every res.city record has a relation One2many to res.city.zip (old res.better.zip). This way, every zip has a realted city too. Zips can be searched through city code, zip or city name (same as before). Modified tests and deleted not needed tests. Added sql contraints so that zips and cities are unique within it's country / state / city.pull/638/head
Aitor Bouzas
6 years ago
committed by
Pedro M. Baeza
28 changed files with 998 additions and 569 deletions
-
106base_location/README.rst
-
1base_location/__init__.py
-
24base_location/__openerp__.py
-
8base_location/demo/better_zip.xml
-
13base_location/demo/res_city_zip.xml
-
9base_location/models/__init__.py
-
108base_location/models/better_zip.py
-
19base_location/models/res_city.py
-
40base_location/models/res_city_zip.py
-
46base_location/models/res_company.py
-
60base_location/models/res_partner.py
-
11base_location/models/state.py
-
10base_location/readme/CONFIGURE.rst
-
9base_location/readme/CONTRIBUTORS.rst
-
1base_location/readme/CREDITS.rst
-
5base_location/readme/DESCRIPTION.rst
-
3base_location/readme/USAGE.rst
-
3base_location/security/ir.model.access.csv
-
463base_location/static/description/index.html
-
1base_location/tests/__init__.py
-
394base_location/tests/test_base_location.py
-
85base_location/views/better_zip_view.xml
-
63base_location/views/res_city_view.xml
-
56base_location/views/res_city_zip_view.xml
-
0base_location/views/res_company_view.xml
-
2base_location/views/res_country_view.xml
-
1base_location/views/res_partner_view.xml
-
26base_location/views/state_view.xml
@ -1,4 +1,3 @@ |
|||||
# 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 . import models |
from . import models |
@ -1,8 +0,0 @@ |
|||||
<?xml version = "1.0" encoding="utf-8"?> |
|
||||
<odoo> |
|
||||
<record id="demo_brussels" model="res.better.zip"> |
|
||||
<field name="name">1000</field> |
|
||||
<field name="city">Brussels</field> |
|
||||
<field name="country_id" ref="base.be"/> |
|
||||
</record> |
|
||||
</odoo> |
|
@ -0,0 +1,13 @@ |
|||||
|
<?xml version = "1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<record id="demo_brussels_city" model="res.city"> |
||||
|
<field name="name">Brussels</field> |
||||
|
<field name="country_id" ref="base.be"/> |
||||
|
</record> |
||||
|
|
||||
|
<record id="demo_brussels_zip" model="res.city.zip"> |
||||
|
<field name="name">1000</field> |
||||
|
<field name="city_id" ref="demo_brussels_city"/> |
||||
|
</record> |
||||
|
</odoo> |
@ -1,7 +1,6 @@ |
|||||
# 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 . import better_zip |
|
||||
from . import partner |
|
||||
from . import state |
|
||||
from . import company |
|
||||
|
from . import res_city_zip |
||||
|
from . import res_partner |
||||
|
from . import res_company |
||||
|
from . import res_city |
@ -1,108 +0,0 @@ |
|||||
# Copyright 2016 Nicolas Bessi, Camptocamp SA |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|
||||
|
|
||||
from odoo import api, fields, models, _ |
|
||||
from odoo.exceptions import ValidationError |
|
||||
|
|
||||
|
|
||||
class BetterZip(models.Model): |
|
||||
'''City/locations completion object''' |
|
||||
|
|
||||
_name = "res.better.zip" |
|
||||
_description = __doc__ |
|
||||
_order = "name asc" |
|
||||
|
|
||||
name = fields.Char('ZIP') |
|
||||
code = fields.Char( |
|
||||
'City Code', |
|
||||
size=64, |
|
||||
help="The official code for the city" |
|
||||
) |
|
||||
city = fields.Char('City', required=True) |
|
||||
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.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.model |
|
||||
def name_search(self, name='', args=None, operator='ilike', limit=100): |
|
||||
args = list(args or []) |
|
||||
args += ['|', ('city', operator, name), |
|
||||
'|', ('name', operator, name), ('code', operator, name)] |
|
||||
recs = self.search(args, limit=limit) |
|
||||
return recs.name_get() |
|
||||
|
|
||||
@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: |
|
||||
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): |
|
||||
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) |
|
@ -0,0 +1,19 @@ |
|||||
|
# Copyright 2018 Aitor Bouzas <aitor.bouzas@adaptivecity.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class City(models.Model): |
||||
|
_inherit = 'res.city' |
||||
|
|
||||
|
zip_ids = fields.One2many('res.city.zip', 'city_id', |
||||
|
string="Zips in this city") |
||||
|
|
||||
|
_sql_constraints = [ |
||||
|
('name_state_country_uniq', |
||||
|
'UNIQUE(name, state_id, country_id)', |
||||
|
'You already have a city with that name in the same state.' |
||||
|
'The city must have a unique name within ' |
||||
|
'it\'s state and it\'s country'), |
||||
|
] |
@ -0,0 +1,40 @@ |
|||||
|
# Copyright 2016 Nicolas Bessi, Camptocamp SA |
||||
|
# Copyright 2018 Aitor Bouzas <aitor.bouzas@adaptivecity.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class ResCityZip(models.Model): |
||||
|
"""City/locations completion object""" |
||||
|
|
||||
|
_name = "res.city.zip" |
||||
|
_description = __doc__ |
||||
|
_order = "name asc" |
||||
|
_rec_name = "display_name" |
||||
|
|
||||
|
name = fields.Char('ZIP', required=True) |
||||
|
city_id = fields.Many2one( |
||||
|
'res.city', |
||||
|
'City', |
||||
|
required=True, |
||||
|
) |
||||
|
display_name = fields.Char(compute='_compute_new_display_name', |
||||
|
store=True, index=True) |
||||
|
|
||||
|
_sql_constraints = [ |
||||
|
('name_city_uniq', 'UNIQUE(name, city_id)', |
||||
|
'You already have a zip with that code in the same city. ' |
||||
|
'The zip code must be unique within it\'s city'), |
||||
|
] |
||||
|
|
||||
|
@api.multi |
||||
|
@api.depends('name', 'city_id') |
||||
|
def _compute_new_display_name(self): |
||||
|
for rec in self: |
||||
|
name = [rec.name, rec.city_id.name] |
||||
|
if rec.city_id.state_id: |
||||
|
name.append(rec.city_id.state_id.name) |
||||
|
if rec.city_id.country_id: |
||||
|
name.append(rec.city_id.country_id.name) |
||||
|
rec.display_name = ", ".join(name) |
@ -1,11 +0,0 @@ |
|||||
# Copyright 2016 Nicolas Bessi, Camptocamp SA |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|
||||
|
|
||||
from odoo import models, fields |
|
||||
|
|
||||
|
|
||||
class ResCountryState(models.Model): |
|
||||
|
|
||||
_inherit = 'res.country.state' |
|
||||
|
|
||||
better_zip_ids = fields.One2many('res.better.zip', 'state_id', 'Cities') |
|
@ -0,0 +1,10 @@ |
|||||
|
#. Go to *Contacts / Configuration / Localization / Cities*. |
||||
|
#. Create a new City. |
||||
|
|
||||
|
#. Go to *Contacts / Configuration / Localization / Zips*. |
||||
|
#. Create a new Zip and relate it to the city (you can also create the Zip from the City). |
||||
|
|
||||
|
or, with module 'Contacts Directory' installed: |
||||
|
#. Go to *Contacts / Configuration / Localization / Countries*. |
||||
|
#. Locate the desired country. |
||||
|
#. Press on the button 'Cities' / 'Zips'. |
@ -0,0 +1,9 @@ |
|||||
|
* Nicolas Bessi (Camptocamp) |
||||
|
* Ignacio Ibeas (Acysos S.L.) |
||||
|
* Pedro M. Baeza <pedro.baeza@gmail.com> |
||||
|
* Alejandro Santana <alejandrosantana@anubia.es> |
||||
|
* Sandy Carter <sandy.carter@savoirfairelinux.com> |
||||
|
* Yannick Vaucher <yannick.vaucher@camptocamp.com> |
||||
|
* Francesco Apruzzese <f.apruzzese@apuliasoftware.it> |
||||
|
* Dave Lasley <dave@laslabs.com> |
||||
|
* Aitor Bouzas <aitor.bouzas@adaptivecity.com> |
@ -0,0 +1 @@ |
|||||
|
* Icon park: `Icon http://icon-park.com/icon/location-map-pin-orange3/` |
@ -0,0 +1,5 @@ |
|||||
|
This module introduces a zip model that allows you to manage locations in a better way. |
||||
|
|
||||
|
The zips will allow the users to complete automatically all address-related fields by just filling the zip. |
||||
|
|
||||
|
Also allows different search filters. |
@ -0,0 +1,3 @@ |
|||||
|
#. Access a partner record |
||||
|
#. Fill the field *Location completion* |
||||
|
#. Information about country, state, city and zip will be filled automatically |
@ -1,3 +1,2 @@ |
|||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
"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 |
|
||||
|
"ir_model_access_cityzip0","res_city_zip group_user","model_res_city_zip","base.group_partner_manager",1,1,1,1 |
@ -0,0 +1,463 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||
|
<head> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
||||
|
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" /> |
||||
|
<title>Location management (aka Better ZIP)</title> |
||||
|
<style type="text/css"> |
||||
|
|
||||
|
/* |
||||
|
:Author: David Goodger (goodger@python.org) |
||||
|
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ |
||||
|
:Copyright: This stylesheet has been placed in the public domain. |
||||
|
|
||||
|
Default cascading style sheet for the HTML output of Docutils. |
||||
|
|
||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to |
||||
|
customize this style sheet. |
||||
|
*/ |
||||
|
|
||||
|
/* used to remove borders from tables and images */ |
||||
|
.borderless, table.borderless td, table.borderless th { |
||||
|
border: 0 } |
||||
|
|
||||
|
table.borderless td, table.borderless th { |
||||
|
/* Override padding for "table.docutils td" with "! important". |
||||
|
The right padding separates the table cells. */ |
||||
|
padding: 0 0.5em 0 0 ! important } |
||||
|
|
||||
|
.first { |
||||
|
/* Override more specific margin styles with "! important". */ |
||||
|
margin-top: 0 ! important } |
||||
|
|
||||
|
.last, .with-subtitle { |
||||
|
margin-bottom: 0 ! important } |
||||
|
|
||||
|
.hidden { |
||||
|
display: none } |
||||
|
|
||||
|
.subscript { |
||||
|
vertical-align: sub; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
.superscript { |
||||
|
vertical-align: super; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
a.toc-backref { |
||||
|
text-decoration: none ; |
||||
|
color: black } |
||||
|
|
||||
|
blockquote.epigraph { |
||||
|
margin: 2em 5em ; } |
||||
|
|
||||
|
dl.docutils dd { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get bold-faced definition list terms |
||||
|
dl.docutils dt { |
||||
|
font-weight: bold } |
||||
|
*/ |
||||
|
|
||||
|
div.abstract { |
||||
|
margin: 2em 5em } |
||||
|
|
||||
|
div.abstract p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
text-align: center } |
||||
|
|
||||
|
div.admonition, div.attention, div.caution, div.danger, div.error, |
||||
|
div.hint, div.important, div.note, div.tip, div.warning { |
||||
|
margin: 2em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.admonition p.admonition-title, div.hint p.admonition-title, |
||||
|
div.important p.admonition-title, div.note p.admonition-title, |
||||
|
div.tip p.admonition-title { |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
div.attention p.admonition-title, div.caution p.admonition-title, |
||||
|
div.danger p.admonition-title, div.error p.admonition-title, |
||||
|
div.warning p.admonition-title, .code .error { |
||||
|
color: red ; |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in |
||||
|
compound paragraphs. |
||||
|
div.compound .compound-first, div.compound .compound-middle { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
div.compound .compound-last, div.compound .compound-middle { |
||||
|
margin-top: 0.5em } |
||||
|
*/ |
||||
|
|
||||
|
div.dedication { |
||||
|
margin: 2em 5em ; |
||||
|
text-align: center ; |
||||
|
font-style: italic } |
||||
|
|
||||
|
div.dedication p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
font-style: normal } |
||||
|
|
||||
|
div.figure { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
div.footer, div.header { |
||||
|
clear: both; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
div.line-block { |
||||
|
display: block ; |
||||
|
margin-top: 1em ; |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
div.line-block div.line-block { |
||||
|
margin-top: 0 ; |
||||
|
margin-bottom: 0 ; |
||||
|
margin-left: 1.5em } |
||||
|
|
||||
|
div.sidebar { |
||||
|
margin: 0 0 0.5em 1em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em ; |
||||
|
background-color: #ffffee ; |
||||
|
width: 40% ; |
||||
|
float: right ; |
||||
|
clear: right } |
||||
|
|
||||
|
div.sidebar p.rubric { |
||||
|
font-family: sans-serif ; |
||||
|
font-size: medium } |
||||
|
|
||||
|
div.system-messages { |
||||
|
margin: 5em } |
||||
|
|
||||
|
div.system-messages h1 { |
||||
|
color: red } |
||||
|
|
||||
|
div.system-message { |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.system-message p.system-message-title { |
||||
|
color: red ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
div.topic { |
||||
|
margin: 2em } |
||||
|
|
||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, |
||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { |
||||
|
margin-top: 0.4em } |
||||
|
|
||||
|
h1.title { |
||||
|
text-align: center } |
||||
|
|
||||
|
h2.subtitle { |
||||
|
text-align: center } |
||||
|
|
||||
|
hr.docutils { |
||||
|
width: 75% } |
||||
|
|
||||
|
img.align-left, .figure.align-left, object.align-left, table.align-left { |
||||
|
clear: left ; |
||||
|
float: left ; |
||||
|
margin-right: 1em } |
||||
|
|
||||
|
img.align-right, .figure.align-right, object.align-right, table.align-right { |
||||
|
clear: right ; |
||||
|
float: right ; |
||||
|
margin-left: 1em } |
||||
|
|
||||
|
img.align-center, .figure.align-center, object.align-center { |
||||
|
display: block; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
table.align-center { |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
.align-left { |
||||
|
text-align: left } |
||||
|
|
||||
|
.align-center { |
||||
|
clear: both ; |
||||
|
text-align: center } |
||||
|
|
||||
|
.align-right { |
||||
|
text-align: right } |
||||
|
|
||||
|
/* reset inner alignment in figures */ |
||||
|
div.align-right { |
||||
|
text-align: inherit } |
||||
|
|
||||
|
/* div.align-center * { */ |
||||
|
/* text-align: left } */ |
||||
|
|
||||
|
.align-top { |
||||
|
vertical-align: top } |
||||
|
|
||||
|
.align-middle { |
||||
|
vertical-align: middle } |
||||
|
|
||||
|
.align-bottom { |
||||
|
vertical-align: bottom } |
||||
|
|
||||
|
ol.simple, ul.simple { |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
ol.arabic { |
||||
|
list-style: decimal } |
||||
|
|
||||
|
ol.loweralpha { |
||||
|
list-style: lower-alpha } |
||||
|
|
||||
|
ol.upperalpha { |
||||
|
list-style: upper-alpha } |
||||
|
|
||||
|
ol.lowerroman { |
||||
|
list-style: lower-roman } |
||||
|
|
||||
|
ol.upperroman { |
||||
|
list-style: upper-roman } |
||||
|
|
||||
|
p.attribution { |
||||
|
text-align: right ; |
||||
|
margin-left: 50% } |
||||
|
|
||||
|
p.caption { |
||||
|
font-style: italic } |
||||
|
|
||||
|
p.credits { |
||||
|
font-style: italic ; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
p.label { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
p.rubric { |
||||
|
font-weight: bold ; |
||||
|
font-size: larger ; |
||||
|
color: maroon ; |
||||
|
text-align: center } |
||||
|
|
||||
|
p.sidebar-title { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold ; |
||||
|
font-size: larger } |
||||
|
|
||||
|
p.sidebar-subtitle { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
p.topic-title { |
||||
|
font-weight: bold } |
||||
|
|
||||
|
pre.address { |
||||
|
margin-bottom: 0 ; |
||||
|
margin-top: 0 ; |
||||
|
font: inherit } |
||||
|
|
||||
|
pre.literal-block, pre.doctest-block, pre.math, pre.code { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
pre.code .ln { color: grey; } /* line numbers */ |
||||
|
pre.code, code { background-color: #eeeeee } |
||||
|
pre.code .comment, code .comment { color: #5C6576 } |
||||
|
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } |
||||
|
pre.code .literal.string, code .literal.string { color: #0C5404 } |
||||
|
pre.code .name.builtin, code .name.builtin { color: #352B84 } |
||||
|
pre.code .deleted, code .deleted { background-color: #DEB0A1} |
||||
|
pre.code .inserted, code .inserted { background-color: #A3D289} |
||||
|
|
||||
|
span.classifier { |
||||
|
font-family: sans-serif ; |
||||
|
font-style: oblique } |
||||
|
|
||||
|
span.classifier-delimiter { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
span.interpreted { |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
span.option { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
span.pre { |
||||
|
white-space: pre } |
||||
|
|
||||
|
span.problematic { |
||||
|
color: red } |
||||
|
|
||||
|
span.section-subtitle { |
||||
|
/* font-size relative to parent (h1..h6 element) */ |
||||
|
font-size: 80% } |
||||
|
|
||||
|
table.citation { |
||||
|
border-left: solid 1px gray; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docinfo { |
||||
|
margin: 2em 4em } |
||||
|
|
||||
|
table.docutils { |
||||
|
margin-top: 0.5em ; |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
table.footnote { |
||||
|
border-left: solid 1px black; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docutils td, table.docutils th, |
||||
|
table.docinfo td, table.docinfo th { |
||||
|
padding-left: 0.5em ; |
||||
|
padding-right: 0.5em ; |
||||
|
vertical-align: top } |
||||
|
|
||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name { |
||||
|
font-weight: bold ; |
||||
|
text-align: left ; |
||||
|
white-space: nowrap ; |
||||
|
padding-left: 0 } |
||||
|
|
||||
|
/* "booktabs" style (no vertical lines) */ |
||||
|
table.docutils.booktabs { |
||||
|
border: 0px; |
||||
|
border-top: 2px solid; |
||||
|
border-bottom: 2px solid; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
table.docutils.booktabs * { |
||||
|
border: 0px; |
||||
|
} |
||||
|
table.docutils.booktabs th { |
||||
|
border-bottom: thin solid; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, |
||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { |
||||
|
font-size: 100% } |
||||
|
|
||||
|
ul.auto-toc { |
||||
|
list-style-type: none } |
||||
|
|
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="document" id="location-management-aka-better-zip"> |
||||
|
<h1 class="title">Location management (aka Better ZIP)</h1> |
||||
|
|
||||
|
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> |
||||
|
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/partner-contact/tree/12.0/base_location"><img alt="OCA/partner-contact" src="https://img.shields.io/badge/github-OCA%2Fpartner--contact-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/partner-contact-12-0/partner-contact-12-0-base_location"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/134/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> |
||||
|
<p>This module introduces a zip model that allows you to manage locations in a better way.</p> |
||||
|
<p>The zips will allow the users to complete automatically all address-related fields by just filling the zip.</p> |
||||
|
<p>Also allows different search filters.</p> |
||||
|
<p><strong>Table of contents</strong></p> |
||||
|
<div class="contents local topic" id="contents"> |
||||
|
<ul class="simple"> |
||||
|
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li> |
||||
|
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li> |
||||
|
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li> |
||||
|
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul> |
||||
|
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li> |
||||
|
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li> |
||||
|
<li><a class="reference internal" href="#other-credits" id="id7">Other credits</a></li> |
||||
|
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="configuration"> |
||||
|
<h1><a class="toc-backref" href="#id1">Configuration</a></h1> |
||||
|
<ol class="arabic simple"> |
||||
|
<li>Go to <em>Contacts / Configuration / Localization / Cities</em>.</li> |
||||
|
<li>Create a new City.</li> |
||||
|
<li>Go to <em>Contacts / Configuration / Localization / Zips</em>.</li> |
||||
|
<li>Create a new Zip and relate it to the city (you can also create the Zip from the City).</li> |
||||
|
</ol> |
||||
|
<p>or, with module ‘Contacts Directory’ installed: |
||||
|
#. Go to <em>Contacts / Configuration / Localization / Countries</em>. |
||||
|
#. Locate the desired country. |
||||
|
#. Press on the button ‘Cities’ / ‘Zips’.</p> |
||||
|
</div> |
||||
|
<div class="section" id="usage"> |
||||
|
<h1><a class="toc-backref" href="#id2">Usage</a></h1> |
||||
|
<ol class="arabic simple"> |
||||
|
<li>Access a partner record</li> |
||||
|
<li>Fill the field <em>Location completion</em></li> |
||||
|
<li>Information about country, state, city and zip will be filled automatically</li> |
||||
|
</ol> |
||||
|
</div> |
||||
|
<div class="section" id="bug-tracker"> |
||||
|
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1> |
||||
|
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/partner-contact/issues">GitHub Issues</a>. |
||||
|
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 |
||||
|
<a class="reference external" href="https://github.com/OCA/partner-contact/issues/new?body=module:%20base_location%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> |
||||
|
<p>Do not contact contributors directly about support or help with technical issues.</p> |
||||
|
</div> |
||||
|
<div class="section" id="credits"> |
||||
|
<h1><a class="toc-backref" href="#id4">Credits</a></h1> |
||||
|
<div class="section" id="authors"> |
||||
|
<h2><a class="toc-backref" href="#id5">Authors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>Camptocamp</li> |
||||
|
<li>ACYSOS S.L.</li> |
||||
|
<li>Alejandro Santana</li> |
||||
|
<li>Tecnativa</li> |
||||
|
<li>AdaptiveCity</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="contributors"> |
||||
|
<h2><a class="toc-backref" href="#id6">Contributors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>Nicolas Bessi (Camptocamp)</li> |
||||
|
<li>Ignacio Ibeas (Acysos S.L.)</li> |
||||
|
<li>Pedro M. Baeza <<a class="reference external" href="mailto:pedro.baeza@gmail.com">pedro.baeza@gmail.com</a>></li> |
||||
|
<li>Alejandro Santana <<a class="reference external" href="mailto:alejandrosantana@anubia.es">alejandrosantana@anubia.es</a>></li> |
||||
|
<li>Sandy Carter <<a class="reference external" href="mailto:sandy.carter@savoirfairelinux.com">sandy.carter@savoirfairelinux.com</a>></li> |
||||
|
<li>Yannick Vaucher <<a class="reference external" href="mailto:yannick.vaucher@camptocamp.com">yannick.vaucher@camptocamp.com</a>></li> |
||||
|
<li>Francesco Apruzzese <<a class="reference external" href="mailto:f.apruzzese@apuliasoftware.it">f.apruzzese@apuliasoftware.it</a>></li> |
||||
|
<li>Dave Lasley <<a class="reference external" href="mailto:dave@laslabs.com">dave@laslabs.com</a>></li> |
||||
|
<li>Aitor Bouzas <<a class="reference external" href="mailto:aitor.bouzas@adaptivecity.com">aitor.bouzas@adaptivecity.com</a>></li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="other-credits"> |
||||
|
<h2><a class="toc-backref" href="#id7">Other credits</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>Icon park: <cite>Icon http://icon-park.com/icon/location-map-pin-orange3/</cite></li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="maintainers"> |
||||
|
<h2><a class="toc-backref" href="#id8">Maintainers</a></h2> |
||||
|
<p>This module is maintained by the OCA.</p> |
||||
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> |
||||
|
<p>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.</p> |
||||
|
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/partner-contact/tree/12.0/base_location">OCA/partner-contact</a> project on GitHub.</p> |
||||
|
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
@ -1,4 +1,3 @@ |
|||||
# 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_base_location |
from . import test_base_location |
@ -1,85 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<odoo> |
|
||||
|
|
||||
<record model="ir.ui.view" id="better_zip_form"> |
|
||||
<field name="name">res.better.zip.form</field> |
|
||||
<field name="model">res.better.zip</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form string="City"> |
|
||||
<group col="4"> |
|
||||
<group> |
|
||||
<field name="name"/> |
|
||||
<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="enforce_cities" invisible="1"/> |
|
||||
</group> |
|
||||
<group> |
|
||||
<field name="code"/> |
|
||||
<field name="state_id" |
|
||||
attrs="{'invisible': [('enforce_cities', '=', True)]}"/> |
|
||||
</group> |
|
||||
</group> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
<record model="ir.ui.view" id="better_zip_tree"> |
|
||||
<field name="name">res.better.zip.tree</field> |
|
||||
<field name="model">res.better.zip</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<tree string="Cities"> |
|
||||
<field name="name"/> |
|
||||
<field name="code"/> |
|
||||
<field name="city"/> |
|
||||
<field name="state_id"/> |
|
||||
<field name="country_id"/> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
<record id="view_better_zip_filter" model="ir.ui.view"> |
|
||||
<field name="name">res.better.zip.select</field> |
|
||||
<field name="model">res.better.zip</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<search string="Search city"> |
|
||||
<field name="name"/> |
|
||||
<field name="code"/> |
|
||||
<field name="city"/> |
|
||||
<field name="state_id"/> |
|
||||
<field name="country_id"/> |
|
||||
<group expand="0" string="Group By"> |
|
||||
<filter string="State" domain="[]" |
|
||||
context="{'group_by':'state_id'}"/> |
|
||||
<filter string="Country" domain="[]" |
|
||||
context="{'group_by':'country_id'}"/> |
|
||||
</group> |
|
||||
</search> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
<record id="action_zip_tree" model="ir.actions.act_window"> |
|
||||
<field name="name">Locations</field> |
|
||||
<field name="res_model">res.better.zip</field> |
|
||||
<field name="view_type">form</field> |
|
||||
<field name="view_mode">tree,form</field> |
|
||||
<field ref="better_zip_tree" name="view_id"/> |
|
||||
<field name="search_view_id" ref="view_better_zip_filter"/> |
|
||||
</record> |
|
||||
|
|
||||
<menuitem |
|
||||
name="Locations Management" |
|
||||
id="locations_root_menu" |
|
||||
parent="base.menu_custom" |
|
||||
/> |
|
||||
|
|
||||
<menuitem |
|
||||
name="Locations" |
|
||||
id="locations_menu" |
|
||||
parent="locations_root_menu" |
|
||||
action="action_zip_tree" |
|
||||
/> |
|
||||
|
|
||||
</odoo> |
|
@ -0,0 +1,63 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<record id="view_city_tree_inherit" model="ir.ui.view"> |
||||
|
<field name="model">res.city</field> |
||||
|
<field name="inherit_id" ref="base_address_city.view_city_tree"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree position="attributes"> |
||||
|
<attribute name="editable"/> |
||||
|
</tree> |
||||
|
<field name="zipcode" position="attributes"> |
||||
|
<attribute name="invisible">1</attribute> |
||||
|
</field> |
||||
|
<field name="zipcode" position="after"> |
||||
|
<field name="zip_ids" widget="many2many_tags"/> |
||||
|
</field> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_city_form" model="ir.ui.view"> |
||||
|
<field name="model">res.city</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<group> |
||||
|
<field name="name"/> |
||||
|
<field name="country_id"/> |
||||
|
<field name="state_id"/> |
||||
|
</group> |
||||
|
<notebook> |
||||
|
<page name="zips" string="Zips"> |
||||
|
<field name="zip_ids"/> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_res_city_full" model="ir.actions.act_window"> |
||||
|
<field name="name">Cities</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">res.city</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="view_ids" |
||||
|
eval="[(5,0,0), |
||||
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('base_address_city.view_city_tree')}), |
||||
|
(0, 0, {'view_mode': 'form', 'view_id': ref('view_city_form')})]"/> |
||||
|
<field name="help"> |
||||
|
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. |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem |
||||
|
name="Cities" |
||||
|
id="locations_menu_cities" |
||||
|
parent="contacts.menu_localisation" |
||||
|
action="action_res_city_full" |
||||
|
sequence="4" |
||||
|
/> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1,56 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<record model="ir.ui.view" id="city_zip_form"> |
||||
|
<field name="name">res.city.zip.form</field> |
||||
|
<field name="model">res.city.zip</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Zip"> |
||||
|
<group> |
||||
|
<field name="name"/> |
||||
|
<field name="city_id"/> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="city_zip_tree"> |
||||
|
<field name="name">res.city.zip.tree</field> |
||||
|
<field name="model">res.city.zip</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Zips" editable="top"> |
||||
|
<field name="name"/> |
||||
|
<field name="city_id"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_city_zip_filter" model="ir.ui.view"> |
||||
|
<field name="name">res.city.zip.select</field> |
||||
|
<field name="model">res.city.zip</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Search zip"> |
||||
|
<field name="name"/> |
||||
|
<field name="city_id"/> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_zip_tree" model="ir.actions.act_window"> |
||||
|
<field name="name">Locations</field> |
||||
|
<field name="res_model">res.city.zip</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field ref="city_zip_tree" name="view_id"/> |
||||
|
<field name="search_view_id" ref="view_city_zip_filter"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem |
||||
|
name="Zips" |
||||
|
id="locations_menu_zips" |
||||
|
parent="contacts.menu_localisation" |
||||
|
action="action_zip_tree" |
||||
|
sequence="5" |
||||
|
/> |
||||
|
|
||||
|
</odoo> |
@ -1,26 +0,0 @@ |
|||||
<?xml version="1.0"?> |
|
||||
<odoo> |
|
||||
|
|
||||
<!-- Add cities to the State form --> |
|
||||
<record model="ir.ui.view" id="view_country_state_form2"> |
|
||||
<field name="name">view_country_state_form2</field> |
|
||||
<field name="model">res.country.state</field> |
|
||||
<field name="inherit_id" ref="base.view_country_state_form"/> |
|
||||
<field name="arch" type="xml"> |
|
||||
<field name="country_id" position="after"> |
|
||||
<field name="better_zip_ids" |
|
||||
context="{'country_id': country_id}" |
|
||||
colspan="2" |
|
||||
nolabel="1"> |
|
||||
<tree editable="top"> |
|
||||
<field name="name"/> |
|
||||
<field name="code"/> |
|
||||
<field name="city"/> |
|
||||
<field name="country_id"/> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</field> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
</odoo> |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue