folio-migration-tools 1.9.0rc6__tar.gz → 1.9.0rc7__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.0rc6 → folio_migration_tools-1.9.0rc7}/PKG-INFO +1 -1
  2. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/pyproject.toml +1 -1
  3. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/custom_exceptions.py +7 -7
  4. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/item_mapper.py +2 -4
  5. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py +3 -7
  6. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/conditions.py +1 -1
  7. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py +4 -1
  8. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/transaction_migration/legacy_loan.py +25 -27
  9. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/LICENSE +0 -0
  10. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/README.md +0 -0
  11. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/__init__.py +0 -0
  12. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/__main__.py +0 -0
  13. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/circulation_helper.py +0 -0
  14. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/colors.py +0 -0
  15. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/config_file_load.py +0 -0
  16. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/custom_dict.py +0 -0
  17. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/extradata_writer.py +0 -0
  18. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/folder_structure.py +0 -0
  19. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/helper.py +0 -0
  20. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/holdings_helper.py +0 -0
  21. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/i18n_config.py +0 -0
  22. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/library_configuration.py +0 -0
  23. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapper_base.py +0 -0
  24. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/__init__.py +0 -0
  25. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/courses_mapper.py +0 -0
  26. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/holdings_mapper.py +0 -0
  27. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py +0 -0
  28. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/notes_mapper.py +0 -0
  29. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/order_mapper.py +0 -0
  30. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/organization_mapper.py +0 -0
  31. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/ref_data_mapping.py +0 -0
  32. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/mapping_file_transformation/user_mapper.py +0 -0
  33. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/__init__.py +0 -0
  34. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py +0 -0
  35. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/hrid_handler.py +0 -0
  36. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/loc_language_codes.xml +0 -0
  37. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/marc_file_processor.py +0 -0
  38. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py +0 -0
  39. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_authorities.py +0 -0
  40. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_base.py +0 -0
  41. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py +0 -0
  42. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_report.py +0 -0
  43. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/__init__.py +0 -0
  44. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/authority_transformer.py +0 -0
  45. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/batch_poster.py +0 -0
  46. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/bibs_transformer.py +0 -0
  47. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/courses_migrator.py +0 -0
  48. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/holdings_csv_transformer.py +0 -0
  49. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/holdings_marc_transformer.py +0 -0
  50. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/items_transformer.py +0 -0
  51. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/loans_migrator.py +0 -0
  52. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py +0 -0
  53. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/migration_task_base.py +0 -0
  54. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/orders_transformer.py +0 -0
  55. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/organization_transformer.py +0 -0
  56. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/requests_migrator.py +0 -0
  57. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/reserves_migrator.py +0 -0
  58. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/migration_tasks/user_transformer.py +0 -0
  59. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/task_configuration.py +0 -0
  60. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/test_infrastructure/__init__.py +0 -0
  61. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/test_infrastructure/mocked_classes.py +0 -0
  62. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/transaction_migration/__init__.py +0 -0
  63. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/transaction_migration/legacy_request.py +0 -0
  64. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/transaction_migration/legacy_reserve.py +0 -0
  65. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/transaction_migration/transaction_result.py +0 -0
  66. {folio_migration_tools-1.9.0rc6 → folio_migration_tools-1.9.0rc7}/src/folio_migration_tools/translations/en.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: folio_migration_tools
3
- Version: 1.9.0rc6
3
+ Version: 1.9.0rc7
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "folio_migration_tools"
3
- version = "1.9.0rc6"
3
+ version = "1.9.0rc7"
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"},
@@ -5,12 +5,12 @@ import i18n
5
5
  from folio_migration_tools import StrCoercible
6
6
 
7
7
 
8
- class TransfomationError(Exception):
8
+ class TransformationError(Exception):
9
9
  pass
10
10
 
11
11
 
12
- class TransformationFieldMappingError(TransfomationError):
13
- """Raised when the a field mapping fails, but the error is not critical.
12
+ class TransformationFieldMappingError(TransformationError):
13
+ """Raised when the field mapping fails, but the error is not critical.
14
14
  The issue should be logged for the library to act upon it"""
15
15
 
16
16
  def __init__(self, index_or_id="", message="", data_value: Union[str, StrCoercible]=""):
@@ -35,8 +35,8 @@ class TransformationFieldMappingError(TransfomationError):
35
35
  )
36
36
 
37
37
 
38
- class TransformationRecordFailedError(TransfomationError):
39
- """Raised when the a field mapping fails, Error is critical and means tranformation fails"""
38
+ class TransformationRecordFailedError(TransformationError):
39
+ """Raised when the field mapping fails, Error is critical and means transformation fails"""
40
40
 
41
41
  def __init__(self, index_or_id, message="", data_value=""):
42
42
  self.index_or_id = index_or_id
@@ -61,8 +61,8 @@ class TransformationRecordFailedError(TransfomationError):
61
61
  )
62
62
 
63
63
 
64
- class TransformationProcessError(TransfomationError):
65
- """Raised when the transformation fails due to incorrect configuraiton,
64
+ class TransformationProcessError(TransformationError):
65
+ """Raised when the transformation fails due to incorrect configuration,
66
66
  mapping or reference data. This error should take the process to a halt."""
