From 9ecf8279b4271ef0db970ba77a73b1d7b5aedb08 Mon Sep 17 00:00:00 2001 From: pawelaugustyn <26120235+pawelaugustyn@users.noreply.github.com> Date: Sun, 15 Feb 2026 22:59:17 +0100 Subject: [PATCH 1/3] feat: default account for new transactions --- app/apps/transactions/forms.py | 11 +++++++++ app/apps/users/forms.py | 24 +++++++++++++++++++ .../0024_usersettings_default_account.py | 20 ++++++++++++++++ app/apps/users/models.py | 6 +++++ 4 files changed, 61 insertions(+) create mode 100644 app/apps/users/migrations/0024_usersettings_default_account.py diff --git a/app/apps/transactions/forms.py b/app/apps/transactions/forms.py index f6f9b70..04fafe8 100644 --- a/app/apps/transactions/forms.py +++ b/app/apps/transactions/forms.py @@ -5,6 +5,7 @@ from apps.common.fields.forms.dynamic_select import ( DynamicModelChoiceField, DynamicModelMultipleChoiceField, ) +from apps.common.middleware.thread_local import get_current_user from apps.common.widgets.crispy.daisyui import Switch from apps.common.widgets.crispy.submit import NoClassSubmit from apps.common.widgets.datepicker import AirDatePickerInput, AirMonthYearPickerInput @@ -116,6 +117,9 @@ class TransactionForm(forms.ModelForm): self.fields["account"].queryset = Account.objects.filter( is_archived=False, ) + user_settings = get_current_user().settings + if user_settings.default_account: + self.fields["account"].initial = user_settings.default_account self.fields["category"].queryset = TransactionCategory.objects.filter( active=True @@ -768,6 +772,9 @@ class InstallmentPlanForm(forms.ModelForm): ).distinct() else: self.fields["account"].queryset = Account.objects.filter(is_archived=False) + user_settings = get_current_user().settings + if user_settings.default_account: + self.fields["account"].initial = user_settings.default_account self.fields["category"].queryset = TransactionCategory.objects.filter( active=True @@ -1010,6 +1017,10 @@ class RecurringTransactionForm(forms.ModelForm): ).distinct() else: self.fields["account"].queryset = Account.objects.filter(is_archived=False) + + user_settings = get_current_user().settings + if user_settings.default_account: + self.fields["account"].initial = user_settings.default_account self.fields["category"].queryset = TransactionCategory.objects.filter( active=True diff --git a/app/apps/users/forms.py b/app/apps/users/forms.py index e48aaac..71e1b5f 100644 --- a/app/apps/users/forms.py +++ b/app/apps/users/forms.py @@ -1,6 +1,8 @@ from apps.common.middleware.thread_local import get_current_user from apps.common.widgets.crispy.submit import NoClassSubmit +from apps.common.widgets.tom_select import TomSelect from apps.users.models import UserSettings +from apps.accounts.models import Account from crispy_forms.bootstrap import ( FormActions, ) @@ -116,6 +118,15 @@ class UserSettingsForm(forms.ModelForm): label=_("Number Format"), ) + default_account = forms.ModelChoiceField( + queryset=Account.objects.filter( + is_archived=False, + ), + label=_("Default Account"), + widget=TomSelect(clear_button=False, group_by="group"), + required=False, + ) + class Meta: model = UserSettings fields = [ @@ -126,11 +137,19 @@ class UserSettingsForm(forms.ModelForm): "datetime_format", "number_format", "volume", + "default_account", ] + widgets = { + "default_account": TomSelect(clear_button=False, group_by="group"), + } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.fields["default_account"].queryset = Account.objects.filter( + is_archived=False, + ) + self.helper = FormHelper() self.helper.form_tag = False self.helper.form_method = "post" @@ -141,6 +160,7 @@ class UserSettingsForm(forms.ModelForm): "date_format", "datetime_format", "number_format", + "default_account", HTML('
'), "start_page", HTML('
'), @@ -157,6 +177,10 @@ class UserSettingsForm(forms.ModelForm): "translation_link": 'translations.herculino.com' } + self.fields["default_account"].help_text = _( + "Selects the account by default when creating new transactions" + ) + class UserUpdateForm(forms.ModelForm): new_password1 = forms.CharField( diff --git a/app/apps/users/migrations/0024_usersettings_default_account.py b/app/apps/users/migrations/0024_usersettings_default_account.py new file mode 100644 index 0000000..4fc6caa --- /dev/null +++ b/app/apps/users/migrations/0024_usersettings_default_account.py @@ -0,0 +1,20 @@ +# Generated by Django 5.2.9 on 2026-02-15 21:35 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0016_account_untracked_by'), + ('users', '0023_alter_usersettings_timezone'), + ] + + operations = [ + migrations.AddField( + model_name='usersettings', + name='default_account', + field=models.ForeignKey(blank=True, default=0, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.account', verbose_name='Default account'), + ), + ] diff --git a/app/apps/users/models.py b/app/apps/users/models.py index 6f286c7..aec7919 100644 --- a/app/apps/users/models.py +++ b/app/apps/users/models.py @@ -510,6 +510,12 @@ class UserSettings(models.Model): default=StartPage.MONTHLY, verbose_name=_("Start page"), ) + default_account = models.ForeignKey( + "accounts.Account", on_delete=models.SET_NULL, + verbose_name=_("Default account"), + blank=True, + null=True, + ) def __str__(self): return f"{self.user.email}'s settings" From 0413921dbe7a7ed1f0809fd39ee96be222ae3781 Mon Sep 17 00:00:00 2001 From: Herculino Trotta Date: Sun, 15 Feb 2026 23:22:10 -0300 Subject: [PATCH 2/3] fix: migrations set default as 0 instead of null --- .../0024_usersettings_default_account.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/apps/users/migrations/0024_usersettings_default_account.py b/app/apps/users/migrations/0024_usersettings_default_account.py index 4fc6caa..0523c80 100644 --- a/app/apps/users/migrations/0024_usersettings_default_account.py +++ b/app/apps/users/migrations/0024_usersettings_default_account.py @@ -5,16 +5,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0016_account_untracked_by'), - ('users', '0023_alter_usersettings_timezone'), + ("accounts", "0016_account_untracked_by"), + ("users", "0023_alter_usersettings_timezone"), ] operations = [ migrations.AddField( - model_name='usersettings', - name='default_account', - field=models.ForeignKey(blank=True, default=0, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.account', verbose_name='Default account'), + model_name="usersettings", + name="default_account", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="accounts.account", + verbose_name="Default account", + ), ), ] From c787565c04ba4b263223727340da43371128a082 Mon Sep 17 00:00:00 2001 From: Herculino Trotta Date: Sun, 15 Feb 2026 23:22:52 -0300 Subject: [PATCH 3/3] refactor: move help_text to model definition --- app/apps/users/forms.py | 10 +++------- ...0025_alter_usersettings_default_account.py | 20 +++++++++++++++++++ app/apps/users/models.py | 4 +++- 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 app/apps/users/migrations/0025_alter_usersettings_default_account.py diff --git a/app/apps/users/forms.py b/app/apps/users/forms.py index 71e1b5f..a2b06e9 100644 --- a/app/apps/users/forms.py +++ b/app/apps/users/forms.py @@ -120,8 +120,8 @@ class UserSettingsForm(forms.ModelForm): default_account = forms.ModelChoiceField( queryset=Account.objects.filter( - is_archived=False, - ), + is_archived=False, + ), label=_("Default Account"), widget=TomSelect(clear_button=False, group_by="group"), required=False, @@ -160,9 +160,9 @@ class UserSettingsForm(forms.ModelForm): "date_format", "datetime_format", "number_format", - "default_account", HTML('
'), "start_page", + "default_account", HTML('
'), "volume", FormActions( @@ -177,10 +177,6 @@ class UserSettingsForm(forms.ModelForm): "translation_link": 'translations.herculino.com' } - self.fields["default_account"].help_text = _( - "Selects the account by default when creating new transactions" - ) - class UserUpdateForm(forms.ModelForm): new_password1 = forms.CharField( diff --git a/app/apps/users/migrations/0025_alter_usersettings_default_account.py b/app/apps/users/migrations/0025_alter_usersettings_default_account.py new file mode 100644 index 0000000..d10bef2 --- /dev/null +++ b/app/apps/users/migrations/0025_alter_usersettings_default_account.py @@ -0,0 +1,20 @@ +# Generated by Django 5.2.9 on 2026-02-16 01:32 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0016_account_untracked_by'), + ('users', '0024_usersettings_default_account'), + ] + + operations = [ + migrations.AlterField( + model_name='usersettings', + name='default_account', + field=models.ForeignKey(blank=True, help_text='Selects the account by default when creating new transactions', null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.account', verbose_name='Default account'), + ), + ] diff --git a/app/apps/users/models.py b/app/apps/users/models.py index aec7919..d1e4b32 100644 --- a/app/apps/users/models.py +++ b/app/apps/users/models.py @@ -511,8 +511,10 @@ class UserSettings(models.Model): verbose_name=_("Start page"), ) default_account = models.ForeignKey( - "accounts.Account", on_delete=models.SET_NULL, + "accounts.Account", + on_delete=models.SET_NULL, verbose_name=_("Default account"), + help_text=_("Selects the account by default when creating new transactions"), blank=True, null=True, )