folio-migration-tools 1.9.3__tar.gz → 1.9.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/PKG-INFO +2 -1
  2. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/pyproject.toml +17 -9
  3. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/circulation_helper.py +8 -0
  4. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/helper.py +4 -0
  5. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py +2 -2
  6. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py +7 -1
  7. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/batch_poster.py +119 -18
  8. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/items_transformer.py +4 -1
  9. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/loans_migrator.py +237 -82
  10. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/organization_transformer.py +1 -0
  11. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/transaction_migration/legacy_loan.py +51 -15
  12. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/translations/en.json +19 -10
  13. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/LICENSE +0 -0
  14. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/README.md +0 -0
  15. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/__init__.py +0 -0
  16. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/__main__.py +0 -0
  17. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/colors.py +0 -0
  18. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/config_file_load.py +0 -0
  19. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/custom_dict.py +0 -0
  20. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/custom_exceptions.py +0 -0
  21. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/extradata_writer.py +0 -0
  22. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/folder_structure.py +0 -0
  23. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/holdings_helper.py +0 -0
  24. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/i18n_config.py +0 -0
  25. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/library_configuration.py +0 -0
  26. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapper_base.py +0 -0
  27. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/__init__.py +0 -0
  28. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/courses_mapper.py +0 -0
  29. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/holdings_mapper.py +0 -0
  30. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/item_mapper.py +0 -0
  31. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py +0 -0
  32. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py +0 -0
  33. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/notes_mapper.py +0 -0
  34. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/order_mapper.py +0 -0
  35. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/organization_mapper.py +0 -0
  36. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/ref_data_mapping.py +0 -0
  37. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/mapping_file_transformation/user_mapper.py +0 -0
  38. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/__init__.py +0 -0
  39. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/conditions.py +0 -0
  40. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py +0 -0
  41. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/hrid_handler.py +0 -0
  42. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/loc_language_codes.xml +0 -0
  43. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/marc_file_processor.py +0 -0
  44. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py +0 -0
  45. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_authorities.py +0 -0
  46. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_base.py +0 -0
  47. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_report.py +0 -0
  48. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/__init__.py +0 -0
  49. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/authority_transformer.py +0 -0
  50. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/bibs_transformer.py +0 -0
  51. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/courses_migrator.py +0 -0
  52. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/holdings_csv_transformer.py +0 -0
  53. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/holdings_marc_transformer.py +0 -0
  54. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py +0 -0
  55. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/migration_task_base.py +0 -0
  56. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/orders_transformer.py +0 -0
  57. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/requests_migrator.py +0 -0
  58. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/reserves_migrator.py +0 -0
  59. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/migration_tasks/user_transformer.py +0 -0
  60. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/task_configuration.py +0 -0
  61. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/test_infrastructure/__init__.py +0 -0
  62. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/test_infrastructure/mocked_classes.py +0 -0
  63. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/transaction_migration/__init__.py +0 -0
  64. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/transaction_migration/legacy_request.py +0 -0
  65. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/transaction_migration/legacy_reserve.py +0 -0
  66. {folio_migration_tools-1.9.3 → folio_migration_tools-1.9.5}/src/folio_migration_tools/transaction_migration/transaction_result.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: folio_migration_tools
3
- Version: 1.9.3
3
+ Version: 1.9.5
4
4
  Summary: A tool allowing you to migrate data from legacy ILS:s (Library systems) into FOLIO LSP
5
5
  License: MIT
6
6
  Keywords: FOLIO,ILS,LSP,Library Systems,MARC21,Library data
@@ -19,6 +19,7 @@ Requires-Dist: argparse-prompt (>=0.0.5,<0.0.6)
19
19
  Requires-Dist: art (>=6.5,<7.0)
20
20
  Requires-Dist: deepdiff (>=6.2.3,<7.0.0)
21
21
  Requires-Dist: defusedxml (>=0.7.1,<0.8.0)
22
+ Requires-Dist: folio-data-import (>=0.3.2,<0.4.0)
22
23
  Requires-Dist: folio-uuid (>=0.2.8,<0.3.0)
23
24
  Requires-Dist: folioclient (>=0.70.1,<0.71.0)
24
25
  Requires-Dist: pyaml (>=21.10.1,<22.0.0)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "folio_migration_tools"
3
- version = "1.9.3"
3
+ version = "1.9.5"
4
4
  description = "A tool allowing you to migrate data from legacy ILS:s (Library systems) into FOLIO LSP"
