From 369942e2e4c7fba260436b5c2cc36ca20386bddb Mon Sep 17 00:00:00 2001 From: jr-garnier Date: Sat, 7 Aug 2021 22:28:18 +0000 Subject: [PATCH] feat: Create deposits app --- deposits/__init__.py | 0 deposits/admin.py | 41 ++ deposits/apps.py | 27 ++ deposits/forms.py | 89 ++++ deposits/locale/fr/LC_MESSAGES/django.po | 293 ++++++++++++++ deposits/migrations/0001_initial.py | 51 +++ deposits/migrations/__init__.py | 0 deposits/models.py | 149 +++++++ .../templates/deposits/aff_deposit_item.html | 48 +++ deposits/templates/deposits/aff_deposits.html | 89 ++++ deposits/templates/deposits/aff_profil.html | 48 +++ deposits/templates/deposits/aff_stats.html | 40 ++ deposits/templates/deposits/delete.html | 39 ++ deposits/templates/deposits/deposit.html | 44 ++ .../deposits/index_deposit_item.html | 40 ++ .../templates/deposits/index_deposits.html | 64 +++ deposits/templates/deposits/index_stats.html | 36 ++ deposits/templates/deposits/navbar.html | 39 ++ deposits/templates/deposits/sidebar.html | 28 ++ deposits/tests.py | 3 + deposits/urls.py | 45 ++ deposits/utils.py | 38 ++ deposits/views.py | 383 ++++++++++++++++++ 23 files changed, 1634 insertions(+) create mode 100644 deposits/__init__.py create mode 100644 deposits/admin.py create mode 100644 deposits/apps.py create mode 100644 deposits/forms.py create mode 100644 deposits/locale/fr/LC_MESSAGES/django.po create mode 100644 deposits/migrations/0001_initial.py create mode 100644 deposits/migrations/__init__.py create mode 100644 deposits/models.py create mode 100644 deposits/templates/deposits/aff_deposit_item.html create mode 100644 deposits/templates/deposits/aff_deposits.html create mode 100644 deposits/templates/deposits/aff_profil.html create mode 100644 deposits/templates/deposits/aff_stats.html create mode 100644 deposits/templates/deposits/delete.html create mode 100644 deposits/templates/deposits/deposit.html create mode 100644 deposits/templates/deposits/index_deposit_item.html create mode 100644 deposits/templates/deposits/index_deposits.html create mode 100644 deposits/templates/deposits/index_stats.html create mode 100644 deposits/templates/deposits/navbar.html create mode 100644 deposits/templates/deposits/sidebar.html create mode 100644 deposits/tests.py create mode 100644 deposits/urls.py create mode 100644 deposits/utils.py create mode 100644 deposits/views.py diff --git a/deposits/__init__.py b/deposits/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/deposits/admin.py b/deposits/admin.py new file mode 100644 index 00000000..f9ebd881 --- /dev/null +++ b/deposits/admin.py @@ -0,0 +1,41 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Deposit admin model +""" + + +from django.contrib import admin +from reversion.admin import VersionAdmin + +from .models import Deposit, DepositItem + + +class DepositAdmin(VersionAdmin): + pass + + +class DepositItemAdmin(VersionAdmin): + pass + + +admin.site.register(Deposit, DepositAdmin) +admin.site.register(DepositItem, DepositItemAdmin) diff --git a/deposits/apps.py b/deposits/apps.py new file mode 100644 index 00000000..a0b92c1e --- /dev/null +++ b/deposits/apps.py @@ -0,0 +1,27 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from django.apps import AppConfig + + +class DepositsConfig(AppConfig): + """Configuration of the optional deposits app.""" + + name = "deposits" diff --git a/deposits/forms.py b/deposits/forms.py new file mode 100644 index 00000000..8ce46c21 --- /dev/null +++ b/deposits/forms.py @@ -0,0 +1,89 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Deposit form +""" + +from django import forms +from django.forms import Form, ModelForm +from django.utils.translation import ugettext_lazy as _ + +from re2o.mixins import FormRevMixin + +from .models import Deposit, DepositItem + + +class DepositForm(FormRevMixin, ModelForm): + """ + Form used to manage and create an invoice and its fields. + """ + + def __init__(self, *args, creation=False, **kwargs): + user = kwargs.pop("user") + super(DepositForm, self).__init__(*args, **kwargs) + + # Set the fields' label to handle translation + self.fields["item"].label = _("Deposit item") + self.fields["payment_method"].label = _("Payment method") + self.fields["returned"].label = _("Deposit returned") + + if creation: + # During creation, we only need to select the item and payment + # method, no need to add the "returned" checkbox + self.fields = { + "item": self.fields["item"], + "payment_method": self.fields["payment_method"], + } + + class Meta: + model = Deposit + fields = ("item", "payment_method", "returned") + + +class DepositItemForm(FormRevMixin, ModelForm): + """ + Form used to create a deposit item. + """ + + class Meta: + model = DepositItem + fields = "__all__" + + +class DelDepositItemForm(FormRevMixin, Form): + """ + Form used to delete one or more of the currently available deposit items. + The user must choose the one to delete by checking the boxes. + """ + + deposit_items = forms.ModelMultipleChoiceField( + queryset=DepositItem.objects.none(), + label=_("Current deposit items"), + widget=forms.CheckboxSelectMultiple, + ) + + def __init__(self, *args, **kwargs): + instances = kwargs.pop("instances", None) + super(DelDepositItemForm, self).__init__(*args, **kwargs) + if instances: + self.fields["deposit_items"].queryset = instances + else: + self.fields["deposit_items"].queryset = DepositItem.objects.all() diff --git a/deposits/locale/fr/LC_MESSAGES/django.po b/deposits/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 00000000..11267cf4 --- /dev/null +++ b/deposits/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,293 @@ +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-08-07 23:10+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: deposits/forms.py:44 deposits/templates/deposits/aff_deposit_item.html:31 +#: deposits/views.py:301 +msgid "Deposit item" +msgstr "Article (caution)" + +#: deposits/forms.py:45 deposits/templates/deposits/aff_deposits.html:48 +#: deposits/views.py:272 +msgid "Payment method" +msgstr "Moyen de paiement" + +#: deposits/forms.py:46 +msgid "Deposit returned" +msgstr "Caution rendue" + +#: deposits/forms.py:79 +msgid "Current deposit items" +msgstr "Articles sous cautions actuels" + +#: deposits/models.py:52 +msgid "date" +msgstr "date" + +#: deposits/models.py:53 +msgid "returned" +msgstr "rendue" + +#: deposits/models.py:55 deposits/models.py:140 +msgid "deposit amount" +msgstr "montant de la caution" + +#: deposits/models.py:60 deposits/views.py:116 +msgid "deposit" +msgstr "caution" + +#: deposits/models.py:61 +msgid "deposits" +msgstr "cautions" + +#: deposits/models.py:70 +#, python-brace-format +msgid "Deposit from {name} for {item} at {date}, returned" +msgstr "Caution de {name} pour {item} à {date}, rendue" + +#: deposits/models.py:77 +#, python-brace-format +msgid "Deposit from {name} for {item} at {date}, not yet returned" +msgstr "Caution de {name} pour {item} à {date}, pas encore rendue" + +#: deposits/models.py:105 +msgid "You don't have the right to view other deposits than yours." +msgstr "Vous n'avez pas le droit de voir les cautions d'autres utilisateurs." + +#: deposits/models.py:117 +msgid "You don't have the right to view the list of deposits." +msgstr "Vous n'avez pas le droit de voir la liste des cautions." + +#: deposits/models.py:137 +msgid "designation" +msgstr "désignation" + +#: deposits/models.py:145 +msgid "deposit item" +msgstr "article (caution)" + +#: deposits/models.py:146 +msgid "deposit items" +msgstr "articles (cautions)" + +#: deposits/templates/deposits/aff_deposit_item.html:32 +#: deposits/templates/deposits/aff_deposits.html:44 deposits/views.py:276 +#: deposits/views.py:305 deposits/views.py:338 +msgid "Amount" +msgstr "Montant" + +#: deposits/templates/deposits/aff_deposits.html:36 +msgid "User" +msgstr "Utilisateur" + +#: deposits/templates/deposits/aff_deposits.html:40 +msgid "Item" +msgstr "Article (caution)" + +#: deposits/templates/deposits/aff_deposits.html:52 +msgid "Date" +msgstr "Date" + +#: deposits/templates/deposits/aff_deposits.html:56 +msgid "Returned" +msgstr "Rendue" + +#: deposits/templates/deposits/aff_profil.html:29 +#: deposits/templates/deposits/navbar.html:25 +msgid "Deposits" +msgstr "Cautions" + +#: deposits/templates/deposits/aff_profil.html:36 +msgid "Add a deposit" +msgstr "Ajouter une caution" + +#: deposits/templates/deposits/aff_profil.html:44 +msgid "No deposit" +msgstr "Pas de caution" + +#: deposits/templates/deposits/delete.html:27 +msgid "Deletion of deposit items" +msgstr "Suppression d'articles sous caution" + +#: deposits/templates/deposits/delete.html:34 +#, python-format +msgid "" +"Warning: are you sure you really want to delete this %(objet_name)s object " +"( %(objet)s )?" +msgstr "" +"Attention: voulez-vous vraiment supprimer cet objet %(objet_name)s " +"( %(objet)s ) ?" + +#: deposits/templates/deposits/delete.html:36 deposits/views.py:72 +msgid "Confirm" +msgstr "Confirmer" + +#: deposits/templates/deposits/deposit.html:28 +msgid "Create or edit deposit" +msgstr "Créer ou modifier une caution" + +#: deposits/templates/deposits/deposit.html:35 deposits/views.py:179 +msgid "Add" +msgstr "Ajouter" + +#: deposits/templates/deposits/index_deposit_item.html:27 +#: deposits/templates/deposits/navbar.html:33 +msgid "Deposit items" +msgstr "Articles sous caution" + +#: deposits/templates/deposits/index_deposit_item.html:30 +msgid "List of deposit items" +msgstr "Liste des articles sous caution" + +#: deposits/templates/deposits/index_deposit_item.html:33 +msgid "Add a deposit item" +msgstr "Ajouter un article" + +#: deposits/templates/deposits/index_deposit_item.html:36 +msgid "Delete one or several deposit items" +msgstr "Supprimer ou un plusieurs articles" + +#: deposits/templates/deposits/index_deposits.html:29 +msgid "List of deposits" +msgstr "Liste des cautions" + +#: deposits/templates/deposits/index_deposits.html:35 +msgid "Deposit" +msgid_plural "Deposits" +msgstr[0] "Caution" +msgstr[1] "Cautions" + +#: deposits/templates/deposits/index_deposits.html:38 +msgid "Unreturned deposit" +msgid_plural "Unreturned deposits" +msgstr[0] "Caution non rendue" +msgstr[1] "Cautions non rendues" + +#: deposits/templates/deposits/index_deposits.html:45 deposits/views.py:274 +#: deposits/views.py:303 +msgid "Unreturned deposits" +msgstr "Cautions non rendues" + +#: deposits/templates/deposits/index_deposits.html:56 deposits/views.py:273 +#: deposits/views.py:302 +msgid "Returned deposits" +msgstr "Cautions rendues" + +#: deposits/templates/deposits/index_stats.html:28 +#: deposits/templates/deposits/index_stats.html:31 +#: deposits/templates/deposits/navbar.html:36 +msgid "Deposits statistics" +msgstr "Statistiques sur les cautions" + +#: deposits/templates/deposits/navbar.html:30 +msgid "View deposits" +msgstr "Voir les cautions" + +#: deposits/views.py:66 +msgid "The deposit was created." +msgstr "La caution a été créée." + +#: deposits/views.py:73 +msgid "New deposit" +msgstr "Nouvelle caution" + +#: deposits/views.py:91 +msgid "The deposit was edited." +msgstr "La caution a été modifiée." + +#: deposits/views.py:97 deposits/views.py:202 +msgid "Edit" +msgstr "Modifier" + +#: deposits/views.py:98 +msgid "Edit deposit" +msgstr "Modifier la caution" + +#: deposits/views.py:113 +msgid "The deposit was deleted." +msgstr "La caution a été supprimée." + +#: deposits/views.py:174 +msgid "The item was created." +msgstr "L'article a été créé." + +#: deposits/views.py:180 +msgid "New deposit item" +msgstr "Nouvel article (caution)" + +#: deposits/views.py:197 +msgid "The item was edited." +msgstr "L'article a été modifié." + +#: deposits/views.py:203 +msgid "Edit deposit item" +msgstr "Modifier l'article" + +#: deposits/views.py:220 +msgid "The items were deleted." +msgstr "Les articles ont été supprimés." + +#: deposits/views.py:225 +msgid "Delete" +msgstr "Supprimer" + +#: deposits/views.py:226 +msgid "Delete deposit item" +msgstr "Supprimer l'article" + +#: deposits/views.py:270 +msgid "Deposits by payment method" +msgstr "Cautions par moyen de paiement" + +#: deposits/views.py:275 deposits/views.py:304 deposits/views.py:337 +msgid "Total" +msgstr "Total" + +#: deposits/views.py:299 +msgid "Deposits by item type" +msgstr "Cautions par type d'article" + +#: deposits/views.py:321 +msgid "Not yet returned" +msgstr "Pas encore rendues" + +#: deposits/views.py:326 +msgid "Already returned" +msgstr "Déjà rendues" + +#: deposits/views.py:334 +msgid "Deposits amounts" +msgstr "Montants de cautions" + +#: deposits/views.py:336 +msgid "Category" +msgstr "Catégorie" diff --git a/deposits/migrations/0001_initial.py b/deposits/migrations/0001_initial.py new file mode 100644 index 00000000..dadcb74f --- /dev/null +++ b/deposits/migrations/0001_initial.py @@ -0,0 +1,51 @@ +# Generated by Django 2.2.18 on 2021-08-07 11:08 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import re2o.mixins + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('cotisations', '0004_auto_20210208_1827'), + ] + + operations = [ + migrations.CreateModel( + name='DepositItem', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, unique=True, verbose_name='designation')), + ('deposit_amount', models.DecimalField(decimal_places=2, max_digits=5, verbose_name='deposit amount')), + ], + options={ + 'verbose_name': 'deposit item', + 'verbose_name_plural': 'deposit items', + 'abstract': False, + }, + bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), + ), + migrations.CreateModel( + name='Deposit', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(auto_now_add=True, verbose_name='date')), + ('returned', models.BooleanField(default=False, verbose_name='returned')), + ('deposit_amount', models.DecimalField(decimal_places=2, max_digits=5, verbose_name='deposit amount')), + ('item', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='deposits.DepositItem')), + ('payment_method', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cotisations.Paiement')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'deposit', + 'verbose_name_plural': 'deposits', + 'abstract': False, + }, + bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), + ), + ] diff --git a/deposits/migrations/__init__.py b/deposits/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/deposits/models.py b/deposits/models.py new file mode 100644 index 00000000..efea975a --- /dev/null +++ b/deposits/models.py @@ -0,0 +1,149 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Arthur Grisel-Davy +# Copyright © 2020 Gabriel Détraz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Deposit model +""" + +from __future__ import absolute_import + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from re2o.mixins import AclMixin, RevMixin + + +class Deposit(RevMixin, AclMixin, models.Model): + """ + The model for a deposit. It reprensents the fact that a user made a deposit + as a guarantee for an item which should be returned to get the deposit + back. + + A deposit is linked to : + * a user (the one who made the deposit) + * an item (borrowed in exchange for the deposit) + Every deposit is dated throught the 'date' value. Its amount is saved in + the 'deposit_amount' in case an item's amount changes later on. + A deposit has a 'returned' value (default: False) which means that the item + was returned by the user and the deposit was payed back. + """ + + user = models.ForeignKey("users.User", on_delete=models.PROTECT) + item = models.ForeignKey("DepositItem", on_delete=models.PROTECT) + payment_method = models.ForeignKey("cotisations.Paiement", on_delete=models.PROTECT) + date = models.DateTimeField(auto_now_add=True, verbose_name=_("date")) + returned = models.BooleanField(default=False, verbose_name=_("returned")) + deposit_amount = models.DecimalField( + max_digits=5, decimal_places=2, verbose_name=_("deposit amount") + ) + + class Meta: + abstract = False + verbose_name = _("deposit") + verbose_name_plural = _("deposits") + + def __init__(self, *args, **kwargs): + super(Deposit, self).__init__(*args, **kwargs) + self.__original_item = getattr(self, "item", None) + self.__original_deposit_amount = getattr(self, "deposit_amount", None) + + def __str__(self): + if self.returned: + return _("Deposit from {name} for {item} at {date}, returned").format( + name=self.user.get_full_name(), + item=self.item, + date=self.date, + ) + else: + return _( + "Deposit from {name} for {item} at {date}, not yet returned" + ).format( + name=self.user.get_full_name(), + item=self.item, + date=self.date, + ) + + def save(self, *args, **kwargs): + # Save the item's deposit amount in the deposit's attribute + self.deposit_amount = self.item.deposit_amount + + # If the item didn't change, keep the previous deposit_amount + # This is done in case a DepositItem's deposit_amount is changed, we + # want to make sure deposits created before keep the same amount + if self.__original_deposit_amount and self.item == self.__original_item: + self.deposit_amount = self.__original_deposit_amount + + super(Deposit, self).save(*args, **kwargs) + + def can_view(self, user_request, *_args, **_kwargs): + """Check that the user has the right to view the deposit or that it + belongs to them.""" + if ( + not user_request.has_perm("deposits.view_deposit") + and self.user != user_request + ): + return ( + False, + _("You don't have the right to view other deposits than yours."), + ("deposits.view_deposit",), + ) + else: + return True, None, None + + @staticmethod + def can_view_all(user_request, *_args, **_kwargs): + """Check that the user has access to the list of all tickets.""" + can = user_request.has_perm("deposits.view_deposit") + return ( + can, + _("You don't have the right to view the list of deposits.") + if not can + else None, + ("deposits.view_deposit",), + ) + + +class DepositItem(RevMixin, AclMixin, models.Model): + """An item for a deposit. + + Attributes: + name: the name of this deposit item. + deposit_amount: the amount needed to be deposited by users. + """ + + name = models.CharField( + max_length=255, + blank=False, + null=False, + unique=True, + verbose_name=_("designation"), + ) + deposit_amount = models.DecimalField( + max_digits=5, decimal_places=2, verbose_name=_("deposit amount") + ) + + class Meta: + abstract = False + verbose_name = _("deposit item") + verbose_name_plural = _("deposit items") + + def __str__(self): + return self.name diff --git a/deposits/templates/deposits/aff_deposit_item.html b/deposits/templates/deposits/aff_deposit_item.html new file mode 100644 index 00000000..60bff968 --- /dev/null +++ b/deposits/templates/deposits/aff_deposit_item.html @@ -0,0 +1,48 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load i18n %} +{% load logs_extra %} +{% load design %} + + + + + + + + + + {% for item in item_list %} + + + + + + {% endfor %} +
{% trans "Deposit item" %}{% trans "Amount" %}
{{ item.name }}{{ item.deposit_amount }} € + {% can_edit item %} + {% include 'buttons/edit.html' with href='deposits:edit-deposit-item' id=item.id %} + {% acl_end %} + {% history_button item %} +
diff --git a/deposits/templates/deposits/aff_deposits.html b/deposits/templates/deposits/aff_deposits.html new file mode 100644 index 00000000..1b32ebd4 --- /dev/null +++ b/deposits/templates/deposits/aff_deposits.html @@ -0,0 +1,89 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load acl %} +{% load i18n %} +{% load logs_extra %} + +{% block content %} + +
+ + + + + + + + + + + + + {% for deposit in deposits_list %} + + + + + + + {% if deposit.returned %} + + {% else %} + + {% endif %} + + + {% endfor %} + + +
+ {% trans "User" as tr_user %} + {% include 'buttons/sort.html' with prefix='deposit' col="user" text=tr_user %} + + {% trans "Item" as tr_item %} + {% include 'buttons/sort.html' with prefix='deposit' col="item" text=tr_item %} + + {% trans "Amount" as tr_amount %} + {% include 'buttons/sort.html' with prefix='deposit' col="amount" text=tr_amount %} + + {% trans "Payment method" as tr_payment %} + {% include 'buttons/sort.html' with prefix='deposit' col="payment" text=tr_payment %} + + {% trans "Date" as tr_date %} + {% include 'buttons/sort.html' with prefix='deposit' col="date" text=tr_date %} + + {% trans "Returned" as tr_returned %} + {% include 'buttons/sort.html' with prefix='deposit' col="returned" text=tr_returned %} +
{{ deposit.user.get_short_name }}{{ deposit.item.name }}{{ deposit.deposit_amount }} €{{ deposit.payment_method.moyen }}{{ deposit.date }} + {% can_edit deposit %} + {% include 'buttons/edit.html' with href='deposits:edit-deposit' id=deposit.id %} + {% acl_end %} + {% history_button deposit %} +
+ + {% if deposits_list.paginator and show_pagination is not False %} + {% include 'pagination.html' with list=deposits_list go_to_id="deposits" %} + {% endif %} +
+{% endblock %} diff --git a/deposits/templates/deposits/aff_profil.html b/deposits/templates/deposits/aff_profil.html new file mode 100644 index 00000000..862f4a4d --- /dev/null +++ b/deposits/templates/deposits/aff_profil.html @@ -0,0 +1,48 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load i18n %} + +
+
+

