folio-migration-tools 1.2.1__py3-none-any.whl → 1.9.10__py3-none-any.whl
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.
- folio_migration_tools/__init__.py +11 -0
- folio_migration_tools/__main__.py +169 -85
- folio_migration_tools/circulation_helper.py +96 -59
- folio_migration_tools/config_file_load.py +66 -0
- folio_migration_tools/custom_dict.py +6 -4
- folio_migration_tools/custom_exceptions.py +21 -19
- folio_migration_tools/extradata_writer.py +46 -0
- folio_migration_tools/folder_structure.py +63 -66
- folio_migration_tools/helper.py +29 -21
- folio_migration_tools/holdings_helper.py +57 -34
- folio_migration_tools/i18n_config.py +9 -0
- folio_migration_tools/library_configuration.py +173 -13
- folio_migration_tools/mapper_base.py +317 -106
- folio_migration_tools/mapping_file_transformation/courses_mapper.py +203 -0
- folio_migration_tools/mapping_file_transformation/holdings_mapper.py +83 -69
- folio_migration_tools/mapping_file_transformation/item_mapper.py +98 -94
- folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py +352 -0
- folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py +702 -223
- folio_migration_tools/mapping_file_transformation/notes_mapper.py +90 -0
- folio_migration_tools/mapping_file_transformation/order_mapper.py +492 -0
- folio_migration_tools/mapping_file_transformation/organization_mapper.py +389 -0
- folio_migration_tools/mapping_file_transformation/ref_data_mapping.py +38 -27
- folio_migration_tools/mapping_file_transformation/user_mapper.py +149 -361
- folio_migration_tools/marc_rules_transformation/conditions.py +650 -246
- folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py +292 -130
- folio_migration_tools/marc_rules_transformation/hrid_handler.py +244 -0
- folio_migration_tools/marc_rules_transformation/loc_language_codes.xml +20846 -0
- folio_migration_tools/marc_rules_transformation/marc_file_processor.py +300 -0
- folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py +136 -0
- folio_migration_tools/marc_rules_transformation/rules_mapper_authorities.py +241 -0
- folio_migration_tools/marc_rules_transformation/rules_mapper_base.py +681 -201
- folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py +395 -429
- folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py +531 -100
- folio_migration_tools/migration_report.py +85 -38
- folio_migration_tools/migration_tasks/__init__.py +1 -3
- folio_migration_tools/migration_tasks/authority_transformer.py +119 -0
- folio_migration_tools/migration_tasks/batch_poster.py +911 -198
- folio_migration_tools/migration_tasks/bibs_transformer.py +121 -116
- folio_migration_tools/migration_tasks/courses_migrator.py +192 -0
- folio_migration_tools/migration_tasks/holdings_csv_transformer.py +252 -247
- folio_migration_tools/migration_tasks/holdings_marc_transformer.py +321 -115
- folio_migration_tools/migration_tasks/items_transformer.py +264 -84
- folio_migration_tools/migration_tasks/loans_migrator.py +506 -195
- folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py +187 -0
- folio_migration_tools/migration_tasks/migration_task_base.py +364 -74
- folio_migration_tools/migration_tasks/orders_transformer.py +373 -0
- folio_migration_tools/migration_tasks/organization_transformer.py +451 -0
- folio_migration_tools/migration_tasks/requests_migrator.py +130 -62
- folio_migration_tools/migration_tasks/reserves_migrator.py +253 -0
- folio_migration_tools/migration_tasks/user_transformer.py +180 -139
- folio_migration_tools/task_configuration.py +46 -0
- folio_migration_tools/test_infrastructure/__init__.py +0 -0
- folio_migration_tools/test_infrastructure/mocked_classes.py +406 -0
- folio_migration_tools/transaction_migration/legacy_loan.py +148 -34
- folio_migration_tools/transaction_migration/legacy_request.py +65 -25
- folio_migration_tools/transaction_migration/legacy_reserve.py +47 -0
- folio_migration_tools/transaction_migration/transaction_result.py +12 -1
- folio_migration_tools/translations/en.json +476 -0
- folio_migration_tools-1.9.10.dist-info/METADATA +169 -0
- folio_migration_tools-1.9.10.dist-info/RECORD +67 -0
- {folio_migration_tools-1.2.1.dist-info → folio_migration_tools-1.9.10.dist-info}/WHEEL +1 -2
- folio_migration_tools-1.9.10.dist-info/entry_points.txt +3 -0
- folio_migration_tools/generate_schemas.py +0 -46
- folio_migration_tools/mapping_file_transformation/mapping_file_mapping_base_impl.py +0 -44
- folio_migration_tools/mapping_file_transformation/user_mapper_base.py +0 -212
- folio_migration_tools/marc_rules_transformation/bibs_processor.py +0 -163
- folio_migration_tools/marc_rules_transformation/holdings_processor.py +0 -284
- folio_migration_tools/report_blurbs.py +0 -219
- folio_migration_tools/transaction_migration/legacy_fee_fine.py +0 -36
- folio_migration_tools-1.2.1.dist-info/METADATA +0 -134
- folio_migration_tools-1.2.1.dist-info/RECORD +0 -50
- folio_migration_tools-1.2.1.dist-info/top_level.txt +0 -1
- {folio_migration_tools-1.2.1.dist-info → folio_migration_tools-1.9.10.dist-info/licenses}/LICENSE +0 -0
|
@@ -2,274 +2,126 @@ import csv
|
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
4
|
import sys
|
|
5
|
-
import uuid
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from typing import Dict
|
|
8
5
|
|
|
6
|
+
import i18n
|
|
9
7
|
from dateutil.parser import parse
|
|
10
8
|
from folio_uuid.folio_namespaces import FOLIONamespaces
|
|
11
9
|
from folioclient import FolioClient
|
|
12
|
-
|
|
10
|
+
|
|
11
|
+
from folio_migration_tools.custom_exceptions import (
|
|
12
|
+
TransformationProcessError,
|
|
13
|
+
TransformationRecordFailedError,
|
|
14
|
+
)
|
|
13
15
|
from folio_migration_tools.mapping_file_transformation.mapping_file_mapper_base import (
|
|
14
16
|
MappingFileMapperBase,
|
|
15
17
|
)
|
|
16
|
-
from folio_migration_tools.mapping_file_transformation.
|
|
17
|
-
MappingFileMappingBaseImpl,
|
|
18
|
-
)
|
|
18
|
+
from folio_migration_tools.mapping_file_transformation.notes_mapper import NotesMapper
|
|
19
19
|
from folio_migration_tools.mapping_file_transformation.ref_data_mapping import (
|
|
20
20
|
RefDataMapping,
|
|
21
21
|
)
|
|
22
|
-
from folio_migration_tools.mapping_file_transformation.user_mapper_base import (
|
|
23
|
-
UserMapperBase,
|
|
24
|
-
)
|
|
25
|
-
from folio_migration_tools.report_blurbs import Blurbs
|
|
26
22
|
|
|
27
23
|
|
|
28
|
-
class UserMapper(
|
|
24
|
+
class UserMapper(MappingFileMapperBase):
|
|
29
25
|
def __init__(
|
|
30
26
|
self,
|
|
31
27
|
folio_client: FolioClient,
|
|
32
28
|
task_config,
|
|
33
29
|
library_config,
|
|
30
|
+
user_map,
|
|
34
31
|
departments_mapping,
|
|
35
32
|
groups_map,
|
|
36
33
|
):
|
|
37
34
|
try:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
self.noteprops = None
|
|
41
|
-
self.notes_schemas = None
|
|
42
|
-
self.notes_mapper = None
|
|
43
|
-
self.task_config = task_config
|
|
44
|
-
self.folio_keys = []
|
|
45
|
-
self.mapped_legacy_keys = []
|
|
46
|
-
self.library_config = library_config
|
|
47
|
-
self.user_schema = FolioClient.get_latest_from_github(
|
|
35
|
+
user_schema = folio_client.get_from_github(
|
|
48
36
|
"folio-org", "mod-user-import", "/ramls/schemas/userdataimport.json"
|
|
49
37
|
)
|
|
50
|
-
self.ids_dict: Dict[str, set] = {}
|
|
51
|
-
self.custom_props = {}
|
|
52
|
-
# TODO: Use RefDataMapping
|
|
53
|
-
if departments_mapping:
|
|
54
|
-
self.departments_mapping = RefDataMapping(
|
|
55
|
-
self.folio_client,
|
|
56
|
-
"/departments",
|
|
57
|
-
"departments",
|
|
58
|
-
departments_mapping,
|
|
59
|
-
"name",
|
|
60
|
-
Blurbs.DepartmentsMapping,
|
|
61
|
-
)
|
|
62
|
-
else:
|
|
63
|
-
self.departments_mapping = None
|
|
64
|
-
if groups_map:
|
|
65
|
-
self.groups_mapping = RefDataMapping(
|
|
66
|
-
self.folio_client,
|
|
67
|
-
"/groups",
|
|
68
|
-
"usergroups",
|
|
69
|
-
groups_map,
|
|
70
|
-
"group",
|
|
71
|
-
Blurbs.UserGroupMapping,
|
|
72
|
-
)
|
|
73
|
-
else:
|
|
74
|
-
self.groups_mapping = None
|
|
75
|
-
self.setup_notes_mapping()
|
|
76
|
-
logging.info("Init done.")
|
|
77
|
-
except TransformationProcessError as tpe:
|
|
78
|
-
logging.critical(tpe)
|
|
79
|
-
print(f"\n{tpe.message}")
|
|
80
|
-
sys.exit(1)
|
|
81
|
-
|
|
82
|
-
def setup_notes_mapping(self):
|
|
83
|
-
self.notes_schemas = FolioClient.get_latest_from_github(
|
|
84
|
-
"folio-org",
|
|
85
|
-
"mod-notes",
|
|
86
|
-
"src/main/resources/swagger.api/schemas/note.yaml",
|
|
87
|
-
)
|
|
88
|
-
notes_common = FolioClient.get_latest_from_github(
|
|
89
|
-
"folio-org",
|
|
90
|
-
"mod-notes",
|
|
91
|
-
"src/main/resources/swagger.api/schemas/common.yaml",
|
|
92
|
-
)
|
|
93
|
-
for prop in self.notes_schemas["note"]["properties"].items():
|
|
94
|
-
if prop[1].get("$ref", "") == "common.yaml#/uuid":
|
|
95
|
-
prop[1]["type"] = notes_common["uuid"]["type"]
|
|
96
|
-
|
|
97
|
-
for p in ["links", "metadata", "id"]:
|
|
98
|
-
del self.notes_schemas["note"]["properties"][p]
|
|
99
38
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
self.noteprops = {
|
|
103
|
-
"data": [
|
|
104
|
-
p for p in user_map["data"] if p["folio_field"].startswith("notes[")
|
|
105
|
-
]
|
|
106
|
-
}
|
|
107
|
-
logging.info(
|
|
108
|
-
"Set %s props used for note mapping", len(self.noteprops["data"])
|
|
39
|
+
user_schema["properties"]["requestPreference"] = folio_client.get_from_github(
|
|
40
|
+
"folio-org", "mod-user-import", "/ramls/schemas/userImportRequestPreference.json"
|
|
109
41
|
)
|
|
110
|
-
if any(self.noteprops["data"]):
|
|
111
|
-
notes_schema = self.notes_schemas["noteCollection"]
|
|
112
|
-
notes_schema["properties"]["notes"]["items"] = self.notes_schemas["note"]
|
|
113
|
-
notes_schema["required"] = []
|
|
114
|
-
if self.notes_mapper is None:
|
|
115
|
-
self.notes_mapper = MappingFileMappingBaseImpl(
|
|
116
|
-
self.library_config,
|
|
117
|
-
self.folio_client,
|
|
118
|
-
notes_schema,
|
|
119
|
-
self.noteprops,
|
|
120
|
-
FOLIONamespaces.other,
|
|
121
|
-
True,
|
|
122
|
-
)
|
|
123
|
-
logging.info("Initiated mapper for User notes")
|
|
124
|
-
for note in self.notes_mapper.do_map(
|
|
125
|
-
legacy_user, legacy_id, FOLIONamespaces.other
|
|
126
|
-
)[0].get("notes", []):
|
|
127
|
-
if note.get("content", "").strip():
|
|
128
|
-
note["links"] = [{"id": user_uuid, "type": "user"}]
|
|
129
42
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def do_map(self, legacy_user, user_map, legacy_id):
|
|
139
|
-
if not self.folio_keys and not self.mapped_legacy_keys:
|
|
140
|
-
self.folio_keys = (
|
|
141
|
-
MappingFileMapperBase.get_mapped_folio_properties_from_map(user_map)
|
|
43
|
+
super().__init__(
|
|
44
|
+
folio_client,
|
|
45
|
+
user_schema,
|
|
46
|
+
user_map,
|
|
47
|
+
None,
|
|
48
|
+
FOLIONamespaces.users,
|
|
49
|
+
library_config,
|
|
50
|
+
task_config
|
|
142
51
|
)
|
|
143
|
-
self.
|
|
144
|
-
|
|
52
|
+
self.task_config = self.task_configuration
|
|
53
|
+
self.notes_mapper: NotesMapper = NotesMapper(
|
|
54
|
+
self.library_configuration,
|
|
55
|
+
None,
|
|
56
|
+
self.folio_client,
|
|
57
|
+
self.record_map,
|
|
58
|
+
FOLIONamespaces.users,
|
|
59
|
+
True,
|
|
145
60
|
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
61
|
+
self.notes_mapper.migration_report = self.migration_report
|
|
62
|
+
self.departments_mapping = self.setup_departments_mapping(departments_mapping)
|
|
63
|
+
self.groups_mapping = self.setup_groups_mapping(groups_map)
|
|
64
|
+
|
|
65
|
+
for m in self.record_map["data"]:
|
|
66
|
+
if m["folio_field"].startswith("customFields"):
|
|
67
|
+
if "properties" not in self.schema["properties"]["customFields"]:
|
|
68
|
+
self.schema["properties"]["customFields"]["properties"] = {}
|
|
69
|
+
custom_field_prop_name = m["folio_field"].split(".")[-1]
|
|
70
|
+
self.schema["properties"]["customFields"]["properties"][
|
|
71
|
+
custom_field_prop_name
|
|
72
|
+
] = {"type": "string", "description": "dynamically added custom prop"}
|
|
158
73
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# TODO: Create ID-Legacy ID Mapping file!
|
|
165
|
-
# TODO: Check for ID duplicates (barcodes, externalsystemID:s, usernames, emails?)
|
|
166
|
-
|
|
167
|
-
folio_user = self.instantiate_user(legacy_id)
|
|
168
|
-
for prop_name, prop in self.user_schema["properties"].items():
|
|
169
|
-
self.add_prop(legacy_user, user_map, folio_user, prop_name, prop)
|
|
74
|
+
logging.info("Init done.")
|
|
75
|
+
except TransformationProcessError as tpe:
|
|
76
|
+
logging.critical(tpe)
|
|
77
|
+
print(f"\n{tpe.message}\t{tpe.data_value}")
|
|
78
|
+
sys.exit(1)
|
|
170
79
|
|
|
171
|
-
|
|
80
|
+
def perform_additional_mapping(self, legacy_user, folio_user, index_or_id):
|
|
81
|
+
self.notes_mapper.map_notes(
|
|
82
|
+
legacy_user, index_or_id, folio_user["id"], FOLIONamespaces.users
|
|
83
|
+
)
|
|
84
|
+
if "personal" not in folio_user:
|
|
85
|
+
folio_user["personal"] = {}
|
|
86
|
+
folio_user["personal"]["preferredContactTypeId"] = "email"
|
|
172
87
|
folio_user["active"] = True
|
|
173
|
-
folio_user
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
88
|
+
if folio_user.get("requestPreference"):
|
|
89
|
+
folio_user["requestPreference"].update(
|
|
90
|
+
{
|
|
91
|
+
"holdShelf": True,
|
|
92
|
+
"delivery": False,
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
folio_user["requestPreference"] = {
|
|
97
|
+
"holdShelf": True,
|
|
98
|
+
"delivery": False,
|
|
99
|
+
}
|
|
100
|
+
|
|
180
101
|
clean_folio_object = self.validate_required_properties(
|
|
181
|
-
|
|
102
|
+
index_or_id, folio_user, self.schema, FOLIONamespaces.users
|
|
182
103
|
)
|
|
104
|
+
if not clean_folio_object.get("personal", {}).get("lastName", ""):
|
|
105
|
+
raise TransformationRecordFailedError(index_or_id, "Last name is missing", "")
|
|
183
106
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def add_prop(self, legacy_object, user_map, folio_user, prop_name, prop):
|
|
189
|
-
if prop["type"] == "object":
|
|
190
|
-
if "customFields" in prop_name:
|
|
191
|
-
for k, v in self.custom_props.items():
|
|
192
|
-
if legacy_value := legacy_object.get(v, ""):
|
|
193
|
-
folio_user["customFields"][k] = legacy_value
|
|
194
|
-
else:
|
|
195
|
-
folio_user[prop_name] = {}
|
|
196
|
-
prop_key = prop_name
|
|
197
|
-
if "properties" in prop:
|
|
198
|
-
for sub_prop_name, sub_prop in prop["properties"].items():
|
|
199
|
-
sub_prop_key = f"{prop_key}.{sub_prop_name}"
|
|
200
|
-
if "properties" in sub_prop:
|
|
201
|
-
for sub_prop_name2, sub_prop2 in sub_prop[
|
|
202
|
-
"properties"
|
|
203
|
-
].items():
|
|
204
|
-
sub_prop_key2 = f"{sub_prop_key}.{sub_prop_name2}"
|
|
205
|
-
if sub_prop2["type"] == "array":
|
|
206
|
-
logging.warning(f"Array: {sub_prop_key2} ")
|
|
207
|
-
elif sub_prop["type"] == "array":
|
|
208
|
-
folio_user[prop_name][sub_prop_name] = []
|
|
209
|
-
for i in range(5):
|
|
210
|
-
if sub_prop["items"]["type"] == "object":
|
|
211
|
-
temp = {
|
|
212
|
-
sub_prop_name2: self.get_prop(
|
|
213
|
-
legacy_object,
|
|
214
|
-
user_map,
|
|
215
|
-
f"{sub_prop_key}.{sub_prop_name2}",
|
|
216
|
-
i,
|
|
217
|
-
)
|
|
218
|
-
for sub_prop_name2, sub_prop2 in sub_prop[
|
|
219
|
-
"items"
|
|
220
|
-
]["properties"].items()
|
|
221
|
-
}
|
|
107
|
+
if "preferredFirstName" in clean_folio_object.get(
|
|
108
|
+
"personal", {}
|
|
109
|
+
) and not clean_folio_object.get("personal", {}).get("preferredFirstName", ""):
|
|
110
|
+
del clean_folio_object["personal"]["preferredFirstName"]
|
|
222
111
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if key
|
|
227
|
-
not in ["id", "primaryAddress", "addressTypeId"]
|
|
228
|
-
):
|
|
229
|
-
continue
|
|
230
|
-
folio_user[prop_name][sub_prop_name].append(temp)
|
|
231
|
-
else:
|
|
232
|
-
mkey = f"{sub_prop_key}.{sub_prop_name2}"
|
|
233
|
-
folio_user[prop_name][
|
|
234
|
-
sub_prop_name
|
|
235
|
-
] = self.get_prop(legacy_object, mkey, i)
|
|
112
|
+
if self.task_config.remove_id_and_request_preferences:
|
|
113
|
+
del clean_folio_object["id"]
|
|
114
|
+
del clean_folio_object["requestPreference"]
|
|
236
115
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if folio_user[prop_name] == {}:
|
|
242
|
-
del folio_user[prop_name]
|
|
243
|
-
elif prop["type"] == "array":
|
|
244
|
-
if prop["items"]["type"] == "string":
|
|
245
|
-
prop_names = [p for p in self.folio_keys if p.startswith(prop_name)]
|
|
246
|
-
for idx, arr_prop_name in enumerate(prop_names):
|
|
247
|
-
actual_prop_name = arr_prop_name.split("[")[0]
|
|
248
|
-
if any(folio_user.get(actual_prop_name, [])):
|
|
249
|
-
folio_user[actual_prop_name].append(
|
|
250
|
-
self.get_prop(
|
|
251
|
-
legacy_object, user_map, actual_prop_name, idx
|
|
252
|
-
)
|
|
253
|
-
)
|
|
254
|
-
else:
|
|
255
|
-
folio_user[actual_prop_name] = [
|
|
256
|
-
self.get_prop(
|
|
257
|
-
legacy_object, user_map, actual_prop_name, idx
|
|
258
|
-
)
|
|
259
|
-
]
|
|
260
|
-
if prop_name in folio_user and not any(folio_user.get(prop_name, [])):
|
|
261
|
-
del folio_user[prop_name]
|
|
262
|
-
else:
|
|
263
|
-
logging.info("Edge case %s", prop_name)
|
|
264
|
-
else:
|
|
265
|
-
self.map_basic_props(legacy_object, user_map, prop_name, folio_user)
|
|
116
|
+
if self.task_config.remove_request_preferences:
|
|
117
|
+
del clean_folio_object["requestPreference"]
|
|
118
|
+
self.report_folio_mapping_no_schema(clean_folio_object)
|
|
119
|
+
self.report_legacy_mapping_no_schema(legacy_user)
|
|
266
120
|
|
|
267
|
-
|
|
268
|
-
if self.has_property(legacy_user, user_map, prop):
|
|
269
|
-
if temp_prop := self.get_prop(legacy_user, user_map, prop).strip():
|
|
270
|
-
folio_user[prop] = temp_prop
|
|
121
|
+
return clean_folio_object
|
|
271
122
|
|
|
272
|
-
|
|
123
|
+
@staticmethod
|
|
124
|
+
def get_users(source_file, file_format: str):
|
|
273
125
|
csv.register_dialect("tsv", delimiter="\t")
|
|
274
126
|
if file_format == "tsv":
|
|
275
127
|
reader = csv.DictReader(source_file, dialect="tsv")
|
|
@@ -282,149 +134,85 @@ class UserMapper(UserMapperBase):
|
|
|
282
134
|
)
|
|
283
135
|
yield row
|
|
284
136
|
|
|
285
|
-
def get_prop(self, legacy_user,
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
self.migration_report.add(
|
|
289
|
-
Blurbs.DefaultValuesAdded, f"{value} added to {folio_prop_name}"
|
|
290
|
-
)
|
|
291
|
-
return value
|
|
292
|
-
# All other cases are mapped from legacy fields.
|
|
293
|
-
legacy_user_keys = list(
|
|
294
|
-
get_legacy_user_keys(folio_prop_name, user_map["data"], i)
|
|
137
|
+
def get_prop(self, legacy_user, folio_prop_name, index_or_id, schema_default_value):
|
|
138
|
+
mapped_value = super().get_prop(
|
|
139
|
+
legacy_user, folio_prop_name, index_or_id, schema_default_value
|
|
295
140
|
)
|
|
296
|
-
if not any(legacy_user_keys):
|
|
297
|
-
return ""
|
|
298
|
-
|
|
299
|
-
legacy_user_key = legacy_user_keys[0]
|
|
300
|
-
|
|
301
141
|
if folio_prop_name == "personal.addresses.id":
|
|
302
142
|
return ""
|
|
303
|
-
elif folio_prop_name.split("[")[0] == "departments":
|
|
304
|
-
if not self.departments_mapping:
|
|
305
|
-
raise TransformationProcessError(
|
|
306
|
-
"",
|
|
307
|
-
"No Departments mapping set up. Set up a departments mapping file "
|
|
308
|
-
" or remove the mapping of the Departments field",
|
|
309
|
-
)
|
|
310
|
-
legacy_dept = legacy_user.get(legacy_user_key, "")
|
|
311
|
-
gid = self.get_mapped_name(
|
|
312
|
-
self.departments_mapping,
|
|
313
|
-
legacy_user,
|
|
314
|
-
id,
|
|
315
|
-
folio_prop_name.split("[")[0],
|
|
316
|
-
True,
|
|
317
|
-
)
|
|
318
|
-
self.migration_report.add(
|
|
319
|
-
Blurbs.DepartmentsMapping, f"{legacy_dept} -> {gid}"
|
|
320
|
-
)
|
|
321
|
-
return gid
|
|
322
143
|
elif folio_prop_name == "patronGroup":
|
|
323
|
-
legacy_group = legacy_user.get(legacy_user_key, "")
|
|
324
144
|
if self.groups_mapping:
|
|
325
|
-
|
|
145
|
+
return self.get_mapped_name(
|
|
326
146
|
self.groups_mapping,
|
|
327
147
|
legacy_user,
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
True,
|
|
148
|
+
index_or_id,
|
|
149
|
+
False,
|
|
331
150
|
)
|
|
332
|
-
return gid
|
|
333
151
|
else:
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
"expirationDate",
|
|
342
|
-
"enrollmentDate",
|
|
343
|
-
"personal.dateOfBirth",
|
|
344
|
-
]:
|
|
345
|
-
try:
|
|
346
|
-
if not legacy_user.get(legacy_user_key):
|
|
347
|
-
return ""
|
|
348
|
-
format_date = parse(legacy_user.get(legacy_user_key), fuzzy=True)
|
|
349
|
-
fmt_string = (
|
|
350
|
-
f"{folio_prop_name}: {legacy_user.get(legacy_user_key)}"
|
|
351
|
-
f" -> {format_date.isoformat()}"
|
|
152
|
+
return mapped_value
|
|
153
|
+
elif folio_prop_name.startswith("departments"):
|
|
154
|
+
if not self.departments_mapping:
|
|
155
|
+
raise TransformationProcessError(
|
|
156
|
+
"",
|
|
157
|
+
"No Departments mapping set up. Set up a departments mapping file "
|
|
158
|
+
" or remove the mapping of the Departments field",
|
|
352
159
|
)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
v = legacy_user.get(legacy_user_key)
|
|
357
|
-
logging.error(f"{folio_prop_name} {v} could not be parsed: {ee}")
|
|
358
|
-
fmt_string = (
|
|
359
|
-
f"Parsing error! {folio_prop_name}: {v}. NOW() was returned"
|
|
160
|
+
if len(self.departments_mapping.mapped_legacy_keys) == 1 and self.library_configuration.multi_field_delimiter in legacy_user.get(self.departments_mapping.mapped_legacy_keys[0], ""):
|
|
161
|
+
split_departments = legacy_user.get(self.departments_mapping.mapped_legacy_keys[0], "").split(
|
|
162
|
+
self.library_configuration.multi_field_delimiter
|
|
360
163
|
)
|
|
361
|
-
self.
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
164
|
+
return self.library_configuration.multi_field_delimiter.join([
|
|
165
|
+
self.get_mapped_name(
|
|
166
|
+
self.departments_mapping,
|
|
167
|
+
{self.departments_mapping.mapped_legacy_keys[0]: dept},
|
|
168
|
+
index_or_id,
|
|
169
|
+
True,
|
|
170
|
+
) for dept in split_departments
|
|
171
|
+
])
|
|
172
|
+
else:
|
|
173
|
+
return self.get_mapped_name(
|
|
174
|
+
self.departments_mapping,
|
|
175
|
+
legacy_user,
|
|
176
|
+
index_or_id,
|
|
177
|
+
True,
|
|
374
178
|
)
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
179
|
+
elif folio_prop_name in ["expirationDate", "enrollmentDate", "personal.dateOfBirth"]:
|
|
180
|
+
return self.get_parsed_date(mapped_value, folio_prop_name)
|
|
181
|
+
return mapped_value
|
|
378
182
|
|
|
379
|
-
def
|
|
380
|
-
|
|
381
|
-
(
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
def legacy_property(self, user_map, folio_prop_name):
|
|
393
|
-
if value := next(
|
|
394
|
-
(
|
|
395
|
-
k.get("value", "")
|
|
396
|
-
for k in user_map["data"]
|
|
397
|
-
if k["folio_field"] == folio_prop_name
|
|
398
|
-
),
|
|
399
|
-
"",
|
|
400
|
-
):
|
|
401
|
-
self.migration_report.add(
|
|
402
|
-
Blurbs.DefaultValuesAdded, f"{value} added to {folio_prop_name}"
|
|
183
|
+
def get_parsed_date(self, mapped_value, folio_prop_name: str):
|
|
184
|
+
try:
|
|
185
|
+
if not mapped_value.strip():
|
|
186
|
+
return ""
|
|
187
|
+
format_date = parse(mapped_value, fuzzy=True)
|
|
188
|
+
return format_date.isoformat()
|
|
189
|
+
except Exception as ee:
|
|
190
|
+
v = mapped_value
|
|
191
|
+
logging.error(f"{folio_prop_name} {v} could not be parsed: {ee}")
|
|
192
|
+
fmt_string = i18n.t(
|
|
193
|
+
"Parsing error! %{prop_name}: %{value}. The empty string was returned",
|
|
194
|
+
prop_name=folio_prop_name,
|
|
195
|
+
value=v,
|
|
403
196
|
)
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
k["legacy_field"]
|
|
407
|
-
for k in user_map["data"]
|
|
408
|
-
if k["folio_field"] == folio_prop_name
|
|
409
|
-
)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
def get_legacy__user_value(folio_prop_name, data, i):
|
|
413
|
-
return next(
|
|
414
|
-
(
|
|
415
|
-
k.get("value", "")
|
|
416
|
-
for k in data
|
|
417
|
-
if k["folio_field"].replace(f"[{i}]", "") == folio_prop_name
|
|
418
|
-
or k["folio_field"] == folio_prop_name
|
|
419
|
-
),
|
|
420
|
-
"",
|
|
421
|
-
)
|
|
422
|
-
|
|
197
|
+
self.migration_report.add("DateTimeConversions", fmt_string)
|
|
198
|
+
return ""
|
|
423
199
|
|
|
424
|
-
def
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
200
|
+
def setup_groups_mapping(self, groups_map):
|
|
201
|
+
return RefDataMapping(
|
|
202
|
+
self.folio_client,
|
|
203
|
+
"/groups",
|
|
204
|
+
"usergroups",
|
|
205
|
+
groups_map,
|
|
206
|
+
"group",
|
|
207
|
+
"UserGroupMapping",
|
|
208
|
+
) if groups_map else None
|
|
209
|
+
|
|
210
|
+
def setup_departments_mapping(self, departments_mapping):
|
|
211
|
+
return RefDataMapping(
|
|
212
|
+
self.folio_client,
|
|
213
|
+
"/departments",
|
|
214
|
+
"departments",
|
|
215
|
+
departments_mapping,
|
|
216
|
+
"name",
|
|
217
|
+
"DepartmentsMapping",
|
|
218
|
+
) if departments_mapping else None
|