5
5
  authors = [
6
6
  {name = "Theodor Tolstoy", email = "github.teddes@tolstoy.se"},
@@ -56,6 +56,7 @@ deepdiff = "^6.2.3"
56
56
  pyaml = "^21.10.1"
57
57
  python-i18n = "^0.3.9"
58
58
  art = "^6.5"
59
+ folio-data-import = "^0.3.2"
59
60
 
60
61
  [tool.poetry.group.dev.dependencies]
61
62
  pytest = "^7.1.3"
@@ -63,24 +64,31 @@ lxml = ">4.9"
63
64
  coverage = {extras = ["toml"], version = "^6.5.0"}
64
65
  pytest-cov = "^4.0.0"
65
66
  black = "^22.10.0"
66
- flake8 = "^5.0.4"
67
+ flake8 = "^7.3.0"
67
68
  mypy = "^0.982"
68
- flake8-black = "^0.3.3"
69
- flake8-bugbear = "^22.9.23"
69
+ flake8-black = "^0.3.6"
70
+ flake8-bugbear = "^24.12.12"
70
71
  flake8-bandit = "^4.1.1"
71
- flake8-isort = "^5.0.0"
72
+ flake8-isort = "^6.1.2"
72
73
  flake8-docstrings = "^1.6.0"
73
74
  darglint = "^1.8.1"
74
- sphinx = "^5.3.0"
75
- sphinx-autodoc-typehints = "^1.19.4"
76
- myst-parser = "^0.18.1"
77
75
  types-requests = "^2.28.11.17"
78
76
  types-python-dateutil = "^2.8.19.11"
79
77
  ipykernel = "^6.29.5"
80
78
  pytest-asyncio = "^0.23.0"
79
+ sphinx-autobuild = "^2024.10.3"
80
+
81
+ [tool.poetry.group.docs.dependencies]
82
+ m2r = "^0.2.1"
83
+ myst-parser = "<4.0.0"
84
+ sphinx = ">=6.0.0, <8.0.0"
85
+ sphinx-autodoc-typehints = "^1.17.0"
86
+ sphinx-rtd-theme = "^1.0.0"
87
+ toml = "^0.10.2"
88
+ sphinx-book-theme = "^1.1.4"
81
89
 
82
90
  [tool.poetry.extras]
83
- docs = ["m2r", "sphinx", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "toml"]
91
+ docs = ["m2r", "sphinx", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "toml",]
84
92
 
85
93
  [tool.poetry.requires-plugins]
86
94
  poetry-plugin-export = ">=1.8"
@@ -198,6 +198,14 @@ class CirculationHelper:
198
198
  error_message_from_folio,
199
199
  error_message_from_folio,
200
200
  )
201
+ elif "Item is already checked out" in error_message_from_folio:
202
+ return TransactionResult(
203
+ False,
204
+ True,
205
+ None,
206
+ error_message_from_folio,
207
+ error_message_from_folio,
208
+ )
201
209
  logging.error(
202
210
  f"{error_message} "
203
211
  f"Patron barcode: {legacy_loan.patron_barcode} "
@@ -56,6 +56,10 @@ class Helper:
56
56
  @staticmethod
57
57
  def log_data_issue(index_or_id, message, legacy_value):
58
58
  logging.log(26, "DATA ISSUE\t%s\t%s\t%s", index_or_id, message, legacy_value)
59
+
60
+ @staticmethod
61
+ def log_data_issue_failed(index_or_id, message, legacy_value):
62
+ logging.log(26, "RECORD FAILED\t%s\t%s\t%s", index_or_id, message, legacy_value)
59
63
 
60
64
  @staticmethod
61
65
  def write_to_file(file, folio_record):
@@ -174,11 +174,11 @@ class BibsRulesMapper(RulesMapperBase):
174
174
  self.process_marc_field(folio_instance, main_entry_fields[0], ignored_subsequent_fields, legacy_ids)
175
175
  try:
176
176
  self.process_marc_field(folio_instance, marc_record['245'], ignored_subsequent_fields, legacy_ids)
177
- except KeyError:
177
+ except KeyError as ke:
178
178
  raise TransformationRecordFailedError(
179
179
  legacy_ids,
180
180
  "No 245 field in MARC record"
181
- )
181
+ ) from ke
182
182
 