67
67
 
68
68
  def __init__(
@@ -75,9 +75,7 @@ class ItemMapper(MappingFileMapperBase):
75
75
  self.folio_client,
76
76
  "/locations",
77
77
  "locations",
78
- self.validate_location_map(
79
- temporary_location_mapping, self.folio_client.locations
80
- ),
78
+ temporary_location_mapping,
81
79
  "code",
82
80
  "TemporaryLocationMapping",
83
81
  )
@@ -118,7 +116,7 @@ class ItemMapper(MappingFileMapperBase):
118
116
  self.folio_client,
119
117
  "/locations",
120
118
  "locations",
121
- self.validate_location_map(location_map, self.folio_client.locations),
119
+ location_map,
122
120
  "code",
123
121
  "LocationMapping",
124
122
  )
@@ -755,12 +755,8 @@ class MappingFileMapperBase(MapperBase):
755
755
  for k in data
756
756
  if k["folio_field"] == folio_prop_name
757
757
  and any(
758
- [
759
- is_set_or_bool_or_numeric(k.get("value", "")),
760
- is_set_or_bool_or_numeric(k.get("legacy_field", "")),
761
- is_set_or_bool_or_numeric(k.get("fallback_legacy_field", "")),
762
- is_set_or_bool_or_numeric(k.get("fallback_value", "")),
763
- ]
758
+ is_set_or_bool_or_numeric(k.get(key, ""))
759
+ for key in ("value", "legacy_field", "fallback_legacy_field", "fallback_value")
764
760
  )
765
761
  )
766
762
 
@@ -972,4 +968,4 @@ def in_deep(dictionary, keys):
972
968
 
973
969
 
974
970
  def is_set_or_bool_or_numeric(any_value):
975
- return any(isinstance(any_value, t) for t in [int, bool, float, complex]) or any_value.strip()
971
+ return (isinstance(any_value, str) and (any_value.strip() not in empty_vals)) or isinstance(any_value, (int, float, complex))
@@ -818,7 +818,7 @@ class Conditions:
818
818
  """
819
819
  This method handles the mapping of electronic access relationship IDs.
820
820
  If the record type being mapped is FOLIO holdings, it provides an (optional) alternative
821
- mapping baseed on a provided name parameter, bypassing the FOLIO MARC-to-Holdings mapping
821
+ mapping based on a provided name parameter, bypassing the FOLIO MARC-to-Holdings mapping
822
822
  engine behavior. This requires use of a supplemental mapping rules file in the
823
823
  HoldingsMarcTransformer task definition containing the name parameter.
824
824
  """
@@ -61,7 +61,10 @@ class RulesMapperHoldings(RulesMapperBase):
61
61
  self.boundwith_relationship_map = self.setup_boundwith_relationship_map(
62
62
  boundwith_relationship_map
63
63
  )
64
- self.location_map = location_map
64
+ self.location_map = self.validate_location_map(
65
+ location_map,
66
+ self.folio_client.locations,
67
+ )
65
68
  self.holdings_id_map: dict = {}
66
69
  self.ref_data_dicts: dict = {}
67
70
  self.fallback_holdings_type_id = self.task_configuration.fallback_holdings_type_id
@@ -3,9 +3,10 @@ from datetime import datetime
3
3
  from zoneinfo import ZoneInfo
4
4
 
5
5
  from dateutil import tz
6
- from dateutil.parser import parse
6
+ from dateutil.parser import parse, ParserError
7
7
 
8
8
  from folio_migration_tools.migration_report import MigrationReport
9
+ from folio_migration_tools.custom_exceptions import TransformationProcessError
9
10
 
10
11
  utc = ZoneInfo("UTC")
11
12
 
@@ -42,46 +43,47 @@ class LegacyLoan(object):
42
43
 
43
44
  self.tenant_timezone = tenant_timezone
44
45
  self.errors = []
46
+ self.row = row
45
47
  for prop in correct_headers:
46
48
  if prop not in legacy_loan_dict and prop not in optional_headers:
47
- self.errors.append(("Missing properties in legacy data", prop))
49
+ self.errors.append((f"Missing properties in legacy data {row=}", prop))
48
50
  if (
49
51
  prop != "next_item_status"
50
52
  and not legacy_loan_dict.get(prop, "").strip()
51
53
  and prop not in optional_headers
52
54
  ):
53
- self.errors.append(("Empty properties in legacy data", prop))
55
+ self.errors.append((f"Empty properties in legacy data {row=}", prop))
54
56
  try:
55
57
  temp_date_due: datetime = parse(legacy_loan_dict["due_date"])
56
58
  if temp_date_due.tzinfo != tz.UTC:
57
59
  temp_date_due = temp_date_due.replace(tzinfo=self.tenant_timezone)
