From 79bd879eb473808deb8f6fd5dca763a14f9363cc Mon Sep 17 00:00:00 2001 From: Rad0van Date: Tue, 18 Jan 2022 22:38:27 +0100 Subject: [PATCH] [FIX] base_import_match: importing related o2m records The original code did improperly handle importing related one2many records where at best all their attribute values would get overwritten by last of them. This was caused by mapping them only by their first part. --- base_import_match/models/base.py | 46 ++++++++++--------- base_import_match/readme/CONTRIBUTORS.rst | 1 + .../res_partner_email_one2many.csv | 4 ++ base_import_match/tests/test_import.py | 38 +++++++++++++++ 4 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 base_import_match/tests/import_data/res_partner_email_one2many.csv diff --git a/base_import_match/models/base.py b/base_import_match/models/base.py index 57b589fb..11145ca0 100644 --- a/base_import_match/models/base.py +++ b/base_import_match/models/base.py @@ -26,29 +26,33 @@ class Base(models.AbstractModel): # Mock Odoo to believe the user is importing the ID field if "id" not in fields: fields.append("id") - import_fields.append(["id"]) # Needed to match with converted data field names - clean_fields = [f[0] for f in import_fields] for dbid, xmlid, record, info in converted_data: - row = dict(zip(clean_fields, data[info["record"]])) - match = self - if xmlid: - # Skip rows with ID, they do not need all this - row["id"] = xmlid - continue - elif dbid: - # Find the xmlid for this dbid - match = self.browse(dbid) - else: - # Store records that match a combination - match = self.env["base_import.match"]._match_find(self, record, row) - # Give a valid XMLID to this row if a match was found - # To generate externals IDS. - match.export_data(fields) - ext_id = match.get_external_id() - row["id"] = ext_id[match.id] if match else row.get("id", u"") - # Store the modified row, in the same order as fields - newdata.append(tuple(row[f] for f in clean_fields)) + # In case of one2many on empty lines one record may contain several rows + for row_index in range(info["rows"]["from"], info["rows"]["to"] + 1): + row = dict(zip(fields, data[row_index])) + match = self + if xmlid: + # Skip rows with ID, they do not need all this + row["id"] = xmlid + continue + elif dbid: + # Find the xmlid for this dbid + match = self.browse(dbid) + elif row_index == info["rows"]["from"]: + # Store records that match a combination + # But only for first row of record, + # because the rest contain one2many fields + match = self.env["base_import.match"]._match_find( + self, record, row + ) + # Give a valid XMLID to this row if a match was found + # To generate externals IDS. + match.export_data(fields) + ext_id = match.get_external_id() + row["id"] = ext_id[match.id] if match else row.get("id", u"") + # Store the modified row, in the same order as fields + newdata.append(tuple(row[f] for f in fields)) # We will import the patched data to get updates on matches data = newdata # Normal method handles the rest of the job diff --git a/base_import_match/readme/CONTRIBUTORS.rst b/base_import_match/readme/CONTRIBUTORS.rst index f487f960..964a5091 100644 --- a/base_import_match/readme/CONTRIBUTORS.rst +++ b/base_import_match/readme/CONTRIBUTORS.rst @@ -2,3 +2,4 @@ * Jairo Llopis * Vicent Cubells * Ernesto Tejeda +* Radovan Skolnik diff --git a/base_import_match/tests/import_data/res_partner_email_one2many.csv b/base_import_match/tests/import_data/res_partner_email_one2many.csv new file mode 100644 index 00000000..f95307ca --- /dev/null +++ b/base_import_match/tests/import_data/res_partner_email_one2many.csv @@ -0,0 +1,4 @@ +email,function,child_ids/name,child_ids/color,child_ids/email +floyd.steward34@example.com,Bug Fixer,Bart Steward,666,bart.steward@example.com +,,Lisa Steward,777,lisa.steward@example.com +,,Maggie Steward,555,maggie.steward@example.com diff --git a/base_import_match/tests/test_import.py b/base_import_match/tests/test_import.py index 43a5ff4c..ea49163e 100644 --- a/base_import_match/tests/test_import.py +++ b/base_import_match/tests/test_import.py @@ -68,3 +68,41 @@ class ImportCase(TransactionCase): record = self._base_import_record("res.users", "res_users_login") record.do(["login", "name"], [], OPTIONS) self.assertEqual(self.env.ref("base.user_demo").name, "Demo User Changed") + + def test_res_partner_email_one2many(self): + """Change function based on email and import one2many record.""" + record = self._base_import_record("res.partner", "res_partner_email_one2many") + record.do( + [ + "email", + "function", + "child_ids/name", + "child_ids/color", + "child_ids/email", + ], + [], + OPTIONS, + ) + self.assertEqual( + self.env.ref("base.res_partner_address_4").function, "Bug Fixer" + ) + self.assertTrue(self.env.ref("base.res_partner_address_4").child_ids,) + self.assertEqual( + len(self.env.ref("base.res_partner_address_4").child_ids), 3, + ) + self.assertEqual( + set(self.env.ref("base.res_partner_address_4").mapped("child_ids.name")), + {"Bart Steward", "Lisa Steward", "Maggie Steward"}, + ) + self.assertEqual( + set(self.env.ref("base.res_partner_address_4").mapped("child_ids.email")), + { + "bart.steward@example.com", + "lisa.steward@example.com", + "maggie.steward@example.com", + }, + ) + self.assertEqual( + set(self.env.ref("base.res_partner_address_4").mapped("child_ids.color")), + {666, 777, 555}, + )