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
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import csv
|
|
2
1
|
import json
|
|
3
2
|
import logging
|
|
4
|
-
from abc import abstractmethod
|
|
5
3
|
import sys
|
|
6
|
-
from typing import
|
|
4
|
+
from typing import Optional, Annotated
|
|
5
|
+
from pydantic import Field
|
|
7
6
|
|
|
7
|
+
import i18n
|
|
8
8
|
from folio_uuid.folio_namespaces import FOLIONamespaces
|
|
9
|
-
from
|
|
9
|
+
from art import tprint
|
|
10
|
+
|
|
10
11
|
from folio_migration_tools.custom_exceptions import (
|
|
11
12
|
TransformationProcessError,
|
|
12
13
|
TransformationRecordFailedError,
|
|
@@ -21,18 +22,89 @@ from folio_migration_tools.mapping_file_transformation.mapping_file_mapper_base
|
|
|
21
22
|
)
|
|
22
23
|
from folio_migration_tools.mapping_file_transformation.user_mapper import UserMapper
|
|
23
24
|
from folio_migration_tools.migration_tasks.migration_task_base import MigrationTaskBase
|
|
24
|
-
from
|
|
25
|
+
from folio_migration_tools.task_configuration import AbstractTaskConfiguration
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class UserTransformer(MigrationTaskBase):
|
|
28
|
-
class TaskConfiguration(
|
|
29
|
-
name:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
class TaskConfiguration(AbstractTaskConfiguration):
|
|
30
|
+
name: Annotated[
|
|
31
|
+
str,
|
|
32
|
+
Field(
|
|
33
|
+
title="Migration task name",
|
|
34
|
+
description=(
|
|
35
|
+
"Name of this migration task. The name is being used to call "
|
|
36
|
+
"the specific task, and to distinguish tasks of similar types"
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
]
|
|
40
|
+
migration_task_type: Annotated[
|
|
41
|
+
str,
|
|
42
|
+
Field(
|
|
43
|
+
title="Migration task type",
|
|
44
|
+
description="The type of migration task you want to perform",
|
|
45
|
+
),
|
|
46
|
+
]
|
|
47
|
+
group_map_path: Annotated[
|
|
48
|
+
str,
|
|
49
|
+
Field(
|
|
50
|
+
title="Group map path",
|
|
51
|
+
description="Define the path for group mapping",
|
|
52
|
+
)
|
|
53
|
+
]
|
|
54
|
+
departments_map_path: Annotated[
|
|
55
|
+
Optional[str],
|
|
56
|
+
Field(
|
|
57
|
+
title="Departments map path",
|
|
58
|
+
description=(
|
|
59
|
+
"Define the path for departments mapping. "
|
|
60
|
+
"Optional, by dfault is empty string"
|
|
61
|
+
),
|
|
62
|
+
)
|
|
63
|
+
] = ""
|
|
64
|
+
use_group_map: Annotated[
|
|
65
|
+
Optional[bool],
|
|
66
|
+
Field(
|
|
67
|
+
title="Use group map",
|
|
68
|
+
description=(
|
|
69
|
+
"Specify whether to use group mapping. "
|
|
70
|
+
"Optional, by default is True"
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
] = True
|
|
74
|
+
user_mapping_file_name: Annotated[
|
|
75
|
+
str,
|
|
76
|
+
Field(
|
|
77
|
+
title="User mapping file name",
|
|
78
|
+
description="Specify the user mapping file name",
|
|
79
|
+
)
|
|
80
|
+
]
|
|
81
|
+
user_file: Annotated[
|
|
82
|
+
FileDefinition,
|
|
83
|
+
Field(
|
|
84
|
+
title="User file",
|
|
85
|
+
description="Select the user data file",
|
|
86
|
+
)
|
|
87
|
+
]
|
|
88
|
+
remove_id_and_request_preferences: Annotated[
|
|
89
|
+
Optional[bool],
|
|
90
|
+
Field(
|
|
91
|
+
title="Remove ID and request preferences",
|
|
92
|
+
description=(
|
|
93
|
+
"Specify whether to remove user ID and request preferences. "
|
|
94
|
+
"Optional, by default is False"
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
] = False
|
|
98
|
+
remove_request_preferences: Annotated[
|
|
99
|
+
Optional[bool],
|
|
100
|
+
Field(
|
|
101
|
+
title="Remove request preferences",
|
|
102
|
+
description=(
|
|
103
|
+
"Specify whether to remove user request preferences. "
|
|
104
|
+
"Optional, by default is False"
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
] = False
|
|
36
108
|
|
|
37
109
|
@staticmethod
|
|
38
110
|
def get_object_type() -> FOLIONamespaces:
|
|
@@ -42,20 +114,19 @@ class UserTransformer(MigrationTaskBase):
|
|
|
42
114
|
self,
|
|
43
115
|
task_config: TaskConfiguration,
|
|
44
116
|
library_config: LibraryConfiguration,
|
|
117
|
+
folio_client,
|
|
45
118
|
use_logging: bool = True,
|
|
46
119
|
):
|
|
47
|
-
super().__init__(library_config, task_config, use_logging)
|
|
120
|
+
super().__init__(library_config, task_config, folio_client, use_logging)
|
|
48
121
|
self.task_config = task_config
|
|
122
|
+
self.task_configuration = self.task_config
|
|
49
123
|
self.total_records = 0
|
|
50
124
|
|
|
51
125
|
self.user_map = self.setup_records_map(
|
|
52
|
-
self.folder_structure.mapping_files_folder
|
|
53
|
-
/ self.task_config.user_mapping_file_name
|
|
126
|
+
self.folder_structure.mapping_files_folder / self.task_config.user_mapping_file_name
|
|
54
127
|
)
|
|
55
128
|
self.folio_keys = []
|
|
56
|
-
self.folio_keys = MappingFileMapperBase.get_mapped_folio_properties_from_map(
|
|
57
|
-
self.user_map
|
|
58
|
-
)
|
|
129
|
+
self.folio_keys = MappingFileMapperBase.get_mapped_folio_properties_from_map(self.user_map)
|
|
59
130
|
# Properties
|
|
60
131
|
self.failed_ids = []
|
|
61
132
|
self.failed_objects = []
|
|
@@ -64,67 +135,60 @@ class UserTransformer(MigrationTaskBase):
|
|
|
64
135
|
).is_file():
|
|
65
136
|
group_mapping = self.load_ref_data_mapping_file(
|
|
66
137
|
"patronGroup",
|
|
67
|
-
self.folder_structure.mapping_files_folder
|
|
68
|
-
/ self.task_config.group_map_path,
|
|
138
|
+
self.folder_structure.mapping_files_folder / self.task_config.group_map_path,
|
|
69
139
|
self.folio_keys,
|
|
70
140
|
)
|
|
71
141
|
else:
|
|
72
142
|
logging.info(
|
|
73
143
|
"%s not found. No patronGroup mapping will be performed",
|
|
74
|
-
self.folder_structure.mapping_files_folder
|
|
75
|
-
/ self.task_config.group_map_path,
|
|
144
|
+
self.folder_structure.mapping_files_folder / self.task_config.group_map_path,
|
|
76
145
|
)
|
|
77
146
|
group_mapping = []
|
|
78
147
|
|
|
79
148
|
if (
|
|
80
|
-
self.folder_structure.mapping_files_folder
|
|
81
|
-
/ self.task_config.departments_map_path
|
|
149
|
+
self.folder_structure.mapping_files_folder / self.task_config.departments_map_path
|
|
82
150
|
).is_file():
|
|
83
151
|
departments_mapping = self.load_ref_data_mapping_file(
|
|
84
152
|
"departments",
|
|
85
|
-
self.folder_structure.mapping_files_folder
|
|
86
|
-
/ self.task_config.departments_map_path,
|
|
153
|
+
self.folder_structure.mapping_files_folder / self.task_config.departments_map_path,
|
|
87
154
|
self.folio_keys,
|
|
88
155
|
)
|
|
89
156
|
else:
|
|
90
157
|
logging.info(
|
|
91
158
|
"%s not found. No departments mapping will be performed",
|
|
92
|
-
self.folder_structure.mapping_files_folder
|
|
93
|
-
/ self.task_config.departments_map_path,
|
|
159
|
+
self.folder_structure.mapping_files_folder / self.task_config.departments_map_path,
|
|
94
160
|
)
|
|
95
161
|
departments_mapping = []
|
|
96
|
-
|
|
97
|
-
self.
|
|
98
|
-
task_config,
|
|
99
|
-
library_config,
|
|
100
|
-
departments_mapping,
|
|
101
|
-
group_mapping,
|
|
162
|
+
map_path = (
|
|
163
|
+
self.folder_structure.mapping_files_folder / self.task_config.user_mapping_file_name
|
|
102
164
|
)
|
|
165
|
+
with open(map_path, encoding="utf8") as mapping_file:
|
|
166
|
+
user_map = json.load(mapping_file)
|
|
167
|
+
self.mapper = UserMapper(
|
|
168
|
+
self.folio_client,
|
|
169
|
+
task_config,
|
|
170
|
+
library_config,
|
|
171
|
+
user_map,
|
|
172
|
+
departments_mapping,
|
|
173
|
+
group_mapping,
|
|
174
|
+
)
|
|
175
|
+
|
|
103
176
|
logging.info("UserTransformer init done")
|
|
104
177
|
|
|
105
178
|
def do_work(self):
|
|
106
179
|
logging.info("Starting....")
|
|
107
180
|
source_path = (
|
|
108
|
-
self.folder_structure.legacy_records_folder
|
|
109
|
-
/ self.task_config.user_file.file_name
|
|
110
|
-
)
|
|
111
|
-
map_path = (
|
|
112
|
-
self.folder_structure.mapping_files_folder
|
|
113
|
-
/ self.task_config.user_mapping_file_name
|
|
181
|
+
self.folder_structure.legacy_records_folder / self.task_config.user_file.file_name
|
|
114
182
|
)
|
|
183
|
+
|
|
115
184
|
try:
|
|
116
185
|
with open(
|
|
117
186
|
self.folder_structure.created_objects_path,
|
|
118
187
|
"w+",
|
|
119
188
|
encoding="utf-8",
|
|
120
189
|
) as results_file:
|
|
121
|
-
with open(source_path, encoding="utf8") as object_file
|
|
122
|
-
map_path, encoding="utf8"
|
|
123
|
-
) as mapping_file:
|
|
190
|
+
with open(source_path, encoding="utf8") as object_file:
|
|
124
191
|
logging.info(f"processing {source_path}")
|
|
125
|
-
user_map = json.load(mapping_file)
|
|
126
|
-
legacy_property_name = self.get_legacy_id_prop(user_map)
|
|
127
|
-
|
|
128
192
|
file_format = "tsv" if str(source_path).endswith(".tsv") else "csv"
|
|
129
193
|
for num_users, legacy_user in enumerate(
|
|
130
194
|
self.mapper.get_users(object_file, file_format), start=1
|
|
@@ -134,33 +198,32 @@ class UserTransformer(MigrationTaskBase):
|
|
|
134
198
|
logging.info("First Legacy user")
|
|
135
199
|
logging.info(json.dumps(legacy_user, indent=4))
|
|
136
200
|
print_email_warning()
|
|
137
|
-
folio_user = self.mapper.do_map(
|
|
201
|
+
folio_user, index_or_id = self.mapper.do_map(
|
|
138
202
|
legacy_user,
|
|
139
|
-
|
|
140
|
-
|
|
203
|
+
str(num_users),
|
|
204
|
+
FOLIONamespaces.users,
|
|
205
|
+
)
|
|
206
|
+
folio_user = self.mapper.perform_additional_mapping(
|
|
207
|
+
legacy_user, folio_user, index_or_id
|
|
141
208
|
)
|
|
142
|
-
self.clean_user(folio_user)
|
|
209
|
+
self.clean_user(folio_user, index_or_id)
|
|
143
210
|
results_file.write(f"{json.dumps(folio_user)}\n")
|
|
144
211
|
if num_users == 1:
|
|
145
212
|
logging.info("## First FOLIO user")
|
|
146
|
-
logging.info(
|
|
147
|
-
json.dumps(folio_user, indent=4, sort_keys=True)
|
|
148
|
-
)
|
|
213
|
+
logging.info(json.dumps(folio_user, indent=4, sort_keys=True))
|
|
149
214
|
self.mapper.migration_report.add_general_statistics(
|
|
150
|
-
"Successful user transformations"
|
|
215
|
+
i18n.t("Successful user transformations")
|
|
151
216
|
)
|
|
152
217
|
if num_users % 1000 == 0:
|
|
153
218
|
logging.info(f"{num_users} users processed.")
|
|
154
219
|
except TransformationRecordFailedError as tre:
|
|
155
220
|
self.mapper.migration_report.add_general_statistics(
|
|
156
|
-
"Records failed"
|
|
157
|
-
)
|
|
158
|
-
Helper.log_data_issue(
|
|
159
|
-
tre.index_or_id, tre.message, tre.data_value
|
|
221
|
+
i18n.t("Records failed")
|
|
160
222
|
)
|
|
223
|
+
Helper.log_data_issue(tre.index_or_id, tre.message, tre.data_value)
|
|
161
224
|
logging.error(tre)
|
|
162
225
|
except TransformationProcessError as tpe:
|
|
163
|
-
logging.
|
|
226
|
+
logging.critical(tpe)
|
|
164
227
|
print(f"\n{tpe.message}: {tpe.data_value}")
|
|
165
228
|
print("\nHalting")
|
|
166
229
|
sys.exit(1)
|
|
@@ -172,63 +235,24 @@ class UserTransformer(MigrationTaskBase):
|
|
|
172
235
|
logging.error(num_users)
|
|
173
236
|
logging.error(json.dumps(legacy_user))
|
|
174
237
|
self.mapper.migration_report.add_general_statistics(
|
|
175
|
-
"Failed user transformations"
|
|
238
|
+
i18n.t("Failed user transformations")
|
|
176
239
|
)
|
|
177
240
|
logging.error(ee, exc_info=True)
|
|
178
241
|
|
|
179
242
|
self.total_records = num_users
|
|
180
|
-
except FileNotFoundError as
|
|
243
|
+
except FileNotFoundError as fn:
|
|
181
244
|
logging.exception("File not found")
|
|
182
|
-
print(f"\n{
|
|
245
|
+
print(f"\n{fn}")
|
|
183
246
|
sys.exit(1)
|
|
184
247
|
|
|
185
|
-
@staticmethod
|
|
186
|
-
def get_legacy_id_prop(record_map):
|
|
187
|
-
field_map = {} # Map of folio_fields and source fields as an array
|
|
188
|
-
for k in record_map["data"]:
|
|
189
|
-
if not field_map.get(k["folio_field"]):
|
|
190
|
-
field_map[k["folio_field"]] = [k["legacy_field"]]
|
|
191
|
-
else:
|
|
192
|
-
field_map[k["folio_field"]].append(k["legacy_field"])
|
|
193
|
-
if "legacyIdentifier" not in field_map:
|
|
194
|
-
raise TransformationProcessError(
|
|
195
|
-
"",
|
|
196
|
-
(
|
|
197
|
-
"property legacyIdentifier is not in map. Add this property "
|
|
198
|
-
"to the mapping file as if it was a FOLIO property"
|
|
199
|
-
),
|
|
200
|
-
)
|
|
201
|
-
try:
|
|
202
|
-
legacy_id_property_name = field_map["legacyIdentifier"][0]
|
|
203
|
-
logging.info(
|
|
204
|
-
"Legacy identifier will be mapped from %s", legacy_id_property_name
|
|
205
|
-
)
|
|
206
|
-
return legacy_id_property_name
|
|
207
|
-
except Exception as exception:
|
|
208
|
-
raise TransformationProcessError(
|
|
209
|
-
"",
|
|
210
|
-
(
|
|
211
|
-
f"property legacyIdentifier not setup in map: "
|
|
212
|
-
f"{field_map.get('legacyIdentifier', '') ({exception})}"
|
|
213
|
-
),
|
|
214
|
-
) from exception
|
|
215
|
-
|
|
216
248
|
def wrap_up(self):
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
json.dump(self.mapper.legacy_id_map, id_map_file, indent=4)
|
|
224
|
-
with open(
|
|
225
|
-
self.folder_structure.migration_reports_file, "w"
|
|
226
|
-
) as migration_report_file:
|
|
227
|
-
logging.info(
|
|
228
|
-
"Writing migration- and mapping report to %s",
|
|
229
|
-
self.folder_structure.migration_reports_file,
|
|
249
|
+
self.extradata_writer.flush()
|
|
250
|
+
with open(self.folder_structure.migration_reports_file, "w") as migration_report_file:
|
|
251
|
+
self.mapper.migration_report.write_migration_report(
|
|
252
|
+
i18n.t("Users transformation report"),
|
|
253
|
+
migration_report_file,
|
|
254
|
+
self.mapper.start_datetime,
|
|
230
255
|
)
|
|
231
|
-
self.mapper.migration_report.write_migration_report(migration_report_file)
|
|
232
256
|
Helper.print_mapping_report(
|
|
233
257
|
migration_report_file,
|
|
234
258
|
self.total_records,
|
|
@@ -236,42 +260,59 @@ class UserTransformer(MigrationTaskBase):
|
|
|
236
260
|
self.mapper.mapped_legacy_fields,
|
|
237
261
|
)
|
|
238
262
|
logging.info("All done!")
|
|
263
|
+
self.clean_out_empty_logs()
|
|
239
264
|
|
|
240
265
|
@staticmethod
|
|
241
|
-
def clean_user(folio_user):
|
|
242
|
-
|
|
243
|
-
|
|
266
|
+
def clean_user(folio_user, index_or_id):
|
|
267
|
+
valid_addresses = remove_empty_addresses(folio_user)
|
|
268
|
+
# Make sure the user has exactly one primary address
|
|
269
|
+
if valid_addresses:
|
|
270
|
+
primary_true = find_primary_addresses(valid_addresses)
|
|
271
|
+
if len(primary_true) < 1:
|
|
272
|
+
valid_addresses[0]["primaryAddress"] = True
|
|
273
|
+
elif len(primary_true) > 1:
|
|
274
|
+
logging.log(
|
|
275
|
+
26,
|
|
276
|
+
"DATA ISSUE\t%s\t%s\t%s",
|
|
277
|
+
index_or_id,
|
|
278
|
+
"Too many addresses mapped as primary. Setting first one to primary.",
|
|
279
|
+
primary_true,
|
|
280
|
+
)
|
|
281
|
+
for pt in primary_true[1:]:
|
|
282
|
+
pt["primaryAddress"] = False
|
|
283
|
+
folio_user["personal"]["addresses"] = valid_addresses
|
|
244
284
|
|
|
245
|
-
for address in addresses:
|
|
246
|
-
if "id" in address:
|
|
247
|
-
del address["id"]
|
|
248
285
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if not primary_address_exists:
|
|
253
|
-
addresses[0]["primaryAddress"] = True
|
|
286
|
+
def print_email_warning():
|
|
287
|
+
tprint("\nEMAILS?\n", space=2)
|
|
254
288
|
|
|
255
289
|
|
|
256
|
-
def
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
print(s)
|
|
290
|
+
def remove_empty_addresses(folio_user):
|
|
291
|
+
valid_addresses = []
|
|
292
|
+
# Remove empty addresses
|
|
293
|
+
if addresses := folio_user.get("personal", {}).pop("addresses", []):
|
|
294
|
+
for address in addresses:
|
|
295
|
+
address_fields = [
|
|
296
|
+
x for x in address.keys() if x not in ["primaryAddress", "addressTypeId", "id"]
|
|
297
|
+
]
|
|
298
|
+
if address_fields:
|
|
299
|
+
valid_addresses.append(address)
|
|
300
|
+
return valid_addresses
|
|
268
301
|
|
|
269
302
|
|
|
270
|
-
def
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
"
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
303
|
+
def find_primary_addresses(addresses):
|
|
304
|
+
primary_true = []
|
|
305
|
+
for address in addresses:
|
|
306
|
+
if "primaryAddress" not in address:
|
|
307
|
+
address["primaryAddress"] = False
|
|
308
|
+
elif (
|
|
309
|
+
isinstance(address["primaryAddress"], bool)
|
|
310
|
+
and address["primaryAddress"] is True
|
|
311
|
+
) or (
|
|
312
|
+
isinstance(address["primaryAddress"], str)
|
|
313
|
+
and address["primaryAddress"].lower() == "true"
|
|
314
|
+
):
|
|
315
|
+
primary_true.append(address)
|
|
316
|
+
else:
|
|
317
|
+
address["primaryAddress"] = False
|
|
318
|
+
return primary_true
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from humps import camelize
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def to_camel(string):
|
|
9
|
+
return camelize(string)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AbstractTaskConfiguration(BaseModel):
|
|
13
|
+
"""Abstract class for task configuration."""
|
|
14
|
+
|
|
15
|
+
name: Annotated[
|
|
16
|
+
str,
|
|
17
|
+
Field(
|
|
18
|
+
description=(
|
|
19
|
+
"Name of this migration task. The name is being used to call the specific "
|
|
20
|
+
"task, and to distinguish tasks of similar types"
|
|
21
|
+
)
|
|
22
|
+
),
|
|
23
|
+
]
|
|
24
|
+
migration_task_type: Annotated[
|
|
25
|
+
str,
|
|
26
|
+
Field(
|
|
27
|
+
title="Migration task type",
|
|
28
|
+
description=(
|
|
29
|
+
"The type of migration task you want to perform."
|
|
30
|
+
),
|
|
31
|
+
),
|
|
32
|
+
]
|
|
33
|
+
ecs_tenant_id: Annotated[
|
|
34
|
+
str,
|
|
35
|
+
Field(
|
|
36
|
+
title="ECS tenant ID",
|
|
37
|
+
description=(
|
|
38
|
+
"The tenant ID to use when making requests to FOLIO APIs "
|
|
39
|
+
"for this task, if different from library configuration",
|
|
40
|
+
),
|
|
41
|
+
),
|
|
42
|
+
] = ""
|
|
43
|
+
|
|
44
|
+
class Config:
|
|
45
|
+
alias_generator = to_camel
|
|
46
|
+
allow_population_by_field_name = True
|
|
File without changes
|