58
60
  self.report(
59
- f"Provided due_date is not UTC, "
60
- f"setting tzinfo to tenant timezone ({self.tenant_timezone})"
61
+ f"Provided due_date is not UTC in {row=}, "
62
+ f"setting tz-info to tenant timezone ({self.tenant_timezone})"
61
63
  )
62
64
  if temp_date_due.hour == 0 and temp_date_due.minute == 0:
63
65
  temp_date_due = temp_date_due.replace(hour=23, minute=59)
64
66
  self.report(
65
- "Hour and minute not specified for due date. "
67
+ f"Hour and minute not specified for due date in {row=}. "
66
68
  "Assuming end of local calendar day (23:59)..."
67
69
  )
68
- except Exception as ee:
70
+ except (ParserError, OverflowError) as ee:
69
71
  logging.error(ee)
70
- self.errors.append(("Parse date failure. Setting UTC NOW", "due_date"))
72
+ self.errors.append((f"Parse date failure in {row=}. Setting UTC NOW", "due_date"))
71
73
  temp_date_due = datetime.now(ZoneInfo("UTC"))
72
74
  try:
73
75
  temp_date_out: datetime = parse(legacy_loan_dict["out_date"])
74
76
  if temp_date_out.tzinfo != tz.UTC:
75
77
  temp_date_out = temp_date_out.replace(tzinfo=self.tenant_timezone)
76
78
  self.report(
77
- f"Provided out_date is not UTC, "
78
- f"setting tzinfo to tenant timezone ({self.tenant_timezone})"
79
+ f"Provided out_date is not UTC in {row=}, "
80
+ f"setting tz-info to tenant timezone ({self.tenant_timezone})"
79
81
  )
80
- except Exception:
82
+ except (ParserError, OverflowError):
81
83
  temp_date_out = datetime.now(
82
84
  ZoneInfo("UTC")
83
85
  ) # TODO: Consider moving this assignment block above the temp_date_due
84
- self.errors.append(("Parse date failure. Setting UTC NOW", "out_date"))
86
+ self.errors.append((f"Parse date failure in {row=}. Setting UTC NOW", "out_date"))
85
87
 
86
88
  # good to go, set properties
87
89
  self.item_barcode: str = legacy_loan_dict["item_barcode"].strip()
@@ -94,7 +96,7 @@ class LegacyLoan(object):
94
96
  self.renewal_count = self.set_renewal_count(legacy_loan_dict)
95
97
  self.next_item_status = legacy_loan_dict.get("next_item_status", "").strip()
96
98
  if self.next_item_status not in legal_statuses:
97
- self.errors.append(("Not an allowed status", self.next_item_status))
99
+ self.errors.append((f"Not an allowed status {row=}", self.next_item_status))
98
100
  self.service_point_id = (
99
101
  legacy_loan_dict["service_point_id"]
100
102
  if legacy_loan_dict.get("service_point_id", "")
@@ -107,23 +109,19 @@ class LegacyLoan(object):
107
109
  try:
108
110
  return int(renewal_count)
109
111
  except ValueError:
110
- self.report(
111
- f"Unresolvable {renewal_count=} was replaced with 0.")
112
+ self.report(f"Unresolvable {renewal_count=} was replaced with 0.")
112
113
  else:
113
114
  self.report(f"Missing renewal count was replaced with 0.")
114
115
  return 0
115
116
 
116
117
  def correct_for_1_day_loans(self):
117
- try:
118
- if self.due_date.date() <= self.out_date.date():
119
- if self.due_date.hour == 0:
120
- self.due_date = self.due_date.replace(hour=23, minute=59)
121
- if self.out_date.hour == 0:
122
- self.out_date = self.out_date.replace(hour=0, minute=1)
123
- if self.due_date <= self.out_date:
124
- raise ValueError("Due date is before out date")
125
- except Exception:
126
- self.errors.append(("Time alignment issues", "both dates"))
118
+ if self.due_date.date() <= self.out_date.date():
119
+ if self.due_date.hour == 0:
120
+ self.due_date = self.due_date.replace(hour=23, minute=59)
121
+ if self.out_date.hour == 0:
122
+ self.out_date = self.out_date.replace(hour=0, minute=1)
123
+ if self.due_date <= self.out_date:
124
+ raise TransformationProcessError(self.row, "Due date is before out date")
127
125
 
128
126
  def to_dict(self):
129
127
  return {
@@ -140,8 +138,8 @@ class LegacyLoan(object):
140
138
  if self.tenant_timezone != ZoneInfo("UTC"):
141
139
  self.due_date = self.due_date.astimezone(ZoneInfo("UTC"))
142
140
  self.out_date = self.out_date.astimezone(ZoneInfo("UTC"))
143
- except Exception:
144
- self.errors.append(("UTC correction issues", "both dates"))
141
+ except TypeError:
142
+ self.errors.append((f"UTC correction issues {self.row}", "both dates"))
145
143
 
146
144
  def report(self, what_to_report: str):
147
145
  self.migration_report.add("Details", what_to_report)