diff --git a/littlepay/api/funding_sources.py b/littlepay/api/funding_sources.py index c3d0550..e401672 100644 --- a/littlepay/api/funding_sources.py +++ b/littlepay/api/funding_sources.py @@ -19,6 +19,7 @@ class FundingSourceResponse: participant_id: str is_fpan: bool related_funding_sources: List[dict] + created_date: datetime | None = None card_category: Optional[str] = None issuer_country_code: Optional[str] = None issuer_country_numeric_code: Optional[str] = None @@ -31,6 +32,22 @@ class FundingSourceResponse: def from_kwargs(cls, **kwargs): return from_kwargs(cls, **kwargs) + def __post_init__(self): + """Parses any date parameters into Python datetime objects. + + For @dataclasses with a generated __init__ function, this function is called automatically. + + Includes a workaround for Python 3.10 where datetime.fromisoformat() can only parse the format output + by datetime.isoformat(), i.e. without a trailing 'Z' offset character and with UTC offset expressed + as +/-HH:mm + + https://docs.python.org/3.11/library/datetime.html#datetime.datetime.fromisoformat + """ + if self.created_date: + self.created_date = datetime.fromisoformat(self.created_date.replace("Z", "+00:00", 1)) + else: + self.created_date = None + @dataclass class FundingSourceDateFields: diff --git a/tests/api/test_funding_sources.py b/tests/api/test_funding_sources.py index a776d97..be4070c 100644 --- a/tests/api/test_funding_sources.py +++ b/tests/api/test_funding_sources.py @@ -35,7 +35,7 @@ def ListResponse_FundingSourceGroups(expected_expiry_str): @pytest.fixture -def mock_ClientProtocol_get_FundingResource(mocker): +def mock_ClientProtocol_get_FundingResource(mocker, expected_expiry_str): funding_source = FundingSourceResponse( id="0", card_first_digits="0000", @@ -47,6 +47,7 @@ def mock_ClientProtocol_get_FundingResource(mocker): participant_id="cst", is_fpan=True, related_funding_sources=[], + created_date=expected_expiry_str, ) return mocker.patch("littlepay.api.ClientProtocol._get", return_value=funding_source) @@ -78,6 +79,43 @@ def test_FundingSourceResponse_unexpected_fields(): FundingSourceResponse.from_kwargs(**response_json) +def test_FundingSourceResponse_no_date_field(): + response_json = { + "id": "0", + "card_first_digits": "0000", + "card_last_digits": "0000", + "card_expiry_month": "11", + "card_expiry_year": "24", + "card_scheme": "Visa", + "form_factor": "unknown", + "participant_id": "cst", + "is_fpan": True, + "related_funding_sources": [], + } + + funding_source = FundingSourceResponse.from_kwargs(**response_json) + assert funding_source.created_date is None + + +def test_FundingSourceResponse_with_date_field(expected_expiry_str, expected_expiry): + response_json = { + "id": "0", + "card_first_digits": "0000", + "card_last_digits": "0000", + "card_expiry_month": "11", + "card_expiry_year": "24", + "card_scheme": "Visa", + "form_factor": "unknown", + "participant_id": "cst", + "is_fpan": True, + "related_funding_sources": [], + "created_date": expected_expiry_str, + } + + funding_source = FundingSourceResponse.from_kwargs(**response_json) + assert funding_source.created_date == expected_expiry + + def test_FundingSourceDateFields(expected_expiry_str, expected_expiry): fields = FundingSourceDateFields( created_date=expected_expiry_str, updated_date=expected_expiry_str, expiry_date=expected_expiry_str