Files
WYGIWYH/app/apps/rules/forms.py
2025-12-14 11:42:51 -03:00

504 lines
18 KiB
Python

from crispy_forms.bootstrap import Alert
from apps.common.fields.forms.dynamic_select import DynamicModelChoiceField
from apps.common.widgets.crispy.daisyui import Switch
from apps.common.widgets.crispy.submit import NoClassSubmit
from apps.common.widgets.tom_select import TomSelect, TransactionSelect
from apps.rules.models import (
TransactionRule,
TransactionRuleAction,
UpdateOrCreateTransactionRuleAction,
)
from apps.transactions.forms import BulkEditTransactionForm
from apps.transactions.models import Transaction
from crispy_forms.bootstrap import AccordionGroup, FormActions, Accordion
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Column, Field, Layout, Row
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
class TransactionRuleForm(forms.ModelForm):
class Meta:
model = TransactionRule
fields = "__all__"
exclude = ("owner", "shared_with", "visibility")
labels = {
"on_create": _("Run on creation"),
"on_update": _("Run on update"),
"on_delete": _("Run on delete"),
"trigger": _("If..."),
}
widgets = {"description": forms.widgets.TextInput}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_method = "post"
self.helper.layout = Layout(
Switch("active"),
"name",
Row(
Column(Switch("on_update")),
Column(Switch("on_create")),
Column(Switch("on_delete")),
),
"order",
Switch("sequenced"),
"description",
"trigger",
Alert(
_("You can add actions to this rule in the next screen."), dismiss=True
),
)
if self.instance and self.instance.pk:
self.helper.layout.append(
FormActions(
NoClassSubmit("submit", _("Update"), css_class="btn btn-primary"),
),
)
else:
self.helper.layout.append(
FormActions(
NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
),
)
class TransactionRuleActionForm(forms.ModelForm):
class Meta:
model = TransactionRuleAction
fields = ("value", "field", "order")
labels = {
"field": _("Set field"),
"value": _("To"),
"order": _("Order"),
}
widgets = {"field": TomSelect(clear_button=False)}
def __init__(self, *args, **kwargs):
self.rule = kwargs.pop("rule", None)
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_method = "post"
# TO-DO: Add helper with available commands
self.helper.layout = Layout(
"order",
"field",
"value",
)
if self.instance and self.instance.pk:
self.helper.layout.append(
FormActions(
NoClassSubmit("submit", _("Update"), css_class="btn btn-primary"),
),
)
else:
self.helper.layout.append(
FormActions(
NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
),
)
def clean(self):
cleaned_data = super().clean()
field = cleaned_data.get("field")
if field and self.rule:
# Create a queryset that excludes the current instance
existing_action = TransactionRuleAction.objects.filter(
rule=self.rule, field=field
)
if self.instance.pk:
existing_action = existing_action.exclude(pk=self.instance.pk)
if existing_action.exists():
raise ValidationError(
_("A value for this field already exists in the rule.")
)
return cleaned_data
def save(self, commit=True):
instance = super().save(commit=False)
instance.rule = self.rule
if commit:
instance.save()
return instance
class UpdateOrCreateTransactionRuleActionForm(forms.ModelForm):
class Meta:
model = UpdateOrCreateTransactionRuleAction
exclude = ("rule",)
widgets = {
"search_account_operator": TomSelect(clear_button=False),
"search_type_operator": TomSelect(clear_button=False),
"search_is_paid_operator": TomSelect(clear_button=False),
"search_date_operator": TomSelect(clear_button=False),
"search_reference_date_operator": TomSelect(clear_button=False),
"search_amount_operator": TomSelect(clear_button=False),
"search_description_operator": TomSelect(clear_button=False),
"search_notes_operator": TomSelect(clear_button=False),
"search_category_operator": TomSelect(clear_button=False),
"search_internal_note_operator": TomSelect(clear_button=False),
"search_internal_id_operator": TomSelect(clear_button=False),
"search_mute_operator": TomSelect(clear_button=False),
}
labels = {
"order": _("Order"),
"search_account_operator": _("Operator"),
"search_type_operator": _("Operator"),
"search_is_paid_operator": _("Operator"),
"search_date_operator": _("Operator"),
"search_reference_date_operator": _("Operator"),
"search_amount_operator": _("Operator"),
"search_description_operator": _("Operator"),
"search_notes_operator": _("Operator"),
"search_category_operator": _("Operator"),
"search_internal_note_operator": _("Operator"),
"search_internal_id_operator": _("Operator"),
"search_tags_operator": _("Operator"),
"search_entities_operator": _("Operator"),
"search_mute_operator": _("Operator"),
"search_account": _("Account"),
"search_type": _("Type"),
"search_is_paid": _("Paid"),
"search_date": _("Date"),
"search_reference_date": _("Reference Date"),
"search_amount": _("Amount"),
"search_description": _("Description"),
"search_notes": _("Notes"),
"search_category": _("Category"),
"search_internal_note": _("Internal Note"),
"search_internal_id": _("Internal ID"),
"search_tags": _("Tags"),
"search_entities": _("Entities"),
"search_mute": _("Mute"),
"set_account": _("Account"),
"set_type": _("Type"),
"set_is_paid": _("Paid"),
"set_date": _("Date"),
"set_reference_date": _("Reference Date"),
"set_amount": _("Amount"),
"set_description": _("Description"),
"set_tags": _("Tags"),
"set_entities": _("Entities"),
"set_notes": _("Notes"),
"set_category": _("Category"),
"set_internal_note": _("Internal Note"),
"set_internal_id": _("Internal ID"),
"set_mute": _("Mute"),
}
def __init__(self, *args, **kwargs):
self.rule = kwargs.pop("rule", None)
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_method = "post"
self.helper.layout = Layout(
"order",
Accordion(
AccordionGroup(
_("Search Criteria"),
Field("filter", rows=1),
Row(
Column(
Field("search_type_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_type", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_is_paid_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_is_paid", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_mute_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_mute", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_account_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_account", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_entities_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_entities", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_date_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_date", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_reference_date_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_reference_date", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_description_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_description", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_amount_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_amount", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_category_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_category", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_tags_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_tags", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_notes_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_notes", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_internal_note_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_internal_note", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
Row(
Column(
Field("search_internal_id_operator"),
css_class="col-span-12 md:col-span-4",
),
Column(
Field("search_internal_id", rows=1),
css_class="col-span-12 md:col-span-8",
),
),
active=True,
),
AccordionGroup(
_("Set Values"),
Field("set_type", rows=1),
Field("set_is_paid", rows=1),
Field("set_mute", rows=1),
Field("set_account", rows=1),
Field("set_entities", rows=1),
Field("set_date", rows=1),
Field("set_reference_date", rows=1),
Field("set_description", rows=1),
Field("set_amount", rows=1),
Field("set_category", rows=1),
Field("set_tags", rows=1),
Field("set_notes", rows=1),
Field("set_internal_note", rows=1),
Field("set_internal_id", rows=1),
css_class="mb-3",
active=True,
),
always_open=True,
),
)
if self.instance and self.instance.pk:
self.helper.layout.append(
FormActions(
NoClassSubmit("submit", _("Update"), css_class="btn btn-primary"),
),
)
else:
self.helper.layout.append(
FormActions(
NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
),
)
def save(self, commit=True):
instance = super().save(commit=False)
instance.rule = self.rule
if commit:
instance.save()
return instance
class DryRunCreatedTransacion(forms.Form):
transaction = DynamicModelChoiceField(
model=Transaction,
to_field_name="id",
label=_("Transaction"),
required=True,
queryset=Transaction.objects.none(),
widget=TransactionSelect(clear_button=False, income=True, expense=True),
help_text=_("Type to search for a transaction"),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
"transaction",
FormActions(
NoClassSubmit("submit", _("Test"), css_class="btn btn-primary"),
),
)
if self.data.get("transaction"):
try:
transaction = Transaction.objects.get(id=self.data.get("transaction"))
except Transaction.DoesNotExist:
transaction = None
if transaction:
self.fields["transaction"].queryset = Transaction.objects.filter(
id=transaction.id
)
class DryRunDeletedTransacion(forms.Form):
transaction = DynamicModelChoiceField(
model=Transaction,
to_field_name="id",
label=_("Transaction"),
required=True,
queryset=Transaction.objects.none(),
widget=TransactionSelect(clear_button=False, income=True, expense=True),
help_text=_("Type to search for a transaction"),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
"transaction",
FormActions(
NoClassSubmit("submit", _("Test"), css_class="btn btn-primary"),
),
)
if self.data.get("transaction"):
try:
transaction = Transaction.objects.get(id=self.data.get("transaction"))
except Transaction.DoesNotExist:
transaction = None
if transaction:
self.fields["transaction"].queryset = Transaction.objects.filter(
id=transaction.id
)
class DryRunUpdatedTransactionForm(BulkEditTransactionForm):
transaction = DynamicModelChoiceField(
model=Transaction,
to_field_name="id",
label=_("Transaction"),
required=True,
queryset=Transaction.objects.none(),
widget=TransactionSelect(clear_button=False, income=True, expense=True),
help_text=_("Type to search for a transaction"),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.layout.insert(0, "transaction")
self.helper.layout.insert(1, HTML('<hr class="hr my-3" />'))
# Change submit button
self.helper.layout[-1] = FormActions(
NoClassSubmit("submit", _("Test"), css_class="btn btn-primary")
)
if self.data.get("transaction"):
try:
transaction = Transaction.objects.get(id=self.data.get("transaction"))
except Transaction.DoesNotExist:
transaction = None
if transaction:
self.fields["transaction"].queryset = Transaction.objects.filter(
id=transaction.id
)