folio-migration-tools 1.9.4__py3-none-any.whl → 1.9.5__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.
@@ -198,6 +198,14 @@ class CirculationHelper:
198
198
  error_message_from_folio,
199
199
  error_message_from_folio,
200
200
  )
201
+ elif "Item is already checked out" in error_message_from_folio:
202
+ return TransactionResult(
203
+ False,
204
+ True,
205
+ None,
206
+ error_message_from_folio,
207
+ error_message_from_folio,
208
+ )
201
209
  logging.error(
202
210
  f"{error_message} "
203
211
  f"Patron barcode: {legacy_loan.patron_barcode} "
@@ -56,6 +56,10 @@ class Helper:
56
56
  @staticmethod
57
57
  def log_data_issue(index_or_id, message, legacy_value):
58
58
  logging.log(26, "DATA ISSUE\t%s\t%s\t%s", index_or_id, message, legacy_value)
59
+
60
+ @staticmethod
61
+ def log_data_issue_failed(index_or_id, message, legacy_value):
62
+ logging.log(26, "RECORD FAILED\t%s\t%s\t%s", index_or_id, message, legacy_value)
59
63
 
60
64
  @staticmethod
61
65
  def write_to_file(file, folio_record):
@@ -6,7 +6,7 @@ import sys
6
6
  import time
7
7
  import traceback
8
8
  from datetime import datetime, timedelta
9
- from typing import Annotated, Literal, Optional
9
+ from typing import Annotated, List, Literal, Optional
10
10
  from urllib.error import HTTPError
11
11
  from zoneinfo import ZoneInfo
12
12
  from pydantic import Field
@@ -110,7 +110,7 @@ class LoansMigrator(MigrationTaskBase):
110
110
  self.failed: dict = {}
111
111
  self.failed_and_not_dupe: dict = {}
112
112
  self.migration_report = MigrationReport()
113
- self.valid_legacy_loans = []
113
+ self.valid_legacy_loans: List[LegacyLoan] = []
114
114
  super().__init__(library_config, task_configuration, folio_client)
115
115
  self.circulation_helper = CirculationHelper(
116
116
  self.folio_client,
@@ -227,6 +227,12 @@ class LoansMigrator(MigrationTaskBase):
227
227
  )
228
228
  try:
229
229
  self.checkout_single_loan(legacy_loan)
230
+ except TransformationRecordFailedError as ee:
231
+ logging.error(
232
+ f"Transformation failed in row {num_loans} Item barcode: {legacy_loan.item_barcode} "
233
+ f"Patron barcode: {legacy_loan.patron_barcode}"
234
+ )
235
+ ee.log_it()
230
236
  except Exception as ee:
231
237
  logging.exception(
232
238
  f"Error in row {num_loans} Item barcode: {legacy_loan.item_barcode} "
@@ -277,11 +283,6 @@ class LoansMigrator(MigrationTaskBase):
277
283
  else:
278
284
  self.failed[legacy_loan.item_barcode] = legacy_loan
279
285
  self.migration_report.add_general_statistics(i18n.t("Failed loans"))
280
- Helper.log_data_issue(
281
- "",
282
- "Loans failing during checkout",
283
- json.dumps(legacy_loan.to_dict()),
284
- )
285
286
  logging.error(
286
287
  "Failed on second try: %s", res_checkout2.error_message
287
288
  )
@@ -290,6 +291,11 @@ class LoansMigrator(MigrationTaskBase):
290
291
  i18n.t("Second failure")
291
292
  + f": {res_checkout2.migration_report_message}",
292
293
  )
294
+ raise TransformationRecordFailedError(
295
+ f"Row {legacy_loan.row}",
296
+ i18n.t("Loans failing during checkout, second try"),
297
+ json.dumps(legacy_loan.to_dict()),
298
+ )
293
299
  elif not res_checkout.should_be_retried:
294
300
  logging.error(
295
301
  "Failed first time. No retries: %s", res_checkout.error_message
@@ -301,8 +307,10 @@ class LoansMigrator(MigrationTaskBase):
301
307
  + f": {res_checkout.migration_report_message}",
302
308
  )
303
309
  self.failed[legacy_loan.item_barcode] = legacy_loan
304
- Helper.log_data_issue(
305
- "", "Loans failing during checkout", json.dumps(legacy_loan.to_dict())
310
+ raise TransformationRecordFailedError(
311
+ f"Row {legacy_loan.row}",
312
+ i18n.t("Loans failing during checkout"),
313
+ json.dumps(legacy_loan.to_dict()),
306
314
  )
307
315
 
308
316
  def set_new_status(self, legacy_loan: LegacyLoan, res_checkout: TransactionResult):
@@ -400,7 +408,7 @@ class LoansMigrator(MigrationTaskBase):
400
408
  + f": {has_proxy_barcode}",
401
409
  )
402
410
  if not has_item_barcode:
403
- Helper.log_data_issue(
411
+ Helper.log_data_issue_failed(
404
412
  "", "Loan without matched item barcode", json.dumps(loan.to_dict())
405
413
  )
406
414
  if not has_patron_barcode:
@@ -410,7 +418,7 @@ class LoansMigrator(MigrationTaskBase):
410
418
  json.dumps(loan.to_dict()),
411
419
  )
412
420
  if not has_proxy_barcode:
413
- Helper.log_data_issue(
421
+ Helper.log_data_issue_failed(
414
422
  "",
415
423
  "Loan without matched proxy patron barcode",
416
424
  json.dumps(loan.to_dict()),
@@ -502,6 +510,8 @@ class LoansMigrator(MigrationTaskBase):
502
510
  "Cannot check out item that already has an open loan"
503
511
  ):
504
512
  return self.handle_checked_out_item(legacy_loan)
513
+ elif "Item is already checked out" in folio_checkout.error_message:
514
+ return self.handle_checked_out_item(legacy_loan)
505
515
  elif "Aged to lost" in folio_checkout.error_message:
506
516
  return self.handle_lost_item(legacy_loan, "Aged to lost")
507
517
  elif folio_checkout.error_message == "Declared lost":
@@ -7,6 +7,7 @@ from zoneinfo import ZoneInfo
7
7
  from dateutil import tz
8
8
  from dateutil.parser import parse, ParserError
9
9
 
10
+ from folio_migration_tools.helper import Helper
10
11
  from folio_migration_tools.migration_report import MigrationReport
11
12
  from folio_migration_tools.custom_exceptions import TransformationRecordFailedError
12
13
 
@@ -62,15 +63,25 @@ class LegacyLoan(object):
62
63
  temp_date_due: datetime = parse(self.legacy_loan_dict["due_date"])
63
64
  if temp_date_due.tzinfo != tz.UTC:
64
65
  temp_date_due = temp_date_due.replace(tzinfo=self.tenant_timezone)
65
- self.report(
66
+ Helper.log_data_issue(
67
+ self.row,
66
68
  f"Provided due_date is not UTC in {row=}, "
67
- f"setting tz-info to tenant timezone ({self.tenant_timezone})"
69
+ f"setting tz-info to tenant timezone ({self.tenant_timezone})",
70
+ json.dumps(self.legacy_loan_dict)
71
+ )
72
+ self.report(
73
+ f"Provided due_date is not UTC, setting tz-info to tenant timezone ({self.tenant_timezone})"
68
74
  )
69
75
  if temp_date_due.hour == 0 and temp_date_due.minute == 0:
70
76
  temp_date_due = temp_date_due.replace(hour=23, minute=59)
71
- self.report(
77
+ Helper.log_data_issue(
78
+ self.row,
72
79
  f"Hour and minute not specified for due date in {row=}. "
73
- "Assuming end of local calendar day (23:59)..."
80
+ "Assuming end of local calendar day (23:59)...",
81
+ json.dumps(self.legacy_loan_dict)
82
+ )
83
+ self.report(
84
+ "Hour and minute not specified for due date"
74
85
  )
75
86
  except (ParserError, OverflowError) as ee:
76
87
  logging.error(ee)
@@ -82,9 +93,14 @@ class LegacyLoan(object):
82
93
  temp_date_out: datetime = parse(self.legacy_loan_dict["out_date"])
83
94
  if temp_date_out.tzinfo != tz.UTC:
84
95
  temp_date_out = temp_date_out.replace(tzinfo=self.tenant_timezone)
85
- self.report(
96
+ Helper.log_data_issue(
97
+ self.row,
86
98
  f"Provided out_date is not UTC in {row=}, "
87
- f"setting tz-info to tenant timezone ({self.tenant_timezone})"
99
+ f"setting tz-info to tenant timezone ({self.tenant_timezone})",
100
+ json.dumps(self.legacy_loan_dict)
101
+ )
102
+ self.report(
103
+ f"Provided out_date is not UTC, setting tz-info to tenant timezone ({self.tenant_timezone})"
88
104
  )
89
105
  except (ParserError, OverflowError):
90
106
  temp_date_out = datetime.now(
@@ -122,11 +138,17 @@ class LegacyLoan(object):
122
138
  try:
123
139
  return int(renewal_count)
124
140
  except ValueError:
125
- self.report(
126
- i18n.t("Unresolvable %{renewal_count=} was replaced with 0.")
141
+ Helper.log_data_issue(
142
+ self.row,
143
+ i18n.t("Unresolvable %{renewal_count=} was replaced with 0."),
144
+ json.dumps(loan)
127
145
  )
128
146
  else:
129
- self.report(i18n.t("Missing renewal count was replaced with 0."))
147
+ Helper.log_data_issue(
148
+ self.row,
149
+ i18n.t("Missing renewal count was replaced with 0."),
150
+ json.dumps(loan)
151
+ )
130
152
  return 0
131
153
 
132
154
  def correct_for_1_day_loans(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: folio_migration_tools
3
- Version: 1.9.4
3
+ Version: 1.9.5
4
4
  Summary: A tool allowing you to migrate data from legacy ILS:s (Library systems) into FOLIO LSP
5
5
  License: MIT
6
6
  Keywords: FOLIO,ILS,LSP,Library Systems,MARC21,Library data
@@ -1,13 +1,13 @@
1
1
  folio_migration_tools/__init__.py,sha256=DXvzUKFSpSZjflFWaNm0L8yhFk0u7RVIvQMskwMmKFc,238
2
2
  folio_migration_tools/__main__.py,sha256=kfo4iKf3GJD7deh4RvIizKnC4zvIgCpNo-Bs7HBM34s,8453
3
- folio_migration_tools/circulation_helper.py,sha256=V2VM30i2OigOKb64B4FFKTeHu9NTkhptalaOfziPhTo,14199
3
+ folio_migration_tools/circulation_helper.py,sha256=iib2p0WGzOcAnwaJppDYiONc-1Jdna66dPAtBmAIuCE,14538
4
4
  folio_migration_tools/colors.py,sha256=GP0wdI_GZ2WD5SjrbPN-S3u8vvN_u6rGQIBBcWv_0ZM,227
5
5
  folio_migration_tools/config_file_load.py,sha256=zHHa6NDkN6EJiQE4DgjrFQPVKsd70POsfbGkB8308jg,2822
6
6
  folio_migration_tools/custom_dict.py,sha256=-FUnhKp90Dg8EHlY6twx-PYQxBUWEO7FgxL2b7pf-xk,678
7
7
  folio_migration_tools/custom_exceptions.py,sha256=1zgOKy3NBUVGG6i9YxK6w2Hntlea8MHmm7mdnjBtzvQ,2687
8
8
  folio_migration_tools/extradata_writer.py,sha256=fuchNcMc6BYb9IyfAcvXg7X4J2TfX6YiROfT2hr0JMw,1678
9
9
  folio_migration_tools/folder_structure.py,sha256=bZlmKGtxdytWcqjnM2lE4Vpx4nHyYRk7CNL1tZhLtXY,6917
10
- folio_migration_tools/helper.py,sha256=KkOkNAGO_fuYqxdLrsbLzCJLQHUrFZG1NzD4RmpQ-KM,2804
10
+ folio_migration_tools/helper.py,sha256=iWQhdcuzbGzVpEAiHQczO4hdhIH_iciLEp1SCGDynMI,2983
11
11
  folio_migration_tools/holdings_helper.py,sha256=yJpz6aJrKRBiJ1MtT5bs2vXAc88uJuGh2_KDuCySOKc,7559
12
12
  folio_migration_tools/i18n_config.py,sha256=3AH_2b9zTsxE4XTe4isM_zYtPJSlK0ix6eBmV7kAYUM,228
13
13
  folio_migration_tools/library_configuration.py,sha256=LzICsZQdOkXwIqdDfh59x0-Cx77Lb18qVnWroNqekS8,7046
@@ -43,7 +43,7 @@ folio_migration_tools/migration_tasks/courses_migrator.py,sha256=CzXnsu-KGP7B4zc
43
43
  folio_migration_tools/migration_tasks/holdings_csv_transformer.py,sha256=kMhtHE8DJjA4d6kXBcfflueha3R3nwlBQjdec8CaY8c,21926
44
44
  folio_migration_tools/migration_tasks/holdings_marc_transformer.py,sha256=c_ruhOgidyJdSnnRwWUs3wwFMiLqbVMPOhhCaYuH_TI,14343
45
45
  folio_migration_tools/migration_tasks/items_transformer.py,sha256=oTbFX2saF7-ZCb1mO3baLvODnBSEbbN5F_GtSth3iG4,19755
46
- folio_migration_tools/migration_tasks/loans_migrator.py,sha256=9DQf58CZpgTM1m_miZTzsfVOGBWLsHrSFalQBO7g9DE,39406
46
+ folio_migration_tools/migration_tasks/loans_migrator.py,sha256=PF8DNpGKsppSDr7wX96Ao13UTFu6dl9cz2URLqSsOzE,40052
47
47
  folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py,sha256=CnmlTge7nChUJ10EiUkriQtJlVxWqglgfhjgneh2_yM,7247
48
48
  folio_migration_tools/migration_tasks/migration_task_base.py,sha256=Q-57h6rmt74bC9LidA9ZoagEcwVd_ytq8IUWelVOm2E,22521
49
49
  folio_migration_tools/migration_tasks/orders_transformer.py,sha256=6SnzU_rUTu2B5hQykI2nRA7vI1rg-uxuF9Ncupe0AEY,14302
@@ -55,13 +55,13 @@ folio_migration_tools/task_configuration.py,sha256=73OWc8TX--fwPRptv3eQVEVv0-XmN
55
55
  folio_migration_tools/test_infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  folio_migration_tools/test_infrastructure/mocked_classes.py,sha256=BurU3NGU_Q8as_BGmW98q9O6bujZDkOfFmvKKdVw9t8,15056
57
57
  folio_migration_tools/transaction_migration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- folio_migration_tools/transaction_migration/legacy_loan.py,sha256=2GHqHDVShdZuoUlW2yvePcsesJZ5-Huq3leD71tNtaE,6618
58
+ folio_migration_tools/transaction_migration/legacy_loan.py,sha256=sLw2fCBao1VWZykOx-BWpMndLHjJNj-HJZFYqbpVV5A,7561
59
59
  folio_migration_tools/transaction_migration/legacy_request.py,sha256=1ulyFzPQw_InOjyPzkWpGnNptgXdQ18nmri0J8Nlpkc,6124
60
60
  folio_migration_tools/transaction_migration/legacy_reserve.py,sha256=qzw0okg4axAE_ezXopP9gFsQ_e60o0zh7zqRzFBSWHY,1806
61
61
  folio_migration_tools/transaction_migration/transaction_result.py,sha256=cTdCN0BnlI9_ZJB2Z3Fdkl9gpymIi-9mGZsRFlQcmDk,656
62
62
  folio_migration_tools/translations/en.json,sha256=6IpYYNFCtQoXACndPM0d1Oa25GYuaF-G-b4YpzTjQH0,41656
63
- folio_migration_tools-1.9.4.dist-info/LICENSE,sha256=PhIEkitVi3ejgq56tt6sWoJIG_zmv82cjjd_aYPPGdI,1072
64
- folio_migration_tools-1.9.4.dist-info/METADATA,sha256=L36bpdFWAhsV2r8FBIjpZ-1N4Vl0u4EMV0f7g5ObNgg,7494
65
- folio_migration_tools-1.9.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
66
- folio_migration_tools-1.9.4.dist-info/entry_points.txt,sha256=Hbe-HjqMcU8FwVshVIkeWyZd9XwgT1CCMNf06EpHQu8,77
67
- folio_migration_tools-1.9.4.dist-info/RECORD,,
63
+ folio_migration_tools-1.9.5.dist-info/LICENSE,sha256=PhIEkitVi3ejgq56tt6sWoJIG_zmv82cjjd_aYPPGdI,1072
64
+ folio_migration_tools-1.9.5.dist-info/METADATA,sha256=nkA-xhhnIR5-fawBRyzv7cLMqEycu7IqM00H5QqQpKs,7494
65
+ folio_migration_tools-1.9.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
66
+ folio_migration_tools-1.9.5.dist-info/entry_points.txt,sha256=Hbe-HjqMcU8FwVshVIkeWyZd9XwgT1CCMNf06EpHQu8,77
67
+ folio_migration_tools-1.9.5.dist-info/RECORD,,