Skip to content

Commit

Permalink
Merge pull request #82 from MITLibraries/ENSY-187-bursar-transfer-suc…
Browse files Browse the repository at this point in the history
…cess-email-from-bursar-transfer-lambda-should-include-number-of-lines-and-total-charges

Ensy 187 bursar transfer success email from bursar transfer lambda should include number of lines and total charges
  • Loading branch information
adamshire123 committed Sep 29, 2023
2 parents 5ce88a5 + d59da25 commit 01ee673
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 117 deletions.
210 changes: 110 additions & 100 deletions Pipfile.lock

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ bursar's system.
docker run --env-file .env -p 9000:8080 bursar_transfer:latest
```

- Upload a sample bursar export .xml file to the `SOURCE_BUCKET` specified in your `.env`. rename the file and move to a different subfolder if necessary so that the object key looks like `[SOURCE_PREFIX]-[job_id]-[timestamp].xml`
- Upload a sample bursar export .xml file to the `SOURCE_BUCKET` specified in your `.env`. Rename the file and move to a different subfolder if necessary so that the object key looks like `[SOURCE_PREFIX]-[job_id]-[timestamp].xml`
- For example the object key could be `test/bursar/export-1234-5678.xml`
- Note that the timestamp can be any string, it doesn't have to be a 'real' timestamp
- You can use the fixture file in this repo `tests/fixtures/test.xml` as your sample file.
Expand All @@ -78,5 +78,8 @@ bursar's system.
- Observe output:

```
{"target_file": "[TARGET_BUCKET]/[TARGET_PREFIX]-1234-5678.csv"}
{"target_file": "[TARGET_BUCKET]/[TARGET_PREFIX]-1234-5678.csv",
"records": [count of records in the file],
"total_charges: [sum of charges in the file]
}
```
33 changes: 28 additions & 5 deletions lambdas/bursar_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
from datetime import date
from io import StringIO
from math import fsum
from xml.etree import ElementTree # nosec

import boto3
Expand Down Expand Up @@ -101,7 +102,7 @@ def billing_term(today: date) -> str:
return f"{term_year}{term_code}"


def xml_to_csv(alma_xml: str, today: date) -> str:
def xml_to_csv(alma_xml: str, today: date) -> StringIO:
"""Convert xml from the alma bursar export to a csv.
See https://mitlibraries.atlassian.net/browse/ENSY-182 for details on bursar's
Expand Down Expand Up @@ -154,7 +155,7 @@ def xml_to_csv(alma_xml: str, today: date) -> str:
"One or more required values are missing from the export file"
)

return csv_file.getvalue()
return csv_file


def put_csv(s3_client: S3Client, bucket: str, key: str, csv_file: str) -> None:
Expand All @@ -163,8 +164,25 @@ def put_csv(s3_client: S3Client, bucket: str, key: str, csv_file: str) -> None:
)


def get_records_and_total_charges(bursar_csv: StringIO) -> tuple[int, float]:
"""Return the number of records and sum of charges in the bursar export file.
Takes a `StringIO` containing the transformed bursar csv and returns the sum of
the charges from the Amount column and the number of records in the file excluding
the header row.
"""
bursar_csv.seek(0)
record_count = 0
total_charges = float()

for row in csv.DictReader(bursar_csv):
record_count += 1
total_charges = round(fsum([total_charges, float(row["AMOUNT"])]), 2)
return record_count, total_charges


def lambda_handler(event: dict, context: object) -> dict: # noqa
logger.debug("lambda handler starting with event: %s", json.dumps(event))
logger.debug("Lambda handler starting with event: %s", json.dumps(event))
if not os.getenv("WORKSPACE"):
raise RuntimeError("Required env variable WORKSPACE is not set")

Expand Down Expand Up @@ -194,8 +212,13 @@ def lambda_handler(event: dict, context: object) -> dict: # noqa
s3_client,
os.environ["TARGET_BUCKET"],
target_key,
bursar_csv,
bursar_csv.getvalue(),
)
csv_location = f"{os.environ['TARGET_BUCKET']}/{target_key}"
record_count, total_charges = get_records_and_total_charges(bursar_csv)
logger.info("Bursar csv available for download at %s", csv_location)
return {"target_file": csv_location}
return {
"target_file": csv_location,
"record_count": record_count,
"total_charges": total_charges,
}
7 changes: 6 additions & 1 deletion tests/fixtures/test.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
"MITID","STUDENTNAME","DETAILCODE","DESCRIPTION","AMOUNT","EFFECTIVEDATE","BILLINGTERM"
"12345678","Transfer, Bursar","ROLH","LOSTITEMREPLACEMENTFEE","123.45","effective_date","2023SP"
"12345678","Transfer, Bursar","ROLH","OVERDUEFINE","123.45","effective_date","2023SP"
"12345678","Transfer, Bursar","ROLH","OVERDUEFINE","0.82","effective_date","2023SP"
"12345678","Transfer, Bursar","ROLH","LOSTITEMREPLACEMENTFEE","300","effective_date","2023SP"
"12345678","Transfer, Bursar","ROLH","OVERDUEFINE","1.45","effective_date","2023SP"
"09876","The Beaver, Tim","ROLH","LOSTITEMREPLACEMENTFEE","100","effective_date","2023SP"
"09876","The Beaver, Tim","ROLH","OVERDUEFINE","14","effective_date","2023SP"
152 changes: 148 additions & 4 deletions tests/fixtures/test.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<xb:xml-fragment xmlns:xb="http://com/exlibris/urm/rep/externalsysfinesfees/xmlbeans">
<xb:userExportedFineFees>
<xb:exportNumber>13592334070006761</xb:exportNumber>
<xb:exportNumber>15216075870006761</xb:exportNumber>
</xb:userExportedFineFees>
<xb:userExportedFineFees>
<xb:userExportedList>
Expand All @@ -18,13 +18,13 @@
<xb:userFineFee>
<xb:fineFeeComment xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:fineFeeType>LOSTITEMREPLACEMENTFEE</xb:fineFeeType>
<xb:fineFeeType>OVERDUEFINE</xb:fineFeeType>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
<xb:libraryId>161686070006761</xb:libraryId>
<xb:libraryCode>RTC</xb:libraryCode>
</xb:owneredEntity>
<xb:lastTransactionDate>05/12/2023 00:08:34</xb:lastTransactionDate>
<xb:lastTransactionDate>09/12/2023 15:22:06</xb:lastTransactionDate>
<xb:itemTitle>Ecology of the saguaro /</xb:itemTitle>
<xb:itemCallNumebr>QK495.C11 S64 1977</xb:itemCallNumebr>
<xb:itemLibrary>Hayden Library.</xb:itemLibrary>
Expand All @@ -39,7 +39,151 @@
<xb:vat xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</xb:compositeSum>
<xb:bursarTransactionId>13592333900006761</xb:bursarTransactionId>
<xb:bursarTransactionId>15216075630006761</xb:bursarTransactionId>
</xb:userFineFee>
<xb:userFineFee>
<xb:fineFeeComment xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:fineFeeType>OVERDUEFINE</xb:fineFeeType>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
<xb:libraryId>161686070006761</xb:libraryId>
<xb:libraryCode>RTC</xb:libraryCode>
</xb:owneredEntity>
<xb:lastTransactionDate>09/12/2023 15:22:26</xb:lastTransactionDate>
<xb:itemTitle>Ecology of the saguaro /</xb:itemTitle>
<xb:itemCallNumebr>QK495.C11 S64 1977</xb:itemCallNumebr>
<xb:itemLibrary>Hayden Library.</xb:itemLibrary>
<xb:itemLocation>Stacks</xb:itemLocation>
<xb:itemInternalLocation>Stacks</xb:itemInternalLocation>
<xb:itemDueDate xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:itemBarcode>39080036507785</xb:itemBarcode>
<xb:compositeSum>
<xb:currency>USD</xb:currency>
<xb:sum>0.82</xb:sum>
<xb:vat xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</xb:compositeSum>
<xb:bursarTransactionId>15216075640006761</xb:bursarTransactionId>
</xb:userFineFee>
<xb:userFineFee>
<xb:fineFeeComment xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:fineFeeType>LOSTITEMREPLACEMENTFEE</xb:fineFeeType>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
<xb:libraryId>161686070006761</xb:libraryId>
<xb:libraryCode>RTC</xb:libraryCode>
</xb:owneredEntity>
<xb:lastTransactionDate>09/12/2023 15:15:23</xb:lastTransactionDate>
<xb:itemTitle>The Rough-Stuff Fellowship archive /</xb:itemTitle>
<xb:itemCallNumebr>GV1056.R68 2019</xb:itemCallNumebr>
<xb:itemLibrary>Hayden Library</xb:itemLibrary>
<xb:itemLocation>Stacks</xb:itemLocation>
<xb:itemInternalLocation>Stacks</xb:itemInternalLocation>
<xb:itemDueDate xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:itemBarcode>39080037379556</xb:itemBarcode>
<xb:compositeSum>
<xb:currency>USD</xb:currency>
<xb:sum>300</xb:sum>
<xb:vat xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</xb:compositeSum>
<xb:bursarTransactionId>15216075490006761</xb:bursarTransactionId>
</xb:userFineFee>
<xb:userFineFee>
<xb:fineFeeComment xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:fineFeeType>OVERDUEFINE</xb:fineFeeType>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
<xb:libraryId>161686070006761</xb:libraryId>
<xb:libraryCode>RTC</xb:libraryCode>
</xb:owneredEntity>
<xb:lastTransactionDate>09/12/2023 15:22:53</xb:lastTransactionDate>
<xb:itemTitle>The Rough-Stuff Fellowship archive /</xb:itemTitle>
<xb:itemCallNumebr>GV1056.R68 2019</xb:itemCallNumebr>
<xb:itemLibrary>Hayden Library</xb:itemLibrary>
<xb:itemLocation>Stacks</xb:itemLocation>
<xb:itemInternalLocation>Stacks</xb:itemInternalLocation>
<xb:itemDueDate xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:itemBarcode>39080037379556</xb:itemBarcode>
<xb:compositeSum>
<xb:currency>USD</xb:currency>
<xb:sum>1.45</xb:sum>
<xb:vat xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</xb:compositeSum>
<xb:bursarTransactionId>15216075650006761</xb:bursarTransactionId>
</xb:userFineFee>
</xb:finefeeList>
</xb:userExportedFineFeesList>
<xb:userExportedFineFeesList>
<xb:user>
<xb:type>02</xb:type>
<xb:value>09876</xb:value>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
</xb:owneredEntity>
</xb:user>
<xb:patronName>The Beaver, Tim</xb:patronName>
<xb:finefeeList>
<xb:userFineFee>
<xb:fineFeeComment xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:fineFeeType>LOSTITEMREPLACEMENTFEE</xb:fineFeeType>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
<xb:libraryId>161686070006761</xb:libraryId>
<xb:libraryCode>RTC</xb:libraryCode>
</xb:owneredEntity>
<xb:lastTransactionDate>09/12/2023 15:24:14</xb:lastTransactionDate>
<xb:itemTitle>Case studies of child play areas and child support facilities
: travel and field research report /</xb:itemTitle>
<xb:itemCallNumebr>HV854.C56</xb:itemCallNumebr>
<xb:itemLibrary>Rotch Library</xb:itemLibrary>
<xb:itemLocation>Stacks</xb:itemLocation>
<xb:itemInternalLocation>Stacks</xb:itemInternalLocation>
<xb:itemDueDate xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:itemBarcode>39080002699707</xb:itemBarcode>
<xb:compositeSum>
<xb:currency>USD</xb:currency>
<xb:sum>100</xb:sum>
<xb:vat xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</xb:compositeSum>
<xb:bursarTransactionId>15216075700006761</xb:bursarTransactionId>
</xb:userFineFee>
<xb:userFineFee>
<xb:fineFeeComment xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:fineFeeType>OVERDUEFINE</xb:fineFeeType>
<xb:owneredEntity>
<xb:InstitutionId>6761</xb:InstitutionId>
<xb:libraryId>161686070006761</xb:libraryId>
<xb:libraryCode>RTC</xb:libraryCode>
</xb:owneredEntity>
<xb:lastTransactionDate>09/12/2023 15:23:25</xb:lastTransactionDate>
<xb:itemTitle>Case studies of child play areas and child support facilities
: travel and field research report /</xb:itemTitle>
<xb:itemCallNumebr>HV854.C56</xb:itemCallNumebr>
<xb:itemLibrary>Rotch Library</xb:itemLibrary>
<xb:itemLocation>Stacks</xb:itemLocation>
<xb:itemInternalLocation>Stacks</xb:itemInternalLocation>
<xb:itemDueDate xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<xb:itemBarcode>39080002699707</xb:itemBarcode>
<xb:compositeSum>
<xb:currency>USD</xb:currency>
<xb:sum>14</xb:sum>
<xb:vat xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</xb:compositeSum>
<xb:bursarTransactionId>15216075690006761</xb:bursarTransactionId>
</xb:userFineFee>
</xb:finefeeList>
</xb:userExportedFineFeesList>
Expand Down
19 changes: 14 additions & 5 deletions tests/test_bursar_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ def test_xml_to_csv_error_if_missing_field(test_xml: str) -> None:


def test_xml_to_csv(test_xml: str) -> None:
with open("tests/fixtures/test.csv", encoding="utf-8") as file:
expected_file = file.read()
with open("tests/fixtures/test.csv", encoding="utf-8") as expected_file:
today = date(2023, 3, 1)
assert bursar_transfer.xml_to_csv(test_xml, today) == expected_file
assert (
bursar_transfer.xml_to_csv(test_xml, today).getvalue()
== expected_file.read()
)


def test_put_csv(mocked_s3) -> None:
Expand Down Expand Up @@ -145,8 +147,15 @@ def test_lambda_handler_success(event_data, caplog) -> None:
with caplog.at_level(logging.DEBUG, logger="lambdas.bursar_transfer"):
response = bursar_transfer.lambda_handler(event_data, {})
assert (
f"lambda handler starting with event: {json.dumps(event_data)}" in caplog.text
f"Lambda handler starting with event: {json.dumps(event_data)}" in caplog.text
)

records = 6
total_charges = 539.72
response = bursar_transfer.lambda_handler(event_data, {})
assert f"Bursar csv available for download at {csv_location}" in caplog.text
assert response == {"target_file": csv_location}
assert response == {
"target_file": csv_location,
"record_count": records,
"total_charges": total_charges,
}

0 comments on commit 01ee673

Please sign in to comment.