Source code for richy.transactions.forms
import re
from django import forms
from django.core.validators import MinValueValidator, RegexValidator
from django.utils.translation import gettext as _
from ..core.fields import MultipleFileField
from ..core.models import Item
from ..core.widgets import NoLabelCheckboxSelectMultiple
from ..staking.models import Staking
from .models import Attachment, Transaction
[docs]
class TransactionForm(forms.ModelForm):
attachments = MultipleFileField(
required=False, delete_url_pattern="transactions:delete_attachment"
)
class Meta:
model = Transaction
fields = (
"parents",
"item",
"price",
"amount",
"fee",
"currency",
"target",
"date",
"exchange",
"note",
"is_closing",
"is_closed",
"is_deposit",
"closed_on",
)
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["item"].empty_label = ""
self.fields["item"].queryset = Item.objects.filter(
pk__in=user.useritem_set.values_list("item", flat=True)
).order_by("symbol")
self.fields["exchange"].empty_label = ""
self.fields["date"].widget.attrs["autocomplete"] = "off"
self.fields["closed_on"].widget.attrs["autocomplete"] = "off"
self.fields["parents"].queryset = (
Transaction.objects.by_user(user)
.select_related("item", "exchange")
.order_by("-date")
)
self.fields["currency"].validators = [
RegexValidator(
"^[a-zA-Z]{3}$", message=_("Please enter 3 alpha only chars")
),
]
self.fields["price"].validators = [MinValueValidator(0)]
self.fields["fee"].validators = [MinValueValidator(0)]
self.fields["target"].help_text = _(
'Use as a price target or percentage gain with "%" character.'
)
self.fields["is_deposit"].help_text = _(
"Marks the transaction as an entrypoint of transaction chain."
)
self.fields["is_closing"].help_text = _(
"Marks the transaction as an endpoint of transaction chain."
)
self.fields["is_closed"].help_text = _(
"Marks the transaction as closed. Closed transactions are those whose assets has been sold."
)
[docs]
def clean(self):
"""
Validates:
* if exchange is filled for coins
* echanging is forbidden for shares (not possbible)
"""
data = super().clean()
# Coins must have exchange filled.
if hasattr(data.get("item"), "coin") and not data.get("exchange"):
self.add_error("exchange", _("Please choose an exchange."))
# Deposit cannot be closing.
if data.get("is_closing") and data.get("is_deposit"):
self.add_error("is_closing", _("Deposit cannot be closing."))
# Positive transaction cannot be closing - only negative ones.
if 0 < data.get("amount") and data.get("is_closing"):
self.add_error("is_closing", _("Positive transaction cannot be closing."))
# Closed transaction must have closed date filled.
if (data.get("is_closing") or data.get("is_closed")) and not data.get(
"closed_on"
):
self.add_error("closed_on", _("Please fill in closed date."))
# Negative amount (sell transaction) must have a parent(s).
if 0 > data.get("amount") and not data.get("parents"):
self.add_error("parents", _("Please select parent transaction."))
return data
[docs]
def clean_target(self):
target = self.cleaned_data["target"]
# Match numbers only with the possibility of trailing "%".
if target and not re.match("^[0-9]+%?$", target):
raise forms.ValidationError(
'Target must contains of numbers and one "%" symbol only.'
)
return target
[docs]
def save(self, *args, **kwargs):
to_return = super().save(*args, **kwargs)
for file in self.files.getlist("attachments"):
Attachment.objects.create(
transaction=self.instance,
file=file,
)
return to_return
[docs]
class PostClosedOrClosingTransactionForm(forms.Form):
parents = forms.ModelMultipleChoiceField(
queryset=Transaction.objects.all(),
required=False,
widget=NoLabelCheckboxSelectMultiple(),
)
stakings = forms.ModelMultipleChoiceField(
queryset=Staking.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple(),
)
def __init__(self, parents, stakings, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["parents"].queryset = parents
self.fields["stakings"].queryset = stakings