mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-21 01:48:21 +02:00
Merge branch 'master' into tranfer_front
This commit is contained in:
@ -78,7 +78,11 @@ class AliasSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Alias
|
||||
fields = '__all__'
|
||||
read_only_fields = ('note', )
|
||||
|
||||
def validate(self, attrs):
|
||||
instance = Alias(**attrs)
|
||||
instance.clean()
|
||||
return attrs
|
||||
|
||||
|
||||
class NotePolymorphicSerializer(PolymorphicSerializer):
|
||||
|
@ -2,8 +2,13 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from django.db.models import Q
|
||||
from django.core.exceptions import ValidationError
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
|
||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
||||
|
||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
|
||||
@ -52,6 +57,22 @@ class AliasViewSet(ReadProtectedModelViewSet):
|
||||
search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ]
|
||||
ordering_fields = ['name', 'normalized_name']
|
||||
|
||||
def get_serializer_class(self):
|
||||
serializer_class = self.serializer_class
|
||||
if self.request.method in ['PUT', 'PATCH']:
|
||||
#alias owner cannot be change once establish
|
||||
setattr(serializer_class.Meta, 'read_only_fields', ('note',))
|
||||
return serializer_class
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
try:
|
||||
self.perform_destroy(instance)
|
||||
except ValidationError as e:
|
||||
print(e)
|
||||
return Response({e.code:e.message},status.HTTP_400_BAD_REQUEST)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Parse query and apply filters.
|
||||
@ -104,7 +125,7 @@ class TemplateCategoryViewSet(ReadProtectedModelViewSet):
|
||||
search_fields = ['$name', ]
|
||||
|
||||
|
||||
class TransactionTemplateViewSet(ReadProtectedModelViewSet):
|
||||
class TransactionTemplateViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
REST API View set.
|
||||
The djangorestframework plugin will get all `TransactionTemplate` objects, serialize it to JSON with the given serializer,
|
||||
@ -112,8 +133,9 @@ class TransactionTemplateViewSet(ReadProtectedModelViewSet):
|
||||
"""
|
||||
queryset = TransactionTemplate.objects.all()
|
||||
serializer_class = TransactionTemplateSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filter_backends = [SearchFilter, DjangoFilterBackend]
|
||||
filterset_fields = ['name', 'amount', 'display', 'category', ]
|
||||
search_fields = ['$name', ]
|
||||
|
||||
|
||||
class TransactionViewSet(ReadProtectedModelViewSet):
|
||||
|
58
apps/note/fixtures/button.json
Normal file
58
apps/note/fixtures/button.json
Normal file
@ -0,0 +1,58 @@
|
||||
[
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Soft"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "Pulls"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "Gala"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "Clubs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"name": "Bouffe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"name": "BDA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"name": "Autre"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"name": "Alcool"
|
||||
}
|
||||
}
|
||||
]
|
@ -70,7 +70,7 @@
|
||||
"balance": 0,
|
||||
"last_negative": null,
|
||||
"is_active": true,
|
||||
"display_image": "",
|
||||
"display_image": "pic/default.png",
|
||||
"created_at": "2020-02-20T20:09:38.615Z"
|
||||
}
|
||||
},
|
||||
@ -85,23 +85,8 @@
|
||||
"balance": 0,
|
||||
"last_negative": null,
|
||||
"is_active": true,
|
||||
"display_image": "",
|
||||
"created_at": "2020-02-20T20:16:14.753Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.note",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"polymorphic_ctype": [
|
||||
"note",
|
||||
"noteuser"
|
||||
],
|
||||
"balance": 0,
|
||||
"last_negative": null,
|
||||
"is_active": true,
|
||||
"display_image": "pic/default.png",
|
||||
"created_at": "2020-03-22T13:01:35.680Z"
|
||||
"created_at": "2020-02-20T20:16:14.753Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -199,61 +184,5 @@
|
||||
"normalized_name": "kfet",
|
||||
"note": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Soft"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "Pulls"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "Gala"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "Clubs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"name": "Bouffe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"name": "BDA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"name": "Autre"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "note.templatecategory",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"name": "Alcool"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
@ -9,17 +9,6 @@ from .models import Alias
|
||||
from .models import TransactionTemplate
|
||||
|
||||
|
||||
class AliasForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Alias
|
||||
fields = ("name",)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["name"].label = False
|
||||
self.fields["name"].widget.attrs = {"placeholder": _('New Alias')}
|
||||
|
||||
|
||||
class ImageForm(forms.Form):
|
||||
image = forms.ImageField(required=False,
|
||||
label=_('select an image'),
|
||||
|
@ -3,12 +3,12 @@
|
||||
|
||||
from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
|
||||
from .transactions import MembershipTransaction, Transaction, \
|
||||
TemplateCategory, TransactionTemplate, RecurrentTransaction
|
||||
TemplateCategory, TransactionTemplate, RecurrentTransaction, SpecialTransaction
|
||||
|
||||
__all__ = [
|
||||
# Notes
|
||||
'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
|
||||
# Transactions
|
||||
'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
|
||||
'RecurrentTransaction',
|
||||
'RecurrentTransaction', 'SpecialTransaction',
|
||||
]
|
||||
|
@ -228,7 +228,7 @@ class Alias(models.Model):
|
||||
for cat in {'M', 'P', 'Z', 'C'})).casefold()
|
||||
|
||||
def clean(self):
|
||||
normalized_name = Alias.normalize(self.name)
|
||||
normalized_name = self.normalize(self.name)
|
||||
if len(normalized_name) >= 255:
|
||||
raise ValidationError(_('Alias is too long.'),
|
||||
code='alias_too_long')
|
||||
@ -242,8 +242,12 @@ class Alias(models.Model):
|
||||
pass
|
||||
self.normalized_name = normalized_name
|
||||
|
||||
def save(self,*args,**kwargs):
|
||||
self.normalized_name = self.normalize(self.name)
|
||||
super().save(*args,**kwargs)
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
if self.name == str(self.note):
|
||||
raise ValidationError(_("You can't delete your main alias."),
|
||||
code="cant_delete_main_alias")
|
||||
code="main_alias")
|
||||
return super().delete(using, keep_parents)
|
||||
|
@ -2,6 +2,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import F
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -93,12 +94,26 @@ class Transaction(PolymorphicModel):
|
||||
related_name='+',
|
||||
verbose_name=_('source'),
|
||||
)
|
||||
|
||||
source_alias = models.CharField(
|
||||
max_length=255,
|
||||
default="", # Will be remplaced by the name of the note on save
|
||||
verbose_name=_('used alias'),
|
||||
)
|
||||
|
||||
destination = models.ForeignKey(
|
||||
Note,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='+',
|
||||
verbose_name=_('destination'),
|
||||
)
|
||||
|
||||
destination_alias = models.CharField(
|
||||
max_length=255,
|
||||
default="", # Will be remplaced by the name of the note on save
|
||||
verbose_name=_('used alias'),
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(
|
||||
verbose_name=_('created at'),
|
||||
default=timezone.now,
|
||||
@ -115,11 +130,19 @@ class Transaction(PolymorphicModel):
|
||||
verbose_name=_('reason'),
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
valid = models.BooleanField(
|
||||
verbose_name=_('valid'),
|
||||
default=True,
|
||||
)
|
||||
|
||||
invalidity_reason = models.CharField(
|
||||
verbose_name=_('invalidity reason'),
|
||||
max_length=255,
|
||||
default=None,
|
||||
null=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("transaction")
|
||||
verbose_name_plural = _("transactions")
|
||||
@ -134,6 +157,13 @@ class Transaction(PolymorphicModel):
|
||||
When saving, also transfer money between two notes
|
||||
"""
|
||||
|
||||
# If the aliases are not entered, we assume that the used alias is the name of the note
|
||||
if not self.source_alias:
|
||||
self.source_alias = str(self.source)
|
||||
|
||||
if not self.destination_alias:
|
||||
self.destination_alias = str(self.destination)
|
||||
|
||||
if self.source.pk == self.destination.pk:
|
||||
# When source == destination, no money is transfered
|
||||
super().save(*args, **kwargs)
|
||||
@ -152,6 +182,10 @@ class Transaction(PolymorphicModel):
|
||||
self.source.balance -= to_transfer
|
||||
self.destination.balance += to_transfer
|
||||
|
||||
# When a transaction is declared valid, we ensure that the invalidity reason is null, if it was
|
||||
# previously invalid
|
||||
self.invalidity_reason = None
|
||||
|
||||
# We save first the transaction, in case of the user has no right to transfer money
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
@ -5,11 +5,12 @@ import html
|
||||
|
||||
import django_tables2 as tables
|
||||
from django.db.models import F
|
||||
from django.utils.html import format_html
|
||||
from django_tables2.utils import A
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models.notes import Alias
|
||||
from .models.transactions import Transaction
|
||||
from .models.transactions import Transaction, TransactionTemplate
|
||||
from .templatetags.pretty_money import pretty_money
|
||||
|
||||
|
||||
@ -20,19 +21,48 @@ class HistoryTable(tables.Table):
|
||||
'table table-condensed table-striped table-hover'
|
||||
}
|
||||
model = Transaction
|
||||
exclude = ("id", "polymorphic_ctype", )
|
||||
exclude = ("id", "polymorphic_ctype", "invalidity_reason", "source_alias", "destination_alias",)
|
||||
template_name = 'django_tables2/bootstrap4.html'
|
||||
sequence = ('...', 'type', 'total', 'valid', )
|
||||
sequence = ('...', 'type', 'total', 'valid',)
|
||||
orderable = False
|
||||
|
||||
source = tables.Column(
|
||||
attrs={
|
||||
"td": {
|
||||
"data-toggle": "tooltip",
|
||||
"title": lambda record: _("used alias").capitalize() + " : " + record.source_alias,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
destination = tables.Column(
|
||||
attrs={
|
||||
"td": {
|
||||
"data-toggle": "tooltip",
|
||||
"title": lambda record: _("used alias").capitalize() + " : " + record.destination_alias,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
type = tables.Column()
|
||||
|
||||
total = tables.Column() # will use Transaction.total() !!
|
||||
|
||||
valid = tables.Column(attrs={"td": {"id": lambda record: "validate_" + str(record.id),
|
||||
"class": lambda record: str(record.valid).lower() + ' validate',
|
||||
"onclick": lambda record: 'de_validate(' + str(record.id) + ', '
|
||||
+ str(record.valid).lower() + ')'}})
|
||||
valid = tables.Column(
|
||||
attrs={
|
||||
"td": {
|
||||
"id": lambda record: "validate_" + str(record.id),
|
||||
"class": lambda record: str(record.valid).lower() + ' validate',
|
||||
"data-toggle": "tooltip",
|
||||
"title": lambda record: _("Click to invalidate") if record.valid else _("Click to validate"),
|
||||
"onclick": lambda record: 'in_validate(' + str(record.id) + ', ' + str(record.valid).lower() + ')',
|
||||
"onmouseover": lambda record: '$("#invalidity_reason_'
|
||||
+ str(record.id) + '").show();$("#invalidity_reason_'
|
||||
+ str(record.id) + '").focus();',
|
||||
"onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
def order_total(self, queryset, is_descending):
|
||||
# needed for rendering
|
||||
@ -53,15 +83,32 @@ class HistoryTable(tables.Table):
|
||||
def render_reason(self, value):
|
||||
return html.unescape(value)
|
||||
|
||||
def render_valid(self, value):
|
||||
return "✔" if value else "✖"
|
||||
def render_valid(self, value, record):
|
||||
"""
|
||||
When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason
|
||||
"""
|
||||
val = "✔" if value else "✖"
|
||||
val += "<input type='text' class='form-control' id='invalidity_reason_" + str(record.id) \
|
||||
+ "' value='" + (html.escape(record.invalidity_reason)
|
||||
if record.invalidity_reason else ("" if value else str(_("No reason specified")))) \
|
||||
+ "'" + ("" if value else " disabled") \
|
||||
+ " placeholder='" + html.escape(_("invalidity reason").capitalize()) + "'" \
|
||||
+ " style='position: absolute; width: 15em; margin-left: -15.5em; margin-top: -2em; display: none;'>"
|
||||
return format_html(val)
|
||||
|
||||
|
||||
# function delete_button(id) provided in template file
|
||||
DELETE_TEMPLATE = """
|
||||
<button id="{{ record.pk }}" class="btn btn-danger btn-sm" onclick="delete_button(this.id)"> {{ delete_trans }}</button>
|
||||
"""
|
||||
|
||||
|
||||
class AliasTable(tables.Table):
|
||||
class Meta:
|
||||
attrs = {
|
||||
'class':
|
||||
'table table condensed table-striped table-hover'
|
||||
'table table condensed table-striped table-hover',
|
||||
'id':"alias_table"
|
||||
}
|
||||
model = Alias
|
||||
fields = ('name',)
|
||||
@ -69,9 +116,37 @@ class AliasTable(tables.Table):
|
||||
|
||||
show_header = False
|
||||
name = tables.Column(attrs={'td': {'class': 'text-center'}})
|
||||
delete = tables.LinkColumn('member:user_alias_delete',
|
||||
args=[A('pk')],
|
||||
attrs={
|
||||
'td': {'class': 'col-sm-2'},
|
||||
'a': {'class': 'btn btn-danger'}},
|
||||
text='delete', accessor='pk')
|
||||
|
||||
delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
|
||||
extra_context={"delete_trans": _('delete')},
|
||||
attrs={'td': {'class': 'col-sm-1'}})
|
||||
|
||||
|
||||
|
||||
class ButtonTable(tables.Table):
|
||||
class Meta:
|
||||
attrs = {
|
||||
'class':
|
||||
'table table-bordered condensed table-hover'
|
||||
}
|
||||
row_attrs = {
|
||||
'class': lambda record: 'table-row ' + 'table-success' if record.display else 'table-danger',
|
||||
'id': lambda record: "row-" + str(record.pk),
|
||||
'data-href': lambda record: record.pk
|
||||
}
|
||||
|
||||
model = TransactionTemplate
|
||||
|
||||
edit = tables.LinkColumn('note:template_update',
|
||||
args=[A('pk')],
|
||||
attrs={'td': {'class': 'col-sm-1'},
|
||||
'a': {'class': 'btn btn-sm btn-primary'}},
|
||||
text=_('edit'),
|
||||
accessor='pk')
|
||||
|
||||
delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
|
||||
extra_context={"delete_trans": _('delete')},
|
||||
attrs={'td': {'class': 'col-sm-1'}})
|
||||
|
||||
def render_amount(self, value):
|
||||
return pretty_money(value)
|
||||
|
@ -18,5 +18,10 @@ def pretty_money(value):
|
||||
)
|
||||
|
||||
|
||||
def cents_to_euros(value):
|
||||
return "{:.02f}".format(value / 100) if value else ""
|
||||
|
||||
|
||||
register = template.Library()
|
||||
register.filter('pretty_money', pretty_money)
|
||||
register.filter('cents_to_euros', cents_to_euros)
|
||||
|
@ -8,7 +8,7 @@ from .models import Note
|
||||
|
||||
app_name = 'note'
|
||||
urlpatterns = [
|
||||
path('transfer/', views.TransactionCreate.as_view(), name='transfer'),
|
||||
path('transfer/', views.TransactionCreateView.as_view(), name='transfer'),
|
||||
path('buttons/create/', views.TransactionTemplateCreateView.as_view(), name='template_create'),
|
||||
path('buttons/update/<int:pk>/', views.TransactionTemplateUpdateView.as_view(), name='template_update'),
|
||||
path('buttons/', views.TransactionTemplateListView.as_view(), name='template_list'),
|
||||
|
@ -6,22 +6,25 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import CreateView, ListView, UpdateView
|
||||
from django.views.generic import CreateView, UpdateView
|
||||
from django_tables2 import SingleTableView
|
||||
from django.urls import reverse_lazy
|
||||
from permission.backends import PermissionBackend
|
||||
|
||||
from .forms import TransactionTemplateForm
|
||||
from .models import Transaction, TransactionTemplate, Alias, RecurrentTransaction, NoteSpecial
|
||||
from .models.transactions import SpecialTransaction
|
||||
from .tables import HistoryTable
|
||||
from .tables import HistoryTable, ButtonTable
|
||||
|
||||
|
||||
class TransactionCreate(LoginRequiredMixin, SingleTableView):
|
||||
class TransactionCreateView(LoginRequiredMixin, SingleTableView):
|
||||
"""
|
||||
Show transfer page
|
||||
View for the creation of Transaction between two note which are not :models:`transactions.RecurrentTransaction`.
|
||||
e.g. for donation/transfer between people and clubs or for credit/debit with :models:`note.NoteSpecial`
|
||||
"""
|
||||
template_name = "note/transaction_form.html"
|
||||
|
||||
model = Transaction
|
||||
# Transaction history table
|
||||
table_class = HistoryTable
|
||||
table_pagination = {"per_page": 50}
|
||||
@ -46,13 +49,14 @@ class TransactionCreate(LoginRequiredMixin, SingleTableView):
|
||||
|
||||
class NoteAutocomplete(autocomplete.Select2QuerySetView):
|
||||
"""
|
||||
Auto complete note by aliases
|
||||
Auto complete note by aliases. Used in every search field for note
|
||||
ex: :view:`ConsoView`, :view:`TransactionCreateView`
|
||||
"""
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Quand une personne cherche un alias, une requête est envoyée sur l'API dédiée à l'auto-complétion.
|
||||
Cette fonction récupère la requête, et renvoie la liste filtrée des aliases.
|
||||
When someone look for an :models:`note.Alias`, a query is sent to the dedicated API.
|
||||
This function handles the result and return a filtered list of aliases.
|
||||
"""
|
||||
# Un utilisateur non connecté n'a accès à aucune information
|
||||
if not self.request.user.is_authenticated:
|
||||
@ -81,6 +85,10 @@ class NoteAutocomplete(autocomplete.Select2QuerySetView):
|
||||
return qs
|
||||
|
||||
def get_result_label(self, result):
|
||||
"""
|
||||
Show the selected alias and the username associated
|
||||
<Alias> (aka. <Username> )
|
||||
"""
|
||||
# Gère l'affichage de l'alias dans la recherche
|
||||
res = result.name
|
||||
note_name = str(result.note)
|
||||
@ -89,7 +97,9 @@ class NoteAutocomplete(autocomplete.Select2QuerySetView):
|
||||
return res
|
||||
|
||||
def get_result_value(self, result):
|
||||
# Le résultat renvoyé doit être l'identifiant de la note, et non de l'alias
|
||||
"""
|
||||
The value used for the transactions will be the id of the Note.
|
||||
"""
|
||||
return str(result.note.pk)
|
||||
|
||||
|
||||
@ -99,14 +109,15 @@ class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
|
||||
"""
|
||||
model = TransactionTemplate
|
||||
form_class = TransactionTemplateForm
|
||||
success_url = reverse_lazy('note:template_list')
|
||||
|
||||
|
||||
class TransactionTemplateListView(LoginRequiredMixin, ListView):
|
||||
class TransactionTemplateListView(LoginRequiredMixin, SingleTableView):
|
||||
"""
|
||||
List TransactionsTemplates
|
||||
"""
|
||||
model = TransactionTemplate
|
||||
form_class = TransactionTemplateForm
|
||||
table_class = ButtonTable
|
||||
|
||||
|
||||
class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
|
||||
@ -114,11 +125,13 @@ class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
|
||||
"""
|
||||
model = TransactionTemplate
|
||||
form_class = TransactionTemplateForm
|
||||
success_url = reverse_lazy('note:template_list')
|
||||
|
||||
|
||||
class ConsoView(LoginRequiredMixin, SingleTableView):
|
||||
"""
|
||||
Consume
|
||||
The Magic View that make people pay their beer and burgers.
|
||||
(Most of the magic happens in the dark world of Javascript see consos.js)
|
||||
"""
|
||||
template_name = "note/conso_form.html"
|
||||
|
||||
|
Reference in New Issue
Block a user