diff --git a/l10n_nl_tax_statement/models/account_move_line.py b/l10n_nl_tax_statement/models/account_move_line.py index 82c1c368a..3de356bc7 100644 --- a/l10n_nl_tax_statement/models/account_move_line.py +++ b/l10n_nl_tax_statement/models/account_move_line.py @@ -31,9 +31,53 @@ def _get_l10n_nl_vat_statement_protected_fields(self): "tax_tag_ids", ] + def check_field_is_equal(self, changed_protected_field, values): + self.ensure_one() + field = self._fields.get(changed_protected_field) + old_value = self[changed_protected_field] + new_value = values[changed_protected_field] + if field.type in ["many2many", "one2many"]: + # if field is X2M , the only acceptable value is + # [[6,0,self[changed_protected_field].ids]] + # wich is what the web client posts in case there is a editable X2M in form + # that is unchanged. + # If it is a list of tuple-commands, and the last one is precisely + # values[changed_protected_field][2] == self[changed_protected_field].ids + # we will not accept any modification to protected fields, + # only the standard 6,0,[ids] coming from the default web edit. + return ( + len(new_value) == 1 + and new_value[0][0] == 6 + and new_value[0][2] == old_value.ids + ) + if new_value: + return old_value == new_value + return bool(old_value) == bool(new_value) + def write(self, values): + # before doing anything we check the nl_vat_statement:check_state, + if not self._l10n_nl_vat_statement_should_check_write(values): + return super().write(values) + # now we add code to check if any of the modified fields present in + # values are the same as existing field value. this is a known limitation + # of odoo web client, it passes all non-readonly value fields in a form + # for writing , even if the value has not been changed. + protected_fields = self._get_l10n_nl_vat_statement_protected_fields() + protected_fields_in_values = [x for x in values.keys() if x in protected_fields] + invalid_fields = set() + for this in self: + for protected_field in protected_fields_in_values: + is_equal = this.check_field_is_equal(protected_field, values) + if not is_equal: + # if the field is invalid in even one + # of the records it cannot be popped + invalid_fields.add(protected_field) + for protected_field in protected_fields_in_values: + if protected_field not in invalid_fields: + values.pop(protected_field) if self._l10n_nl_vat_statement_should_check_write(values): - self._l10n_nl_vat_statement_check_state() + for this in self: + this._l10n_nl_vat_statement_check_state() return super().write(values) @api.model diff --git a/l10n_nl_tax_statement/tests/test_l10n_nl_vat_statement.py b/l10n_nl_tax_statement/tests/test_l10n_nl_vat_statement.py index e9d4454e2..16fdec7ad 100644 --- a/l10n_nl_tax_statement/tests/test_l10n_nl_vat_statement.py +++ b/l10n_nl_tax_statement/tests/test_l10n_nl_vat_statement.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import datetime +import logging from dateutil.relativedelta import relativedelta @@ -13,6 +14,8 @@ from odoo.tests.common import TransactionCase from odoo.tools import convert_file +_logger = logging.getLogger(__name__) + class TestVatStatement(TransactionCase): def _load(self, module, *args): @@ -157,6 +160,22 @@ def _create_test_invoice(self): self.invoice_1 = invoice_form.save() self.assertEqual(len(self.invoice_1.line_ids), 5) + # testing noop writing now allowed + for line in self.invoice_1.line_ids: + values = {"name": line.name} + self.assertEqual(line.write(values), True) + self.assertEqual(line.check_field_is_equal("name", values), True) + # testing noop writing on tax_id Many2Many allowed + for line in self.invoice_1.line_ids: + values = {"tax_ids": [(6, 0, line.tax_ids.ids)]} + self.assertEqual(line.check_field_is_equal("tax_ids", values), True) + self.assertEqual(line.write(values), True) + + # testing no protected field code branch: + line = self.invoice_1.line_ids[0] + values = {"ref": 12345} + self.assertEqual(line.write(values), True) + def test_01_onchange(self): daterange_type = self.env["date.range.type"].create({"name": "Type 1"}) daterange = self.env["date.range"].create( @@ -355,7 +374,7 @@ def test_12_undeclared_invoice(self): ) self.assertTrue(invoice_lines) with self.assertRaises(UserError): - invoice_lines[0].date = fields.Date.today() + invoice_lines[0].date = fields.Date.today() + relativedelta(day=1) def test_13_no_previous_statement_posted(self): statement2 = self.env["l10n.nl.vat.statement"].create({"name": "Statement 2"})