|
|
@@ -1,9 +1,9 @@ |
|
|
import glob |
|
|
import glob |
|
|
import logging |
|
|
import logging |
|
|
import pandas as pd |
|
|
import pandas as pd |
|
|
import ynab |
|
|
|
|
|
from pathlib import Path |
|
|
from pathlib import Path |
|
|
|
|
|
|
|
|
|
|
|
from ynab_api import write_to_api |
|
|
from bank_parsers.sparebank1 import parse_sparebank1 |
|
|
from bank_parsers.sparebank1 import parse_sparebank1 |
|
|
from bank_parsers.bank_norwegian import parse_bank_norwegian |
|
|
from bank_parsers.bank_norwegian import parse_bank_norwegian |
|
|
from bank_parsers.sparebanken_norge import parse_sparebanken_norge |
|
|
from bank_parsers.sparebanken_norge import parse_sparebanken_norge |
|
|
@@ -121,72 +121,6 @@ def write_output_file(bank_name, bank_config, ynab_data, output_directory, overw |
|
|
logging.info(f"Data saved to {output_file}") |
|
|
logging.info(f"Data saved to {output_file}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def write_to_api(file_path, ynab_data, api_token): |
|
|
|
|
|
configuration = ynab.Configuration( |
|
|
|
|
|
access_token = api_token |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
with ynab.ApiClient(configuration) as api_client: |
|
|
|
|
|
budgets_api = ynab.BudgetsApi(api_client) |
|
|
|
|
|
budgets = budgets_api.get_budgets().data.budgets |
|
|
|
|
|
|
|
|
|
|
|
if len(budgets) == 1: |
|
|
|
|
|
budget = budgets[0] |
|
|
|
|
|
else: |
|
|
|
|
|
budget_options = ", ".join([f"{i}: {budget.name}" for i, budget in enumerate(budgets)]) |
|
|
|
|
|
print(f"Which budget should {file_path} be imported to?") |
|
|
|
|
|
budget_index = input(f"{budget_options} ") |
|
|
|
|
|
budget = budgets[int(budget_index)] |
|
|
|
|
|
|
|
|
|
|
|
accounts_api = ynab.AccountsApi(api_client) |
|
|
|
|
|
accounts = accounts_api.get_accounts(budget.id).data.accounts |
|
|
|
|
|
|
|
|
|
|
|
if len(accounts) == 1: |
|
|
|
|
|
account = accounts[0] |
|
|
|
|
|
else: |
|
|
|
|
|
account_options = ", ".join([f"{i}: {account.name}" for i, account in enumerate(accounts)]) |
|
|
|
|
|
account_index = input(f"Which account? {account_options} ") |
|
|
|
|
|
account = accounts[int(account_index)] |
|
|
|
|
|
|
|
|
|
|
|
transactions = [] |
|
|
|
|
|
|
|
|
|
|
|
for i, row in ynab_data.iterrows(): |
|
|
|
|
|
import_id = f"IMPORT:{row['Date'].date()}:{row['Inflow']}:{row['Outflow']}:{i}" |
|
|
|
|
|
amount = int((row['Inflow'] - row['Outflow']) * 100) |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
transaction = ynab.models.new_transaction.NewTransaction( |
|
|
|
|
|
account_id = account.id, |
|
|
|
|
|
var_date = row['Date'], |
|
|
|
|
|
amount = amount, |
|
|
|
|
|
payee_name = row['Payee'], |
|
|
|
|
|
memo = row['Memo'], |
|
|
|
|
|
cleared = 'cleared' if row['Cleared'] else 'uncleared', |
|
|
|
|
|
import_id = import_id, |
|
|
|
|
|
) |
|
|
|
|
|
except: |
|
|
|
|
|
logging.error(f"Could not format transaction {row} for YNAB") |
|
|
|
|
|
raise |
|
|
|
|
|
|
|
|
|
|
|
transactions.append(transaction) |
|
|
|
|
|
|
|
|
|
|
|
print(f"Adding {len(transactions)} transactions to account {account.name} in budget {budget.name}:") |
|
|
|
|
|
print(f"{'Date':<12}{'Payee':<50}{'Memo':<50}{'Amount':10}{'Status':<9}{'Import ID'}") |
|
|
|
|
|
for transaction in transactions: |
|
|
|
|
|
print(f"{transaction.var_date} {transaction.payee_name:<50}{transaction.memo:<50}{transaction.amount/100:<10}{transaction.cleared:<9}{transaction.import_id}") |
|
|
|
|
|
|
|
|
|
|
|
confirmed = input("Is this correct? (y/N) ") |
|
|
|
|
|
if confirmed.lower() != 'y': |
|
|
|
|
|
print("Stopping processing") |
|
|
|
|
|
exit(1) |
|
|
|
|
|
|
|
|
|
|
|
transaction_api = ynab.TransactionsApi(api_client) |
|
|
|
|
|
transaction_data = ynab.PostTransactionsWrapper() |
|
|
|
|
|
transaction_data.transactions = transactions |
|
|
|
|
|
response = transaction_api.create_transaction(budget.id, transaction_data) |
|
|
|
|
|
logging.debug(f"Create transaction response: {response}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_on_success(file_path, on_success, archive_directory, overwrite): |
|
|
def handle_on_success(file_path, on_success, archive_directory, overwrite): |
|
|
if on_success == 'delete': |
|
|
if on_success == 'delete': |
|
|
logging.info(f"Deleting {file_path}") |
|
|
logging.info(f"Deleting {file_path}") |
|
|
@@ -259,7 +193,7 @@ def convert_bank_statements_to_ynab(input_paths, output_directory, archive_direc |
|
|
if output_type == 'file': |
|
|
if output_type == 'file': |
|
|
write_output_file(bank_name, bank_config, ynab_data, output_directory, overwrite) |
|
|
write_output_file(bank_name, bank_config, ynab_data, output_directory, overwrite) |
|
|
elif output_type == 'api': |
|
|
elif output_type == 'api': |
|
|
write_to_api(file_path, ynab_data, api_token) |
|
|
|
|
|
|
|
|
write_to_api(file_path, bank_name, ynab_data, api_token) |
|
|
else: |
|
|
else: |
|
|
logging.error(f"Unknown output type '{output_type}'") |
|
|
logging.error(f"Unknown output type '{output_type}'") |
|
|
exit(1) |
|
|
exit(1) |
|
|
|