Coverage for benefits/enrollment_init/api.py: 100%
54 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-08 19:50 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-08 19:50 +0000
1import base64
2from dataclasses import dataclass
4import requests
5from django.conf import settings
7from benefits.enrollment.api import BaseDataClass
10@dataclass
11class TransitAccountResponse(BaseDataClass):
12 Id: int
13 CardholderId: int
16@dataclass
17class CardholderResponse(BaseDataClass):
18 FareCategory: int
19 FareCategoryExpiry: str
22class Client:
23 def __init__(self, api_url, username, password):
24 self.api_url = api_url.strip("/")
26 encoded_bytes = base64.b64encode(bytes(f"{username}:{password}", "utf-8"))
27 self.authorization_header_value = f"Basic {encoded_bytes.decode()}"
29 def _endpoint_url(self, endpoint):
30 return f"{self.api_url}/api/{endpoint}"
32 def _authorization_header(self):
33 return {"Authorization": self.authorization_header_value}
35 def get_transit_account(self, banking_service_token, timeout=settings.REQUESTS_TIMEOUT) -> TransitAccountResponse:
36 url = self._endpoint_url("TransitAccounts")
37 response = requests.get(
38 url,
39 params={
40 "BankingServiceToken": banking_service_token,
41 },
42 headers=self._authorization_header(),
43 timeout=timeout,
44 )
46 response.raise_for_status()
48 response_json = response.json()
49 total_count = response_json["TotalCount"]
50 results = response_json["Result"]
52 if total_count == 1:
53 return TransitAccountResponse.from_kwargs(**results[0])
54 elif total_count == 0:
55 return None
56 else:
57 raise ValueError(f"Unexpectedly received more than 1 TransitAccount for token {banking_service_token}")
59 def get_cardholder(self, cardholder_id: int, timeout=settings.REQUESTS_TIMEOUT) -> CardholderResponse:
60 url = self._endpoint_url("Cardholders") + f"/{cardholder_id}"
61 response = requests.get(
62 url,
63 headers=self._authorization_header(),
64 timeout=timeout,
65 )
67 response.raise_for_status()
69 response_json = response.json()
71 if "Id" in response_json and response_json["Id"] == cardholder_id:
72 return CardholderResponse.from_kwargs(**response_json)
73 else:
74 raise ValueError(f"Unexpected response when querying for cardholder {cardholder_id}: {response_json}")
76 def post_cardholder(
77 self, fare_category: int, transit_account_id: int, timeout=settings.REQUESTS_TIMEOUT
78 ) -> CardholderResponse:
79 url = self._endpoint_url("Cardholders")
80 request_body = {
81 "FareCategory": fare_category,
82 "TransitAccountId": transit_account_id,
83 }
84 response = requests.post(
85 url,
86 json=request_body,
87 headers=self._authorization_header(),
88 timeout=timeout,
89 )
91 response.raise_for_status()
93 return CardholderResponse.from_kwargs(**response.json())
95 def put_cardholder(self, cardholder_id: int, fare_category: int, timeout=settings.REQUESTS_TIMEOUT) -> CardholderResponse:
96 url = self._endpoint_url("Cardholders") + f"/{cardholder_id}"
97 request_body = {
98 "FareCategory": fare_category,
99 }
100 response = requests.put(
101 url,
102 json=request_body,
103 headers=self._authorization_header(),
104 timeout=timeout,
105 )
107 response.raise_for_status()
109 return CardholderResponse.from_kwargs(**response.json())