183
183
  def perform_additional_parsing(
184
184
  self,
@@ -196,9 +196,15 @@ class RulesMapperHoldings(RulesMapperBase):
196
196
  if "004" not in marc_record:
197
197
  raise TransformationProcessError(
198
198
  "",
199
- ("No 004 in record. The tools only support bib-mfhd linking throuh 004"),
199
+ ("No 004 in record. The tools only support bib-mfhd linking through 004"),
200
200
  legacy_ids,
201
201
  )
202
+ if len(marc_record.get_fields("004")) > 1:
203
+ Helper.log_data_issue(
204
+ legacy_ids,
205
+ "More than one linked bib (004) found in record. Using the first one",
206
+ [str(x) for x in marc_record.get_fields("004")],
207
+ )
202
208
  legacy_instance_id = marc_record["004"].data.strip()
203
209
  folio_holding["formerIds"].append(f"{self.bib_id_template}{legacy_instance_id}")
204
210
  if legacy_instance_id in self.parent_id_map:
@@ -131,6 +131,56 @@ class BatchPoster(MigrationTaskBase):
131
131
  ),
132
132
  ),
133
133
  ] = False
134
+ preserve_statistical_codes: Annotated[
135
+ bool,
136
+ Field(
137
+ title="Preserve statistical codes",
138
+ description=(
139
+ "Toggles whether or not to preserve statistical codes "
140
+ "during the upsert process. Defaults to False"
141
+ ),
142
+ ),
143
+ ] = False
144
+ preserve_administrative_notes: Annotated[
145
+ bool,
146
+ Field(
147
+ title="Preserve administrative notes",
148
+ description=(
149
+ "Toggles whether or not to preserve administrative notes "
150
+ "during the upsert process. Defaults to False"
151
+ ),
152
+ ),
153
+ ] = False
154
+ preserve_temporary_locations: Annotated[
155
+ bool,
156
+ Field(
157
+ title="Preserve temporary locations",
158
+ description=(
159
+ "Toggles whether or not to preserve temporary locations "
160
+ "on items during the upsert process. Defaults to False"
161
+ ),
162
+ ),
163
+ ] = False
164
+ preserve_temporary_loan_types: Annotated[
165
+ bool,
166
+ Field(
167
+ title="Preserve temporary loan types",
168
+ description=(
169
+ "Toggles whether or not to preserve temporary loan types "
170
+ "on items during the upsert process. Defaults to False"
171
+ ),
172
+ ),
173
+ ] = False
174
+ preserve_item_status: Annotated[
175
+ bool,
176
+ Field(
177
+ title="Preserve item status",
178
+ description=(
179
+ "Toggles whether or not to preserve item status "
180
+ "on items during the upsert process. Defaults to False"
181
+ ),
182
+ ),
183
+ ] = True
134
184
 
135
185
  task_configuration: TaskConfiguration
136
186
 
