diff --git a/addons/web/models/ir_qweb.py b/addons/web/models/ir_qweb.py index 875899f7d57..51694a3bc42 100644 --- a/addons/web/models/ir_qweb.py +++ b/addons/web/models/ir_qweb.py @@ -21,20 +21,12 @@ class Image(models.AbstractModel): _description = 'Qweb Field Image' _inherit = 'ir.qweb.field.image' - @api.model - def record_to_html(self, record, field_name, options): - assert options['tagName'] != 'img',\ - "Oddly enough, the root tag of an image field can not be img. " \ - "That is because the image goes into the tag, or it gets the " \ - "hose again." - - if options.get('qweb_img_raw_data', False): - return super(Image, self).record_to_html(record, field_name, options) - - aclasses = ['img', 'img-fluid'] if options.get('qweb_img_responsive', True) else ['img'] - aclasses += options.get('class', '').split() - classes = ' '.join(map(escape, aclasses)) + def _get_src_urls(self, record, field_name, options): + """Considering the rendering options, returns the src and data-zoom-image urls. + :return: src, src_zoom urls + :rtype: tuple + """ max_size = None if options.get('resize'): max_size = options.get('resize') @@ -56,6 +48,30 @@ class Image(models.AbstractModel): src = '/web/image/%s/%s/%s%s/%s?unique=%s' % (record._name, record.id, options.get('preview_image', field_name), max_size, url_quote(filename), sha) + src_zoom = None + if options.get('zoom') and getattr(record, options['zoom'], None): + src_zoom = '/web/image/%s/%s/%s%s/%s?unique=%s' % (record._name, record.id, options['zoom'], max_size, url_quote(filename), sha) + elif options.get('zoom'): + src_zoom = options['zoom'] + + return src, src_zoom + + @api.model + def record_to_html(self, record, field_name, options): + assert options['tagName'] != 'img',\ + "Oddly enough, the root tag of an image field can not be img. " \ + "That is because the image goes into the tag, or it gets the " \ + "hose again." + + if options.get('qweb_img_raw_data', False): + return super(Image, self).record_to_html(record, field_name, options) + + aclasses = ['img', 'img-fluid'] if options.get('qweb_img_responsive', True) else ['img'] + aclasses += options.get('class', '').split() + classes = ' '.join(map(escape, aclasses)) + + src, src_zoom = self._get_src_urls(record, field_name, options) + if options.get('alt-field') and getattr(record, options['alt-field'], None): alt = escape(record[options['alt-field']]) elif options.get('alt'): @@ -63,12 +79,6 @@ class Image(models.AbstractModel): else: alt = escape(record.display_name) - src_zoom = None - if options.get('zoom') and getattr(record, options['zoom'], None): - src_zoom = '/web/image/%s/%s/%s%s/%s?unique=%s' % (record._name, record.id, options['zoom'], max_size, url_quote(filename), sha) - elif options.get('zoom'): - src_zoom = options['zoom'] - itemprop = None if options.get('itemprop'): itemprop = options['itemprop'] @@ -96,3 +106,11 @@ class Image(models.AbstractModel): img.append('/>') return u''.join(img) + +class ImageUrlConverter(models.AbstractModel): + _description = 'Qweb Field Image' + _inherit = 'ir.qweb.field.image_url' + + def _get_src_urls(self, record, field_name, options): + image_url = record[options.get('preview_image', field_name)] + return image_url, options.get("zoom", None) diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 3e49fdbf250..8ebde6cbda9 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -1955,6 +1955,45 @@ var FieldBinaryImage = AbstractFieldBinary.extend({ }, }); +var CharImageUrl = AbstractField.extend({ + className: 'o_field_image', + description: _lt("Image"), + supportedFieldTypes: ['char'], + placeholder: "/web/static/src/img/placeholder.png", + + _renderReadonly: function () { + var self = this; + const url = this.value; + if (url) { + var $img = $(qweb.render("FieldBinaryImage-img", {widget: this, url: url})); + // override css size attributes (could have been defined in css files) + // if specified on the widget + const width = this.nodeOptions.size ? this.nodeOptions.size[0] : this.attrs.width; + const height = this.nodeOptions.size ? this.nodeOptions.size[1] : this.attrs.height; + if (width) { + $img.attr('width', width); + $img.css('max-width', width + 'px'); + } + if (height) { + $img.attr('height', height); + $img.css('max-height', height + 'px'); + } + this.$('> img').remove(); + this.$el.prepend($img); + + $img.one('error', function () { + $img.attr('src', self.placeholder); + self.displayNotification({ + type: 'info', + message: _t("Could not display the specified image url."), + }); + }); + } + + return this._super.apply(this, arguments); + }, +}); + var KanbanFieldBinaryImage = FieldBinaryImage.extend({ // In kanban views, there is a weird logic to determine whether or not a // click on a card should open the record in a form view. This logic checks @@ -1966,6 +2005,17 @@ var KanbanFieldBinaryImage = FieldBinaryImage.extend({ events: {}, }); +var KanbanCharImageUrl = CharImageUrl.extend({ + // In kanban views, there is a weird logic to determine whether or not a + // click on a card should open the record in a form view. This logic checks + // if the clicked element has click handlers bound on it, and if so, does + // not open the record (assuming that the click will be handled by someone + // else). In the case of this widget, there are clicks handler but they + // only apply in edit mode, which is never the case in kanban views, so we + // simply remove them. + events: {}, +}); + var FieldBinaryFile = AbstractFieldBinary.extend({ description: _lt("File"), template: 'FieldBinaryFile', @@ -3539,6 +3589,8 @@ return { AbstractFieldBinary: AbstractFieldBinary, FieldBinaryImage: FieldBinaryImage, KanbanFieldBinaryImage: KanbanFieldBinaryImage, + CharImageUrl: CharImageUrl, + KanbanCharImageUrl: KanbanCharImageUrl, FieldBoolean: FieldBoolean, BooleanToggle: BooleanToggle, FieldChar: FieldChar, diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js index ef174702579..e96ee705b77 100644 --- a/addons/web/static/src/js/fields/field_registry.js +++ b/addons/web/static/src/js/fields/field_registry.js @@ -43,7 +43,9 @@ registry .add('CopyClipboardText', basic_fields.TextCopyClipboard) .add('CopyClipboardChar', basic_fields.CharCopyClipboard) .add('image', basic_fields.FieldBinaryImage) + .add('image_url', basic_fields.CharImageUrl) .add('kanban.image', basic_fields.KanbanFieldBinaryImage) + .add('kanban.image_url', basic_fields.KanbanCharImageUrl) .add('binary', basic_fields.FieldBinaryFile) .add('pdf_viewer', basic_fields.FieldPdfViewer) .add('monetary', basic_fields.FieldMonetary) diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 76783a90d31..8debec81b3a 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -24,6 +24,9 @@ var _t = core._t; // Base64 images for testing purpose const MY_IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; const PRODUCT_IMAGE = 'R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7'; +const FR_FLAG_URL = '/base/static/img/country_flags/fr.png'; +const EN_FLAG_URL = '/base/static/img/country_flags/gb.png'; + QUnit.module('fields', {}, function () { @@ -2889,6 +2892,131 @@ QUnit.module('basic_fields', { form.destroy(); }); + /** + * Same tests than for Image fields, but for Char fields with image_url widget. + */ + QUnit.module('FieldChar-ImageUrlWidget', { + beforeEach: function () { + // specific sixth partner data for image_url widget tests + this.data.partner.records.push({id: 6, bar: false, foo: FR_FLAG_URL, int_field: 5, qux: 0.0, timmy: []}); + }, + }); + + QUnit.test('image fields are correctly rendered', async function (assert) { + assert.expect(6); + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + ' ' + + '', + res_id: 6, + async mockRPC(route, args) { + if (route === FR_FLAG_URL) { + assert.ok(true, "the correct route should have been called."); + } + return this._super.apply(this, arguments); + }, + }); + + assert.hasClass(form.$('div[name="foo"]'), 'o_field_image', + "the widget should have the correct class"); + assert.containsOnce(form, 'div[name="foo"] > img', + "the widget should contain an image"); + assert.hasClass(form.$('div[name="foo"] > img'), 'img-fluid', + "the image should have the correct class"); + assert.hasAttrValue(form.$('div[name="foo"] > img'), 'width', "90", + "the image should correctly set its attributes"); + assert.strictEqual(form.$('div[name="foo"] > img').css('max-width'), "90px", + "the image should correctly set its attributes"); + form.destroy(); + }); + + QUnit.test('image_url widget in subviews are loaded correctly', async function (assert) { + assert.expect(6); + + this.data.partner_type.fields.image = {name: 'image', type: 'char'}; + this.data.partner_type.records[0].image = EN_FLAG_URL; + this.data.partner.records[5].timmy = [12]; + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '', + res_id: 6, + async mockRPC(route) { + if (route === FR_FLAG_URL) { + assert.step("The view's image should have been fetched"); + return 'wow'; + } + if (route === EN_FLAG_URL) { + assert.step("The dialog's image should have been fetched"); + return; + } + return this._super.apply(this, arguments); + }, + }); + assert.verifySteps(["The view's image should have been fetched"]); + + assert.containsOnce(form, 'tr.o_data_row', + 'There should be one record in the many2many'); + + // Actual flow: click on an element of the m2m to get its form view + await testUtils.dom.click(form.$('tbody td:contains(gold)')); + assert.strictEqual($('.modal').length, 1, + 'The modal should have opened'); + assert.verifySteps(["The dialog's image should have been fetched"]); + + form.destroy(); + }); + + QUnit.test('image fields in x2many list are loaded correctly', async function (assert) { + assert.expect(2); + + this.data.partner_type.fields.image = {name: 'image', type: 'char'}; + this.data.partner_type.records[0].image = EN_FLAG_URL; + this.data.partner.records[5].timmy = [12]; + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 6, + async mockRPC(route) { + if (route === EN_FLAG_URL) { + assert.ok(true, "The list's image should have been fetched"); + return; + } + return this._super.apply(this, arguments); + }, + }); + + assert.containsOnce(form, 'tr.o_data_row', + 'There should be one record in the many2many'); + + form.destroy(); + }); + QUnit.module('JournalDashboardGraph', { beforeEach: function () { _.extend(this.data.partner.fields, { diff --git a/addons/website/data/website_data.xml b/addons/website/data/website_data.xml index b9e21640add..c7ed6fa16b8 100644 --- a/addons/website/data/website_data.xml +++ b/addons/website/data/website_data.xml @@ -250,8 +250,8 @@ business_conference.jpg ir.ui.view - binary - + url + /website/static/src/img/library/business_conference.jpg diff --git a/addons/website/models/website_visitor.py b/addons/website/models/website_visitor.py index ca54d20d883..b4eccd5264e 100644 --- a/addons/website/models/website_visitor.py +++ b/addons/website/models/website_visitor.py @@ -38,7 +38,7 @@ class WebsiteVisitor(models.Model): # localisation and info country_id = fields.Many2one('res.country', 'Country', readonly=True) - country_flag = fields.Binary(related="country_id.image", string="Country Flag") + country_flag = fields.Char(related="country_id.image_url", string="Country Flag") lang_id = fields.Many2one('res.lang', string='Language', help="Language from the website when visitor has been created") timezone = fields.Selection(_tz_get, string='Timezone') email = fields.Char(string='Email', compute='_compute_email_phone') diff --git a/addons/website/tests/test_performance.py b/addons/website/tests/test_performance.py index 466167b436f..48763dc75b9 100644 --- a/addons/website/tests/test_performance.py +++ b/addons/website/tests/test_performance.py @@ -33,8 +33,6 @@ class UtilPerf(HttpCase): class TestStandardPerformance(UtilPerf): def test_10_perf_sql_img_controller(self): self.authenticate('demo', 'demo') - url = '/web/image/res.country/4/image' - self.assertEqual(self._get_url_hot_query(url), 4) url = '/web/image/res.users/2/image_256' self.assertEqual(self._get_url_hot_query(url), 8) diff --git a/addons/website/views/website_visitor_views.xml b/addons/website/views/website_visitor_views.xml index 9ec67f4503f..6a07151fd66 100644 --- a/addons/website/views/website_visitor_views.xml +++ b/addons/website/views/website_visitor_views.xml @@ -82,6 +82,7 @@ + @@ -109,10 +110,10 @@ -
- Country + +
+ Country
@@ -147,7 +148,8 @@ Country + t-att-src="record.country_flag.raw_value" + class="o_country_flag" alt="Country"/>
Active
@@ -196,7 +198,9 @@ -
+
+ +

@@ -227,7 +231,7 @@ - + diff --git a/addons/website_event_track_exhibitor/models/event_sponsor.py b/addons/website_event_track_exhibitor/models/event_sponsor.py index 4f812034e3e..878938f739a 100644 --- a/addons/website_event_track_exhibitor/models/event_sponsor.py +++ b/addons/website_event_track_exhibitor/models/event_sponsor.py @@ -92,11 +92,11 @@ class EventSponsor(models.Model): sponsor.is_in_opening_hours = opening_from <= now_tz < opening_to - @api.depends('partner_id.country_id.image') + @api.depends('partner_id.country_id.image_url') def _compute_country_flag_url(self): for sponsor in self: if sponsor.partner_id.country_id: - sponsor.country_flag_url = self.env['website'].image_url(sponsor.partner_id.country_id, 'image', size=256) + sponsor.country_flag_url = sponsor.partner_id.country_id.image_url else: sponsor.country_flag_url = False diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index d24ea064a5f..3e8e8aea253 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -1641,7 +1641,7 @@
diff --git a/odoo/addons/base/data/res_country_data.xml b/odoo/addons/base/data/res_country_data.xml index 2f35c017426..d436eb684d2 100644 --- a/odoo/addons/base/data/res_country_data.xml +++ b/odoo/addons/base/data/res_country_data.xml @@ -5,49 +5,42 @@ United Arab Emirates ae - Afghanistan af - Antigua and Barbuda ag - Anguilla ai - Albania al - Armenia am - @@ -55,7 +48,6 @@ Angola ao 0 -
@@ -69,7 +61,6 @@ Argentina ar 1 - CUIT @@ -78,14 +69,12 @@ American Samoa as - Austria at - @@ -95,7 +84,6 @@ Australia au 1 - @@ -103,49 +91,42 @@ Aruba aw - Åland Islands ax - Azerbaijan az - Bosnia and Herzegovina ba - Barbados bb - Bangladesh bd - Belgium be - @@ -154,14 +135,12 @@ Burkina Faso bf - Bulgaria bg - VAT @@ -169,14 +148,12 @@ Bahrain bh - Burundi bi - @@ -184,35 +161,30 @@ Benin bj 0 - Saint Barthélémy bl - Bermuda bm - Brunei Darussalam bn - Bolivia bo - @@ -225,7 +197,6 @@ Brazil br - @@ -233,14 +204,12 @@ Bahamas bs - Bhutan bt - @@ -253,14 +222,12 @@ Botswana bw - Belarus by - @@ -268,7 +235,6 @@ Belize bz 0 - @@ -276,7 +242,6 @@ Canada ca 1 - @@ -285,35 +250,30 @@ Cocos (Keeling) Islands cc - Central African Republic cf - Democratic Republic of the Congo cd - Congo cg - Switzerland ch - @@ -321,35 +281,30 @@ Côte d'Ivoire ci - Cook Islands ck - Chile cl - Cameroon cm - China cn - @@ -358,7 +313,6 @@ Colombia co NIT - @@ -366,42 +320,36 @@ Costa Rica cr - Cuba cu - Cape Verde cv - Curaçao cw - Christmas Island cx - Cyprus cy - VAT @@ -409,7 +357,6 @@ Czech Republic cz - VAT @@ -417,7 +364,6 @@ Germany de - @@ -426,14 +372,12 @@ Djibouti dj - Denmark dk - @@ -442,14 +386,12 @@ Dominica dm - Dominican Republic do - @@ -458,21 +400,18 @@ Algeria dz - Ecuador ec - Estonia ee - VAT @@ -480,7 +419,6 @@ Egypt eg - @@ -493,14 +431,12 @@ Eritrea er - Spain es - @@ -509,14 +445,12 @@ Ethiopia et - Finland fi - @@ -525,35 +459,30 @@ Fiji fj - Falkland Islands fk - Micronesia fm - Faroe Islands fo - France fr - @@ -562,21 +491,18 @@ Gabon ga - Grenada gd - Georgia ge - @@ -589,42 +515,36 @@ Ghana gh - Gibraltar gi - Guernsey gg - Greenland gl - Gambia gm - Guinea gn - @@ -637,14 +557,12 @@ Equatorial Guinea gq - Greece gr - VAT @@ -652,14 +570,12 @@ South Georgia and the South Sandwich Islands gs - Guatemala gt - NIT @@ -667,21 +583,18 @@ Guam gu - Guinea-Bissau gw - Guyana gy - @@ -689,7 +602,6 @@ Hong Kong hk 0 - @@ -702,14 +614,12 @@ Honduras hn - Croatia hr - @@ -718,14 +628,12 @@ Haiti ht - Hungary hu - VAT @@ -734,7 +642,6 @@ Indonesia id 1 - NPWP @@ -743,7 +650,6 @@ Ireland ie 0 - VAT @@ -751,14 +657,12 @@ Israel il - Isle of Man im - @@ -766,7 +670,6 @@ India in 1 - @@ -775,28 +678,24 @@ British Indian Ocean Territory io - Iraq iq - Iran ir - Iceland is - @@ -804,7 +703,6 @@ Italy it 1 - VAT @@ -812,21 +710,18 @@ Jersey je - Jamaica jm - Jordan jo - @@ -834,7 +729,6 @@ Japan jp 1 - after @@ -843,105 +737,90 @@ Kenya ke - Kyrgyzstan kg - Cambodia kh - Kiribati ki - Comoros km - Saint Kitts and Nevis kn - North Korea kp - South Korea kr - Kuwait kw - Cayman Islands ky - Kazakhstan kz - Laos la - Lebanon lb - Saint Lucia lc - Liechtenstein li - @@ -949,28 +828,24 @@ Sri Lanka lk - Liberia lr - Lesotho ls - Lithuania lt - VAT @@ -978,7 +853,6 @@ Luxembourg lu - VAT @@ -986,7 +860,6 @@ Latvia lv - VAT @@ -994,14 +867,12 @@ Libya ly - Morocco ma - @@ -1009,20 +880,17 @@ Monaco mc - Moldova md - Montenegro me - @@ -1035,42 +903,36 @@ Madagascar mg - Marshall Islands mh - North Macedonia mk - Mali ml - Myanmar mm - Mongolia mn - @@ -1078,42 +940,36 @@ Macau mo 0 - Northern Mariana Islands mp - Martinique mq - Mauritania mr - Montserrat ms - Malta mt - VAT @@ -1121,7 +977,6 @@ Mauritius mu - @@ -1129,14 +984,12 @@ Maldives mv - Malawi mw - @@ -1144,7 +997,6 @@ Mexico mx 1 - RFC @@ -1153,63 +1005,54 @@ Malaysia my - Mozambique mz - Namibia na - New Caledonia nc - Niger ne - Norfolk Island nf - Nigeria ng - Nicaragua ni - Netherlands nl - @@ -1218,7 +1061,6 @@ Norway no - @@ -1226,42 +1068,36 @@ Nepal np - Nauru nr - Niue nu - New Zealand nz - Oman om - Panama pa - @@ -1269,42 +1105,36 @@ Peru pe - French Polynesia pf - Papua New Guinea pg - Philippines ph - Pakistan pk - Poland pl - @@ -1313,21 +1143,18 @@ Saint Pierre and Miquelon pm - Pitcairn Islands pn - Puerto Rico pr - @@ -1340,7 +1167,6 @@ Portugal pt - VAT @@ -1348,21 +1174,18 @@ Palau pw - Paraguay py - Qatar qa - @@ -1375,7 +1198,6 @@ Romania ro - VAT @@ -1383,56 +1205,48 @@ Serbia rs - Russian Federation ru - Rwanda rw - Saudi Arabia sa - Solomon Islands sb - Seychelles sc - Sudan sd - Sweden se - VAT @@ -1440,7 +1254,6 @@ Singapore sg - GST No. @@ -1448,14 +1261,12 @@ Saint Helena, Ascension and Tristan da Cunha sh - Slovenia si - VAT @@ -1469,7 +1280,6 @@ Slovakia sk - VAT @@ -1477,161 +1287,138 @@ Sierra Leone sl - San Marino sm - Senegal sn - Somalia so - Suriname sr - South Sudan ss - São Tomé and Príncipe st - El Salvador sv - Sint Maarten (Dutch part) sx - Syria sy - Swaziland sz - Turks and Caicos Islands tc - Chad td - French Southern Territories tf - Togo tg - Thailand th - Tajikistan tj - Tokelau tk - Turkmenistan tm - Tunisia tn - Tonga to - Timor-Leste tl - Turkey tr - @@ -1639,14 +1426,12 @@ Trinidad and Tobago tt - Tuvalu tv - @@ -1659,21 +1444,18 @@ Tanzania tz - Ukraine ua - Uganda ug - @@ -1681,7 +1463,6 @@ United Kingdom gb - VAT @@ -1696,7 +1477,6 @@ United States us 1 - @@ -1705,56 +1485,48 @@ Uruguay uy - Uzbekistan uz - Holy See (Vatican City State) va - Saint Vincent and the Grenadines vc - Venezuela ve - Virgin Islands (British) vg - Virgin Islands (USA) vi - Vietnam vn - @@ -1762,7 +1534,6 @@ Vanuatu vu - @@ -1775,14 +1546,12 @@ Samoa ws - Yemen ye - @@ -1795,28 +1564,24 @@ South Africa za - Zambia zm - Zimbabwe zw - Kosovo xk - diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py index 28591cb917c..7db65109aca 100644 --- a/odoo/addons/base/models/ir_qweb_fields.py +++ b/odoo/addons/base/models/ir_qweb_fields.py @@ -385,6 +385,17 @@ class ImageConverter(models.AbstractModel): return u'' % (Image.MIME[image.format], value.decode('ascii')) +class ImageUrlConverter(models.AbstractModel): + """ ``image_url`` widget rendering, inserts an image tag in the + document. + """ + _name = 'ir.qweb.field.image_url' + _description = 'Qweb Field Image' + _inherit = 'ir.qweb.field.image' + + @api.model + def value_to_html(self, value, options): + return u'' % (value) class MonetaryConverter(models.AbstractModel): """ ``monetary`` converter, has a mandatory option diff --git a/odoo/addons/base/models/res_country.py b/odoo/addons/base/models/res_country.py index ad53687d981..dfcf758bdbd 100644 --- a/odoo/addons/base/models/res_country.py +++ b/odoo/addons/base/models/res_country.py @@ -10,6 +10,24 @@ from odoo.tools.translate import _ _logger = logging.getLogger(__name__) +FLAG_MAPPING = { + "GF": "fr", + "BV": "no", + "BQ": "nl", + "GP": "fr", + "HM": "au", + "YT": "fr", + "RE": "fr", + "MF": "fr", + "UM": "us", +} + +NO_FLAG_COUNTRIES = [ + "AQ", #Antarctica + "SJ", #Svalbard + Jan Mayen : separate jurisdictions : no dedicated flag +] + + class Country(models.Model): _name = 'res.country' _description = 'Country' @@ -37,7 +55,10 @@ class Country(models.Model): "(in reports for example), while this field is used to modify the input form for " "addresses.") currency_id = fields.Many2one('res.currency', string='Currency') - image = fields.Binary(attachment=True) + image_url = fields.Char( + compute="_compute_image_url", string="Flag", + help="Url of static flag image", + ) phone_code = fields.Integer(string='Country Calling Code') country_group_ids = fields.Many2many('res.country.group', 'res_country_res_country_group_rel', 'res_country_id', 'res_country_group_id', string='Country Groups') @@ -90,6 +111,15 @@ class Country(models.Model): self.ensure_one() return re.findall(r'\((.+?)\)', self.address_format) + @api.depends('code') + def _compute_image_url(self): + for country in self: + if not country.code or country.code in NO_FLAG_COUNTRIES: + country.image_url = False + else: + code = FLAG_MAPPING.get(country.code, country.code.lower()) + country.image_url = "/base/static/img/country_flags/%s.png" % code + class CountryGroup(models.Model): _description = "Country Group" diff --git a/odoo/addons/base/security/ir.model.access.csv b/odoo/addons/base/security/ir.model.access.csv index 220116ea7c0..d56f7b55b79 100644 --- a/odoo/addons/base/security/ir.model.access.csv +++ b/odoo/addons/base/security/ir.model.access.csv @@ -43,7 +43,8 @@ "access_res_country_group_all","res_country group_user_all","model_res_country",,1,0,0,0 "access_res_country_state_group_all","res_country_state group_user_all","model_res_country_state",,1,0,0,0 "access_res_country_group_group_all","res_country_group group_user_all","model_res_country_group",,1,0,0,0 -"access_res_country_group_user","res_country group_user","model_res_country","group_partner_manager",1,1,1,1 +"access_res_country_group_user","res_country group_user","model_res_country","group_partner_manager",1,0,0,0 +"access_res_country_group_system","res_country_group_system","model_res_country","group_system",1,1,1,1 "access_res_country_state_group_user","res_country_state group_user","model_res_country_state","group_partner_manager",1,1,1,1 "access_res_country_group_group_user","res_country_group group_user","model_res_country_group","group_partner_manager",1,1,1,1 "access_res_currency_group_all","res_currency group_all","model_res_currency",,1,0,0,0 diff --git a/odoo/addons/base/static/img/country_flags/eh.png b/odoo/addons/base/static/img/country_flags/eh.png new file mode 100644 index 00000000000..85a25c02920 Binary files /dev/null and b/odoo/addons/base/static/img/country_flags/eh.png differ diff --git a/odoo/addons/base/static/img/country_flags/ps.png b/odoo/addons/base/static/img/country_flags/ps.png new file mode 100644 index 00000000000..1899b5a3d0a Binary files /dev/null and b/odoo/addons/base/static/img/country_flags/ps.png differ diff --git a/odoo/addons/base/static/img/country_flags/tw.png b/odoo/addons/base/static/img/country_flags/tw.png new file mode 100644 index 00000000000..3c6b7d2a69b Binary files /dev/null and b/odoo/addons/base/static/img/country_flags/tw.png differ diff --git a/odoo/addons/base/static/img/country_flags/wf.png b/odoo/addons/base/static/img/country_flags/wf.png new file mode 100644 index 00000000000..497467d14b0 Binary files /dev/null and b/odoo/addons/base/static/img/country_flags/wf.png differ diff --git a/odoo/addons/base/views/ir_qweb_widget_templates.xml b/odoo/addons/base/views/ir_qweb_widget_templates.xml index 0671c8a04a3..19dc914372b 100644 --- a/odoo/addons/base/views/ir_qweb_widget_templates.xml +++ b/odoo/addons/base/views/ir_qweb_widget_templates.xml @@ -7,8 +7,8 @@ - - + + diff --git a/odoo/addons/base/views/res_country_views.xml b/odoo/addons/base/views/res_country_views.xml index 02bd9c78d5e..00fd602556b 100644 --- a/odoo/addons/base/views/res_country_views.xml +++ b/odoo/addons/base/views/res_country_views.xml @@ -8,7 +8,7 @@ res.country.tree res.country - + @@ -19,11 +19,11 @@ res.country.form res.country -
+
- +