mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-30 23:39:54 +01:00 
			
		
		
		
	Manage remittance types
This commit is contained in:
		| @@ -1,16 +1,27 @@ | ||||
| # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
| # SPDX-License-Identifier: GPL-3.0-or-lateré | ||||
|  | ||||
| from django.contrib import admin | ||||
|  | ||||
| from .models import Invoice, Product | ||||
| from .models import RemittanceType, Remittance | ||||
|  | ||||
|  | ||||
| @admin.register(Invoice) | ||||
| class InvoiceAdmin(admin.ModelAdmin): | ||||
|     list_display = ('id', 'name', 'object', 'acquitted', ) | ||||
| @admin.register(RemittanceType) | ||||
| class RemittanceTypeAdmin(admin.ModelAdmin): | ||||
|     """ | ||||
|     Admin customisation for RemiitanceType | ||||
|     """ | ||||
|     list_display = ('note', ) | ||||
|  | ||||
|  | ||||
| @admin.register(Product) | ||||
| class ProductAdmin(admin.ModelAdmin): | ||||
|     list_display = ('designation', 'quantity', 'amount', ) | ||||
| @admin.register(Remittance) | ||||
| class RemittanceAdmin(admin.ModelAdmin): | ||||
|     """ | ||||
|     Admin customisation for Remittance | ||||
|     """ | ||||
|     list_display = ('remittance_type', 'date', 'comment', 'count', 'amount', 'closed', ) | ||||
|  | ||||
|     def has_change_permission(self, request, obj=None): | ||||
|         if not obj: | ||||
|             return True | ||||
|         return not obj.closed and super().has_change_permission(request, obj) | ||||
|   | ||||
| @@ -2,8 +2,9 @@ | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| from rest_framework import serializers | ||||
| from note.api.serializers import SpecialTransactionSerializer | ||||
|  | ||||
| from ..models import Invoice, Product | ||||
| from ..models import Invoice, Product, RemittanceType, Remittance | ||||
|  | ||||
|  | ||||
| class ProductSerializer(serializers.ModelSerializer): | ||||
| @@ -32,3 +33,30 @@ class InvoiceSerializer(serializers.ModelSerializer): | ||||
|     def get_products(self, obj): | ||||
|         return serializers.ListSerializer(child=ProductSerializer())\ | ||||
|             .to_representation(Product.objects.filter(invoice=obj).all()) | ||||
|  | ||||
|  | ||||
| class RemittanceTypeSerializer(serializers.ModelSerializer): | ||||
|     """ | ||||
|     REST API Serializer for RemittanceType types. | ||||
|     The djangorestframework plugin will analyse the model `RemittanceType` and parse all fields in the API. | ||||
|     """ | ||||
|  | ||||
|     class Meta: | ||||
|         model = RemittanceType | ||||
|         fields = '__all__' | ||||
|  | ||||
|  | ||||
| class RemittanceSerializer(serializers.ModelSerializer): | ||||
|     """ | ||||
|     REST API Serializer for Remittance types. | ||||
|     The djangorestframework plugin will analyse the model `Remittance` and parse all fields in the API. | ||||
|     """ | ||||
|  | ||||
|     transactions = serializers.SerializerMethodField() | ||||
|  | ||||
|     class Meta: | ||||
|         model = Remittance | ||||
|         fields = '__all__' | ||||
|  | ||||
|     def get_transactions(self, obj): | ||||
|         return serializers.ListSerializer(child=SpecialTransactionSerializer()).to_representation(obj.transactions) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| from .views import InvoiceViewSet, ProductViewSet | ||||
| from .views import InvoiceViewSet, ProductViewSet, RemittanceViewSet, RemittanceTypeViewSet | ||||
|  | ||||
|  | ||||
| def register_treasury_urls(router, path): | ||||
| @@ -10,3 +10,5 @@ def register_treasury_urls(router, path): | ||||
|     """ | ||||
|     router.register(path + '/invoice', InvoiceViewSet) | ||||
|     router.register(path + '/product', ProductViewSet) | ||||
|     router.register(path + '/remittance_type', RemittanceTypeViewSet) | ||||
|     router.register(path + '/remittance', RemittanceViewSet) | ||||
|   | ||||
| @@ -5,8 +5,8 @@ from django_filters.rest_framework import DjangoFilterBackend | ||||
| from rest_framework.filters import SearchFilter | ||||
| from api.viewsets import ReadProtectedModelViewSet | ||||
|  | ||||
| from .serializers import InvoiceSerializer, ProductSerializer | ||||
| from ..models import Invoice, Product | ||||
| from .serializers import InvoiceSerializer, ProductSerializer, RemittanceTypeSerializer, RemittanceSerializer | ||||
| from ..models import Invoice, Product, RemittanceType, Remittance | ||||
|  | ||||
|  | ||||
| class InvoiceViewSet(ReadProtectedModelViewSet): | ||||
| @@ -31,3 +31,23 @@ class ProductViewSet(ReadProtectedModelViewSet): | ||||
|     serializer_class = ProductSerializer | ||||
|     filter_backends = [SearchFilter] | ||||
|     search_fields = ['$designation', ] | ||||
|  | ||||
|  | ||||
| class RemittanceTypeViewSet(ReadProtectedModelViewSet): | ||||
|     """ | ||||
|     REST API View set. | ||||
|     The djangorestframework plugin will get all `RemittanceType` objects, serialize it to JSON with the given serializer | ||||
|     then render it on /api/treasury/remittance_type/ | ||||
|     """ | ||||
|     queryset = RemittanceType.objects.all() | ||||
|     serializer_class = RemittanceTypeSerializer | ||||
|  | ||||
|  | ||||
| class RemittanceViewSet(ReadProtectedModelViewSet): | ||||
|     """ | ||||
|     REST API View set. | ||||
|     The djangorestframework plugin will get all `Remittance` objects, serialize it to JSON with the given serializer, | ||||
|     then render it on /api/treasury/remittance/ | ||||
|     """ | ||||
|     queryset = Remittance.objects.all() | ||||
|     serializer_class = RemittanceSerializer | ||||
|   | ||||
							
								
								
									
										9
									
								
								apps/treasury/fixtures/initial.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apps/treasury/fixtures/initial.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| [ | ||||
|   { | ||||
|     "model": "treasury.remittancetype", | ||||
|     "pk": 1, | ||||
|     "fields": { | ||||
|       "note": 3 | ||||
|     } | ||||
|   } | ||||
| ] | ||||
| @@ -49,8 +49,8 @@ class RemittanceForm(forms.ModelForm): | ||||
|         self.helper = FormHelper() | ||||
|  | ||||
|         if self.instance.pk: | ||||
|             self.fields["type"].disabled = True | ||||
|             self.fields["type"].required = False | ||||
|             self.fields["remittance_type"].disabled = True | ||||
|             self.fields["remittance_type"].required = False | ||||
|  | ||||
|         if not self.instance.closed: | ||||
|             self.helper.add_input(Submit('submit', _("Submit"), attr={'class': 'btn btn-block btn-primary'})) | ||||
| @@ -66,8 +66,8 @@ class RemittanceForm(forms.ModelForm): | ||||
|  | ||||
|         cleaned_data = super().clean() | ||||
|  | ||||
|         if "type" in self.changed_data: | ||||
|             self.add_error("type", _("You can't change the type of the remittance.")) | ||||
|         if self.instance.pk and cleaned_data.get("remittance_type") != self.instance.remittance_type: | ||||
|             self.add_error("remittance_type", _("You can't change the type of the remittance.")) | ||||
|  | ||||
|         if "close" in self.data: | ||||
|             self.instance.closed = True | ||||
| @@ -77,7 +77,7 @@ class RemittanceForm(forms.ModelForm): | ||||
|  | ||||
|     class Meta: | ||||
|         model = Remittance | ||||
|         fields = ('type', 'comment', ) | ||||
|         fields = ('remittance_type', 'comment',) | ||||
|  | ||||
|  | ||||
| class LinkTransactionToRemittanceForm(forms.ModelForm): | ||||
|   | ||||
| @@ -96,6 +96,20 @@ class Product(models.Model): | ||||
|         return self.total / 100 | ||||
|  | ||||
|  | ||||
| class RemittanceType(models.Model): | ||||
|     """ | ||||
|     Store what kind of remittances can be stored. | ||||
|     """ | ||||
|  | ||||
|     note = models.OneToOneField( | ||||
|         NoteSpecial, | ||||
|         on_delete=models.CASCADE, | ||||
|     ) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return str(self.note) | ||||
|  | ||||
|  | ||||
| class Remittance(models.Model): | ||||
|     """ | ||||
|     Treasurers want to regroup checks or bank transfers in bank remittances. | ||||
| @@ -106,8 +120,8 @@ class Remittance(models.Model): | ||||
|         verbose_name=_("Date"), | ||||
|     ) | ||||
|  | ||||
|     type = models.ForeignKey( | ||||
|         NoteSpecial, | ||||
|     remittance_type = models.ForeignKey( | ||||
|         RemittanceType, | ||||
|         on_delete=models.PROTECT, | ||||
|         verbose_name=_("Type"), | ||||
|     ) | ||||
| @@ -133,13 +147,13 @@ class Remittance(models.Model): | ||||
|     def amount(self): | ||||
|         return sum(transaction.total for transaction in self.transactions.all()) | ||||
|  | ||||
|     def full_clean(self, exclude=None, validate_unique=True): | ||||
|         ret = super().full_clean(exclude, validate_unique) | ||||
|     def save(self, force_insert=False, force_update=False, using=None, | ||||
|              update_fields=None): | ||||
|  | ||||
|         if self.transactions.filter(~Q(source=self.type)).exists(): | ||||
|         if self.transactions.filter(~Q(source=self.remittance_type.note)).exists(): | ||||
|             raise ValidationError("All transactions in a remittance must have the same type") | ||||
|  | ||||
|         return ret | ||||
|         return super().save(force_insert, force_update, using, update_fields) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return _("Remittance #{:d}: {}").format(self.id, self.comment, ) | ||||
|   | ||||
| @@ -56,7 +56,7 @@ class RemittanceTable(tables.Table): | ||||
|         } | ||||
|         model = Remittance | ||||
|         template_name = 'django_tables2/bootstrap4.html' | ||||
|         fields = ('id', 'date', 'type', 'comment', 'count', 'amount', 'view',) | ||||
|         fields = ('id', 'date', 'remittance_type', 'comment', 'count', 'amount', 'view',) | ||||
|  | ||||
|  | ||||
| class SpecialTransactionTable(tables.Table): | ||||
|   | ||||
| @@ -17,11 +17,11 @@ from django.urls import reverse_lazy | ||||
| from django.views.generic import CreateView, UpdateView | ||||
| from django.views.generic.base import View, TemplateView | ||||
| from django_tables2 import SingleTableView | ||||
| from note.models import SpecialTransaction | ||||
| from note.models import SpecialTransaction, NoteSpecial | ||||
| from note_kfet.settings.base import BASE_DIR | ||||
|  | ||||
| from .forms import InvoiceForm, ProductFormSet, ProductFormSetHelper, RemittanceForm, LinkTransactionToRemittanceForm | ||||
| from .models import Invoice, Product, Remittance, SpecialTransactionProxy | ||||
| from .models import Invoice, Product, Remittance, SpecialTransactionProxy, RemittanceType | ||||
| from .tables import InvoiceTable, RemittanceTable, SpecialTransactionTable | ||||
|  | ||||
|  | ||||
| @@ -212,11 +212,11 @@ class RemittanceListView(LoginRequiredMixin, TemplateView): | ||||
|         ctx["opened_remittances"] = RemittanceTable(data=Remittance.objects.filter(closed=False).all()) | ||||
|         ctx["closed_remittances"] = RemittanceTable(data=Remittance.objects.filter(closed=True).reverse().all()) | ||||
|         ctx["special_transactions_no_remittance"] = SpecialTransactionTable( | ||||
|             data=SpecialTransaction.objects.filter(source__polymorphic_ctype__model="notespecial", | ||||
|             data=SpecialTransaction.objects.filter(source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)), | ||||
|                                                    specialtransactionproxy__remittance=None).all(), | ||||
|             exclude=('remittance_remove', )) | ||||
|         ctx["special_transactions_with_remittance"] = SpecialTransactionTable( | ||||
|             data=SpecialTransaction.objects.filter(source__polymorphic_ctype__model="notespecial", | ||||
|             data=SpecialTransaction.objects.filter(source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)), | ||||
|                                                    specialtransactionproxy__remittance__closed=False).all(), | ||||
|             exclude=('remittance_add', )) | ||||
|  | ||||
| @@ -236,7 +236,6 @@ class RemittanceUpdateView(LoginRequiredMixin, UpdateView): | ||||
|     def get_context_data(self, **kwargs): | ||||
|         ctx = super().get_context_data(**kwargs) | ||||
|  | ||||
|         form = ctx["form"] | ||||
|         ctx["table"] = RemittanceTable(data=Remittance.objects.all()) | ||||
|         data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).all() | ||||
|         ctx["special_transactions"] = SpecialTransactionTable( | ||||
| @@ -262,7 +261,7 @@ class LinkTransactionToRemittanceView(LoginRequiredMixin, UpdateView): | ||||
|         form.fields["bank"].initial = self.object.transaction.bank | ||||
|         form.fields["amount"].initial = self.object.transaction.amount | ||||
|         form.fields["remittance"].queryset = form.fields["remittance"] \ | ||||
|             .queryset.filter(type=self.object.transaction.source) | ||||
|             .queryset.filter(remittance_type__note=self.object.transaction.source) | ||||
|  | ||||
|         return ctx | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2020-03-24 01:00+0100\n" | ||||
| "POT-Creation-Date: 2020-03-24 15:49+0100\n" | ||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| @@ -576,28 +576,29 @@ msgstr "" | ||||
| msgid "Unit price" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/models.py:106 | ||||
| #: apps/treasury/models.py:120 | ||||
| msgid "Date" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/models.py:112 | ||||
| #: apps/treasury/models.py:126 | ||||
| msgid "Type" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/models.py:117 | ||||
| #: apps/treasury/models.py:131 | ||||
| msgid "Comment" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/models.py:122 | ||||
| #: apps/treasury/models.py:136 | ||||
| msgid "Closed" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/models.py:145 | ||||
| #: apps/treasury/models.py:159 | ||||
| msgid "Remittance #{:d}: {}" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/models.py:164 apps/treasury/tables.py:64 | ||||
| #: apps/treasury/tables.py:72 | ||||
| #: apps/treasury/models.py:178 apps/treasury/tables.py:64 | ||||
| #: apps/treasury/tables.py:72 templates/treasury/invoice_list.html:13 | ||||
| #: templates/treasury/remittance_list.html:13 | ||||
| msgid "Remittance" | ||||
| msgstr "" | ||||
|  | ||||
| @@ -605,7 +606,8 @@ msgstr "" | ||||
| msgid "Invoice #{:d}" | ||||
| msgstr "" | ||||
|  | ||||
| #: apps/treasury/tables.py:19 | ||||
| #: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10 | ||||
| #: templates/treasury/remittance_list.html:10 | ||||
| msgid "Invoice" | ||||
| msgstr "" | ||||
|  | ||||
| @@ -952,7 +954,7 @@ msgstr "" | ||||
| msgid "Remove product" | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/invoice_list.html:8 | ||||
| #: templates/treasury/invoice_list.html:21 | ||||
| msgid "New invoice" | ||||
| msgstr "" | ||||
|  | ||||
| @@ -977,34 +979,34 @@ msgstr "" | ||||
| msgid "There is no transaction linked with this remittance." | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:6 | ||||
| #: templates/treasury/remittance_list.html:19 | ||||
| msgid "Opened remittances" | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:11 | ||||
| #: templates/treasury/remittance_list.html:24 | ||||
| msgid "There is no opened remittance." | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:15 | ||||
| #: templates/treasury/remittance_list.html:28 | ||||
| msgid "New remittance" | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:19 | ||||
| #: templates/treasury/remittance_list.html:32 | ||||
| msgid "Transfers without remittances" | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:24 | ||||
| #: templates/treasury/remittance_list.html:37 | ||||
| msgid "There is no transaction without any linked remittance." | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:30 | ||||
| #: templates/treasury/remittance_list.html:43 | ||||
| msgid "Transfers with opened remittances" | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:35 | ||||
| #: templates/treasury/remittance_list.html:48 | ||||
| msgid "There is no transaction without an opened linked remittance." | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:41 | ||||
| #: templates/treasury/remittance_list.html:54 | ||||
| msgid "Closed remittances" | ||||
| msgstr "" | ||||
|   | ||||
| @@ -3,7 +3,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2020-03-24 01:00+0100\n" | ||||
| "POT-Creation-Date: 2020-03-24 15:49+0100\n" | ||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| @@ -576,28 +576,29 @@ msgstr "Quantité" | ||||
| msgid "Unit price" | ||||
| msgstr "Prix unitaire" | ||||
|  | ||||
| #: apps/treasury/models.py:106 | ||||
| #: apps/treasury/models.py:120 | ||||
| msgid "Date" | ||||
| msgstr "Date" | ||||
|  | ||||
| #: apps/treasury/models.py:112 | ||||
| #: apps/treasury/models.py:126 | ||||
| msgid "Type" | ||||
| msgstr "Type" | ||||
|  | ||||
| #: apps/treasury/models.py:117 | ||||
| #: apps/treasury/models.py:131 | ||||
| msgid "Comment" | ||||
| msgstr "Commentaire" | ||||
|  | ||||
| #: apps/treasury/models.py:122 | ||||
| #: apps/treasury/models.py:136 | ||||
| msgid "Closed" | ||||
| msgstr "Fermée" | ||||
|  | ||||
| #: apps/treasury/models.py:145 | ||||
| #: apps/treasury/models.py:159 | ||||
| msgid "Remittance #{:d}: {}" | ||||
| msgstr "Remise n°{:d} : {}" | ||||
|  | ||||
| #: apps/treasury/models.py:164 apps/treasury/tables.py:64 | ||||
| #: apps/treasury/tables.py:72 | ||||
| #: apps/treasury/models.py:178 apps/treasury/tables.py:64 | ||||
| #: apps/treasury/tables.py:72 templates/treasury/invoice_list.html:13 | ||||
| #: templates/treasury/remittance_list.html:13 | ||||
| msgid "Remittance" | ||||
| msgstr "Remise" | ||||
|  | ||||
| @@ -605,7 +606,8 @@ msgstr "Remise" | ||||
| msgid "Invoice #{:d}" | ||||
| msgstr "Facture n°{:d}" | ||||
|  | ||||
| #: apps/treasury/tables.py:19 | ||||
| #: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10 | ||||
| #: templates/treasury/remittance_list.html:10 | ||||
| msgid "Invoice" | ||||
| msgstr "Facture" | ||||
|  | ||||
| @@ -954,7 +956,7 @@ msgstr "Ajouter produit" | ||||
| msgid "Remove product" | ||||
| msgstr "Retirer produit" | ||||
|  | ||||
| #: templates/treasury/invoice_list.html:8 | ||||
| #: templates/treasury/invoice_list.html:21 | ||||
| msgid "New invoice" | ||||
| msgstr "Nouvelle facture" | ||||
|  | ||||
| @@ -979,34 +981,34 @@ msgstr "Transactions liées" | ||||
| msgid "There is no transaction linked with this remittance." | ||||
| msgstr "Il n'y a pas de transaction liée à cette remise." | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:6 | ||||
| #: templates/treasury/remittance_list.html:19 | ||||
| msgid "Opened remittances" | ||||
| msgstr "Remises ouvertes" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:11 | ||||
| #: templates/treasury/remittance_list.html:24 | ||||
| msgid "There is no opened remittance." | ||||
| msgstr "Il n'y a pas de remise ouverte." | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:15 | ||||
| #: templates/treasury/remittance_list.html:28 | ||||
| msgid "New remittance" | ||||
| msgstr "Nouvelle remise" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:19 | ||||
| #: templates/treasury/remittance_list.html:32 | ||||
| msgid "Transfers without remittances" | ||||
| msgstr "Transactions sans remise associée" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:24 | ||||
| #: templates/treasury/remittance_list.html:37 | ||||
| msgid "There is no transaction without any linked remittance." | ||||
| msgstr "Il n'y a pas de transactions sans remise associée." | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:30 | ||||
| #: templates/treasury/remittance_list.html:43 | ||||
| msgid "Transfers with opened remittances" | ||||
| msgstr "Transactions avec remise associée ouverte" | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:35 | ||||
| #: templates/treasury/remittance_list.html:48 | ||||
| msgid "There is no transaction without an opened linked remittance." | ||||
| msgstr "Il n'y a pas de transaction sans remise ouverte associée." | ||||
|  | ||||
| #: templates/treasury/remittance_list.html:41 | ||||
| #: templates/treasury/remittance_list.html:54 | ||||
| msgid "Closed remittances" | ||||
| msgstr "Remises fermées" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user