mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-04-23 09:08:39 +02:00
refactor: move some fields and widgets around
This commit is contained in:
@@ -14,7 +14,7 @@ from apps.common.fields.forms.dynamic_select import (
|
|||||||
from apps.common.widgets.crispy.submit import NoClassSubmit
|
from apps.common.widgets.crispy.submit import NoClassSubmit
|
||||||
from apps.common.widgets.tom_select import TomSelect
|
from apps.common.widgets.tom_select import TomSelect
|
||||||
from apps.transactions.models import TransactionCategory, TransactionTag
|
from apps.transactions.models import TransactionCategory, TransactionTag
|
||||||
from apps.transactions.widgets import ArbitraryDecimalDisplayNumberInput
|
from apps.common.widgets.decimal import ArbitraryDecimalDisplayNumberInput
|
||||||
|
|
||||||
|
|
||||||
class AccountGroupForm(forms.ModelForm):
|
class AccountGroupForm(forms.ModelForm):
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ from django import forms
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from apps.transactions.widgets import MonthYearWidget
|
from apps.common.widgets.month_year import MonthYearWidget
|
||||||
|
|
||||||
|
|
||||||
class MonthYearField(models.DateField):
|
class MonthYearModelField(models.DateField):
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
if value is None or isinstance(value, datetime.date):
|
if value is None or isinstance(value, datetime.date):
|
||||||
return value
|
return value
|
||||||
@@ -27,6 +27,8 @@ class MonthYearField(models.DateField):
|
|||||||
|
|
||||||
|
|
||||||
class MonthYearFormField(forms.DateField):
|
class MonthYearFormField(forms.DateField):
|
||||||
|
widget = MonthYearWidget
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.input_formats = ["%Y-%m"]
|
self.input_formats = ["%Y-%m"]
|
||||||
@@ -34,11 +36,13 @@ class MonthYearFormField(forms.DateField):
|
|||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
if value in self.empty_values:
|
if value in self.empty_values:
|
||||||
return None
|
return None
|
||||||
|
if isinstance(value, datetime.datetime):
|
||||||
|
return value.date()
|
||||||
try:
|
try:
|
||||||
date = datetime.datetime.strptime(value, "%Y-%m")
|
date = datetime.datetime.strptime(value, "%Y-%m")
|
||||||
return date.replace(day=1).date()
|
return date.replace(day=1).date()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError("Invalid date format. Use YYYY-MM.")
|
raise ValidationError(_("Invalid date format. Use YYYY-MM."))
|
||||||
|
|
||||||
def prepare_value(self, value):
|
def prepare_value(self, value):
|
||||||
if isinstance(value, datetime.date):
|
if isinstance(value, datetime.date):
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
from datetime import datetime, date
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from decimal import Decimal, InvalidOperation
|
from decimal import Decimal, InvalidOperation
|
||||||
|
|
||||||
from django.template.defaultfilters import floatformat
|
from django import forms
|
||||||
from django.utils.formats import get_format, number_format
|
from django.utils.formats import get_format, number_format
|
||||||
|
|
||||||
|
|
||||||
@@ -25,19 +22,6 @@ def convert_to_decimal(value: str):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class MonthYearWidget(forms.DateInput):
|
|
||||||
"""
|
|
||||||
Custom widget to display a month-year picker.
|
|
||||||
"""
|
|
||||||
|
|
||||||
input_type = "month" # Set the input type to 'month'
|
|
||||||
|
|
||||||
def format_value(self, value):
|
|
||||||
if isinstance(value, (datetime, date)):
|
|
||||||
return value.strftime("%Y-%m")
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class ArbitraryDecimalDisplayNumberInput(forms.TextInput):
|
class ArbitraryDecimalDisplayNumberInput(forms.TextInput):
|
||||||
"""A widget for displaying and inputing decimal numbers with the least amount of trailing zeros possible. You
|
"""A widget for displaying and inputing decimal numbers with the least amount of trailing zeros possible. You
|
||||||
must set this on your Form's __init__ method."""
|
must set this on your Form's __init__ method."""
|
||||||
16
app/apps/common/widgets/month_year.py
Normal file
16
app/apps/common/widgets/month_year.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
|
||||||
|
class MonthYearWidget(forms.DateInput):
|
||||||
|
"""
|
||||||
|
Custom widget to display a month-year picker.
|
||||||
|
"""
|
||||||
|
|
||||||
|
input_type = "month" # Set the input type to 'month'
|
||||||
|
|
||||||
|
def format_value(self, value):
|
||||||
|
if isinstance(value, (datetime, date)):
|
||||||
|
return value.strftime("%Y-%m")
|
||||||
|
return value
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
from crispy_bootstrap5.bootstrap5 import Switch
|
from crispy_bootstrap5.bootstrap5 import Switch
|
||||||
from crispy_forms.bootstrap import FormActions
|
from crispy_forms.bootstrap import FormActions
|
||||||
from crispy_forms.helper import FormHelper
|
from crispy_forms.helper import FormHelper
|
||||||
from crispy_forms.layout import Layout, Row, Column, Field, Fieldset
|
from crispy_forms.layout import Layout, Row, Column, Field
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from apps.accounts.models import Account
|
from apps.accounts.models import Account
|
||||||
@@ -14,17 +13,15 @@ from apps.common.fields.forms.dynamic_select import (
|
|||||||
DynamicModelMultipleChoiceField,
|
DynamicModelMultipleChoiceField,
|
||||||
)
|
)
|
||||||
from apps.common.widgets.crispy.submit import NoClassSubmit
|
from apps.common.widgets.crispy.submit import NoClassSubmit
|
||||||
from apps.common.widgets.tom_select import TomSelect, TomSelectMultiple
|
from apps.common.widgets.tom_select import TomSelect
|
||||||
from apps.transactions.models import (
|
from apps.transactions.models import (
|
||||||
Transaction,
|
Transaction,
|
||||||
TransactionCategory,
|
TransactionCategory,
|
||||||
TransactionTag,
|
TransactionTag,
|
||||||
InstallmentPlan,
|
InstallmentPlan,
|
||||||
)
|
)
|
||||||
from apps.transactions.widgets import (
|
from apps.common.widgets.decimal import ArbitraryDecimalDisplayNumberInput
|
||||||
ArbitraryDecimalDisplayNumberInput,
|
from apps.common.fields.month_year import MonthYearFormField
|
||||||
MonthYearWidget,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionForm(forms.ModelForm):
|
class TransactionForm(forms.ModelForm):
|
||||||
@@ -40,6 +37,7 @@ class TransactionForm(forms.ModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=_("Tags"),
|
label=_("Tags"),
|
||||||
)
|
)
|
||||||
|
reference_date = MonthYearFormField(label=_("Reference Date"), required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Transaction
|
model = Transaction
|
||||||
@@ -190,7 +188,7 @@ class TransferForm(forms.Form):
|
|||||||
date = forms.DateField(
|
date = forms.DateField(
|
||||||
label="Date", widget=forms.DateInput(attrs={"type": "date"}, format="%Y-%m-%d")
|
label="Date", widget=forms.DateInput(attrs={"type": "date"}, format="%Y-%m-%d")
|
||||||
)
|
)
|
||||||
reference_date = forms.CharField(label="Reference Date", widget=MonthYearWidget())
|
reference_date = MonthYearFormField(label=_("Reference Date"), required=False)
|
||||||
description = forms.CharField(max_length=500, label="Description")
|
description = forms.CharField(max_length=500, label="Description")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -324,6 +322,7 @@ class InstallmentPlanForm(forms.Form):
|
|||||||
label=_("Start Date"),
|
label=_("Start Date"),
|
||||||
widget=forms.DateInput(attrs={"type": "date"}, format="%Y-%m-%d"),
|
widget=forms.DateInput(attrs={"type": "date"}, format="%Y-%m-%d"),
|
||||||
)
|
)
|
||||||
|
reference_date = MonthYearFormField(label=_("Reference Date"), required=False)
|
||||||
description = forms.CharField(max_length=500, label=_("Description"))
|
description = forms.CharField(max_length=500, label=_("Description"))
|
||||||
number_of_installments = forms.IntegerField(
|
number_of_installments = forms.IntegerField(
|
||||||
min_value=1, label=_("Number of Installments")
|
min_value=1, label=_("Number of Installments")
|
||||||
@@ -372,9 +371,13 @@ class InstallmentPlanForm(forms.Form):
|
|||||||
"account",
|
"account",
|
||||||
"description",
|
"description",
|
||||||
Row(
|
Row(
|
||||||
Column("start_date", css_class="form-group col-md-4 mb-0"),
|
Column("number_of_installments", css_class="form-group col-md-6 mb-0"),
|
||||||
Column("number_of_installments", css_class="form-group col-md-4 mb-0"),
|
Column("recurrence", css_class="form-group col-md-6 mb-0"),
|
||||||
Column("recurrence", css_class="form-group col-md-4 mb-0"),
|
css_class="form-row",
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
Column("start_date", css_class="form-group col-md-6 mb-0"),
|
||||||
|
Column("reference_date", css_class="form-group col-md-6 mb-0"),
|
||||||
css_class="form-row",
|
css_class="form-row",
|
||||||
),
|
),
|
||||||
"installment_amount",
|
"installment_amount",
|
||||||
@@ -396,12 +399,16 @@ class InstallmentPlanForm(forms.Form):
|
|||||||
number_of_installments = self.cleaned_data["number_of_installments"]
|
number_of_installments = self.cleaned_data["number_of_installments"]
|
||||||
transaction_type = self.cleaned_data["type"]
|
transaction_type = self.cleaned_data["type"]
|
||||||
start_date = self.cleaned_data["start_date"]
|
start_date = self.cleaned_data["start_date"]
|
||||||
|
reference_date = self.cleaned_data["reference_date"] or start_date
|
||||||
recurrence = self.cleaned_data["recurrence"]
|
recurrence = self.cleaned_data["recurrence"]
|
||||||
account = self.cleaned_data["account"]
|
account = self.cleaned_data["account"]
|
||||||
description = self.cleaned_data["description"]
|
description = self.cleaned_data["description"]
|
||||||
installment_amount = self.cleaned_data["installment_amount"]
|
installment_amount = self.cleaned_data["installment_amount"]
|
||||||
category = self.cleaned_data["category"]
|
category = self.cleaned_data["category"]
|
||||||
|
|
||||||
|
print(reference_date, type(reference_date))
|
||||||
|
print(start_date, type(start_date))
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
installment_plan = InstallmentPlan.objects.create(
|
installment_plan = InstallmentPlan.objects.create(
|
||||||
account=account,
|
account=account,
|
||||||
@@ -421,11 +428,13 @@ class InstallmentPlanForm(forms.Form):
|
|||||||
delta = relativedelta(days=i)
|
delta = relativedelta(days=i)
|
||||||
|
|
||||||
transaction_date = start_date + delta
|
transaction_date = start_date + delta
|
||||||
|
transaction_reference_date = (reference_date + delta).replace(day=1)
|
||||||
new_transaction = Transaction.objects.create(
|
new_transaction = Transaction.objects.create(
|
||||||
account=account,
|
account=account,
|
||||||
type=transaction_type,
|
type=transaction_type,
|
||||||
date=transaction_date,
|
date=transaction_date,
|
||||||
reference_date=transaction_date.replace(day=1),
|
is_paid=False,
|
||||||
|
reference_date=transaction_reference_date,
|
||||||
amount=installment_amount,
|
amount=installment_amount,
|
||||||
description=description,
|
description=description,
|
||||||
notes=f"{i + 1}/{number_of_installments}",
|
notes=f"{i + 1}/{number_of_installments}",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Generated by Django 5.1.1 on 2024-09-19 02:11
|
# Generated by Django 5.1.1 on 2024-09-19 02:11
|
||||||
|
|
||||||
import apps.transactions.fields
|
import apps.common.fields.month_year
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@@ -8,19 +8,31 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = []
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Transaction',
|
name="Transaction",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
('is_paid', models.BooleanField(default=True)),
|
"id",
|
||||||
('date', models.DateField()),
|
models.BigAutoField(
|
||||||
('reference_date', apps.transactions.fields.MonthYearField(help_text='Please enter a month and year in the format MM/YYYY.')),
|
auto_created=True,
|
||||||
('description', models.CharField(max_length=500)),
|
primary_key=True,
|
||||||
('notes', models.TextField(blank=True)),
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("is_paid", models.BooleanField(default=True)),
|
||||||
|
("date", models.DateField()),
|
||||||
|
(
|
||||||
|
"reference_date",
|
||||||
|
apps.common.fields.month_year.MonthYearModelField(
|
||||||
|
help_text="Please enter a month and year in the format MM/YYYY."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("description", models.CharField(max_length=500)),
|
||||||
|
("notes", models.TextField(blank=True)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Generated by Django 5.1.1 on 2024-09-19 13:35
|
# Generated by Django 5.1.1 on 2024-09-19 13:35
|
||||||
|
|
||||||
import apps.transactions.fields
|
import apps.common.fields.month_year
|
||||||
import apps.transactions.validators
|
import apps.transactions.validators
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@@ -9,46 +9,62 @@ from django.db import migrations, models
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('accounts', '0001_initial'),
|
("accounts", "0001_initial"),
|
||||||
('transactions', '0001_initial'),
|
("transactions", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='account',
|
name="account",
|
||||||
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.PROTECT, to='accounts.account', verbose_name='Account'),
|
field=models.ForeignKey(
|
||||||
|
default=0,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
to="accounts.account",
|
||||||
|
verbose_name="Account",
|
||||||
|
),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='amount',
|
name="amount",
|
||||||
field=models.DecimalField(decimal_places=18, default=0, max_digits=30, validators=[apps.transactions.validators.validate_non_negative, apps.transactions.validators.validate_decimal_places], verbose_name='Amount'),
|
field=models.DecimalField(
|
||||||
|
decimal_places=18,
|
||||||
|
default=0,
|
||||||
|
max_digits=30,
|
||||||
|
validators=[
|
||||||
|
apps.transactions.validators.validate_non_negative,
|
||||||
|
apps.transactions.validators.validate_decimal_places,
|
||||||
|
],
|
||||||
|
verbose_name="Amount",
|
||||||
|
),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='date',
|
name="date",
|
||||||
field=models.DateField(verbose_name='Date'),
|
field=models.DateField(verbose_name="Date"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='description',
|
name="description",
|
||||||
field=models.CharField(max_length=500, verbose_name='Description'),
|
field=models.CharField(max_length=500, verbose_name="Description"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='is_paid',
|
name="is_paid",
|
||||||
field=models.BooleanField(default=True, verbose_name='Paid'),
|
field=models.BooleanField(default=True, verbose_name="Paid"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='notes',
|
name="notes",
|
||||||
field=models.TextField(blank=True, verbose_name='Notes'),
|
field=models.TextField(blank=True, verbose_name="Notes"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='reference_date',
|
name="reference_date",
|
||||||
field=apps.transactions.fields.MonthYearField(verbose_name='Reference Date'),
|
field=apps.common.fields.month_year.MonthYearModelField(
|
||||||
|
verbose_name="Reference Date"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ from django.utils.functional import cached_property
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from apps.common.functions.decimals import truncate_decimal
|
from apps.common.functions.decimals import truncate_decimal
|
||||||
from apps.transactions.fields import MonthYearField
|
|
||||||
from apps.transactions.validators import validate_decimal_places, validate_non_negative
|
from apps.transactions.validators import validate_decimal_places, validate_non_negative
|
||||||
from apps.currencies.utils.convert import convert
|
from apps.currencies.utils.convert import convert
|
||||||
|
from apps.common.fields.month_year import MonthYearModelField
|
||||||
|
|
||||||
|
|
||||||
class TransactionCategory(models.Model):
|
class TransactionCategory(models.Model):
|
||||||
@@ -76,7 +76,7 @@ class Transaction(models.Model):
|
|||||||
)
|
)
|
||||||
is_paid = models.BooleanField(default=True, verbose_name=_("Paid"))
|
is_paid = models.BooleanField(default=True, verbose_name=_("Paid"))
|
||||||
date = models.DateField(verbose_name=_("Date"))
|
date = models.DateField(verbose_name=_("Date"))
|
||||||
reference_date = MonthYearField(verbose_name=_("Reference Date"))
|
reference_date = MonthYearModelField(verbose_name=_("Reference Date"))
|
||||||
|
|
||||||
amount = models.DecimalField(
|
amount = models.DecimalField(
|
||||||
max_digits=42,
|
max_digits=42,
|
||||||
|
|||||||
Reference in New Issue
Block a user