@@ -292,7 +342,7 @@ class BatchPoster(MigrationTaskBase):
292
342
  """
293
343
  fetch_batch_size = 90
294
344
  fetch_tasks = []
295
- updates = {}
345
+ existing_records = {}
296
346
  async with httpx.AsyncClient(base_url=self.folio_client.gateway_url) as client:
297
347
  for i in range(0, len(batch), fetch_batch_size):
298
348
  batch_slice = batch[i:i + fetch_batch_size]
@@ -313,31 +363,82 @@ class BatchPoster(MigrationTaskBase):
313
363
  responses = await asyncio.gather(*fetch_tasks)
314
364
 
315
365
  for response in responses:
316
- self.update_record_versions(object_type, updates, response)
366
+ self.collect_existing_records_for_upsert(object_type, response, existing_records)
317
367
  for record in batch:
318
- if record["id"] in updates:
319
- record.update(updates[record["id"]])
368
+ if record["id"] in existing_records:
369
+ self.prepare_record_for_upsert(record, existing_records[record["id"]])
370
+
371
+ def handle_source_marc(self, new_record: dict, existing_record: dict):
372
+ updates = {}
373
+ updates.update(existing_record)
374
+ self.handle_upsert_for_administrative_notes(updates)
375
+ self.handle_upsert_for_statistical_codes(updates)
376
+ keep_new = {k: v for k, v in new_record.items() if k in ["statisticalCodeIds", "administrativeNotes"]}
377
+ if "instanceStatusId" in new_record:
378
+ updates["instanceStatusId"] = new_record["instanceStatusId"]
379
+ for k, v in keep_new.items():
380
+ updates[k] = list(dict.fromkeys(updates.get(k, []) + v))
381
+ new_record.update(updates)
320
382
 
321
383
  @staticmethod
322
- def update_record_versions(object_type, updates, response):
384
+ def collect_existing_records_for_upsert(object_type: str, response: httpx.Response, existing_records: dict):
323
385
  if response.status_code == 200:
324
386
  response_json = response.json()
325
387
  for record in response_json[object_type]:
326
- updates[record["id"]] = {
327
- "_version": record["_version"],
328
- }
329
- if "hrid" in record:
330
- updates[record["id"]]["hrid"] = record["hrid"]
331
- if "status" in record:
332
- updates[record["id"]]["status"] = record["status"]
333
- if "lastCheckIn" in record:
334
- updates[record["id"]]["lastCheckIn"] = record["lastCheckIn"]
388
+ existing_records[record["id"]] = record
335
389
  else:
336
390
  logging.error(
337
- "Failed to fetch current records. HTTP %s\t%s",
338
- response.status_code,
339
- response.text,
340
- )
391
+ "Failed to fetch current records. HTTP %s\t%s",
392
+ response.status_code,
393
+ response.text,
394
+ )
395
+
396
+ def handle_upsert_for_statistical_codes(self, updates: dict):
397
+ if not self.task_configuration.preserve_statistical_codes:
398
+ updates.pop("statisticalCodeIds", None)
399
+
400
+ def handle_upsert_for_administrative_notes(self, updates: dict):
401
+ if not self.task_configuration.preserve_administrative_notes:
402
+ updates.pop("administrativeNotes", None)
403
+
404
+ def handle_upsert_for_temporary_locations(self, updates: dict):
405
+ if not self.task_configuration.preserve_temporary_locations:
406
+ updates.pop("temporaryLocationId", None)
407
+
408
+ def handle_upsert_for_temporary_loan_types(self, updates: dict):
409
+ if not self.task_configuration.preserve_temporary_loan_types:
410
+ updates.pop("temporaryLoanTypeId", None)
411
+
412
+ def keep_existing_fields(self, updates: dict, existing_record: dict):
413
+ keep_existing_fields = ["hrid", "lastCheckIn"]
414
+ if self.task_configuration.preserve_item_status:
415
+ keep_existing_fields.append("status")
416
+ for key in keep_existing_fields:
417
+ if key in existing_record:
418
+ updates[key] = existing_record[key]
419
+
420
+ def prepare_record_for_upsert(self, new_record: dict, existing_record: dict):
421
+ if "source" in existing_record and "MARC" in existing_record["source"]:
422
+ self.handle_source_marc(new_record, existing_record)
423
+ else:
424
+ updates = {
425
+ "_version": existing_record["_version"],
426
+ }
427
+ self.keep_existing_fields(updates, existing_record)
428
+ keep_new = {k: v for k, v in new_record.items() if k in ["statisticalCodeIds", "administrativeNotes"]}
429
+ self.handle_upsert_for_statistical_codes(existing_record)
430
+ self.handle_upsert_for_administrative_notes(existing_record)
431
+ self.handle_upsert_for_temporary_locations(existing_record)
432
+ self.handle_upsert_for_temporary_loan_types(existing_record)
433
+ for k, v in keep_new.items():
434
+ updates[k] = list(dict.fromkeys(existing_record.get(k, []) + v))
435
+ for key in [
436
+ "temporaryLocationId",
437
+ "temporaryLoanTypeId",
438
+ ]:
439
+ if key in existing_record:
440
+ updates[key] = existing_record[key]
441
+ new_record.update(updates)
341
442
 
342
443
  async def get_with_retry(self, client: httpx.AsyncClient, url: str, params=None):
343
444
  if params is None:
@@ -218,7 +218,10 @@ class ItemsTransformer(MigrationTaskBase):
218
218
  self.folio_keys = MappingFileMapperBase.get_mapped_folio_properties_from_map(
219
219
  self.items_map
220
220
  )
221
- if any(k for k in self.folio_keys if k.startswith("statisticalCodeIds")):
221
+ if (
222
+ any(k for k in self.folio_keys if k.startswith("statisticalCodeIds"))
223
+ or any(getattr(k, "statistical_code", "") for k in self.task_configuration.files)
224
+ ):
222
225
  statcode_mapping = self.load_ref_data_mapping_file(
223
226
  "statisticalCodeIds",
224
227
  self.folder_structure.mapping_files_folder