From e3bc974ea4b11e69fd27fb12163d1457e5dcfa4a Mon Sep 17 00:00:00 2001 From: Kartik Chavda Date: Wed, 7 Jun 2023 12:00:50 +0530 Subject: [PATCH] [IMP] base,** : make error message user friendly Before this commit error messages in odoo are boring and not much attractive to user. Those were like odoo is preventing them from doing something user want to do. In this commit, we have modified the message to be a more friendly and humorous tone, making it less tedious and more enjoyable. It aims to enhance the user experience and ensure that interactions with any application are both pleasant and informative. As a result, the messages have been clear, short, easy to understand and informative. task-3356114 Part-of: odoo/odoo#124820 Co-authored-by: Kamlesh Pathekar --- addons/account/models/account_account.py | 4 +- addons/account/models/account_move_line.py | 2 +- addons/crm_iap_mine/models/crm_lead.py | 2 +- .../crm_iap_lead_mining_request_views.xml | 2 +- addons/hr_holidays/models/hr_leave.py | 13 +- .../views/mailing_mailing_views.xml | 13 +- .../mailing_mailing_schedule_date_views.xml | 2 +- addons/mrp/models/mrp_production.py | 8 +- addons/mrp/models/mrp_workorder.py | 2 +- .../onboarding/views/onboarding_templates.xml | 8 +- addons/point_of_sale/models/product.py | 8 +- .../purchase_requisition/models/purchase.py | 2 +- .../models/purchase_requisition.py | 3 +- addons/sale/models/sale_order_line.py | 3 +- addons/stock/models/stock_picking.py | 4 +- addons/stock/models/stock_scrap.py | 2 +- addons/stock/views/stock_scrap_views.xml | 3 +- .../stock/wizard/product_replenish_views.xml | 23 ++-- .../wizard/stock_inventory_adjustment_name.py | 2 +- .../stock_inventory_adjustment_name.xml | 6 +- .../confirmation_dialog.js | 6 +- .../static/src/core/errors/error_dialogs.js | 2 +- .../src/views/calendar/calendar_controller.js | 7 +- .../static/src/views/form/form_controller.js | 6 +- .../src/views/kanban/kanban_controller.js | 6 +- .../static/src/views/list/list_controller.js | 12 +- .../tests/core/errors/error_dialogs_tests.js | 2 +- .../views/calendar/calendar_view_tests.js | 2 +- .../media_dialog/image_selector.xml | 4 +- odoo/addons/base/models/ir_rule.py | 36 +++--- .../test_access_rights/tests/test_feedback.py | 116 +++++++++--------- 31 files changed, 165 insertions(+), 146 deletions(-) diff --git a/addons/account/models/account_account.py b/addons/account/models/account_account.py index 562a5963804..a8b43d54dde 100644 --- a/addons/account/models/account_account.py +++ b/addons/account/models/account_account.py @@ -756,7 +756,9 @@ class AccountAccount(models.Model): if partner_prop_acc: account_name = partner_prop_acc.get_by_record().display_name raise UserError( - _('You cannot remove/deactivate the account %s which is set on a customer or vendor.', account_name) + _("You can't delete the account %s, as it is used on a contact.\n\n" + "Imagine that a customer’s receivables evaporate; your CFO might not like it :)" + , account_name) ) @api.ondelete(at_uninstall=False) diff --git a/addons/account/models/account_move_line.py b/addons/account/models/account_move_line.py index 426097cdf9a..76ca8b6aeb0 100644 --- a/addons/account/models/account_move_line.py +++ b/addons/account/models/account_move_line.py @@ -1563,7 +1563,7 @@ class AccountMoveLine(models.Model): def _unlink_except_posted(self): # Prevent deleting lines on posted entries if not self._context.get('force_delete') and any(m.state == 'posted' for m in self.move_id): - raise UserError(_('You cannot delete an item linked to a posted entry.')) + raise UserError(_("You can't delete a posted journal item. Don’t play Jenga with your accounting records; reset the journal entry to draft before deleting it.")) @api.ondelete(at_uninstall=False) def _prevent_automatic_line_deletion(self): diff --git a/addons/crm_iap_mine/models/crm_lead.py b/addons/crm_iap_mine/models/crm_lead.py index 378aa71203f..1fbc48aaf91 100644 --- a/addons/crm_iap_mine/models/crm_lead.py +++ b/addons/crm_iap_mine/models/crm_lead.py @@ -14,7 +14,7 @@ class Lead(models.Model): def action_generate_leads(self): return { - "name": _("Generate Leads"), + "name": _("Need help reaching your target?"), "type": "ir.actions.act_window", "res_model": "crm.iap.lead.mining.request", "target": "new", diff --git a/addons/crm_iap_mine/views/crm_iap_lead_mining_request_views.xml b/addons/crm_iap_mine/views/crm_iap_lead_mining_request_views.xml index 61e5772010e..b97e72df908 100644 --- a/addons/crm_iap_mine/views/crm_iap_lead_mining_request_views.xml +++ b/addons/crm_iap_mine/views/crm_iap_lead_mining_request_views.xml @@ -47,7 +47,7 @@ -

