Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][IMP] server_action_mass_edit: Improve error message when update record in batch #962

Open
wants to merge 1 commit into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions server_action_mass_edit/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ Contributors

* Jairo Llopis
* Víctor Martínez
* Carlos Dauden
* Tatiana Deribina <[email protected]>
* Hieu, Vo Minh Bao <[email protected]>

Maintainers
~~~~~~~~~~~
Expand Down
22 changes: 21 additions & 1 deletion server_action_mass_edit/demo/mass_editing.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,28 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="field_id" ref="base.field_res_partner_title__shortcut" />
</record>

<!-- Mass Edit Partner -->
<record id="mass_editing_partner" model="ir.actions.server">
<field name="state">mass_edit</field>
<field name="name">Mass Edit</field>
<field name="model_id" ref="base.model_res_partner" />
</record>
<record id="mass_editing_partner_line_1" model="ir.actions.server.mass.edit.line">
<field name="server_action_id" ref="mass_editing_partner" />
<field name="field_id" ref="base.field_res_partner__parent_id" />
</record>
<record id="mass_editing_partner_line_2" model="ir.actions.server.mass.edit.line">
<field name="server_action_id" ref="mass_editing_partner" />
<field name="field_id" ref="base.field_res_partner__type" />
</record>
<record id="mass_editing_partner_line_3" model="ir.actions.server.mass.edit.line">
<field name="server_action_id" ref="mass_editing_partner" />
<field name="field_id" ref="base.field_res_partner__name" />
</record>
<!-- Add context actions -->
<function model="ir.actions.server" name="create_action">
<value eval="[ref('mass_editing_user'), ref('mass_editing_partner_title')]" />
<value
eval="[ref('mass_editing_user'), ref('mass_editing_partner_title'), ref('mass_editing_partner')]"
/>
</function>
</odoo>
2 changes: 2 additions & 0 deletions server_action_mass_edit/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@

* Jairo Llopis
* Víctor Martínez
* Carlos Dauden
* Tatiana Deribina <[email protected]>
* Hieu, Vo Minh Bao <[email protected]>
13 changes: 9 additions & 4 deletions server_action_mass_edit/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

