From 25a2326cf66638aed36e9b7e82b6beeaf76fef8d Mon Sep 17 00:00:00 2001 From: Herculino Trotta Date: Sun, 8 Nov 2026 12:39:17 -0300 Subject: [PATCH] feat(export): include bank sync services and account links in export and restore --- app/apps/export_app/forms.py | 16 +++++++++ app/apps/export_app/resources/bank_sync.py | 39 ++++++++++++++++++++++ app/apps/export_app/views.py | 9 +++++ 3 files changed, 64 insertions(+) create mode 100644 app/apps/export_app/resources/bank_sync.py diff --git a/app/apps/export_app/forms.py b/app/apps/export_app/forms.py index 1581791d..f9b2d229 100644 --- a/app/apps/export_app/forms.py +++ b/app/apps/export_app/forms.py @@ -73,6 +73,13 @@ class ExportForm(forms.Form): label=_("Automatic Exchange Rates"), initial=False, ) + bank_sync = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Bank Sync"), + help_text=_("Includes the providers' API keys"), + initial=False, + ) rules = forms.BooleanField( required=False, widget=forms.CheckboxInput(), @@ -110,6 +117,7 @@ class ExportForm(forms.Form): "recurring_transactions", "exchange_rates_services", "exchange_rates", + "bank_sync", "rules", "dca", "import_profiles", @@ -140,6 +148,12 @@ class RestoreForm(forms.Form): required=False, label=_("Automatic Exchange Rates") ) exchange_rates = forms.FileField(required=False, label=_("Exchange Rates")) + bank_sync_services = forms.FileField( + required=False, label=_("Bank Sync Services") + ) + bank_sync_accounts = forms.FileField( + required=False, label=_("Bank Sync Accounts") + ) transaction_rules = forms.FileField(required=False, label=_("Transaction rules")) transaction_rules_actions = forms.FileField( required=False, label=_("Edit transaction action") @@ -171,6 +185,8 @@ class RestoreForm(forms.Form): "recurring_transactions", "automatic_exchange_rates", "exchange_rates", + "bank_sync_services", + "bank_sync_accounts", "transaction_rules", "transaction_rules_actions", "transaction_rules_update_or_create", diff --git a/app/apps/export_app/resources/bank_sync.py b/app/apps/export_app/resources/bank_sync.py new file mode 100644 index 00000000..b3a2d4db --- /dev/null +++ b/app/apps/export_app/resources/bank_sync.py @@ -0,0 +1,39 @@ +from import_export import fields, resources, widgets + +from apps.accounts.models import Account +from apps.bank_sync.models import BankSyncAccount, BankSyncService + + +class _AnyOwnerWidget(widgets.ForeignKeyWidget): + """By id, across every user. + + The default managers only see the restoring user's rows, and names can clash + between users. Ids survive a restore. + """ + + def get_queryset(self, value, row, *args, **kwargs): + return self.model._base_manager.all() + + +class BankSyncServiceResource(resources.ModelResource): + class Meta: + model = BankSyncService + + def get_queryset(self): + return BankSyncService._base_manager.all() + + +class BankSyncAccountResource(resources.ModelResource): + service = fields.Field( + attribute="service", + column_name="service", + widget=_AnyOwnerWidget(BankSyncService), + ) + account = fields.Field( + attribute="account", + column_name="account", + widget=_AnyOwnerWidget(Account), + ) + + class Meta: + model = BankSyncAccount diff --git a/app/apps/export_app/views.py b/app/apps/export_app/views.py index b60f4a0c..a74e4ae0 100644 --- a/app/apps/export_app/views.py +++ b/app/apps/export_app/views.py @@ -15,6 +15,10 @@ from tablib import Dataset from apps.common.decorators.htmx import only_htmx from apps.export_app.forms import ExportForm, RestoreForm from apps.export_app.resources.accounts import AccountResource +from apps.export_app.resources.bank_sync import ( + BankSyncAccountResource, + BankSyncServiceResource, +) from apps.export_app.resources.currencies import ( CurrencyResource, ExchangeRateResource, @@ -119,6 +123,9 @@ def export_form(request): ) if export_exchange_rates: exports.append((ExchangeRateResource().export(), "exchange_rates")) + if form.cleaned_data.get("bank_sync"): + exports.append((BankSyncServiceResource().export(), "bank_sync_services")) + exports.append((BankSyncAccountResource().export(), "bank_sync_accounts")) if export_rules: exports.append( (TransactionRuleResource().export(), "transaction_rules") @@ -235,6 +242,8 @@ def process_imports(request, cleaned_data): ("installment_plans", InstallmentPlanResource), ("recurring_transactions", RecurringTransactionResource), ("transactions", TransactionResource), + ("bank_sync_services", BankSyncServiceResource), + ("bank_sync_accounts", BankSyncAccountResource), ("dca_strategies", DCAStrategyResource), ("dca_entries", DCAEntryResource), ("import_profiles", ImportProfileResource),