tariochbctools 1.4.1__tar.gz → 1.5.0__tar.gz
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-1.4.1 → tariochbctools-1.5.0}/PKG-INFO +2 -2
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/importers.rst +44 -27
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/setup.cfg +1 -1
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/awardwalletimp/config.py +7 -8
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/awardwalletimp/importer.py +73 -27
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/radicant/importer.py +36 -6
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/PKG-INFO +2 -2
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/requires.txt +1 -1
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/test_awardwallet.py +43 -30
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/.coveragerc +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/.isort.cfg +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/.pre-commit-config.yaml +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/.readthedocs.yml +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/LICENSE.txt +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/MANIFEST.in +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/README.rst +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/_static/.gitignore +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/conf.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/index.rst +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/installation.rst +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/license.rst +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/plugins.rst +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/price_fetchers.rst +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/docs/requirements.txt +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/pyproject.toml +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/setup.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/awardwalletimp/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/bcge/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/bcge/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/bitst/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/bitst/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/blockchain/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/blockchain/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/cembrastatement/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/cembrastatement/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/deduplication.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/mailAdapterImporter.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/mt940importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/priceLookup.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/ibkr/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/ibkr/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/neon/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/neon/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/netbenefits/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/netbenefits/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/nordigen/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/nordigen/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/nordigen/nordigen_config.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/postfinance/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/postfinance/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/quickfile/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/quickfile/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/radicant/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/raiffeisench/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/revolut/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/revolut/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/schedule/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/schedule/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/swisscard/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/swisscard/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/transferwise/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/transferwise/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/truelayer/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/truelayer/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/viseca/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/viseca/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/zak/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/zak/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/zkb/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/zkb/importer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/check_portfolio_sum.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/generate_base_ccy_prices.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/prices/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/prices/ibkr.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/SOURCES.txt +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/dependency_links.txt +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/entry_points.txt +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/not-zip-safe +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/top_level.txt +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/conftest.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/test_quickfile.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/test_truelayer.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/__init__.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/entry_already_exists_expected.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/entry_already_exists_input.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/issue122_expected.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/issue122_input.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/missing_fx_expected.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/missing_fx_input.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/normal_expected.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/data/generate_base_ccy_prices/normal_input.beancount +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/plugins/test_generate_base_ccy_prices.py +0 -0
- {tariochbctools-1.4.1 → tariochbctools-1.5.0}/tox.ini +0 -0
@@ -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
|
@@ -447,48 +447,65 @@ Import PDF from `radicant <https://radicant.com/>`__
|
|
447
447
|
AwardWallet
|
448
448
|
------------------------------
|
449
449
|
|
450
|
-
Import from `AwardWallet <https://awardwallet.com/>`__ using their `Account
|
450
|
+
Import from `AwardWallet <https://awardwallet.com/>`__ using their `Account
|
451
|
+
Access API <https://awardwallet.com/api/account>`__.
|
451
452
|
|
452
|
-
As of 2025 AwardWallet integrates over 460 airline, hotel, shopping and other
|
453
|
+
As of 2025 AwardWallet integrates over 460 airline, hotel, shopping and other
|
454
|
+
loyalty programmes. Many programmes do not support retrieval of transactions,
|
455
|
+
only balances.
|
453
456
|
|
454
|
-
|
457
|
+
1. Update your personal AwardWallet account.
|
458
|
+
The importer can only retrieve data that has already been synced to your AwardWallet account.
|
455
459
|
|
456
|
-
|
460
|
+
2. Follow the instructions in the `API documentation
|
461
|
+
<https://awardwallet.com/api/account#introduction>`__ to register for a
|
462
|
+
free Business account and create an API key.
|
457
463
|
|
458
|
-
|
464
|
+
The API key is restricted to the **allowed IP addresses** you specify in
|
465
|
+
the Business interface API Settings.
|
459
466
|
|
460
|
-
|
467
|
+
3. Link and authorize personal accounts using the included ``awardwallet-conf``
|
468
|
+
CLI tool:
|
461
469
|
|
462
|
-
|
470
|
+
.. code-block:: console
|
463
471
|
|
472
|
+
awardwallet-conf --api-key YOUR_API_KEY get_link_url
|
464
473
|
|
465
|
-
|
466
|
-
|
474
|
+
Manage access to your personal account under `Manage Users
|
475
|
+
<https://awardwallet.com/user/connections>`__ in the personal web
|
476
|
+
interface.
|
467
477
|
|
468
|
-
|
478
|
+
4. Generate a config file for all linked users ending with
|
479
|
+
``awardwallet.yaml`` in your import location (e.g. download folder) and
|
480
|
+
edit it to your needs.
|
469
481
|
|
470
|
-
|
482
|
+
.. code-block:: console
|
471
483
|
|
472
|
-
|
484
|
+
awardwallet-conf --api-key YOUR_API_KEY generate > awardwallet.yaml
|
473
485
|
|
474
|
-
|
486
|
+
If you have multiple accounts using the same points currency (e.g. ``AVIOS``
|
487
|
+
used by BA, Iberia, ...) create sub-accounts for each so that ``balance``
|
488
|
+
directives will work.
|
475
489
|
|
476
|
-
|
477
|
-
users:
|
478
|
-
12345:
|
479
|
-
name: John Smith
|
480
|
-
all_history: false
|
481
|
-
accounts:
|
482
|
-
7654321:
|
483
|
-
provider: "British Airways Club"
|
484
|
-
account: Assets:Current:Points
|
485
|
-
currency: AVIOS
|
490
|
+
Example configuration file:
|
486
491
|
|
492
|
+
.. code-block:: yaml
|
487
493
|
|
488
|
-
|
494
|
+
api_key: YOUR_API_KEY
|
495
|
+
users:
|
496
|
+
12345:
|
497
|
+
name: John Smith
|
498
|
+
all_history: false # only the last 10 txns per account
|
499
|
+
accounts:
|
500
|
+
7654321:
|
501
|
+
provider: "British Airways Club"
|
502
|
+
account: Assets:Current:Points
|
503
|
+
currency: AVIOS
|
489
504
|
|
490
|
-
|
505
|
+
5. Finally, initialize the importer:
|
506
|
+
|
507
|
+
.. code-block:: python
|
491
508
|
|
492
|
-
|
509
|
+
from tariochbctools.importers.awardwalletimp import importer as awimp
|
493
510
|
|
494
|
-
|
511
|
+
CONFIG = [awimp.Importer()]
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/awardwalletimp/config.py
RENAMED
@@ -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]
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/radicant/importer.py
RENAMED
@@ -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
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/test_awardwallet.py
RENAMED
@@ -2,6 +2,8 @@ import json
|
|
2
2
|
from unittest.mock import MagicMock, patch
|
3
3
|
|
4
4
|
import pytest
|
5
|
+
from awardwallet import model
|
6
|
+
from beancount.core.data import Balance
|
5
7
|
from beancount.core.number import D
|
6
8
|
|
7
9
|
from tariochbctools.importers.awardwalletimp import importer as awimp
|
@@ -25,6 +27,7 @@ TEST_CONFIG = b"""
|
|
25
27
|
currency: VIRGINPTS
|
26
28
|
34:
|
27
29
|
name: User with dummy account
|
30
|
+
all_history: true
|
28
31
|
accounts:
|
29
32
|
0:
|
30
33
|
"""
|
@@ -56,6 +59,7 @@ TEST_TRX = b"""
|
|
56
59
|
}
|
57
60
|
"""
|
58
61
|
|
62
|
+
# second account has no optional fields
|
59
63
|
TEST_USER_DETAILS = b"""
|
60
64
|
{
|
61
65
|
"userId": 12,
|
@@ -82,8 +86,8 @@ TEST_USER_DETAILS = b"""
|
|
82
86
|
"autologinUrl": "https://business.awardwallet.com/account/redirect?ID=7654321",
|
83
87
|
"updateUrl": "https://business.awardwallet.com/account/edit/7654321?autosubmit=1",
|
84
88
|
"editUrl": "https://business.awardwallet.com/account/edit/7654321",
|
85
|
-
"balance": "
|
86
|
-
"balanceRaw":
|
89
|
+
"balance": "123,456",
|
90
|
+
"balanceRaw": 123456,
|
87
91
|
"owner": "John Smith",
|
88
92
|
"errorCode": 1,
|
89
93
|
"lastDetectedChange": "+750",
|
@@ -93,49 +97,49 @@ TEST_USER_DETAILS = b"""
|
|
93
97
|
"properties": [
|
94
98
|
{
|
95
99
|
"name": "Next Elite Level",
|
96
|
-
"value":
|
100
|
+
"value": "Bronze",
|
97
101
|
"kind": 9
|
98
102
|
},
|
99
103
|
{
|
100
104
|
"name": "Date of joining the club",
|
101
|
-
"value":
|
105
|
+
"value": "20 Jun 2013",
|
102
106
|
"kind": 5
|
103
107
|
},
|
104
108
|
{
|
105
109
|
"name": "Lifetime Tier Points",
|
106
|
-
"value":
|
110
|
+
"value": "35,000"
|
107
111
|
},
|
108
112
|
{
|
109
113
|
"name": "Executive Club Tier Points",
|
110
|
-
"value":
|
114
|
+
"value": "35,000"
|
111
115
|
},
|
112
116
|
{
|
113
117
|
"name": "Card expiry date",
|
114
|
-
"value":
|
118
|
+
"value": "31 Mar 2017"
|
115
119
|
},
|
116
120
|
{
|
117
121
|
"name": "Membership year ends",
|
118
|
-
"value":
|
122
|
+
"value": "08 Feb 2016"
|
119
123
|
},
|
120
124
|
{
|
121
125
|
"name": "Last Activity",
|
122
|
-
"value":
|
126
|
+
"value": "10-Dec-15",
|
123
127
|
"kind": 13
|
124
128
|
},
|
125
129
|
{
|
126
130
|
"name": "Name",
|
127
|
-
"value":
|
131
|
+
"value": "Mr Smith",
|
128
132
|
"kind": 12
|
129
133
|
},
|
130
134
|
{
|
131
135
|
"name": "Level",
|
132
|
-
"value":
|
136
|
+
"value": "Blue",
|
133
137
|
"rank": 0,
|
134
138
|
"kind": 3
|
135
139
|
},
|
136
140
|
{
|
137
141
|
"name": "Membership no",
|
138
|
-
"value":
|
142
|
+
"value": "1122334455",
|
139
143
|
"kind": 1
|
140
144
|
}
|
141
145
|
],
|
@@ -219,18 +223,14 @@ TEST_USER_DETAILS = b"""
|
|
219
223
|
"code": "virgin",
|
220
224
|
"displayName": "Virgin Atlantic (Flying Club)",
|
221
225
|
"kind": "Airlines",
|
222
|
-
"
|
223
|
-
"
|
226
|
+
"login": "johnsmith",
|
227
|
+
"autologinUrl": "https://business.awardwallet.com/account/redirect?ID=7654321",
|
228
|
+
"updateUrl": "https://business.awardwallet.com/account/edit/7654321?autosubmit=1",
|
229
|
+
"editUrl": "https://business.awardwallet.com/account/edit/7654321",
|
230
|
+
"balance": "24,680",
|
231
|
+
"balanceRaw": 24680,
|
224
232
|
"owner": "John Smith",
|
225
233
|
"errorCode": 1,
|
226
|
-
"lastDetectedChange": "+750",
|
227
|
-
"properties": [
|
228
|
-
{
|
229
|
-
"name": "Next Elite Level",
|
230
|
-
"value": {"value": "Bronze", "type": "string"},
|
231
|
-
"kind": 9
|
232
|
-
}
|
233
|
-
],
|
234
234
|
"history": [
|
235
235
|
]
|
236
236
|
}
|
@@ -271,12 +271,14 @@ def awardwallet_importer_factory(tmp_path):
|
|
271
271
|
|
272
272
|
@pytest.fixture(name="tmp_trx")
|
273
273
|
def tmp_trx_fixture():
|
274
|
-
|
274
|
+
j = json.loads(TEST_TRX, strict=False)
|
275
|
+
yield model.HistoryItem(**j)
|
275
276
|
|
276
277
|
|
277
278
|
@pytest.fixture(name="tmp_user_details")
|
278
279
|
def tmp_user_details_fixture():
|
279
|
-
|
280
|
+
j = json.loads(TEST_USER_DETAILS, strict=False)
|
281
|
+
yield model.GetConnectedUserDetailsResponse(**j)
|
280
282
|
|
281
283
|
|
282
284
|
def test_identify(importer, tmp_config):
|
@@ -285,9 +287,7 @@ def test_identify(importer, tmp_config):
|
|
285
287
|
|
286
288
|
def test_extract_transaction_simple(importer, tmp_trx):
|
287
289
|
entries = importer._extract_transaction(tmp_trx, "Assets:Other", "POINTS", 7654321)
|
288
|
-
assert entries[0].postings[0].units.number == D(
|
289
|
-
tmp_trx["fields"][3]["value"]["value"]
|
290
|
-
)
|
290
|
+
assert entries[0].postings[0].units.number == D(tmp_trx.fields[3].value.value)
|
291
291
|
|
292
292
|
|
293
293
|
def test_extract_user_history(importer, tmp_user_details):
|
@@ -295,21 +295,34 @@ def test_extract_user_history(importer, tmp_user_details):
|
|
295
295
|
importer.config["users"][12],
|
296
296
|
tmp_user_details,
|
297
297
|
)
|
298
|
-
|
298
|
+
|
299
|
+
assert len(entries) == 5 # three txns, two balances
|
300
|
+
|
301
|
+
balances = [e for e in entries if isinstance(e, Balance)]
|
302
|
+
assert len(balances) == 2
|
303
|
+
assert balances[0].amount.number == D("123456")
|
304
|
+
assert balances[0].amount.currency == "AVIOS"
|
305
|
+
assert balances[1].amount.number == D("24680")
|
306
|
+
assert balances[1].amount.currency == "VIRGINPTS"
|
299
307
|
|
300
308
|
|
301
309
|
@patch("tariochbctools.importers.awardwalletimp.importer.AwardWalletClient")
|
302
310
|
def test_extract_all_users(mock_api, importer, tmp_config, tmp_user_details):
|
303
311
|
importer._extract_user_history = MagicMock()
|
312
|
+
importer._extract_account_history = MagicMock()
|
304
313
|
|
305
314
|
importer.extract(tmp_config)
|
306
|
-
assert importer._extract_user_history.call_count ==
|
315
|
+
assert importer._extract_user_history.call_count == 1
|
316
|
+
assert importer._extract_account_history.call_count == 1
|
307
317
|
|
308
318
|
|
309
319
|
@patch("tariochbctools.importers.awardwalletimp.importer.AwardWalletClient")
|
310
320
|
def test_extract_all_accounts(mock_api, importer, tmp_config, tmp_user_details):
|
311
321
|
importer._extract_transactions = MagicMock()
|
322
|
+
importer._extract_balance = MagicMock()
|
312
323
|
mock_api.return_value.get_connected_user_details.return_value = tmp_user_details
|
324
|
+
# get_account_details mock (for user 34) returns zero txns
|
313
325
|
|
314
326
|
importer.extract(tmp_config)
|
315
|
-
assert importer._extract_transactions.call_count ==
|
327
|
+
assert importer._extract_transactions.call_count == 3
|
328
|
+
assert importer._extract_balance.call_count == 3
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/bitst/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/bitst/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/blockchain/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/blockchain/importer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/deduplication.py
RENAMED
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/mt940importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/general/priceLookup.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/netbenefits/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/netbenefits/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/nordigen/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/nordigen/importer.py
RENAMED
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/postfinance/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/postfinance/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/quickfile/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/quickfile/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/radicant/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/raiffeisench/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/revolut/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/revolut/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/schedule/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/schedule/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/swisscard/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/swisscard/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/transferwise/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/transferwise/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/truelayer/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/truelayer/importer.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/viseca/__init__.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/importers/viseca/importer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/check_portfolio_sum.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools/plugins/generate_base_ccy_prices.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/src/tariochbctools.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/test_quickfile.py
RENAMED
File without changes
|
{tariochbctools-1.4.1 → tariochbctools-1.5.0}/tests/tariochbctools/importers/test_truelayer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|