/
sbanken_session.py
155 lines (128 loc) · 5.17 KB
/
sbanken_session.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import urllib.parse
from os import environ
from typing import List, Dict, Optional, Sequence, Iterable
import requests
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
from ..sbanken.errors import SbankenError
from ..sbanken.transaction import Transaction
class SbankenSession(object):
"""
Class for handling HTTPS requests to the REST API from SBanken.
"""
unbooked_text_keywords = tuple(
map(str.lower, ("Varekjøp", "Varekjøp VISA", "VISA"))
)
unstable_transaction_keys = ("transactionId", "source", "reservationType")
@staticmethod
def _create_authenticated_http_session(
client_id: str, client_secret: str
) -> requests.Session:
oauth2_client = BackendApplicationClient(client_id=client_id)
session = OAuth2Session(client=oauth2_client)
session.fetch_token(
token_url="https://auth.sbanken.no/identityserver/connect/token",
client_id=client_id,
client_secret=urllib.parse.quote(client_secret),
)
return session
def __init__(self):
self.session = SbankenSession._create_authenticated_http_session(
environ["CLIENT_ID"], environ["CLIENT_SECRET"]
)
self.customer_id = environ["CUSTOMER_ID"]
def get_transactions(
self,
account_id: str,
index: int = 0,
length: int = 100,
start_date=None,
end_date=None,
) -> List[Transaction]:
"""
Get the transactions from the given account id
:param account_id: The account id to retrieve transactions from
:param index: The start index of the transactions.
:param length: The maximum number of transactions to return
:param start_date: The start date of the transactions. Defaults to 30 days before end date.
:param end_date: The end date of the transactions. Defaults to today's date.
:return: A list of Transaction objects.
"""
queries = {
"index": str(index),
"length": str(length),
"startDate": start_date,
"endDate": end_date,
}
response = self.session.get(
f"https://api.sbanken.no/bank/api/v1/Transactions/{account_id}",
headers={"customerId": self.customer_id},
params=queries,
).json()
if response["isError"]:
raise SbankenError(f'{response["errorType"]} {response["errorMessage"]}')
data = response["items"]
if "transactionId" in data:
print("TransactionId present")
self._remove_unstable_transaction_keys(data)
transactions = (Transaction(transaction) for transaction in data)
booked_transactions = self._remove_unbooked_transactions(transactions)
return booked_transactions
def get_accounts(self) -> Sequence[Dict]:
"""
Retrieve account information of all accounts for Sbanken object.
:return: A list of dictionaries, each representing one account.
"""
response = self.session.get(
"https://api.sbanken.no/bank/api/v1/Accounts",
headers={"customerId": self.customer_id},
).json()
if not response["isError"]:
return response["items"]
else:
raise SbankenError(f'{response["errorType"]} {response["errorMessage"]}')
def get_account(self, account_name, customer_id=None) -> Optional[Dict]:
"""
Retrieve account information for a specific account, id'd by the
account name and the customer id of the owner.
:param account_name: Name of the account
:param customer_id: Customer id of the owner of the account. Defaults to
the customer id of the Sbanken class.
:return: The account if found, else None.
"""
if customer_id is None:
customer_id = self.customer_id
response = self.session.get(
"https://api.sbanken.no/bank/api/v1/Accounts",
headers={"customerId": self.customer_id},
).json()
if response["isError"]:
raise SbankenError(f'{response["errorType"]} {response["errorMessage"]}')
accounts = response["items"]
for account in accounts:
if (
account["name"] == account_name
and account["ownerCustomerId"] == customer_id
):
return account
return None
def _remove_unstable_transaction_keys(self, data):
"""
These keywords are unstable from Sbanken.
Sometimes they appear, sometimes not. This affects the encoding, if not handled.
"""
for transaction in data:
for keyword in self.unstable_transaction_keys:
if keyword in transaction:
del transaction[keyword]
def _remove_unbooked_transactions(
self, transactions: Iterable[Transaction]
) -> List[Transaction]:
for_keeps = filter(
lambda transaction: all(
keyword != transaction.text.lower()
for keyword in self.unbooked_text_keywords
),
transactions,
)
return list(for_keeps)