+ {% trans "Deposits" %} +

+
+
+
+ {% can_create Deposit %} + + {% trans "Add a deposit" %} + + {% acl_end %} +
+
+ {% if deposits_list %} + {% include 'deposits/aff_deposits.html' with deposits_list=deposits_list %} + {% else %} +

{% trans "No deposit" %}

+ {% endif %} +
+
+
diff --git a/deposits/templates/deposits/aff_stats.html b/deposits/templates/deposits/aff_stats.html new file mode 100644 index 00000000..727e2557 --- /dev/null +++ b/deposits/templates/deposits/aff_stats.html @@ -0,0 +1,40 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +

{{ stats_dict.title }}

+ + + + + {% for header in stats_dict.headers %} + + {% endfor %} + + + {% for stats in stats_dict.data %} + + {% for item in stats %} + + {% endfor %} + + {% endfor %} +
{{ header }}
{{ item }}
diff --git a/deposits/templates/deposits/delete.html b/deposits/templates/deposits/delete.html new file mode 100644 index 00000000..25859783 --- /dev/null +++ b/deposits/templates/deposits/delete.html @@ -0,0 +1,39 @@ +{% extends 'deposits/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block title %}{% trans "Deletion of deposit items" %}{% endblock %} + +{% block content %} + +
+ {% csrf_token %} +

+ {% blocktrans %}Warning: are you sure you really want to delete this {{ objet_name }} object ( {{ objet }} )?{% endblocktrans %} +

+ {% trans "Confirm" as tr_confirm %} + {% bootstrap_button tr_confirm button_type='submit' icon='trash' button_class='btn-danger' %} +
+{% endblock %} diff --git a/deposits/templates/deposits/deposit.html b/deposits/templates/deposits/deposit.html new file mode 100644 index 00000000..24dfb476 --- /dev/null +++ b/deposits/templates/deposits/deposit.html @@ -0,0 +1,44 @@ +{% extends 'deposits/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load staticfiles%} +{% load i18n %} + +{% block title %}{% trans "Create or edit deposit" %}{% endblock %} + +{% block content %} + +{% if title %} +

{{ title }}

+{% else %} +

{% trans "Add" %}

+{% endif %} + +
+ {% csrf_token %} + {% bootstrap_form depositform %} + {% bootstrap_button action_name button_type='submit' icon='ok' button_class='btn-success' %} +
+ +{% endblock %} diff --git a/deposits/templates/deposits/index_deposit_item.html b/deposits/templates/deposits/index_deposit_item.html new file mode 100644 index 00000000..6dc391da --- /dev/null +++ b/deposits/templates/deposits/index_deposit_item.html @@ -0,0 +1,40 @@ +{% extends 'deposits/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load i18n %} + +{% block title %}{% trans "Deposit items" %}{% endblock %} + +{% block content %} +

{% trans "List of deposit items" %}

+ {% can_create DepositItem %} + + {% trans "Add a deposit item" %} + + + {% trans "Delete one or several deposit items" %} + + {% acl_end %} + {% include 'deposits/aff_deposit_item.html' with item_list=item_list %} +{% endblock %} diff --git a/deposits/templates/deposits/index_deposits.html b/deposits/templates/deposits/index_deposits.html new file mode 100644 index 00000000..5c6525a5 --- /dev/null +++ b/deposits/templates/deposits/index_deposits.html @@ -0,0 +1,64 @@ +{% extends 'deposits/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load i18n %} +{% load logs_extra %} + +{% block content %} +

{% trans "List of deposits" %}

+ +
+
+
+
+  {{ nbr_deposits }} {% blocktrans count nb=nbr_deposits %}Deposit{% plural %}Deposits{% endblocktrans %} +
+
+  {{ nbr_deposits_lent }} {% blocktrans count nb=nbr_deposits_lent %}Unreturned deposit{% plural %}Unreturned deposits{% endblocktrans %} +
+
+
+
+ +
+

{% trans "Unreturned deposits" %}

+ {% include 'deposits/aff_deposits.html' with deposits_list=lent_deposits_list show_pagination=False %} + + {% if lent_deposits_list.paginator %} + {% include 'pagination.html' with list=lent_deposits_list page_arg='lpage' go_to_id='unreturned_deposits' %} + {% endif %} +
+ +
+ +
+

{% trans "Returned deposits" %}

+ {% include 'deposits/aff_deposits.html' with deposits_list=returned_deposits_list show_pagination=False %} + + {% if returned_deposits_list.paginator %} + {% include 'pagination.html' with list=returned_deposits_list page_arg='rpage' go_to_id='returned_deposits' %} + {% endif %} +
+ +{% endblock %} diff --git a/deposits/templates/deposits/index_stats.html b/deposits/templates/deposits/index_stats.html new file mode 100644 index 00000000..c982c87b --- /dev/null +++ b/deposits/templates/deposits/index_stats.html @@ -0,0 +1,36 @@ +{% extends 'deposits/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load i18n %} + +{% block title %}{% trans "Deposits statistics" %}{% endblock %} + +{% block content %} +

{% trans "Deposits statistics" %}

+ +{% for stats_dict in stats_list %} + {% include 'deposits/aff_stats.html' with stats_dict=stats_dict %} +
+{% endfor %} + +{% endblock %} diff --git a/deposits/templates/deposits/navbar.html b/deposits/templates/deposits/navbar.html new file mode 100644 index 00000000..c707857f --- /dev/null +++ b/deposits/templates/deposits/navbar.html @@ -0,0 +1,39 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load i18n %} + +
  • + {% trans "Deposits" %} + » + +
  • diff --git a/deposits/templates/deposits/sidebar.html b/deposits/templates/deposits/sidebar.html new file mode 100644 index 00000000..fcf4bcbc --- /dev/null +++ b/deposits/templates/deposits/sidebar.html @@ -0,0 +1,28 @@ +{% extends 'base.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2021 Jean-Romain Garnier + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load i18n %} + +{% block sidebar %} +{% endblock %} diff --git a/deposits/tests.py b/deposits/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/deposits/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/deposits/urls.py b/deposits/urls.py new file mode 100644 index 00000000..898f7481 --- /dev/null +++ b/deposits/urls.py @@ -0,0 +1,45 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Deposits url +""" + +from django.urls import path + +from . import views + +app_name = "deposits" + +urlpatterns = [ + path("new_deposit/", views.new_deposit, name="new-deposit"), + path("edit_deposit/", views.edit_deposit, name="edit-deposit"), + path("del_deposit/", views.del_deposit, name="del-deposit"), + path("index_deposits", views.index_deposits, name="index-deposits"), + path("add_deposit_item", views.add_deposit_item, name="add-deposit-item"), + path( + "edit_deposit_item/", + views.edit_deposit_item, + name="edit-deposit-item", + ), + path("del_deposit_item", views.del_deposit_item, name="del-deposit-item"), + path("index_deposit_item", views.index_deposit_item, name="index-deposit-item"), + path("index_stats", views.index_stats, name="index-stats"), +] diff --git a/deposits/utils.py b/deposits/utils.py new file mode 100644 index 00000000..e6c732b6 --- /dev/null +++ b/deposits/utils.py @@ -0,0 +1,38 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Deposits utils +""" +from re2o.base import SortTable + + +class DepositSortTable(SortTable): + """Extension of the SortTable class to handle the deposit optional app""" + + DEPOSIT_INDEX = { + "deposit_user": ["user__pseudo"], + "deposit_item": ["item__name"], + "deposit_payment": ["payment_method__moyen"], + "deposit_date": ["date"], + "deposit_returned": ["returned"], + "deposit_amount": ["deposit_amount"], + "default": ["-date"], + } diff --git a/deposits/views.py b/deposits/views.py new file mode 100644 index 00000000..b4b7116d --- /dev/null +++ b/deposits/views.py @@ -0,0 +1,383 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2021 Jean-Romain Garnier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Deposits views +""" + +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.shortcuts import redirect, render +from django.template.loader import render_to_string +from django.urls import reverse +from django.utils.translation import ugettext as _ +from django.db.models import Sum + +from preferences.models import GeneralOption +from re2o.acl import ( + can_create, + can_delete, + can_delete_set, + can_edit, + can_view_all, +) +from re2o.base import re2o_paginator +from re2o.views import form +from users.models import User +from cotisations.models import Paiement + +from .forms import DepositForm, DepositItemForm, DelDepositItemForm +from .models import Deposit, DepositItem +from .utils import DepositSortTable + + +@login_required +@can_create(Deposit) +@can_edit(User) +def new_deposit(request, user, userid): + """ + View called to create a new deposit. + """ + deposit = Deposit(user=user) + # Building the invoice form and the article formset + deposit_form = DepositForm( + request.POST or None, instance=deposit, user=request.user, creation=True + ) + + if deposit_form.is_valid(): + deposit_form.save() + messages.success(request, _("The deposit was created.")) + return redirect(reverse("users:profil", kwargs={"userid": deposit.user.pk})) + + return form( + { + "depositform": deposit_form, + "action_name": _("Confirm"), + "title": _("New deposit"), + }, + "deposits/deposit.html", + request, + ) + + +@login_required +@can_edit(Deposit) +def edit_deposit(request, deposit, **_kwargs): + """ + View used to edit an existing deposit. + """ + deposit_form = DepositForm( + request.POST or None, instance=deposit, user=request.user + ) + if deposit_form.is_valid(): + deposit_form.save() + messages.success(request, _("The deposit was edited.")) + return redirect(reverse("users:profil", kwargs={"userid": deposit.user.pk})) + + return form( + { + "depositform": deposit_form, + "action_name": _("Edit"), + "title": _("Edit deposit"), + }, + "deposits/deposit.html", + request, + ) + + +@login_required +@can_delete(Deposit) +def del_deposit(request, deposit, **_kwargs): + """ + View used to delete an existing deposit. + """ + if request.method == "POST": + deposit.delete() + messages.success(request, _("The deposit was deleted.")) + return redirect(reverse("users:profil", kwargs={"userid": deposit.user.pk})) + return form( + {"object": deposit, "objet_name": _("deposit")}, + "deposits/delete.html", + request, + ) + + +@login_required +@can_view_all(Deposit, DepositItem, Paiement, User) +def index_deposits(request): + """ + View used to display the list of all deposits. + """ + pagination_number = GeneralOption.get_cached_value("pagination_number") + + # Get the list of all deposits, sorted according to the user's request + deposits_list = Deposit.objects.select_related("user", "item", "payment_method") + deposits_list = DepositSortTable.sort( + deposits_list, + request.GET.get("col"), + request.GET.get("order"), + DepositSortTable.DEPOSIT_INDEX, + ) + nbr_deposits = deposits_list.count() + + # Split it into 2: the list of those which have not yet been returned... + lent_deposits_list = deposits_list.filter(returned=False) + nbr_deposits_lent = lent_deposits_list.count() + lent_deposits_list = re2o_paginator( + request, lent_deposits_list, pagination_number, page_arg="lpage" + ) + + # ... and the list of those that have already been returned + returned_deposits_list = deposits_list.filter(returned=True) + returned_deposits_list = re2o_paginator( + request, returned_deposits_list, pagination_number, page_arg="rpage" + ) + + return render( + request, + "deposits/index_deposits.html", + { + "lent_deposits_list": lent_deposits_list, + "returned_deposits_list": returned_deposits_list, + "nbr_deposits": nbr_deposits, + "nbr_deposits_lent": nbr_deposits_lent, + }, + ) + + +@login_required +@can_create(DepositItem) +def add_deposit_item(request): + """ + View used to add a deposit item. + """ + item = DepositItemForm(request.POST or None) + if item.is_valid(): + item.save() + messages.success(request, _("The item was created.")) + return redirect(reverse("deposits:index-deposit-item")) + return form( + { + "depositform": item, + "action_name": _("Add"), + "title": _("New deposit item"), + }, + "deposits/deposit.html", + request, + ) + + +@login_required +@can_edit(DepositItem) +def edit_deposit_item(request, item_instance, **_kwargs): + """ + View used to edit a deposit item. + """ + item = DepositItemForm(request.POST or None, instance=item_instance) + if item.is_valid(): + if item.changed_data: + item.save() + messages.success(request, _("The item was edited.")) + return redirect(reverse("deposits:index-deposit-item")) + return form( + { + "depositform": item, + "action_name": _("Edit"), + "title": _("Edit deposit item"), + }, + "deposits/deposit.html", + request, + ) + + +@login_required +@can_delete_set(DepositItem) +def del_deposit_item(request, instances): + """ + View used to delete one of the deposit items. + """ + item = DelDepositItemForm(request.POST or None, instances=instances) + if item.is_valid(): + item_del = item.cleaned_data["deposit_items"] + item_del.delete() + messages.success(request, _("The items were deleted.")) + return redirect(reverse("deposits:index-deposit-item")) + return form( + { + "depositform": item, + "action_name": _("Delete"), + "title": _("Delete deposit item"), + }, + "deposits/deposit.html", + request, + ) + + +@login_required +@can_view_all(DepositItem) +def index_deposit_item(request): + """ + View used to display the list of all available deposit items. + """ + # TODO : Offer other means of sorting + item_list = DepositItem.objects.order_by("name") + return render(request, "deposits/index_deposit_item.html", {"item_list": item_list}) + + +@login_required +@can_view_all(Deposit, DepositItem, Paiement, User) +def index_stats(request): + """ + View used to display general statistics about deposits + """ + # We want to build a list of tables for statistics + stats = [] + + # Statistics for payment methods + payment_data = [] + for method in Paiement.objects.order_by("moyen"): + deposits = Deposit.objects.filter(payment_method=method) + amount = deposits.aggregate(Sum("deposit_amount")).get( + "deposit_amount__sum", None + ) + payment_data.append( + ( + method.moyen, + deposits.filter(returned=False).count(), + deposits.filter(returned=True).count(), + deposits.count(), + "{} €".format(amount or 0), + ) + ) + + stats.append( + { + "title": _("Deposits by payment method"), + "headers": [ + _("Payment method"), + _("Unreturned deposits"), + _("Returned deposits"), + _("Total"), + _("Amount"), + ], + "data": payment_data, + } + ) + + # Statistics for deposit items + items_data = [] + for item in DepositItem.objects.order_by("name"): + deposits = Deposit.objects.filter(item=item) + amount = deposits.aggregate(Sum("deposit_amount")).get( + "deposit_amount__sum", None + ) + items_data.append( + ( + item.name, + deposits.filter(returned=False).count(), + deposits.filter(returned=True).count(), + deposits.count(), + "{} €".format(amount or 0), + ) + ) + + stats.append( + { + "title": _("Deposits by item type"), + "headers": [ + _("Deposit item"), + _("Unreturned deposits"), + _("Returned deposits"), + _("Total"), + _("Amount"), + ], + "data": items_data, + } + ) + + # Statistics for amounts + pending_amount = ( + Deposit.objects.filter(returned=False) + .aggregate(Sum("deposit_amount")) + .get("deposit_amount__sum", None) + ) + returned_amount = ( + Deposit.objects.filter(returned=True) + .aggregate(Sum("deposit_amount")) + .get("deposit_amount__sum", None) + ) + + amounts_data = [ + ( + _("Not yet returned"), + Deposit.objects.filter(returned=False).count(), + "{} €".format(pending_amount or 0), + ), + ( + _("Already returned"), + Deposit.objects.filter(returned=True).count(), + "{} €".format(returned_amount or 0), + ), + ] + + stats.append( + { + "title": _("Deposits amounts"), + "headers": [ + _("Category"), + _("Total"), + _("Amount"), + ], + "data": amounts_data, + } + ) + + return render(request, "deposits/index_stats.html", {"stats_list": stats}) + + +# Canonic views for optional apps +def aff_profil(request, user): + """View used to display the deposits on a user's profile.""" + deposits_list = Deposit.objects.filter(user=user).select_related( + "user", "item", "payment_method" + ) + deposits_list = DepositSortTable.sort( + deposits_list, + request.GET.get("col"), + request.GET.get("order"), + DepositSortTable.DEPOSIT_INDEX, + ) + pagination_number = GeneralOption.get_cached_value("pagination_large_number") + + deposits = re2o_paginator(request, deposits_list, pagination_number) + context = { + "users": user, + "deposits_list": deposits, + } + return render_to_string( + "deposits/aff_profil.html", context=context, request=request, using=None + ) + + +def navbar_user(): + """View used to display a link to deposit items in the navbar (in the dropdown + menu Treasury). + """ + return ("cotisations", render_to_string("deposits/navbar.html"))