What do you need?

+

How many leads would you like?

diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index c1a9ad56b6b..0b096212d68 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -681,8 +681,9 @@ class HolidaysRequest(models.Model): date_to=conflicting_holiday_data['date_to'], state=conflicting_holiday_data['state']) conflicting_holidays_strings.append(conflicting_holidays_string) - raise ValidationError(_('You can not set two time off that overlap on the same day.\nExisting time off:\n%s') % - ('\n'.join(conflicting_holidays_strings))) + raise ValidationError(_("You’ve already booked time off which overlaps with this period:" + + "\n".join(conflicting_holidays_strings) + + "Attempting to double-book your time off won't magically make your vacation 2x better!")) for conflicting_holiday_data in conflicting_holidays_list: conflicting_holidays_string = _('%(employee_name)s - From %(date_from)s To %(date_to)s - %(state)s', employee_name=conflicting_holiday_data['employee_name'], @@ -691,12 +692,8 @@ class HolidaysRequest(models.Model): state=conflicting_holiday_data['state']) conflicting_holidays_strings.append(conflicting_holidays_string) conflicting_employees = set(employee_ids) - set(conflicting_holidays.employee_id.ids) - # Only one employee has a conflicting holiday - if len(conflicting_employees) == len(employee_ids) - 1: - raise ValidationError(_('You can not set two time off that overlap on the same day for the same employee.\nExisting time off:\n%s') % - ('\n'.join(conflicting_holidays_strings))) - raise ValidationError(_('You can not set two time off that overlap on the same day for the same employees.\nExisting time off:\n%s') % - ('\n'.join(conflicting_holidays_strings))) + raise ValidationError(_("An employee already booked time off which overlaps with this period:" + + "\n".join(conflicting_holidays_strings))) @api.constrains('date_from', 'date_to', 'employee_id') def _check_date_state(self): diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index ef423c295a7..0e812c882b3 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -61,8 +61,9 @@
diff --git a/addons/point_of_sale/models/product.py b/addons/point_of_sale/models/product.py index 78caf1118ee..de971654832 100644 --- a/addons/point_of_sale/models/product.py +++ b/addons/point_of_sale/models/product.py @@ -28,7 +28,9 @@ class ProductTemplate(models.Model): product_ctx = dict(self.env.context or {}, active_test=False) if self.with_context(product_ctx).search_count([('id', 'in', self.ids), ('available_in_pos', '=', True)]): if self.env['pos.session'].sudo().search_count([('state', '!=', 'closed')]): - raise UserError(_('You cannot delete a product saleable in point of sale while a session is still opened.')) + raise UserError(_("To delete a product, make sure all point of sale sessions are closed.\n\n" + "Deleting a product available in a session would be like attempting to snatch a" + "hamburger from a customer’s hand mid-bite; chaos will ensue as ketchup and mayo go flying everywhere!")) @api.onchange('sale_ok') def _onchange_sale_ok(self): @@ -51,7 +53,9 @@ class ProductProduct(models.Model): product_ctx = dict(self.env.context or {}, active_test=False) if self.env['pos.session'].sudo().search_count([('state', '!=', 'closed')]): if self.with_context(product_ctx).search_count([('id', 'in', self.ids), ('product_tmpl_id.available_in_pos', '=', True)]): - raise UserError(_('You cannot delete a product saleable in point of sale while a session is still opened.')) + raise UserError(_("To delete a product, make sure all point of sale sessions are closed.\n\n" + "Deleting a product available in a session would be like attempting to snatch a" + "hamburger from a customer’s hand mid-bite; chaos will ensue as ketchup and mayo go flying everywhere!")) def get_product_info_pos(self, price, quantity, pos_config_id): self.ensure_one() diff --git a/addons/purchase_requisition/models/purchase.py b/addons/purchase_requisition/models/purchase.py index cd856cf5766..5e9686b79f9 100644 --- a/addons/purchase_requisition/models/purchase.py +++ b/addons/purchase_requisition/models/purchase.py @@ -113,7 +113,7 @@ class PurchaseOrder(models.Model): if alternative_po_ids: view = self.env.ref('purchase_requisition.purchase_requisition_alternative_warning_form') return { - 'name': _('Remaining Open Alternatives'), + 'name': _("What about the alternative Requests for Quotations?"), 'type': 'ir.actions.act_window', 'view_mode': 'form', 'res_model': 'purchase.requisition.alternative.warning', diff --git a/addons/purchase_requisition/models/purchase_requisition.py b/addons/purchase_requisition/models/purchase_requisition.py index db23c16253f..04faa2b613f 100644 --- a/addons/purchase_requisition/models/purchase_requisition.py +++ b/addons/purchase_requisition/models/purchase_requisition.py @@ -143,7 +143,8 @@ class PurchaseRequisition(models.Model): Generate all purchase order based on selected lines, should only be called on one agreement at a time """ if any(purchase_order.state in ['draft', 'sent', 'to approve'] for purchase_order in self.mapped('purchase_ids')): - raise UserError(_('You have to cancel or validate every RfQ before closing the purchase requisition.')) + raise UserError(_("To close this purchase requisition, cancel related Requests for Quotation.\n\n" + "Imagine the mess if someone confirms these duplicates: double the order, double the trouble :)")) for requisition in self: for requisition_line in requisition.line_ids: requisition_line.supplier_info_ids.sudo().unlink() diff --git a/addons/sale/models/sale_order_line.py b/addons/sale/models/sale_order_line.py index d5b1187a950..31d6ce2387f 100644 --- a/addons/sale/models/sale_order_line.py +++ b/addons/sale/models/sale_order_line.py @@ -1062,7 +1062,8 @@ class SaleOrderLine(models.Model): @api.ondelete(at_uninstall=False) def _unlink_except_confirmed(self): if self._check_line_unlink(): - raise UserError(_("You can not remove an order line once the sales order is confirmed.\nYou should rather set the quantity to 0.")) + raise UserError(_("Once a sales order is confirmed, you can't remove one of its lines (we need to track if something gets invoiced or delivered).\n\ + Set the quantity to 0 instead.")) #=== ACTION METHODS ===# diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index a945a86798b..3d139fddf19 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -1091,7 +1091,7 @@ class Picking(models.Model): if not self._should_show_transfers(): if pickings_without_moves: - raise UserError(_('Please add some items to move.')) + raise UserError(_("You can’t validate an empty transfer. Please add some products to move before proceeding.")) if pickings_without_quantities: raise UserError(self._get_without_quantities_error_message()) if pickings_without_lots: @@ -1588,7 +1588,7 @@ class Picking(models.Model): if move.state not in ('draft', 'cancel') and move.product_id.type in ('product', 'consu'): products |= move.product_id return { - 'name': _('Scrap'), + 'name': _('Scrap Products'), 'view_mode': 'form', 'res_model': 'stock.scrap', 'view_id': view.id, diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py index eb68107be3b..68ecb960f7d 100644 --- a/addons/stock/models/stock_scrap.py +++ b/addons/stock/models/stock_scrap.py @@ -52,7 +52,7 @@ class StockScrap(models.Model): ('done', 'Done')], string='Status', default="draft", readonly=True, tracking=True) date_done = fields.Datetime('Date', readonly=True) - should_replenish = fields.Boolean(string='Replenish Scrapped Quantities') + should_replenish = fields.Boolean(string='Replenish Quantities') @api.depends('product_id') def _compute_product_uom_id(self): diff --git a/addons/stock/views/stock_scrap_views.xml b/addons/stock/views/stock_scrap_views.xml index 72022522593..6619a7ab45c 100644 --- a/addons/stock/views/stock_scrap_views.xml +++ b/addons/stock/views/stock_scrap_views.xml @@ -171,6 +171,7 @@ +
-
diff --git a/addons/stock/wizard/product_replenish_views.xml b/addons/stock/wizard/product_replenish_views.xml index 506defbd2b4..ebb62cbe20e 100644 --- a/addons/stock/wizard/product_replenish_views.xml +++ b/addons/stock/wizard/product_replenish_views.xml @@ -6,9 +6,14 @@

- Use this assistant to replenish your stock. - Depending on your product configuration, launching a replenishment may trigger a request for quotation, - a manufacturing order or a transfer. + The forecasted quantity of + is + + +

@@ -17,10 +22,6 @@ -