|
3 | 3 |
|
4 | 4 | from odoo.tests.common import RecordCapturer, TransactionCase |
5 | 5 |
|
6 | | -from ..models.base_import_import import OPT_USE_QUEUE |
| 6 | +from odoo.addons.queue_job.exception import FailedJobError |
| 7 | + |
| 8 | +from ..wizard.base_import_import import ( |
| 9 | + INIT_PRIORITY, |
| 10 | + OPT_CHUNK_SIZE, |
| 11 | + OPT_HAS_HEADER, |
| 12 | + OPT_QUOTING, |
| 13 | + OPT_SEPARATOR, |
| 14 | + OPT_USE_QUEUE, |
| 15 | +) |
7 | 16 |
|
8 | 17 |
|
9 | 18 | class TestBaseImportImport(TransactionCase): |
@@ -59,6 +68,54 @@ def test_normal_import_res_partners(self): |
59 | 68 | self.assertEqual(len(records_created), 2) |
60 | 69 | self.assertIn("partner1", records_created[0].email) |
61 | 70 |
|
| 71 | + def test_execute_import_res_partners_async(self): |
| 72 | + values = [ |
| 73 | + [ |
| 74 | + "name", |
| 75 | + "email", |
| 76 | + "is_company", |
| 77 | + ], |
| 78 | + [ |
| 79 | + "partner 1", |
| 80 | + |
| 81 | + "1", |
| 82 | + ], |
| 83 | + [ |
| 84 | + "partner 2", |
| 85 | + |
| 86 | + "0", |
| 87 | + ], |
| 88 | + ] |
| 89 | + import_vals = { |
| 90 | + "res_model": self.res_partners._name, |
| 91 | + "file": "\n".join([";".join(values) for values in values]), |
| 92 | + "file_type": "text/csv", |
| 93 | + "file_name": "partners.csv", |
| 94 | + } |
| 95 | + import_wizard = self.import_wizard.create(import_vals) |
| 96 | + opts = { |
| 97 | + OPT_QUOTING: '"', |
| 98 | + OPT_SEPARATOR: ";", |
| 99 | + OPT_HAS_HEADER: True, |
| 100 | + OPT_USE_QUEUE: True, |
| 101 | + } |
| 102 | + preview = import_wizard.parse_preview(opts) |
| 103 | + with RecordCapturer(self.env["queue.job"], []) as capture: |
| 104 | + result = import_wizard.execute_import( |
| 105 | + [field[0] for field in preview["matches"].values()], |
| 106 | + [], |
| 107 | + opts, |
| 108 | + ) |
| 109 | + self.assertEqual(result, []) |
| 110 | + self.assertEqual(len(capture.records), 1) |
| 111 | + job = capture.records[0] |
| 112 | + self.assertEqual(job.method_name, "_split_file") |
| 113 | + self.assertEqual(job.model_name, "base_import.import") |
| 114 | + attachment = self.env["ir.attachment"].search( |
| 115 | + [("res_model", "=", "queue.job"), ("res_id", "=", job.id)], limit=1 |
| 116 | + ) |
| 117 | + self.assertTrue(attachment) |
| 118 | + |
62 | 119 | def test_wrong_import_res_partners(self): |
63 | 120 | values = [ |
64 | 121 | [ |
@@ -97,3 +154,87 @@ def test_wrong_import_res_partners(self): |
97 | 154 | opts, |
98 | 155 | ) |
99 | 156 | self.assertTrue(any(msg["type"] == "error" for msg in results["messages"])) |
| 157 | + |
| 158 | + def test_split_file_creates_chunk_jobs_and_links_attachments(self): |
| 159 | + import_wizard = self.import_wizard.create( |
| 160 | + { |
| 161 | + "res_model": self.res_partners._name, |
| 162 | + "file": "dummy", |
| 163 | + "file_type": "text/csv", |
| 164 | + } |
| 165 | + ) |
| 166 | + fields = ["name", "email", "is_company"] |
| 167 | + data = [ |
| 168 | + [ "partner 1", "[email protected]", "1"], |
| 169 | + [ "partner 2", "[email protected]", "0"], |
| 170 | + [ "partner 3", "[email protected]", "0"], |
| 171 | + ] |
| 172 | + opts = { |
| 173 | + OPT_QUOTING: '"', |
| 174 | + OPT_SEPARATOR: ";", |
| 175 | + OPT_HAS_HEADER: True, |
| 176 | + OPT_CHUNK_SIZE: 2, |
| 177 | + } |
| 178 | + attachment = import_wizard._create_csv_attachment( |
| 179 | + fields, data, opts, "partners.csv" |
| 180 | + ) |
| 181 | + with RecordCapturer(self.env["queue.job"], []) as capture: |
| 182 | + import_wizard._split_file( |
| 183 | + model_name=self.res_partners._name, |
| 184 | + translated_model_name="Contacts", |
| 185 | + attachment=attachment, |
| 186 | + options=opts, |
| 187 | + file_name="partners.csv", |
| 188 | + ) |
| 189 | + jobs = capture.records.sorted("priority") |
| 190 | + self.assertEqual(len(jobs), 2) |
| 191 | + self.assertEqual(jobs.mapped("method_name"), ["_import_one_chunk"] * 2) |
| 192 | + self.assertEqual(jobs.mapped("priority"), [INIT_PRIORITY, INIT_PRIORITY + 1]) |
| 193 | + self.assertEqual( |
| 194 | + jobs.mapped("name"), |
| 195 | + [ |
| 196 | + "Import Contacts from file partners.csv - #0 - lines 2 to 3", |
| 197 | + "Import Contacts from file partners.csv - #1 - lines 4 to 4", |
| 198 | + ], |
| 199 | + ) |
| 200 | + chunk_attachments = self.env["ir.attachment"].search( |
| 201 | + [("name", "in", ["partners-0.csv", "partners-1.csv"])] |
| 202 | + ) |
| 203 | + self.assertEqual(len(chunk_attachments), 2) |
| 204 | + self.assertTrue(all(att.res_model == "queue.job" for att in chunk_attachments)) |
| 205 | + self.assertTrue(all(att.res_id in jobs.ids for att in chunk_attachments)) |
| 206 | + |
| 207 | + def test_import_one_chunk_success_and_error(self): |
| 208 | + import_wizard = self.import_wizard.create( |
| 209 | + { |
| 210 | + "res_model": self.res_partners._name, |
| 211 | + "file": "dummy", |
| 212 | + "file_type": "text/csv", |
| 213 | + } |
| 214 | + ) |
| 215 | + opts = {OPT_QUOTING: '"', OPT_SEPARATOR: ";"} |
| 216 | + |
| 217 | + fields = ["name", "email", "is_company"] |
| 218 | + data = [ |
| 219 | + [ "partner 1", "[email protected]", "1"], |
| 220 | + [ "partner 2", "[email protected]", "0"], |
| 221 | + ] |
| 222 | + attachment = import_wizard._create_csv_attachment( |
| 223 | + fields, data, opts, "partners.csv" |
| 224 | + ) |
| 225 | + with RecordCapturer(self.res_partners, []) as capture: |
| 226 | + result = import_wizard._import_one_chunk( |
| 227 | + self.res_partners._name, attachment, opts |
| 228 | + ) |
| 229 | + self.assertEqual(result["messages"], []) |
| 230 | + self.assertEqual(len(capture.records), 2) |
| 231 | + |
| 232 | + invalid_fields = ["name", "company_type"] |
| 233 | + invalid_data = [["partner 3", "invalid"]] |
| 234 | + invalid_attachment = import_wizard._create_csv_attachment( |
| 235 | + invalid_fields, invalid_data, opts, "invalid.csv" |
| 236 | + ) |
| 237 | + with self.assertRaises(FailedJobError): |
| 238 | + import_wizard._import_one_chunk( |
| 239 | + self.res_partners._name, invalid_attachment, opts |
| 240 | + ) |
0 commit comments