folio-migration-tools 1.10.1__py3-none-any.whl → 1.10.3__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.
Files changed (64) hide show
  1. folio_migration_tools/__init__.py +10 -2
  2. folio_migration_tools/__main__.py +7 -0
  3. folio_migration_tools/circulation_helper.py +23 -8
  4. folio_migration_tools/colors.py +7 -0
  5. folio_migration_tools/config_file_load.py +7 -0
  6. folio_migration_tools/custom_dict.py +17 -0
  7. folio_migration_tools/custom_exceptions.py +40 -4
  8. folio_migration_tools/extradata_writer.py +12 -0
  9. folio_migration_tools/folder_structure.py +16 -0
  10. folio_migration_tools/helper.py +7 -0
  11. folio_migration_tools/holdings_helper.py +11 -5
  12. folio_migration_tools/i18n_config.py +6 -0
  13. folio_migration_tools/library_configuration.py +19 -5
  14. folio_migration_tools/mapper_base.py +15 -0
  15. folio_migration_tools/mapping_file_transformation/__init__.py +1 -0
  16. folio_migration_tools/mapping_file_transformation/courses_mapper.py +17 -0
  17. folio_migration_tools/mapping_file_transformation/holdings_mapper.py +19 -0
  18. folio_migration_tools/mapping_file_transformation/item_mapper.py +24 -0
  19. folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py +18 -0
  20. folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py +26 -9
  21. folio_migration_tools/mapping_file_transformation/notes_mapper.py +16 -0
  22. folio_migration_tools/mapping_file_transformation/order_mapper.py +40 -27
  23. folio_migration_tools/mapping_file_transformation/organization_mapper.py +40 -33
  24. folio_migration_tools/mapping_file_transformation/ref_data_mapping.py +17 -0
  25. folio_migration_tools/mapping_file_transformation/user_mapper.py +16 -0
  26. folio_migration_tools/marc_rules_transformation/__init__.py +1 -0
  27. folio_migration_tools/marc_rules_transformation/conditions.py +49 -36
  28. folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py +9 -3
  29. folio_migration_tools/marc_rules_transformation/hrid_handler.py +16 -1
  30. folio_migration_tools/marc_rules_transformation/marc_file_processor.py +15 -1
  31. folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py +7 -0
  32. folio_migration_tools/marc_rules_transformation/rules_mapper_base.py +35 -29
  33. folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py +23 -18
  34. folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py +46 -27
  35. folio_migration_tools/migration_report.py +14 -6
  36. folio_migration_tools/migration_tasks/__init__.py +2 -0
  37. folio_migration_tools/migration_tasks/batch_poster.py +41 -19
  38. folio_migration_tools/migration_tasks/bibs_transformer.py +16 -0
  39. folio_migration_tools/migration_tasks/courses_migrator.py +15 -0
  40. folio_migration_tools/migration_tasks/holdings_csv_transformer.py +18 -3
  41. folio_migration_tools/migration_tasks/holdings_marc_transformer.py +17 -0
  42. folio_migration_tools/migration_tasks/inventory_batch_poster.py +424 -0
  43. folio_migration_tools/migration_tasks/items_transformer.py +16 -0
  44. folio_migration_tools/migration_tasks/loans_migrator.py +17 -2
  45. folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py +16 -0
  46. folio_migration_tools/migration_tasks/marc_import.py +407 -0
  47. folio_migration_tools/migration_tasks/migration_task_base.py +49 -17
  48. folio_migration_tools/migration_tasks/orders_transformer.py +16 -0
  49. folio_migration_tools/migration_tasks/organization_transformer.py +17 -2
  50. folio_migration_tools/migration_tasks/requests_migrator.py +15 -0
  51. folio_migration_tools/migration_tasks/reserves_migrator.py +15 -0
  52. folio_migration_tools/migration_tasks/user_importer.py +347 -0
  53. folio_migration_tools/migration_tasks/user_transformer.py +16 -0
  54. folio_migration_tools/task_configuration.py +7 -0
  55. folio_migration_tools/transaction_migration/__init__.py +1 -0
  56. folio_migration_tools/transaction_migration/legacy_loan.py +16 -0
  57. folio_migration_tools/transaction_migration/legacy_request.py +14 -0
  58. folio_migration_tools/transaction_migration/legacy_reserve.py +14 -0
  59. folio_migration_tools/transaction_migration/transaction_result.py +16 -0
  60. {folio_migration_tools-1.10.1.dist-info → folio_migration_tools-1.10.3.dist-info}/METADATA +1 -1
  61. folio_migration_tools-1.10.3.dist-info/RECORD +66 -0
  62. folio_migration_tools-1.10.1.dist-info/RECORD +0 -63
  63. {folio_migration_tools-1.10.1.dist-info → folio_migration_tools-1.10.3.dist-info}/WHEEL +0 -0
  64. {folio_migration_tools-1.10.1.dist-info → folio_migration_tools-1.10.3.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,9 @@
1
+ """Course reserves migration task.
2
+
3
+ Migrates course reserve records from legacy ILS to FOLIO Course Reserves module.
4
+ Handles course listings, items on reserve, and reserve relationships.
5
+ """
6
+
1
7
  import csv
2
8
  import json
3
9
  import logging
@@ -27,6 +33,8 @@ from folio_migration_tools.transaction_migration.legacy_reserve import LegacyRes
27
33
 
28
34
  class ReservesMigrator(MigrationTaskBase):
29
35
  class TaskConfiguration(AbstractTaskConfiguration):
36
+ """Task configuration for ReservesMigrator."""
37
+
30
38
  name: Annotated[
31
39
  str,
32
40
  Field(
@@ -62,6 +70,13 @@ class ReservesMigrator(MigrationTaskBase):
62
70
  library_config: LibraryConfiguration,
63
71
  folio_client,
64
72
  ):
73
+ """Initialize ReservesMigrator for migrating course reserves.
74
+
75
+ Args:
76
+ task_configuration (TaskConfiguration): Reserves migration configuration.
77
+ library_config (LibraryConfiguration): Library configuration.
78
+ folio_client: FOLIO API client.
79
+ """
65
80
  csv.register_dialect("tsv", delimiter="\t")
66
81
  self.migration_report = MigrationReport()
67
82
  self.valid_reserves = []
@@ -0,0 +1,347 @@
1
+ """UserImporterTask module for FOLIO user import operations.
2
+
3
+ This module provides an adapter that wraps folio_data_import.UserImporter
4
+ to conform to the folio_migration_tools MigrationTaskBase interface.
5
+ It supports importing users with full relationship handling including
6
+ request preferences, permission users, and service points.
7
+
8
+ This provides an alternative to posting users via BatchPoster with the
9
+ /user-import endpoint, offering more granular control and better error handling.
10
+ """
11
+
12
+ import asyncio
13
+ import logging
14
+ from pathlib import Path
15
+ from typing import Annotated, List, Literal
16
+
17
+ from folio_uuid.folio_namespaces import FOLIONamespaces
18
+ from pydantic import Field
19
+
20
+ from folio_data_import.UserImport import UserImporter as FDIUserImporter
21
+ from folio_data_import.UserImport import UserImporterStats
22
+
23
+ from folio_migration_tools.library_configuration import (
24
+ FileDefinition,
25
+ LibraryConfiguration,
26
+ )
27
+ from folio_migration_tools.migration_report import MigrationReport
28
+ from folio_migration_tools.migration_tasks.migration_task_base import MigrationTaskBase
29
+ from folio_migration_tools.task_configuration import AbstractTaskConfiguration
30
+ from folio_data_import._progress import RichProgressReporter
31
+
32
+
33
+ class UserImportTask(MigrationTaskBase):
34
+ """A wrapper for folio_data_import.UserImporter.
35
+
36
+ This class adapts the UserImporter from folio_data_import to fit within the
37
+ folio_migration_tools MigrationTaskBase framework.
38
+
39
+ This implementation handles:
40
+ - User create/update with full upsert support
41
+ - Automatic mapping of patron groups, address types, departments, service points
42
+ - Creation/update of request preferences
43
+ - Creation of permission users
44
+ - Creation/update of service points users
45
+ - Field protection to prevent overwriting specific fields
46
+
47
+ Parents:
48
+ MigrationTaskBase: Base class for all migration tasks
49
+
50
+ Raises:
51
+ TransformationProcessError: When a critical error occurs during processing
52
+ FileNotFoundError: When input files are not found
53
+ """
54
+
55
+ class TaskConfiguration(AbstractTaskConfiguration):
56
+ """Task configuration for UserImporter."""
57
+
58
+ name: Annotated[
59
+ str,
60
+ Field(
61
+ title="Task name",
62
+ description="The name of the task",
63
+ ),
64
+ ]
65
+ migration_task_type: Annotated[
66
+ str,
67
+ Field(
68
+ title="Migration task type",
69
+ description="The type of migration task",
70
+ ),
71
+ ]
72
+ files: Annotated[
73
+ List[FileDefinition],
74
+ Field(
75
+ title="List of files",
76
+ description=(
77
+ "List of JSONL files to be processed. These should be output files "
78
+ "from UserTransformer containing mod-user-import compatible objects."
79
+ ),
80
+ ),
81
+ ]
82
+ batch_size: Annotated[
83
+ int,
84
+ Field(
85
+ title="Batch size",
86
+ description="Number of users to process concurrently in each batch",
87
+ ge=1,
88
+ le=1000,
89
+ ),
90
+ ] = 250
91
+ user_match_key: Annotated[
92
+ Literal["externalSystemId", "username", "barcode"],
93
+ Field(
94
+ title="User match key",
95
+ description=(
96
+ "The key to use for matching existing users during upsert. "
97
+ "Users with matching values will be updated rather than created."
98
+ ),
99
+ ),
100
+ ] = "externalSystemId"
101
+ only_update_present_fields: Annotated[
102
+ bool,
103
+ Field(
104
+ title="Only update present fields",
105
+ description=(
106
+ "When enabled, only fields present in the input will be updated. "
107
+ "Missing fields will be left unchanged in existing records. "
108
+ "When disabled, missing fields may be cleared."
109
+ ),
110
+ ),
111
+ ] = False
112
+ default_preferred_contact_type: Annotated[
113
+ Literal["001", "002", "003", "004", "005", "mail", "email", "text", "phone", "mobile"],
114
+ Field(
115
+ title="Default preferred contact type",
116
+ description=(
117
+ "Default preferred contact type for users. "
118
+ "Can be specified as ID (001-005) or name (mail/email/text/phone/mobile). "
119
+ "Will be applied to users without a valid value already set."
120
+ ),
121
+ ),
122
+ ] = "002"
123
+ fields_to_protect: Annotated[
124
+ List[str],
125
+ Field(
126
+ title="Fields to protect",
127
+ description=(
128
+ "List of field paths to protect from updates "
129
+ "(e.g., ['personal.email', 'barcode']). "
130
+ "Protected fields will not be modified during updates."
131
+ ),
132
+ ),
133
+ ] = []
134
+ limit_simultaneous_requests: Annotated[
135
+ int,
136
+ Field(
137
+ title="Limit simultaneous requests",
138
+ description="Maximum number of concurrent async HTTP requests",
139
+ ge=1,
140
+ le=100,
141
+ ),
142
+ ] = 10
143
+ no_progress: Annotated[
144
+ bool,
145
+ Field(
146
+ title="No progress",
147
+ description="Disable progress reporting in the console output.",
148
+ ),
149
+ ] = False
150
+
151
+ task_configuration: TaskConfiguration
152
+
153
+ @staticmethod
154
+ def get_object_type() -> FOLIONamespaces:
155
+ return FOLIONamespaces.users
156
+
157
+ def __init__(
158
+ self,
159
+ task_config: TaskConfiguration,
160
+ library_config: LibraryConfiguration,
161
+ folio_client,
162
+ use_logging: bool = True,
163
+ ):
164
+ """Initialize UserImporter for bulk user import via /users APIs.
165
+
166
+ Args:
167
+ task_config (TaskConfiguration): User import configuration.
168
+ library_config (LibraryConfiguration): Library configuration.
169
+ folio_client: FOLIO API client.
170
+ use_logging (bool): Whether to set up task logging.
171
+ """
172
+ super().__init__(library_config, task_config, folio_client, use_logging)
173
+ self.migration_report = MigrationReport()
174
+ self.stats: UserImporterStats = UserImporterStats()
175
+ self.total_records = 0
176
+ self.files_processed: List[str] = []
177
+
178
+ logging.info("UserImporterTask initialized")
179
+ logging.info("Batch size: %s", self.task_configuration.batch_size)
180
+ logging.info("User match key: %s", self.task_configuration.user_match_key)
181
+
182
+ def _create_fdi_config(self, file_paths: List[Path]) -> FDIUserImporter.Config:
183
+ """Create a folio_data_import.UserImporter.Config from our TaskConfiguration.
184
+
185
+ Args:
186
+ file_paths: List of file paths to process
187
+
188
+ Returns:
189
+ FDIUserImporter.Config: Configuration for the underlying UserImporter
190
+ """
191
+ return FDIUserImporter.Config(
192
+ library_name=self.library_configuration.library_name,
193
+ batch_size=self.task_configuration.batch_size,
194
+ user_match_key=self.task_configuration.user_match_key,
195
+ only_update_present_fields=self.task_configuration.only_update_present_fields,
196
+ default_preferred_contact_type=self.task_configuration.default_preferred_contact_type,
197
+ fields_to_protect=self.task_configuration.fields_to_protect,
198
+ limit_simultaneous_requests=self.task_configuration.limit_simultaneous_requests,
199
+ user_file_paths=file_paths,
200
+ no_progress=self.task_configuration.no_progress,
201
+ )
202
+
203
+ async def _do_work_async(self) -> None:
204
+ """Async implementation of the work logic."""
205
+ # Build list of file paths
206
+ file_paths: List[Path] = []
207
+ for file_def in self.task_configuration.files:
208
+ path = self.folder_structure.results_folder / file_def.file_name
209
+ if not path.exists():
210
+ logging.error("File not found: %s", path)
211
+ raise FileNotFoundError(f"File not found: {path}")
212
+ file_paths.append(path)
213
+ self.files_processed.append(file_def.file_name)
214
+ logging.info("Will process file: %s", path)
215
+
216
+ # Count total records for reporting
217
+ for file_path in file_paths:
218
+ with open(file_path, "rb") as f:
219
+ self.total_records += sum(
220
+ buf.count(b"\n") for buf in iter(lambda: f.read(1024 * 1024), b"")
221
+ )
222
+
223
+ # Create the folio_data_import UserImporter config
224
+ fdi_config = self._create_fdi_config(file_paths)
225
+
226
+ # Create Progress Reporter
227
+ if self.task_configuration.no_progress:
228
+ from folio_data_import._progress import NoOpProgressReporter
229
+
230
+ reporter = NoOpProgressReporter()
231
+ else:
232
+ reporter = RichProgressReporter(enabled=True)
233
+
234
+ # Error file path
235
+ error_file_path = self.folder_structure.failed_recs_path
236
+
237
+ # Create and run the importer
238
+ importer = FDIUserImporter(
239
+ folio_client=self.folio_client,
240
+ config=fdi_config,
241
+ reporter=reporter,
242
+ )
243
+
244
+ await importer.setup(error_file_path)
245
+
246
+ try:
247
+ await importer.do_import()
248
+ self.stats = importer.stats
249
+ finally:
250
+ await importer.close()
251
+
252
+ def do_work(self) -> None:
253
+ """Main work method that processes files and imports users to FOLIO.
254
+
255
+ This method reads user records from the configured files and imports them
256
+ to FOLIO using the folio_data_import.UserImporter, handling all related
257
+ objects (request preferences, permission users, service points).
258
+ """
259
+ logging.info("Starting UserImportTask work...")
260
+
261
+ try:
262
+ # Run the async work in an event loop
263
+ asyncio.run(self._do_work_async())
264
+ except FileNotFoundError as e:
265
+ logging.error("File not found: %s", e)
266
+ raise
267
+ except Exception as e:
268
+ logging.error("Error during user import: %s", e)
269
+ raise
270
+
271
+ logging.info("UserImportTask work complete")
272
+
273
+ def _translate_stats_to_migration_report(self) -> None:
274
+ """Translate UserImporterStats to MigrationReport format."""
275
+ # General statistics
276
+ total_processed = self.stats.created + self.stats.updated + self.stats.failed
277
+ self.migration_report.set(
278
+ "GeneralStatistics",
279
+ "Total records in files",
280
+ self.total_records,
281
+ )
282
+ self.migration_report.set(
283
+ "GeneralStatistics",
284
+ "Records processed",
285
+ total_processed,
286
+ )
287
+ self.migration_report.set(
288
+ "GeneralStatistics",
289
+ "Users created",
290
+ self.stats.created,
291
+ )
292
+ self.migration_report.set(
293
+ "GeneralStatistics",
294
+ "Users updated",
295
+ self.stats.updated,
296
+ )
297
+ self.migration_report.set(
298
+ "GeneralStatistics",
299
+ "Users failed",
300
+ self.stats.failed,
301
+ )
302
+
303
+ # Add file information
304
+ for file_name in self.files_processed:
305
+ self.migration_report.add("FilesProcessed", file_name)
306
+
307
+ def wrap_up(self) -> None:
308
+ """Finalize the migration task and write reports.
309
+
310
+ This method translates statistics from the underlying UserImporter
311
+ to the MigrationReport format and writes both markdown and JSON reports.
312
+ """
313
+ logging.info("Done. Wrapping up UserImportTask")
314
+
315
+ # Translate stats to migration report
316
+ self._translate_stats_to_migration_report()
317
+
318
+ # Log summary
319
+ logging.info("=" * 60)
320
+ logging.info("UserImportTask Summary")
321
+ logging.info("=" * 60)
322
+ logging.info("Total records in files: %d", self.total_records)
323
+ logging.info("Users created: %d", self.stats.created)
324
+ logging.info("Users updated: %d", self.stats.updated)
325
+ logging.info("Users failed: %d", self.stats.failed)
326
+ if self.stats.failed > 0:
327
+ logging.info(
328
+ "Failed users written to: %s",
329
+ self.folder_structure.failed_recs_path,
330
+ )
331
+
332
+ # Write markdown report
333
+ with open(self.folder_structure.migration_reports_file, "w+") as report_file:
334
+ self.migration_report.write_migration_report(
335
+ "User import report",
336
+ report_file,
337
+ self.start_datetime,
338
+ )
339
+
340
+ # Write raw JSON report
341
+ with open(self.folder_structure.migration_reports_raw_file, "w") as raw_report_file:
342
+ self.migration_report.write_json_report(raw_report_file)
343
+
344
+ # Clean up empty log files
345
+ self.clean_out_empty_logs()
346
+
347
+ logging.info("UserImportTask wrap up complete")
@@ -1,3 +1,9 @@
1
+ """User/patron records transformation task.
2
+
3
+ Transforms user/patron data from CSV files to FOLIO Users. Handles patron groups,
4
+ addresses, departments, and user permissions with validation and cleanup.
5
+ """
6
+
1
7
  import json
2
8
  import logging
3
9
  import sys
@@ -27,6 +33,8 @@ from folio_migration_tools.task_configuration import AbstractTaskConfiguration
27
33
 
28
34
  class UserTransformer(MigrationTaskBase):
29
35
  class TaskConfiguration(AbstractTaskConfiguration):
36
+ """Task configuration for UserTransformer."""
37
+
30
38
  name: Annotated[
31
39
  str,
32
40
  Field(
@@ -123,6 +131,14 @@ class UserTransformer(MigrationTaskBase):
123
131
  folio_client,
124
132
  use_logging: bool = True,
125
133
  ):
134
+ """Initialize UserTransformer for user record transformations.
135
+
136
+ Args:
137
+ task_config (TaskConfiguration): Users transformation configuration.
138
+ library_config (LibraryConfiguration): Library configuration.
139
+ folio_client: FOLIO API client.
140
+ use_logging (bool): Whether to set up task logging.
141
+ """
126
142
  super().__init__(library_config, task_config, folio_client, use_logging)
127
143
  self.task_config = task_config
128
144
  self.task_configuration = self.task_config
@@ -1,3 +1,10 @@
1
+ """Base task configuration model.
2
+
3
+ Defines the abstract AbstractTaskConfiguration class that all migration task
4
+ configurations inherit from. Provides common configuration fields and utilities
5
+ for camelCase conversion for FOLIO API compatibility.
6
+ """
7
+
1
8
  from typing import Annotated
2
9
 
3
10
  from humps import camelize
@@ -0,0 +1 @@
1
+ """Transaction migration for loans, requests, and other circulation data."""
@@ -1,3 +1,10 @@
1
+ """Legacy loan data model and validation.
2
+
3
+ Defines the LegacyLoan class for representing circulation loans from legacy ILS systems.
4
+ Handles validation, timezone conversion, date normalization, and transformation to FOLIO
5
+ loan format. Supports renewal counts and loan policy mapping.
6
+ """
7
+
1
8
  import json
2
9
  import logging
3
10
  import i18n
@@ -23,6 +30,15 @@ class LegacyLoan(object):
23
30
  tenant_timezone=utc,
24
31
  row=0,
25
32
  ):
33
+ """Initialize LegacyLoan from legacy loan data.
34
+
35
+ Args:
36
+ legacy_loan_dict: Dictionary containing legacy loan data.
37
+ fallback_service_point_id (str): Service point to use if not specified.
38
+ migration_report (MigrationReport): Report for tracking issues.
39
+ tenant_timezone: Timezone of the tenant (default: UTC).
40
+ row (int): Row number in source data for error reporting.
41
+ """
26
42
  self.migration_report: MigrationReport = migration_report
27
43
  # validate
28
44
  correct_headers = [
@@ -1,3 +1,10 @@
1
+ """Legacy request data model and validation.
2
+
3
+ Defines the LegacyRequest class for representing patron requests from legacy ILS systems.
4
+ Handles validation, timezone conversion, request type mapping, and transformation to FOLIO
5
+ request format. Supports hold queue positioning and expiration dates.
6
+ """
7
+
1
8
  import datetime
2
9
  import logging
3
10
  import uuid
@@ -13,6 +20,13 @@ utc = ZoneInfo("UTC")
13
20
 
14
21
  class LegacyRequest(object):
15
22
  def __init__(self, legacy_request_dict, tenant_timezone=utc, row=0):
23
+ """Initialize LegacyRequest from legacy request data.
24
+
25
+ Args:
26
+ legacy_request_dict: Dictionary containing legacy request data.
27
+ tenant_timezone: Timezone of the tenant (default: UTC).
28
+ row (int): Row number in source data for error reporting.
29
+ """
16
30
  # validate
17
31
  correct_headers = [
18
32
  "item_barcode",
@@ -1,3 +1,10 @@
1
+ """Legacy course reserve data model and validation.
2
+
3
+ Defines the LegacyReserve class for representing course reserves from legacy ILS systems.
4
+ Handles validation, course listing lookups, and transformation to FOLIO course reserve
5
+ format. Links items to course listings via barcode lookups.
6
+ """
7
+
1
8
  import uuid
2
9
  from typing import Dict, List, Tuple
3
10
 
@@ -10,6 +17,13 @@ from folio_migration_tools.custom_exceptions import TransformationProcessError
10
17
 
11
18
  class LegacyReserve(object):
12
19
  def __init__(self, legacy_request_dict: Dict, folio_client: FolioClient, row: int = 0):
20
+ """Initialize LegacyReserve from legacy reserve data.
21
+
22
+ Args:
23
+ legacy_request_dict (Dict): Dictionary containing legacy reserve data.
24
+ folio_client (FolioClient): FOLIO API client for lookups.
25
+ row (int): Row number in source data for error reporting.
26
+ """
13
27
  # validate
14
28
  correct_headers = ["legacy_identifier", "item_barcode"]
15
29
  for h in correct_headers:
@@ -1,3 +1,10 @@
1
+ """Transaction result container for migration operations.
2
+
3
+ Defines the TransactionResult class for encapsulating the outcome of transaction
4
+ migration attempts. Tracks success/failure status, error messages, and whether
5
+ retries should be attempted.
6
+ """
7
+
1
8
  from typing import Any
2
9
 
3
10
 
@@ -18,6 +25,15 @@ class TransactionResult(object):
18
25
  error_message: str,
19
26
  migration_report_message: str,
20
27
  ):
28
+ """Initialize TransactionResult for migration tracking.
29
+
30
+ Args:
31
+ was_successful (bool): Whether the transaction was successfully created.
32
+ should_be_retried (bool): Whether a failed transaction should be retried.
33
+ folio_loan (Any): The created FOLIO transaction object.
34
+ error_message (str): Error message if transaction failed.
35
+ migration_report_message (str): Message for migration report.
36
+ """
21
37
  self.was_successful = was_successful
22
38
  self.folio_loan = folio_loan
23
39
  self.should_be_retried = should_be_retried
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: folio-migration-tools
3
- Version: 1.10.1
3
+ Version: 1.10.3
4
4
  Summary: A tool allowing you to migrate data from legacy ILS:s (Library systems) into FOLIO LSP
5
5
  Keywords: FOLIO,ILS,LSP,Library Systems,MARC21,Library data
6
6
  Author: Theodor Tolstoy, Lisa Sjögren, Brooks Travis, Jeremy Nelson, Clinton Bradford
@@ -0,0 +1,66 @@
1
+ folio_migration_tools/__init__.py,sha256=FFvY3IjvJnP0h6j8Qff49iqpzV1hXFqZbBiDip0go78,445
2
+ folio_migration_tools/__main__.py,sha256=pk_BGmhjB3-BGY36r9SLw6MNshY0tr4jCtYP_liLmBo,9531
3
+ folio_migration_tools/circulation_helper.py,sha256=Sybw-UBzgK_0dlTjfIPyGFQsRqghMYmTYLtZFuRd9zw,15487
4
+ folio_migration_tools/colors.py,sha256=0Z381jvWzzgA62PW9QWliYls4K9vu9M_TdA7IL-onT0,389
5
+ folio_migration_tools/config_file_load.py,sha256=KtjWsPiXJHtdK3PIUv77j8N0p8r_fnKsVyR6EumQgRo,3080
6
+ folio_migration_tools/custom_dict.py,sha256=dF9_VfUpvyatLDxhqeJ1Wq2MUVPoVmq6leHlvdm4WyE,1340
7
+ folio_migration_tools/custom_exceptions.py,sha256=RDoomoyBo0a-seZW3q2GAWBHlsodIOyiQ0WHuwIUyi8,4112
8
+ folio_migration_tools/extradata_writer.py,sha256=1BqKJa721fPIWRxjTPci658RVBoZ2kmI0XLsul2C7Bo,2128
9
+ folio_migration_tools/folder_structure.py,sha256=qQwmjdzC64ZfB-l6SVqjN984QTiS13TQTTCzmmWpt5U,8068
10
+ folio_migration_tools/helper.py,sha256=VIDFhOJg1_BU5YcHLqspXGTKwWNUrFDFeIOM530vFP4,3252
11
+ folio_migration_tools/holdings_helper.py,sha256=hvr6HLkZSuJsh6htbeStpKwHo8FnBb7YvRzETOj2PgQ,7809
12
+ folio_migration_tools/i18n_cache.py,sha256=wOJc3OkHwItlFNC2jQB5R9AoIga0g0P1YhQqHgjeqK4,2858
13
+ folio_migration_tools/i18n_config.py,sha256=0qMW0JI8X1T8c6qhaK58GU31ytEMKA2csdqHly5hEik,438
14
+ folio_migration_tools/library_configuration.py,sha256=Mc22UaKfzzrztMWp71kZizycWDyEklI54WsOjzB5dck,9514
15
+ folio_migration_tools/mapper_base.py,sha256=qe9DggRmqf2jq2jYjgsD_p_pbXLqEqge6lmlAnZpDU0,24518
16
+ folio_migration_tools/mapping_file_transformation/__init__.py,sha256=iUABykFuB2NsUml12D0-gB_6GnkZ8nNqU0DkfTZyLWo,80
17
+ folio_migration_tools/mapping_file_transformation/courses_mapper.py,sha256=YtprlWcH8edryEy9Ujlm74bShmnS7EwhGnLywrzfF2Y,8842
18
+ folio_migration_tools/mapping_file_transformation/holdings_mapper.py,sha256=djq12ur8-woz9tGM3vZY-Bm1KFK2_Xk2UaVRZhO-GJk,9243
19
+ folio_migration_tools/mapping_file_transformation/item_mapper.py,sha256=si0EjNxtIUsYwb11qlsTPP9Xlwce6Q1zfbocblGUGHs,11528
20
+ folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py,sha256=bSlARlhGllnZYqFWg2gFSEP6nFKGIqgJLtBK5grxyi8,14350
21
+ folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py,sha256=KGxhSFQ1JVgIt6PuK6VGBbj1MRPA5mppnQVJUu9l56A,39388
22
+ folio_migration_tools/mapping_file_transformation/notes_mapper.py,sha256=rlSRzWWWkUFOdgIkhXG2jkoxVKpbW9b9J1wZpI7gxnA,4261
23
+ folio_migration_tools/mapping_file_transformation/order_mapper.py,sha256=cFyBSs8xsN1vBGif0Cn_VON-LlWeWHmfzuEk9c1AyzA,19432
24
+ folio_migration_tools/mapping_file_transformation/organization_mapper.py,sha256=kJkmsZNj5ow9N839jhD5kKZEZftbJh6JjTYxHynI6WI,15581
25
+ folio_migration_tools/mapping_file_transformation/ref_data_mapping.py,sha256=oQEQCBh7c3XQYX1zbo-NgwxTa9i4DMBggs9OLRr75ko,9790
26
+ folio_migration_tools/mapping_file_transformation/user_mapper.py,sha256=8sz6glwn7mMLpmTOyF-IuHQb3fs0i4a2BGon2qpIJuk,9586
27
+ folio_migration_tools/marc_rules_transformation/__init__.py,sha256=XHQdK6uc_-Y2k158M6hSaojWWcMZjJIzuHYaj8J8ViI,60
28
+ folio_migration_tools/marc_rules_transformation/conditions.py,sha256=Xv4RU4h3QgozKvOn67VsLj3t9mjByRP5FqyRYxQFj10,47306
29
+ folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py,sha256=LiYsBY7nORJ2A4L2P08fWEGfswbspxhPRKhFl1QdWp0,13932
30
+ folio_migration_tools/marc_rules_transformation/hrid_handler.py,sha256=8mmu7bNE-CFDwLPW1F6YFyAC4_KF2tWEJkHeA5oPhmM,10728
31
+ folio_migration_tools/marc_rules_transformation/loc_language_codes.xml,sha256=ztn2_yKws6qySL4oSsZh7sOjxq5bCC1PhAnXJdtgmJ0,382912
32
+ folio_migration_tools/marc_rules_transformation/marc_file_processor.py,sha256=aLWYorowhhq4KySnXdAPXNQMv27lCT9e_cWi2Br4Yf0,13146
33
+ folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py,sha256=-rR9d62BiYHQU9h31otlcM_Mi9-80EhWyBUWlxt4Pq8,5543
34
+ folio_migration_tools/marc_rules_transformation/rules_mapper_base.py,sha256=q981tWbjdKILWwZylxs2VwR_DvIqER1H8J8nZFUpnKY,46102
35
+ folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py,sha256=KU9wTo60AVge80xUHkkEOauqwBaTnFZ1q9GU_-NLgfU,30850
36
+ folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py,sha256=89auENlVrQExwgOHNmqXn0RXTZlXdg7f5wFDLYwcfU8,30247
37
+ folio_migration_tools/migration_report.py,sha256=sTyNPXNxies91RNHrhGF01xI9K4Ti0-k3Q9pl-ezOOg,4961
38
+ folio_migration_tools/migration_tasks/__init__.py,sha256=S7zG9fYfp-B_Wzo4VW_Mhdtu0f18OVf-yfAV0sFW57E,279
39
+ folio_migration_tools/migration_tasks/batch_poster.py,sha256=MxQn3Pzl5Wxm0iLCJZi80VjkiYZaJkRPS0H7_AnokW8,47561
40
+ folio_migration_tools/migration_tasks/bibs_transformer.py,sha256=-1PIW8zT_o07fdEE0fwRO3rmyvJyNcX-DN0OorsWL24,7186
41
+ folio_migration_tools/migration_tasks/courses_migrator.py,sha256=tr3Ed3kOZQ5bv_S1FuTm0F9CAWcNJZ5g650KPauZVoA,7748
42
+ folio_migration_tools/migration_tasks/holdings_csv_transformer.py,sha256=gwROvFN2QmLAJAe7f4skP07YeI1HLhBa716-ANhLkMk,22698
43
+ folio_migration_tools/migration_tasks/holdings_marc_transformer.py,sha256=kL6YVrtAOxTg0O3JWorsG_vRbuJNjq7XjdC9B8v0imI,15116
44
+ folio_migration_tools/migration_tasks/inventory_batch_poster.py,sha256=yrwu8G3vJFzIF6wwFlfK2WcQhogws1lRF3BWCQexIPQ,16388
45
+ folio_migration_tools/migration_tasks/items_transformer.py,sha256=eNlxk50IUqzmG2PhB-oL7IYcwQonnRXEa0k0bnI1u20,20342
46
+ folio_migration_tools/migration_tasks/loans_migrator.py,sha256=fOPujpWBZgxHtS89g8yiPr0UFTysPL5Dqbh3zqh6U1A,39555
47
+ folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py,sha256=gKApM9nLjyATX6qWn-i3hjxoRbY9QXO4JKd3h9hxmXc,8105
48
+ folio_migration_tools/migration_tasks/marc_import.py,sha256=ItRYdS3ZdqAlazW1HWmldlVWWQl0Bz24gWyv_OXBhOU,15575
49
+ folio_migration_tools/migration_tasks/migration_task_base.py,sha256=TdDF0K49sTDBf9S0fjEtkWG45UwYcNIIwm6Jgdt0lIs,23661
50
+ folio_migration_tools/migration_tasks/orders_transformer.py,sha256=qxE5rE0IJH9lKWo6a5hixJ9fS14ryAdAf9yZDS7zbUM,14742
51
+ folio_migration_tools/migration_tasks/organization_transformer.py,sha256=E_g9c-A_NwNQLm8Ciij9jYjAfXgcp_cInuz2Vrn8S1c,17558
52
+ folio_migration_tools/migration_tasks/requests_migrator.py,sha256=0bcjjGZGKasfqsHhUaAKPyJE-lhbNVKQ245txbo8nNg,15537
53
+ folio_migration_tools/migration_tasks/reserves_migrator.py,sha256=hduA8ihe2K54TAKWhMjLICxuETaNYxV2-R-nbSx-80A,10716
54
+ folio_migration_tools/migration_tasks/user_importer.py,sha256=QEqK-FmFGIqZdtMDOF6OS5UWhqSOzQzEl5L_pT4WghM,12960
55
+ folio_migration_tools/migration_tasks/user_transformer.py,sha256=4AxprsUaekHlUQdSeAKu-vj3-mu6K9Z36N1OSjsu5ow,13452
56
+ folio_migration_tools/task_configuration.py,sha256=fvFtelR20At1hPFhh10WOX1pmPe39AY8aOosTaH2VbU,1397
57
+ folio_migration_tools/transaction_migration/__init__.py,sha256=BmTOUIqofyCcM-pv5xrexhT68xg1qxrq87M-NRNnSO4,77
58
+ folio_migration_tools/transaction_migration/legacy_loan.py,sha256=Ts_nyA1dxcSJcTQWtJGVh5aD8UCfy37ylchcOhDbkJ0,8138
59
+ folio_migration_tools/transaction_migration/legacy_request.py,sha256=wcVNOMuqlfD0ZlGaWDGiSLoPzArfnFY8ENcIq91ctQs,6726
60
+ folio_migration_tools/transaction_migration/legacy_reserve.py,sha256=NRxpKsPe3cczzudZeSDXAIwJHAsQuvk07lW0Ex3SNEo,2413
61
+ folio_migration_tools/transaction_migration/transaction_result.py,sha256=wSHEKSE0QKs8pTBX9FS0Gte52rQ_zeE2VyT4VJlsxV4,1383
62
+ folio_migration_tools/translations/en.json,sha256=pS7dhHmj4XBqTcFNIcqFgRMY557fQan1RomdNg6PtdA,40941
63
+ folio_migration_tools-1.10.3.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
64
+ folio_migration_tools-1.10.3.dist-info/entry_points.txt,sha256=mJRRiCNP9j7_NpVXamHEiW8pDEjWQs1vEqD89G354cM,79
65
+ folio_migration_tools-1.10.3.dist-info/METADATA,sha256=rO2e7GZ1zqHRXTMhPDbPWOu7SiUNqROBq5ENbophnhs,7207
66
+ folio_migration_tools-1.10.3.dist-info/RECORD,,