tariochbctools 1.4.1__py2.py3-none-any.whl → 1.5.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tariochbctools/importers/awardwalletimp/config.py +7 -8
- tariochbctools/importers/awardwalletimp/importer.py +73 -27
- tariochbctools/importers/radicant/importer.py +36 -6
- {tariochbctools-1.4.1.dist-info → tariochbctools-1.5.0.dist-info}/METADATA +2 -2
- {tariochbctools-1.4.1.dist-info → tariochbctools-1.5.0.dist-info}/RECORD +9 -9
- {tariochbctools-1.4.1.dist-info → tariochbctools-1.5.0.dist-info}/WHEEL +0 -0
- {tariochbctools-1.4.1.dist-info → tariochbctools-1.5.0.dist-info}/entry_points.txt +0 -0
- {tariochbctools-1.4.1.dist-info → tariochbctools-1.5.0.dist-info}/licenses/LICENSE.txt +0 -0
- {tariochbctools-1.4.1.dist-info → tariochbctools-1.5.0.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@ from typing import Any
|
|
5
5
|
|
6
6
|
import yaml
|
7
7
|
from awardwallet import AwardWalletClient
|
8
|
-
from awardwallet.
|
8
|
+
from awardwallet.client import AccessLevel
|
9
9
|
|
10
10
|
|
11
11
|
def get_link_url(client):
|
@@ -33,19 +33,18 @@ def generate(client):
|
|
33
33
|
connected_users = client.list_connected_users()
|
34
34
|
|
35
35
|
for user in connected_users:
|
36
|
-
|
37
|
-
user_details = client.get_connected_user_details(user_id)
|
36
|
+
user_details = client.get_connected_user_details(user.user_id)
|
38
37
|
account_config = {}
|
39
38
|
|
40
|
-
for account in user_details.
|
41
|
-
account_config[account
|
42
|
-
"provider": account
|
39
|
+
for account in user_details.accounts:
|
40
|
+
account_config[account.account_id] = {
|
41
|
+
"provider": account.display_name,
|
43
42
|
"account": "Assets:Current:Points", # Placeholder, user should adjust
|
44
43
|
"currency": "POINTS",
|
45
44
|
}
|
46
45
|
|
47
|
-
config["users"][user_id] = {
|
48
|
-
"name": user
|
46
|
+
config["users"][user.user_id] = {
|
47
|
+
"name": user.user_name,
|
49
48
|
"all_history": False,
|
50
49
|
"accounts": account_config,
|
51
50
|
}
|
@@ -1,11 +1,13 @@
|
|
1
|
+
import datetime
|
1
2
|
import logging
|
3
|
+
import re
|
4
|
+
from operator import attrgetter
|
2
5
|
from os import path
|
3
|
-
from typing import Any
|
4
6
|
|
5
7
|
import beangulp
|
6
8
|
import dateutil.parser
|
7
9
|
import yaml
|
8
|
-
from awardwallet import AwardWalletClient
|
10
|
+
from awardwallet import AwardWalletClient, model
|
9
11
|
from beancount.core import amount, data
|
10
12
|
from beancount.core.number import D
|
11
13
|
|
@@ -46,27 +48,33 @@ class Importer(beangulp.Importer):
|
|
46
48
|
return entries
|
47
49
|
|
48
50
|
def _extract_user_history(
|
49
|
-
self, user: dict, user_details:
|
51
|
+
self, user: dict, user_details: model.GetConnectedUserDetailsResponse
|
50
52
|
) -> list[data.Transaction]:
|
51
53
|
"""
|
52
54
|
User history is limited to the last 10 history elements per account
|
53
55
|
"""
|
54
56
|
entries = []
|
55
|
-
for account in user_details
|
56
|
-
account_id
|
57
|
-
|
58
|
-
|
59
|
-
logging.info("Extracting account ID %s", account_id)
|
60
|
-
account_config = user["accounts"][account_id]
|
57
|
+
for account in user_details.accounts:
|
58
|
+
if account.account_id in user["accounts"]:
|
59
|
+
logging.info("Extracting account ID %s", account.account_id)
|
60
|
+
account_config = user["accounts"][account.account_id]
|
61
61
|
|
62
62
|
entries.extend(
|
63
63
|
self._extract_transactions(
|
64
|
-
account
|
64
|
+
account.history, account_config, account.account_id
|
65
65
|
)
|
66
66
|
)
|
67
|
+
|
68
|
+
# we fudge the date by using the latest txn (across *all* accounts)
|
69
|
+
latest_txn = max(entries, key=attrgetter("date"), default=None)
|
70
|
+
entries.extend(
|
71
|
+
self._extract_balance(account, account_config, latest_txn)
|
72
|
+
)
|
67
73
|
else:
|
68
74
|
logging.warning(
|
69
|
-
"Ignoring account ID %s: %s",
|
75
|
+
"Ignoring account ID %s: %s",
|
76
|
+
account.account_id,
|
77
|
+
account.display_name,
|
70
78
|
)
|
71
79
|
return entries
|
72
80
|
|
@@ -76,13 +84,15 @@ class Importer(beangulp.Importer):
|
|
76
84
|
entries = []
|
77
85
|
for account_id, account_config in user["accounts"].items():
|
78
86
|
logging.info("Extracting account ID %s", account_id)
|
79
|
-
account = client.get_account_details(account_id)
|
87
|
+
account = client.get_account_details(account_id).account
|
80
88
|
|
81
89
|
entries.extend(
|
82
|
-
self._extract_transactions(
|
83
|
-
account["history"], account_config, account_id
|
84
|
-
)
|
90
|
+
self._extract_transactions(account.history, account_config, account_id)
|
85
91
|
)
|
92
|
+
|
93
|
+
# we fudge the date by using the latest txn (across *all* accounts)
|
94
|
+
latest_txn = max(entries, key=attrgetter("date"), default=None)
|
95
|
+
entries.extend(self._extract_balance(account, account_config, latest_txn))
|
86
96
|
return entries
|
87
97
|
|
88
98
|
def _extract_transactions(
|
@@ -109,7 +119,7 @@ class Importer(beangulp.Importer):
|
|
109
119
|
|
110
120
|
def _extract_transaction(
|
111
121
|
self,
|
112
|
-
trx:
|
122
|
+
trx: model.HistoryItem,
|
113
123
|
local_account: data.Account,
|
114
124
|
currency: str,
|
115
125
|
account_id: str,
|
@@ -121,20 +131,23 @@ class Importer(beangulp.Importer):
|
|
121
131
|
trx_description = None
|
122
132
|
trx_amount = None
|
123
133
|
|
124
|
-
for f in trx.
|
125
|
-
if f
|
126
|
-
trx_date = dateutil.parser.parse(f
|
127
|
-
if f
|
128
|
-
trx_description = f
|
129
|
-
if f
|
130
|
-
trx_amount = D(f
|
131
|
-
if f
|
132
|
-
name =
|
133
|
-
metakv[name] = f
|
134
|
+
for f in trx.fields:
|
135
|
+
if f.code == "PostingDate":
|
136
|
+
trx_date = dateutil.parser.parse(f.value.value).date()
|
137
|
+
if f.code == "Description":
|
138
|
+
trx_description = f.value.value.replace("\n", " ")
|
139
|
+
if f.code == "Miles":
|
140
|
+
trx_amount = D(f.value.value)
|
141
|
+
if f.code == "Info":
|
142
|
+
name = re.sub(r"\W", "-", f.name).lower()
|
143
|
+
metakv[name] = f.value.value.replace("\n", " ")
|
134
144
|
|
135
145
|
assert trx_date
|
136
146
|
assert trx_description
|
137
|
-
|
147
|
+
|
148
|
+
if trx_amount is None:
|
149
|
+
logging.warning("Skipping transaction with no amount: %s", trx)
|
150
|
+
return []
|
138
151
|
|
139
152
|
meta = data.new_metadata("", 0, metakv)
|
140
153
|
entry = data.Transaction(
|
@@ -158,3 +171,36 @@ class Importer(beangulp.Importer):
|
|
158
171
|
)
|
159
172
|
entries.append(entry)
|
160
173
|
return entries
|
174
|
+
|
175
|
+
def _extract_balance(
|
176
|
+
self,
|
177
|
+
account: model.Account,
|
178
|
+
account_config: dict,
|
179
|
+
latest_txn: data.Transaction | None,
|
180
|
+
) -> list[data.Transaction]:
|
181
|
+
local_account = account_config["account"]
|
182
|
+
currency = account_config["currency"]
|
183
|
+
balance = amount.Amount(D(account.balance_raw), currency)
|
184
|
+
metakv = {"account-id": str(account.account_id)}
|
185
|
+
|
186
|
+
optional_date = account.last_change_date or account.last_retrieve_date
|
187
|
+
if optional_date:
|
188
|
+
date = optional_date.date()
|
189
|
+
elif latest_txn:
|
190
|
+
date = latest_txn.date
|
191
|
+
else:
|
192
|
+
logging.warning(
|
193
|
+
"No date information available for balance of account %s, using today",
|
194
|
+
account.account_id,
|
195
|
+
)
|
196
|
+
date = datetime.date.today()
|
197
|
+
|
198
|
+
entry = data.Balance(
|
199
|
+
data.new_metadata("", 0, metakv),
|
200
|
+
date + datetime.timedelta(days=1),
|
201
|
+
local_account,
|
202
|
+
balance,
|
203
|
+
None,
|
204
|
+
None,
|
205
|
+
)
|
206
|
+
return [entry]
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from datetime import datetime
|
2
|
+
from datetime import datetime, timedelta
|
3
3
|
|
4
4
|
import beangulp
|
5
5
|
import camelot
|
@@ -46,6 +46,11 @@ class Importer(beangulp.Importer):
|
|
46
46
|
if conversionOriginal and conversionRate:
|
47
47
|
kv = {"original": conversionOriginal, "rate": conversionRate}
|
48
48
|
text = text.replace("Amount: " + conversionOriginal, "")
|
49
|
+
# handle decimal seperated original amounts
|
50
|
+
[originalCcy, originalAmt] = conversionOriginal.split(" ")
|
51
|
+
text = text.replace(
|
52
|
+
"Amount: " + f"{originalCcy} {float(originalAmt):,}", ""
|
53
|
+
)
|
49
54
|
else:
|
50
55
|
kv = None
|
51
56
|
|
@@ -63,17 +68,34 @@ class Importer(beangulp.Importer):
|
|
63
68
|
],
|
64
69
|
)
|
65
70
|
|
71
|
+
def createBalance(
|
72
|
+
self,
|
73
|
+
filepath: str,
|
74
|
+
date: str,
|
75
|
+
amt: amount.Amount,
|
76
|
+
) -> data.Balance:
|
77
|
+
meta = data.new_metadata(filepath, 0, None)
|
78
|
+
return data.Balance(
|
79
|
+
meta,
|
80
|
+
datetime.strptime(date, "%d.%m.%Y").date() + timedelta(days=1),
|
81
|
+
self._account,
|
82
|
+
amt,
|
83
|
+
None,
|
84
|
+
None,
|
85
|
+
)
|
86
|
+
|
66
87
|
def extract(self, filepath: str, existing: data.Entries) -> data.Entries:
|
67
88
|
entries = []
|
68
89
|
|
69
90
|
conversionPattern = re.compile(r"(?P<original>.+) at the rate of (?P<rate>.+)")
|
91
|
+
balancePattern = re.compile(r"Balance as of (?P<date>\d\d\.\d\d\.\d\d\d\d)")
|
70
92
|
|
71
93
|
tables = camelot.read_pdf(
|
72
94
|
filepath,
|
73
95
|
flavor="stream",
|
74
96
|
pages="all",
|
75
|
-
table_regions=["40,
|
76
|
-
columns=["110,
|
97
|
+
table_regions=["40,600,580,32"],
|
98
|
+
columns=["110,305,370,440,500"],
|
77
99
|
strip_text="\n",
|
78
100
|
layout_kwargs={"word_margin": 0.50},
|
79
101
|
split_text=True,
|
@@ -89,7 +111,7 @@ class Importer(beangulp.Importer):
|
|
89
111
|
conversionOriginal = None
|
90
112
|
conversionRate = None
|
91
113
|
for _, row in df.iterrows():
|
92
|
-
date, text, _, debit, credit,
|
114
|
+
date, text, _, debit, credit, bal = tuple(row)
|
93
115
|
|
94
116
|
# skip stuff before
|
95
117
|
if beforeStart and "Date" != date:
|
@@ -98,8 +120,16 @@ class Importer(beangulp.Importer):
|
|
98
120
|
beforeStart = False
|
99
121
|
continue
|
100
122
|
|
101
|
-
# skip stuff after
|
102
|
-
|
123
|
+
# create balance and skip stuff after
|
124
|
+
balanceMatch = balancePattern.match(text)
|
125
|
+
if balanceMatch:
|
126
|
+
entries.append(
|
127
|
+
self.createBalance(
|
128
|
+
filepath,
|
129
|
+
balanceMatch.group("date"),
|
130
|
+
amount.Amount(D(bal.replace("'", "")), self.currency),
|
131
|
+
)
|
132
|
+
)
|
103
133
|
break
|
104
134
|
|
105
135
|
trxDate = date
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: tariochbctools
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.5.0
|
4
4
|
Summary: Importers, plugins and price fetchers for Beancount
|
5
5
|
Home-page: https://github.com/tarioch/beancounttools/
|
6
6
|
Author: Patrick Ruckstuhl
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
19
19
|
Description-Content-Type: text/x-rst; charset=UTF-8
|
20
20
|
License-File: LICENSE.txt
|
21
21
|
Requires-Dist: importlib-metadata; python_version < "3.8"
|
22
|
-
Requires-Dist: awardwallet
|
22
|
+
Requires-Dist: awardwallet>=0.2
|
23
23
|
Requires-Dist: beancount>=3
|
24
24
|
Requires-Dist: beangulp
|
25
25
|
Requires-Dist: beanprice
|
@@ -1,8 +1,8 @@
|
|
1
1
|
tariochbctools/__init__.py,sha256=pH5i4Fj1tbXLqLtTVIdoojiplZssQn0nnud8-HXodRE,577
|
2
2
|
tariochbctools/importers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
tariochbctools/importers/awardwalletimp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
tariochbctools/importers/awardwalletimp/config.py,sha256=
|
5
|
-
tariochbctools/importers/awardwalletimp/importer.py,sha256=
|
4
|
+
tariochbctools/importers/awardwalletimp/config.py,sha256=OEhKKkA-lJqyT6QImqlsJVAT4iiNeGwX2DKNPZN6cic,2423
|
5
|
+
tariochbctools/importers/awardwalletimp/importer.py,sha256=Z4GeK3xqQTbdNDFQVObDXqL3SWX-KPjhbZ25TtBD-cg,6754
|
6
6
|
tariochbctools/importers/bcge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
tariochbctools/importers/bcge/importer.py,sha256=bAQpkBLURatdsfSoMQdiha-8QfExAXXvpzAgnFFMwoE,1176
|
8
8
|
tariochbctools/importers/bitst/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -30,7 +30,7 @@ tariochbctools/importers/postfinance/importer.py,sha256=PLBbnswb_tHt8wzd7yCC4UAW
|
|
30
30
|
tariochbctools/importers/quickfile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
31
|
tariochbctools/importers/quickfile/importer.py,sha256=HgS7lSi7egxkj-IWd77MS-vhepYNCRXZwVbeCornkzg,6479
|
32
32
|
tariochbctools/importers/radicant/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
-
tariochbctools/importers/radicant/importer.py,sha256=
|
33
|
+
tariochbctools/importers/radicant/importer.py,sha256=chjHX25YoU7jaonegJ8gaV2QzvSm7sdH8a7cj-rUmPA,5602
|
34
34
|
tariochbctools/importers/raiffeisench/importer.py,sha256=5r7hHEG0ZtEp-ePlsF4aHapBv9DJgjeVxE1m_G62bLU,912
|
35
35
|
tariochbctools/importers/revolut/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
36
|
tariochbctools/importers/revolut/importer.py,sha256=5jI91gGIDcP2TMFcauKkA9OWCTqCIl5Phz9n6r9kOeI,3953
|
@@ -53,9 +53,9 @@ tariochbctools/plugins/check_portfolio_sum.py,sha256=naJ2j6BFpQhJhT2c-gfjyIdcYe0
|
|
53
53
|
tariochbctools/plugins/generate_base_ccy_prices.py,sha256=4CDzUosjMWCZfsBJMLrf-i5WNCHexI2rdm5vIDYW-AI,1314
|
54
54
|
tariochbctools/plugins/prices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
55
|
tariochbctools/plugins/prices/ibkr.py,sha256=GYCjnlF-MK-ZFPEr0M6T4iO3Etq0tMmrMlsHGInXUO8,1405
|
56
|
-
tariochbctools-1.
|
57
|
-
tariochbctools-1.
|
58
|
-
tariochbctools-1.
|
59
|
-
tariochbctools-1.
|
60
|
-
tariochbctools-1.
|
61
|
-
tariochbctools-1.
|
56
|
+
tariochbctools-1.5.0.dist-info/licenses/LICENSE.txt,sha256=VR2hkz3p9Sw4hSXc7S5iZTOXGeV4h-i8AO_q0zEmtkE,1074
|
57
|
+
tariochbctools-1.5.0.dist-info/METADATA,sha256=WAKAVrIPoRzgeLpoIT5-UtSvJXRPpu5V9l4HA3Ad448,2180
|
58
|
+
tariochbctools-1.5.0.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
59
|
+
tariochbctools-1.5.0.dist-info/entry_points.txt,sha256=bo7wO1u-PIDHNuqsTEekC56VCAmn2i2vTRcKXxqc770,158
|
60
|
+
tariochbctools-1.5.0.dist-info/top_level.txt,sha256=CiA_NepCI6zDNsaORA55zmpuJFSnTvLESraIL13xiOQ,15
|
61
|
+
tariochbctools-1.5.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|