Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

closes #323 #324

Merged
merged 2 commits into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This is the loose roadmap, in order of most likely implementations first

### Can I use the tools for ongoing imports and integrations?
The tools are primarliy maintained for performing initial data migrations. We recommend that you use native FOLIO functionality for ongoing loads where possible.
In theory, these tools can be used for ongoing patron loads from systems like Banner or PeopleSoft. But we recommend you to weigh your options carefully before going down this path.
In theory, these tools can be used for ongoing patron loads from systems like Banner, Workday, or PeopleSoft. But we recommend you to weigh your options carefully before going down this path.

# Contributing
Want to contribute? Read the [CONTRIBUTING.MD](https://github.com/FOLIO-FSE/folio_migration_tools/blob/main/CONTRIBUTING.md)
Expand Down
2 changes: 1 addition & 1 deletion src/folio_migration_tools/circulation_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def check_out_by_barcode(self, legacy_loan: LegacyLoan) -> TransactionResult:
"itemBarcode": legacy_loan.item_barcode,
"userBarcode": legacy_loan.patron_barcode,
"loanDate": legacy_loan.out_date.isoformat(),
"servicePointId": self.service_point_id,
"servicePointId": legacy_loan.service_point_id,
"overrideBlocks": {
"itemNotLoanableBlock": {"dueDate": legacy_loan.due_date.isoformat()},
"patronBlock": {},
Expand Down
12 changes: 11 additions & 1 deletion src/folio_migration_tools/migration_tasks/loans_migrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ def check_barcodes(self):
)
yield loan
else:
# Add this loan to failed loans for later correction and re-run.
self.failed[loan.item_barcode] = loan
self.migration_report.add(
Blurbs.DiscardedLoans,
f"Loans discarded. Had migrated item barcode: {has_item_barcode}. "
Expand All @@ -285,7 +287,11 @@ def load_and_validate_legacy_loans(self, loans_reader, service_point_id: str) ->
for legacy_loan_count, legacy_loan_dict in enumerate(loans_reader):
try:
legacy_loan = LegacyLoan(
legacy_loan_dict, service_point_id, self.tenant_timezone, legacy_loan_count
legacy_loan_dict,
service_point_id,
self.migration_report,
self.tenant_timezone,
legacy_loan_count,
)
if any(legacy_loan.errors):
num_bad += 1
Expand All @@ -294,6 +300,10 @@ def load_and_validate_legacy_loans(self, loans_reader, service_point_id: str) ->
self.migration_report.add(
Blurbs.DiscardedLoans, f"{error[0]} - {error[1]}"
)
# Add this loan to failed loans for later correction and re-run.
self.failed[
legacy_loan.item_barcode or f"no_barcode_{legacy_loan_count}"
] = legacy_loan
else:
results.append(legacy_loan)
except ValueError as ve:
Expand Down
22 changes: 15 additions & 7 deletions src/folio_migration_tools/transaction_migration/legacy_loan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
from dateutil import tz
from dateutil.parser import parse

from folio_migration_tools.migration_report import MigrationReport
from folio_migration_tools.report_blurbs import Blurbs


class LegacyLoan(object):
def __init__(
self,
legacy_loan_dict,
fallback_service_point_id: str,
migration_report: MigrationReport,
tenant_timezone=ZoneInfo("UTC"),
row=0,
):
self.migration_report: MigrationReport = migration_report
# validate
correct_headers = [
"item_barcode",
Expand Down Expand Up @@ -49,13 +54,13 @@ def __init__(
temp_date_due: datetime = parse(legacy_loan_dict["due_date"])
if temp_date_due.tzinfo != tz.UTC:
temp_date_due = temp_date_due.replace(tzinfo=self.tenant_timezone)
logging.info(
"Provided due_date is not UTC, setting tzinfo to tenant timezone (%s)",
self.tenant_timezone,
self.report(
f"Provided due_date is not UTC, "
f"setting tzinfo to tenant timezone ({self.tenant_timezone})"
)
if temp_date_due.hour == 0 and temp_date_due.minute == 0:
temp_date_due = temp_date_due.replace(hour=23, minute=59)
logging.info(
self.report(
"Hour and minute not specified for due date. "
"Assuming end of local calendar day (23:59)..."
)
Expand All @@ -67,9 +72,9 @@ def __init__(
temp_date_out: datetime = parse(legacy_loan_dict["out_date"])
if temp_date_out.tzinfo != tz.UTC:
temp_date_out = temp_date_out.replace(tzinfo=self.tenant_timezone)
logging.info(
"Provided out_date is not UTC, setting tzinfo to tenant timezone (%s)",
self.tenant_timezone,
self.report(
f"Provided out_date is not UTC, "
f"setting tzinfo to tenant timezone ({self.tenant_timezone})"
)
except Exception:
temp_date_out = datetime.now(
Expand Down Expand Up @@ -123,3 +128,6 @@ def make_utc(self):
self.out_date = self.out_date.astimezone(ZoneInfo("UTC"))
except Exception:
self.errors.append(("UTC correction issues", "both dates"))

def report(self, what_to_report: str):
self.migration_report.add(Blurbs.Details, what_to_report)
67 changes: 61 additions & 6 deletions tests/test_legacy_loan.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from zoneinfo import ZoneInfo

from folio_migration_tools.migration_report import MigrationReport
from folio_migration_tools.report_blurbs import Blurbs
from folio_migration_tools.transaction_migration.legacy_loan import LegacyLoan


Expand All @@ -13,12 +15,14 @@ def test_init():
"next_item_status": "Checked out",
}
tenant_timezone = ZoneInfo("UTC")
legacy_loan = LegacyLoan(loan_dict, "", tenant_timezone)
migration_report = MigrationReport()
legacy_loan = LegacyLoan(loan_dict, "", migration_report, tenant_timezone)
assert legacy_loan.patron_barcode == "the barcode with leading space"
assert legacy_loan.item_barcode == "the barcode with trailing space"
assert legacy_loan.due_date.isoformat() == "2022-01-13T23:59:00+00:00"
assert legacy_loan.out_date.isoformat() == "2022-01-13T00:01:00+00:00"
assert legacy_loan.renewal_count > 0
migration_report.report = {}


def test_init_tz():
Expand All @@ -31,12 +35,22 @@ def test_init_tz():
"next_item_status": "Checked out",
}
tenant_timezone = ZoneInfo("America/Chicago")
legacy_loan = LegacyLoan(loan_dict, "", tenant_timezone)
migration_report = MigrationReport()
legacy_loan = LegacyLoan(loan_dict, "", migration_report, tenant_timezone)
assert legacy_loan.patron_barcode == "the barcode with leading space"
assert legacy_loan.item_barcode == "the barcode with trailing space"
assert legacy_loan.due_date.isoformat() == "2022-01-13T22:00:00+00:00"
assert legacy_loan.out_date.isoformat() == "2022-01-13T20:00:00+00:00"
assert legacy_loan.renewal_count > 0
assert (
"Provided due_date is not UTC, setting tzinfo to tenant timezone (America/Chicago)"
in migration_report.report[Blurbs.Details[0]]
)

assert (
"Provided out_date is not UTC, setting tzinfo to tenant timezone (America/Chicago)"
in migration_report.report[Blurbs.Details[0]]
)


def test_init_tz_2():
Expand All @@ -49,10 +63,24 @@ def test_init_tz_2():
"next_item_status": "Checked out",
}
tenant_timezone = ZoneInfo("UTC")
legacy_loan = LegacyLoan(loan_dict, "", tenant_timezone)
migration_report = MigrationReport()
legacy_loan = LegacyLoan(loan_dict, "", migration_report, tenant_timezone)
assert legacy_loan.due_date.isoformat() == "2019-02-22T23:59:00+00:00"
assert legacy_loan.out_date.isoformat() == "2019-02-22T10:53:00+00:00"
assert legacy_loan.renewal_count > 0
assert (
"Hour and minute not specified for due date. Assuming end of local calendar day (23:59)..."
in migration_report.report[Blurbs.Details[0]]
)

assert (
"Provided out_date is not UTC, setting tzinfo to tenant timezone (UTC)"
in migration_report.report[Blurbs.Details[0]]
)
assert (
"Provided due_date is not UTC, setting tzinfo to tenant timezone (UTC)"
in migration_report.report[Blurbs.Details[0]]
)


def test_init_tz_3():
Expand All @@ -65,12 +93,21 @@ def test_init_tz_3():
"next_item_status": "Checked out",
}
tenant_timezone = ZoneInfo("Australia/Sydney")
legacy_loan = LegacyLoan(loan_dict, "", tenant_timezone)
migration_report = MigrationReport()
legacy_loan = LegacyLoan(loan_dict, "", migration_report, tenant_timezone)
assert legacy_loan.patron_barcode == "the barcode with leading space"
assert legacy_loan.item_barcode == "the barcode with trailing space"
assert legacy_loan.due_date.isoformat() == "2022-01-13T05:00:00+00:00"
assert legacy_loan.out_date.isoformat() == "2022-01-13T03:00:00+00:00"
assert legacy_loan.renewal_count > 0
assert (
"Provided due_date is not UTC, setting tzinfo to tenant timezone (Australia/Sydney)"
in migration_report.report[Blurbs.Details[0]]
)
assert (
"Provided out_date is not UTC, setting tzinfo to tenant timezone (Australia/Sydney)"
in migration_report.report[Blurbs.Details[0]]
)


def test_init_tz_4(): # Test dates with(out) DST
Expand All @@ -83,12 +120,21 @@ def test_init_tz_4(): # Test dates with(out) DST
"next_item_status": "Checked out",
}
tenant_timezone = ZoneInfo("Australia/Sydney")
legacy_loan = LegacyLoan(loan_dict, "", tenant_timezone)
migration_report = MigrationReport()
legacy_loan = LegacyLoan(loan_dict, "", migration_report, tenant_timezone)
assert legacy_loan.patron_barcode == "the barcode with leading space"
assert legacy_loan.item_barcode == "the barcode with trailing space"
assert legacy_loan.due_date.isoformat() == "2022-06-13T06:00:00+00:00"
assert legacy_loan.out_date.isoformat() == "2022-06-13T04:00:00+00:00"
assert legacy_loan.renewal_count > 0
assert (
"Provided due_date is not UTC, setting tzinfo to tenant timezone (Australia/Sydney)"
in migration_report.report[Blurbs.Details[0]]
)
assert (
"Provided out_date is not UTC, setting tzinfo to tenant timezone (Australia/Sydney)"
in migration_report.report[Blurbs.Details[0]]
)


def test_init_tz_5(): # Test dates with(out) DST
Expand All @@ -101,9 +147,18 @@ def test_init_tz_5(): # Test dates with(out) DST
"next_item_status": "Checked out",
}
tenant_timezone = ZoneInfo("America/Chicago")
legacy_loan = LegacyLoan(loan_dict, "", tenant_timezone)
migration_report = MigrationReport()
legacy_loan = LegacyLoan(loan_dict, "", migration_report, tenant_timezone)
assert legacy_loan.patron_barcode == "the barcode with leading space"
assert legacy_loan.item_barcode == "the barcode with trailing space"
assert legacy_loan.due_date.isoformat() == "2022-06-13T21:00:00+00:00"
assert legacy_loan.out_date.isoformat() == "2022-06-13T19:00:00+00:00"
assert legacy_loan.renewal_count > 0
assert (
"Provided due_date is not UTC, setting tzinfo to tenant timezone (America/Chicago)"
in migration_report.report[Blurbs.Details[0]]
)
assert (
"Provided out_date is not UTC, setting tzinfo to tenant timezone (America/Chicago)"
in migration_report.report[Blurbs.Details[0]]
)
3 changes: 3 additions & 0 deletions tests/test_loans_migrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from folio_uuid.folio_namespaces import FOLIONamespaces

from folio_migration_tools.library_configuration import LibraryConfiguration
from folio_migration_tools.migration_report import MigrationReport
from folio_migration_tools.migration_tasks.loans_migrator import LoansMigrator


Expand Down Expand Up @@ -48,6 +49,7 @@ def test_load_and_validate_legacy_loans_set_in_source():
mock_library_conf.okapi_password = ""
mock_migrator = Mock(spec=LoansMigrator)
mock_migrator.tenant_timezone = ZoneInfo("UTC")
mock_migrator.migration_report = MigrationReport()
a = LoansMigrator.load_and_validate_legacy_loans(
mock_migrator, reader, "Set on file or config"
)
Expand Down Expand Up @@ -86,6 +88,7 @@ def test_load_and_validate_legacy_loans_set_centrally():
mock_library_conf.okapi_username = ""
mock_library_conf.okapi_password = ""
mock_migrator = Mock(spec=LoansMigrator)
mock_migrator.migration_report = MigrationReport()
mock_migrator.tenant_timezone = ZoneInfo("UTC")
a = LoansMigrator.load_and_validate_legacy_loans(
mock_migrator, reader, "Set on file or config"
Expand Down