diff --git a/addons/base_geolocalize/models/base_geocoder.py b/addons/base_geolocalize/models/base_geocoder.py index 1c012b86f1d160bcd08e5f189051c2eb7abe371b..2b2431fa8de6542d89b9f944af046d1c709d42f2 100644 --- a/addons/base_geolocalize/models/base_geocoder.py +++ b/addons/base_geolocalize/models/base_geocoder.py @@ -87,7 +87,8 @@ class GeoCoder(models.AbstractModel): return None url = 'https://nominatim.openstreetmap.org/search' try: - headers = {'User-Agent': 'Odoo (http://www.odoo.com/contactus)'} + headers = {'User-Agent': self.env['ir.config_parameter'].get_param('base_geolocalize.user_agent', + 'Odoo (http://www.odoo.com/contactus)')} response = requests.get(url, headers=headers, params={'format': 'json', 'q': addr}) _logger.info('openstreetmap nominatim service called') if response.status_code != 200: diff --git a/addons/portal/static/src/scss/portal.scss b/addons/portal/static/src/scss/portal.scss index a3d82a8ef57ee84ed96e535e89e63fecf249e080..6d19d944e56bdcacfc3d098f3581c0f4e8e6cbd6 100644 --- a/addons/portal/static/src/scss/portal.scss +++ b/addons/portal/static/src/scss/portal.scss @@ -342,6 +342,10 @@ img, .media_iframe_video, .o_image { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + + &:has(a) { + color: $primary; + } } } diff --git a/addons/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py index e407f30bc18605740bac06adaa1016bf2d35967a..391d8c9443678ff2be23856d2c2c1239580111ec 100644 --- a/addons/sale_timesheet/models/project.py +++ b/addons/sale_timesheet/models/project.py @@ -84,7 +84,7 @@ class Project(models.Model): def _compute_warning_employee_rate(self): projects = self.filtered(lambda p: p.allow_billable and p.allow_timesheets and p.bill_type == 'customer_project' and p.pricing_type == 'employee_rate') tasks = projects.task_ids.filtered(lambda t: not t.non_allow_billable) - employees = self.env['account.analytic.line'].read_group([('task_id', 'in', tasks.ids), ('non_allow_billable', '=', False)], ['employee_id', 'project_id'], ['employee_id', 'project_id'], ['employee_id', 'project_id'], lazy=False) + employees = self.env['account.analytic.line'].read_group([('task_id', 'in', tasks.ids), ('non_allow_billable', '=', False)], ['employee_id', 'project_id'], ['employee_id', 'project_id'], lazy=False) dict_project_employee = defaultdict(list) for line in employees: dict_project_employee[line['project_id'][0]] += [line['employee_id'][0]] if line['employee_id'] else [] diff --git a/addons/test_xlsx_export/tests/test_export.py b/addons/test_xlsx_export/tests/test_export.py index 2c336028372865b8a90172212460d263e1327d98..86574093adda1a57a90d3c890a857e68b5e9cdef 100644 --- a/addons/test_xlsx_export/tests/test_export.py +++ b/addons/test_xlsx_export/tests/test_export.py @@ -7,6 +7,7 @@ from unittest.mock import patch from odoo import http from odoo.tests import common, tagged +from odoo.tools import mute_logger from odoo.tools.misc import get_lang from odoo.addons.web.controllers.main import ExportXlsxWriter from odoo.addons.mail.tests.common import mail_new_test_user @@ -412,3 +413,38 @@ class TestComputedBinaryExport(XlsxCreatorCase): ['OdooBot (1)'], ["['computed value']"], ]) + + @mute_logger('odoo.addons.web.controllers.main') + def test_export_with_deleted_field(self): + model = self.env['ir.model']._get('res.partner') + url = '/web/export/namelist' + header = {"Content-Type": "application/json"} + + custom_field = self.env['ir.model.fields'].create([{ + 'name': 'x_test', + 'ttype': 'char', + 'field_description': 'test field', + 'model_id': model.id, + }]) + + export_template = self.env['ir.exports'].create({ + 'name': custom_field.name, + 'export_fields': [(0, 0, {'name': custom_field.name})], + }) + + data = json.dumps({ + 'params': { + 'model': model.model, + 'export_id': export_template.id, + }, + }) + + export_line_field = self.env['ir.exports.line'].search([('name', '=', export_template.name)]) + + self.url_open(url, data, headers=header).json() + self.assertTrue(export_line_field.exists()) + + custom_field.unlink() + + self.url_open(url, data, headers=header).json() + self.assertFalse(export_line_field.exists()) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 972f1589e42760f52a3df6da3ac48237f327c7c9..f8ae022e698e4d4ad1beec79cd65bef97b84d929 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1807,7 +1807,15 @@ class Export(http.Controller): def namelist(self, model, export_id): # TODO: namelist really has no reason to be in Python (although itertools.groupby helps) export = request.env['ir.exports'].browse([export_id]).read()[0] - export_fields_list = request.env['ir.exports.line'].browse(export['export_fields']).read() + exported_fields = request.env['ir.exports.line'].browse(export['export_fields']) + fields = self.fields_get(model) + + for invalid_fields in exported_fields.filtered(lambda f: f.name not in fields): + # ir.exports.line lack a ondelete=cascade foreign key on ir.model.fields + _logger.warning("Field %r not found for saved ir.exports of model %s, deleting", invalid_fields.name, model) + invalid_fields.unlink() + + export_fields_list = exported_fields.read() fields_data = self.fields_info( model, [f['name'] for f in export_fields_list]) diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 0e6f8c1911b9c96619addd7d230212316729864c..df8f490307e0aec20c911b33c9451557f026fe00 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -581,11 +581,11 @@ class WebsiteSale(http.Controller): name_change = partner_su and 'name' in data and data['name'] != partner_su.name email_change = partner_su and 'email' in data and data['email'] != partner_su.email - # Prevent changing the partner name if invoices have been issued. - if name_change and not partner_su.can_edit_vat(): + # Prevent changing the billing partner name if invoices have been issued. + if mode[1] == 'billing' and name_change and not partner_su.can_edit_vat(): error['name'] = 'error' error_message.append(_( - "Changing your name is not allowed once invoices have been issued for your" + "Changing your name is not allowed once documents have been issued for your" " account. Please contact us directly for this operation." )) diff --git a/addons/website_sale/i18n/website_sale.pot b/addons/website_sale/i18n/website_sale.pot index 73e88c89054a3865408b7eb3aa4d0277b227e2a0..6ec2a4f5ede2d74f692fe97f33da2c933cc2619c 100644 --- a/addons/website_sale/i18n/website_sale.pot +++ b/addons/website_sale/i18n/website_sale.pot @@ -782,6 +782,14 @@ msgid "" "account. Please contact us directly for this operation." msgstr "" +#. module: website_sale +#: code:addons/website_sale/controllers/main.py:0 +#, python-format +msgid "" +"Changing your name is not allowed once documents have been issued for your " +"account. Please contact us directly for this operation." +msgstr "" + #. module: website_sale #: model:ir.model.fields,field_description:website_sale.field_product_public_category__child_id msgid "Children Categories"