/*
:Author: David Goodger ([email protected])
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -274,7 +275,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* 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 }
Expand All @@ -300,7 +301,7 @@
span.pre {
white-space: pre }

span.problematic {
span.problematic, pre.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -472,15 +473,19 @@ <h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a><ul>
<li>Jairo Llopis</li>
<li>Víctor Martínez</li>
<li>Carlos Dauden</li>
</ul>
</li>
<li>Tatiana Deribina &lt;<a class="reference external" href="mailto:tatiana.deribina&#64;spritnit.fi">tatiana.deribina&#64;spritnit.fi</a>&gt;</li>
<li>Hieu, Vo Minh Bao &lt;<a class="reference external" href="mailto:hieu.vmb&#64;komit-consulting.com">hieu.vmb&#64;komit-consulting.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">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>
<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>
Expand Down
50 changes: 49 additions & 1 deletion server_action_mass_edit/tests/test_mass_editing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from ast import literal_eval

from odoo.exceptions import ValidationError
from odoo.exceptions import UserError, ValidationError
from odoo.tests import Form, common, new_test_user

from odoo.addons.base.models.ir_actions import IrActionsServer
Expand All @@ -27,12 +27,16 @@ def setUp(self):

self.MassEditingWizard = self.env["mass.editing.wizard"]
self.ResPartnerTitle = self.env["res.partner.title"]
self.ResPartner = self.env["res.partner"]
self.ResLang = self.env["res.lang"]
self.IrActionsActWindow = self.env["ir.actions.act_window"]

self.mass_editing_user = self.env.ref(
"server_action_mass_edit.mass_editing_user"
)
self.mass_editing_partner = self.env.ref(
"server_action_mass_edit.mass_editing_partner"
)
self.mass_editing_partner_title = self.env.ref(
"server_action_mass_edit.mass_editing_partner_title"
)
Expand All @@ -47,6 +51,7 @@ def setUp(self):
groups="base.group_system",
)
self.partner_title = self._create_partner_title()
self.invoice_partner = self._create_invoice_partner()

def _create_partner_title(self):
"""Create a Partner Title."""
Expand All @@ -62,6 +67,14 @@ def _create_partner_title(self):
)
return partner_title

def _create_invoice_partner(self):
invoice_partner = self.ResPartner.create(
{
"type": "invoice",
}
)
return invoice_partner

def _create_wizard_and_apply_values(self, server_action, items, vals):
action = server_action.with_context(
active_model=items._name,
Expand Down Expand Up @@ -405,3 +418,38 @@ def test_onchange_model_id(self):
result,
None,
)

def test_mass_edit_partner_user_error(self):
vals = {
"selection__parent_id": "set",
"parent_id": self.invoice_partner.id,
"write_record_by_record": True,
}
action = self.mass_editing_partner.with_context(
active_model=self.invoice_partner._name,
active_ids=self.invoice_partner.ids,
).run()
try:
self.env[action["res_model"]].with_context(
**literal_eval(action["context"]),
).create(vals)
except Exception as e:
self.assertEqual(type(e), UserError)

def test_mass_edit_partner_sql_error(self):
vals = {
"selection__type": "set",
"type": "contact",
"write_record_by_record": True,
"selection__name": "remove",
}
action = self.mass_editing_partner.with_context(
active_model=self.invoice_partner._name,
active_ids=self.invoice_partner.ids,
).run()
try:
self.env[action["res_model"]].with_context(
**literal_eval(action["context"]),
).create(vals)
except Exception as e:
self.assertEqual(type(e), UserError)
61 changes: 57 additions & 4 deletions server_action_mass_edit/wizard/mass_editing_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import json
import logging

from lxml import etree
from psycopg2 import IntegrityError

from odoo import _, api, fields, models
from odoo.exceptions import (
AccessDenied,
AccessError,
MissingError,
UserError,
ValidationError,
)

from odoo.addons.base.models.ir_ui_view import (
transfer_modifiers_to_node,
Expand All @@ -24,6 +33,12 @@ class MassEditingWizard(models.TransientModel):
operation_description_warning = fields.Text(readonly=True)
operation_description_danger = fields.Text(readonly=True)
message = fields.Text(readonly=True)
write_record_by_record = fields.Boolean(
help="This option will write the records one by one, instead of all at once.\n"
"This is useful when you are editing a lot of records and one of the "
"records raises an error. \n With this option, the error message will be "
"more specific to facillitate the undertanding of the error."
)

@api.model
def default_get(self, fields, active_ids=None):
Expand Down Expand Up @@ -243,12 +258,15 @@ def _clean_check_company_field_domain(self, TargetModel, field, field_info):
return field_info

@api.model_create_multi
def create(self, vals_list):
def create(self, vals_list): # noqa: C901
server_action_id = self.env.context.get("server_action_id")
server_action = self.env["ir.actions.server"].sudo().browse(server_action_id)
active_ids = self.env.context.get("active_ids", [])
if server_action and active_ids:
TargetModel = self.env[server_action.model_id.model]
for vals in vals_list:
write_record_by_record = vals.pop("write_record_by_record", False)
logging.warning("write_record_by_record: %s", write_record_by_record)
values = {}
for key, val in vals.items():
if key.startswith("selection_"):
Expand Down Expand Up @@ -281,9 +299,44 @@ def create(self, vals_list):
values.update({split_key: m2m_list})

if values:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can avoid the complexity warning C901 like this

Suggested change
if values:
if not values:
continue

self.env[server_action.model_id.model].browse(
active_ids
).with_context(mass_edit=True,).write(values)
target_records = TargetModel.browse(active_ids)
if write_record_by_record:
for target_record in target_records:
try:
target_record.with_context(mass_edit=True).write(values)
except (
AccessDenied,
AccessError,
MissingError,
UserError,
ValidationError,
IntegrityError,
) as oe:
if isinstance(oe, IntegrityError):
sql_error_msg_dict = (
models.convert_pgerror_constraint(
self.env[TargetModel._name],
False,
False,
oe,
)
)
sql_error_message = sql_error_msg_dict.get(
"message", ""
)
oe = Exception(sql_error_message)
raise UserError(
_(
'Failed to process the %(model_name)s "%(name)s" '
"[id: %(id)s]:\n\n%(ue)s",
model_name=server_action.model_id.name,
name=target_record.display_name,
id=target_record.id,
ue=str(oe),
)
) from oe
else:
target_records.with_context(mass_edit=True).write(values)
return super().create([{}])

def _prepare_create_values(self, vals_list):
Expand Down
2 changes: 2 additions & 0 deletions server_action_mass_edit/wizard/mass_editing_wizard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
type="object"
class="oe_highlight"
/>
<label for="write_record_by_record" />
<field name="write_record_by_record" />
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
Expand Down
Loading