mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Merge branch 'master' into front_club
This commit is contained in:
		@@ -9,6 +9,11 @@ RUN apt update && \
 | 
				
			|||||||
    apt install -y gettext nginx uwsgi uwsgi-plugin-python3 && \
 | 
					    apt install -y gettext nginx uwsgi uwsgi-plugin-python3 && \
 | 
				
			||||||
    rm -rf /var/lib/apt/lists/*
 | 
					    rm -rf /var/lib/apt/lists/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Install LaTeX requirements
 | 
				
			||||||
 | 
					RUN apt update && \
 | 
				
			||||||
 | 
					    apt install -y texlive-latex-extra texlive-fonts-extra texlive-lang-french && \
 | 
				
			||||||
 | 
					    rm -rf /var/lib/apt/lists/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY . /code/
 | 
					COPY . /code/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Comment what is not needed
 | 
					# Comment what is not needed
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,13 +6,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Installation sur un serveur
 | 
					## Installation sur un serveur
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On supposera pour la suite que vous utiliser debian/ubuntu sur un serveur tout nu ou bien configuré.
 | 
					On supposera pour la suite que vous utilisez Debian/Ubuntu sur un serveur tout nu ou bien configuré.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Paquets nécessaires
 | 
					1. Paquets nécessaires
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $ sudo apt install nginx python3 python3-pip python3-dev uwsgi
 | 
					        $ sudo apt install nginx python3 python3-pip python3-dev uwsgi
 | 
				
			||||||
        $ sudo apt install uwsgi-plugin-python3 python3-venv git acl
 | 
					        $ sudo apt install uwsgi-plugin-python3 python3-venv git acl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    La génération des factures de l'application trésorerie nécessite une installation de LaTeX suffisante :
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ sudo apt install texlive-latex-extra texlive-fonts-extra texlive-lang-french
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. Clonage du dépot
 | 
					2. Clonage du dépot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    on se met au bon endroit :
 | 
					    on se met au bon endroit :
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ from activity.api.urls import register_activity_urls
 | 
				
			|||||||
from api.viewsets import ReadProtectedModelViewSet
 | 
					from api.viewsets import ReadProtectedModelViewSet
 | 
				
			||||||
from member.api.urls import register_members_urls
 | 
					from member.api.urls import register_members_urls
 | 
				
			||||||
from note.api.urls import register_note_urls
 | 
					from note.api.urls import register_note_urls
 | 
				
			||||||
 | 
					from treasury.api.urls import register_treasury_urls
 | 
				
			||||||
from logs.api.urls import register_logs_urls
 | 
					from logs.api.urls import register_logs_urls
 | 
				
			||||||
from permission.api.urls import register_permission_urls
 | 
					from permission.api.urls import register_permission_urls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,6 +75,7 @@ router.register('user', UserViewSet)
 | 
				
			|||||||
register_members_urls(router, 'members')
 | 
					register_members_urls(router, 'members')
 | 
				
			||||||
register_activity_urls(router, 'activity')
 | 
					register_activity_urls(router, 'activity')
 | 
				
			||||||
register_note_urls(router, 'note')
 | 
					register_note_urls(router, 'note')
 | 
				
			||||||
 | 
					register_treasury_urls(router, 'treasury')
 | 
				
			||||||
register_permission_urls(router, 'permission')
 | 
					register_permission_urls(router, 'permission')
 | 
				
			||||||
register_logs_urls(router, 'logs')
 | 
					register_logs_urls(router, 'logs')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.urls import reverse, reverse_lazy
 | 
					from django.urls import reverse, reverse_lazy
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
@@ -67,6 +68,13 @@ class Club(models.Model):
 | 
				
			|||||||
    email = models.EmailField(
 | 
					    email = models.EmailField(
 | 
				
			||||||
        verbose_name=_('email'),
 | 
					        verbose_name=_('email'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    parent_club = models.ForeignKey(
 | 
				
			||||||
 | 
					        'self',
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					        blank=True,
 | 
				
			||||||
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
 | 
					        verbose_name=_('parent club'),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Memberships
 | 
					    # Memberships
 | 
				
			||||||
    membership_fee = models.PositiveIntegerField(
 | 
					    membership_fee = models.PositiveIntegerField(
 | 
				
			||||||
@@ -158,6 +166,12 @@ class Membership(models.Model):
 | 
				
			|||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
 | 
					            return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        if self.club.parent_club is not None:
 | 
				
			||||||
 | 
					            if not Membership.objects.filter(user=self.user, club=self.club.parent_club):
 | 
				
			||||||
 | 
					                raise ValidationError(_('User is not a member of the parent club'))
 | 
				
			||||||
 | 
					        super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        verbose_name = _('membership')
 | 
					        verbose_name = _('membership')
 | 
				
			||||||
        verbose_name_plural = _('memberships')
 | 
					        verbose_name_plural = _('memberships')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
 | 
					from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
 | 
				
			||||||
from .transactions import MembershipTransaction, Transaction, \
 | 
					from .transactions import MembershipTransaction, Transaction, \
 | 
				
			||||||
    TemplateCategory, TransactionTemplate, RecurrentTransaction
 | 
					    TemplateCategory, TransactionTemplate, RecurrentTransaction, SpecialTransaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__all__ = [
 | 
					__all__ = [
 | 
				
			||||||
    # Notes
 | 
					    # Notes
 | 
				
			||||||
    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
 | 
					    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
 | 
				
			||||||
    # Transactions
 | 
					    # Transactions
 | 
				
			||||||
    'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
 | 
					    'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
 | 
				
			||||||
    'RecurrentTransaction',
 | 
					    'RecurrentTransaction', 'SpecialTransaction',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
 | 
					from django.db.models import F
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
from django.utils import timezone
 | 
					from django.utils import timezone
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
@@ -93,12 +94,26 @@ class Transaction(PolymorphicModel):
 | 
				
			|||||||
        related_name='+',
 | 
					        related_name='+',
 | 
				
			||||||
        verbose_name=_('source'),
 | 
					        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(
 | 
					    destination = models.ForeignKey(
 | 
				
			||||||
        Note,
 | 
					        Note,
 | 
				
			||||||
        on_delete=models.PROTECT,
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
        related_name='+',
 | 
					        related_name='+',
 | 
				
			||||||
        verbose_name=_('destination'),
 | 
					        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(
 | 
					    created_at = models.DateTimeField(
 | 
				
			||||||
        verbose_name=_('created at'),
 | 
					        verbose_name=_('created at'),
 | 
				
			||||||
        default=timezone.now,
 | 
					        default=timezone.now,
 | 
				
			||||||
@@ -115,11 +130,19 @@ class Transaction(PolymorphicModel):
 | 
				
			|||||||
        verbose_name=_('reason'),
 | 
					        verbose_name=_('reason'),
 | 
				
			||||||
        max_length=255,
 | 
					        max_length=255,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    valid = models.BooleanField(
 | 
					    valid = models.BooleanField(
 | 
				
			||||||
        verbose_name=_('valid'),
 | 
					        verbose_name=_('valid'),
 | 
				
			||||||
        default=True,
 | 
					        default=True,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    invalidity_reason = models.CharField(
 | 
				
			||||||
 | 
					        verbose_name=_('invalidity reason'),
 | 
				
			||||||
 | 
					        max_length=255,
 | 
				
			||||||
 | 
					        default=None,
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        verbose_name = _("transaction")
 | 
					        verbose_name = _("transaction")
 | 
				
			||||||
        verbose_name_plural = _("transactions")
 | 
					        verbose_name_plural = _("transactions")
 | 
				
			||||||
@@ -134,6 +157,13 @@ class Transaction(PolymorphicModel):
 | 
				
			|||||||
        When saving, also transfer money between two notes
 | 
					        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:
 | 
					        if self.source.pk == self.destination.pk:
 | 
				
			||||||
            # When source == destination, no money is transfered
 | 
					            # When source == destination, no money is transfered
 | 
				
			||||||
            super().save(*args, **kwargs)
 | 
					            super().save(*args, **kwargs)
 | 
				
			||||||
@@ -152,6 +182,10 @@ class Transaction(PolymorphicModel):
 | 
				
			|||||||
            self.source.balance -= to_transfer
 | 
					            self.source.balance -= to_transfer
 | 
				
			||||||
            self.destination.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
 | 
					        # We save first the transaction, in case of the user has no right to transfer money
 | 
				
			||||||
        super().save(*args, **kwargs)
 | 
					        super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import html
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import django_tables2 as tables
 | 
					import django_tables2 as tables
 | 
				
			||||||
from django.db.models import F
 | 
					from django.db.models import F
 | 
				
			||||||
 | 
					from django.utils.html import format_html
 | 
				
			||||||
from django_tables2.utils import A
 | 
					from django_tables2.utils import A
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,19 +21,48 @@ class HistoryTable(tables.Table):
 | 
				
			|||||||
                'table table-condensed table-striped table-hover'
 | 
					                'table table-condensed table-striped table-hover'
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        model = Transaction
 | 
					        model = Transaction
 | 
				
			||||||
        exclude = ("id", "polymorphic_ctype", )
 | 
					        exclude = ("id", "polymorphic_ctype", "invalidity_reason", "source_alias", "destination_alias",)
 | 
				
			||||||
        template_name = 'django_tables2/bootstrap4.html'
 | 
					        template_name = 'django_tables2/bootstrap4.html'
 | 
				
			||||||
        sequence = ('...', 'type', 'total', 'valid', )
 | 
					        sequence = ('...', 'type', 'total', 'valid',)
 | 
				
			||||||
        orderable = False
 | 
					        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()
 | 
					    type = tables.Column()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    total = tables.Column()  # will use Transaction.total() !!
 | 
					    total = tables.Column()  # will use Transaction.total() !!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    valid = tables.Column(attrs={"td": {"id": lambda record: "validate_" + str(record.id),
 | 
					    valid = tables.Column(
 | 
				
			||||||
 | 
					        attrs={
 | 
				
			||||||
 | 
					            "td": {
 | 
				
			||||||
 | 
					                "id": lambda record: "validate_" + str(record.id),
 | 
				
			||||||
                "class": lambda record: str(record.valid).lower() + ' validate',
 | 
					                "class": lambda record: str(record.valid).lower() + ' validate',
 | 
				
			||||||
                                        "onclick": lambda record: 'de_validate(' + str(record.id) + ', '
 | 
					                "data-toggle": "tooltip",
 | 
				
			||||||
                                                                  + str(record.valid).lower() + ')'}})
 | 
					                "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):
 | 
					    def order_total(self, queryset, is_descending):
 | 
				
			||||||
        # needed for rendering
 | 
					        # needed for rendering
 | 
				
			||||||
@@ -53,8 +83,18 @@ class HistoryTable(tables.Table):
 | 
				
			|||||||
    def render_reason(self, value):
 | 
					    def render_reason(self, value):
 | 
				
			||||||
        return html.unescape(value)
 | 
					        return html.unescape(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def render_valid(self, value):
 | 
					    def render_valid(self, value, record):
 | 
				
			||||||
        return "✔" if value else "✖"
 | 
					        """
 | 
				
			||||||
 | 
					        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
 | 
					# function delete_button(id) provided in template file
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 = template.Library()
 | 
				
			||||||
register.filter('pretty_money', pretty_money)
 | 
					register.filter('pretty_money', pretty_money)
 | 
				
			||||||
 | 
					register.filter('cents_to_euros', cents_to_euros)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,4 +28,3 @@ class RolePermissionsAdmin(admin.ModelAdmin):
 | 
				
			|||||||
    Admin customisation for RolePermissions
 | 
					    Admin customisation for RolePermissions
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    list_display = ('role', )
 | 
					    list_display = ('role', )
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@
 | 
				
			|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django_filters.rest_framework import DjangoFilterBackend
 | 
					from django_filters.rest_framework import DjangoFilterBackend
 | 
				
			||||||
 | 
					 | 
				
			||||||
from api.viewsets import ReadOnlyProtectedModelViewSet
 | 
					from api.viewsets import ReadOnlyProtectedModelViewSet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .serializers import PermissionSerializer
 | 
					from .serializers import PermissionSerializer
 | 
				
			||||||
from ..models import Permission
 | 
					from ..models import Permission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -327,7 +327,7 @@
 | 
				
			|||||||
        "note",
 | 
					        "note",
 | 
				
			||||||
        "transaction"
 | 
					        "transaction"
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      "query": "[\"AND\", {\"source\": [\"user\", \"note\"]}, {\"amount__lte\": [\"user\", \"note\", \"balance\"]}]",
 | 
					      "query": "[\"AND\", {\"source\": [\"user\", \"note\"]}, [\"OR\", {\"amount__lte\": [\"user\", \"note\", \"balance\"]}, {\"valid\": false}]]",
 | 
				
			||||||
      "type": "add",
 | 
					      "type": "add",
 | 
				
			||||||
      "mask": 1,
 | 
					      "mask": 1,
 | 
				
			||||||
      "field": "",
 | 
					      "field": "",
 | 
				
			||||||
@@ -387,7 +387,7 @@
 | 
				
			|||||||
        "note",
 | 
					        "note",
 | 
				
			||||||
        "recurrenttransaction"
 | 
					        "recurrenttransaction"
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}]",
 | 
					      "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
 | 
				
			||||||
      "type": "add",
 | 
					      "type": "add",
 | 
				
			||||||
      "mask": 2,
 | 
					      "mask": 2,
 | 
				
			||||||
      "field": "",
 | 
					      "field": "",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ from django.core.exceptions import ValidationError
 | 
				
			|||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.db.models import F, Q, Model
 | 
					from django.db.models import F, Q, Model
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					 | 
				
			||||||
from member.models import Role
 | 
					from member.models import Role
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -281,4 +280,3 @@ class RolePermissions(models.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return str(self.role)
 | 
					        return str(self.role)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_framework.permissions import DjangoObjectPermissions
 | 
					from rest_framework.permissions import DjangoObjectPermissions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .backends import PermissionBackend
 | 
					from .backends import PermissionBackend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SAFE_METHODS = ('HEAD', 'OPTIONS', )
 | 
					SAFE_METHODS = ('HEAD', 'OPTIONS', )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from django.core.exceptions import PermissionDenied
 | 
					from django.core.exceptions import PermissionDenied
 | 
				
			||||||
from django.db.models.signals import pre_save, pre_delete, post_save, post_delete
 | 
					from django.db.models.signals import pre_save, pre_delete, post_save, post_delete
 | 
				
			||||||
 | 
					 | 
				
			||||||
from logs import signals as logs_signals
 | 
					from logs import signals as logs_signals
 | 
				
			||||||
from permission.backends import PermissionBackend
 | 
					 | 
				
			||||||
from note_kfet.middlewares import get_current_authenticated_user
 | 
					from note_kfet.middlewares import get_current_authenticated_user
 | 
				
			||||||
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXCLUDED = [
 | 
					EXCLUDED = [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from django.contrib.contenttypes.models import ContentType
 | 
					from django.contrib.contenttypes.models import ContentType
 | 
				
			||||||
from django.template.defaultfilters import stringfilter
 | 
					from django.template.defaultfilters import stringfilter
 | 
				
			||||||
 | 
					 | 
				
			||||||
from note_kfet.middlewares import get_current_authenticated_user, get_current_session
 | 
					 | 
				
			||||||
from django import template
 | 
					from django import template
 | 
				
			||||||
 | 
					from note_kfet.middlewares import get_current_authenticated_user, get_current_session
 | 
				
			||||||
from permission.backends import PermissionBackend
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								apps/treasury/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								apps/treasury/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					default_app_config = 'treasury.apps.TreasuryConfig'
 | 
				
			||||||
							
								
								
									
										27
									
								
								apps/treasury/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								apps/treasury/admin.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-lateré
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.contrib import admin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .models import RemittanceType, Remittance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@admin.register(RemittanceType)
 | 
				
			||||||
 | 
					class RemittanceTypeAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Admin customisation for RemiitanceType
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    list_display = ('note', )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@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)
 | 
				
			||||||
							
								
								
									
										0
									
								
								apps/treasury/api/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								apps/treasury/api/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										62
									
								
								apps/treasury/api/serializers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								apps/treasury/api/serializers.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					from note.api.serializers import SpecialTransactionSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..models import Invoice, Product, RemittanceType, Remittance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProductSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    REST API Serializer for Product types.
 | 
				
			||||||
 | 
					    The djangorestframework plugin will analyse the model `Product` and parse all fields in the API.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Product
 | 
				
			||||||
 | 
					        fields = '__all__'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    REST API Serializer for Invoice types.
 | 
				
			||||||
 | 
					    The djangorestframework plugin will analyse the model `Invoice` and parse all fields in the API.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Invoice
 | 
				
			||||||
 | 
					        fields = '__all__'
 | 
				
			||||||
 | 
					        read_only_fields = ('bde',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    products = serializers.SerializerMethodField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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)
 | 
				
			||||||
							
								
								
									
										14
									
								
								apps/treasury/api/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								apps/treasury/api/urls.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .views import InvoiceViewSet, ProductViewSet, RemittanceViewSet, RemittanceTypeViewSet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def register_treasury_urls(router, path):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Configure router for treasury REST API.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    router.register(path + '/invoice', InvoiceViewSet)
 | 
				
			||||||
 | 
					    router.register(path + '/product', ProductViewSet)
 | 
				
			||||||
 | 
					    router.register(path + '/remittance_type', RemittanceTypeViewSet)
 | 
				
			||||||
 | 
					    router.register(path + '/remittance', RemittanceViewSet)
 | 
				
			||||||
							
								
								
									
										53
									
								
								apps/treasury/api/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								apps/treasury/api/views.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django_filters.rest_framework import DjangoFilterBackend
 | 
				
			||||||
 | 
					from rest_framework.filters import SearchFilter
 | 
				
			||||||
 | 
					from api.viewsets import ReadProtectedModelViewSet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .serializers import InvoiceSerializer, ProductSerializer, RemittanceTypeSerializer, RemittanceSerializer
 | 
				
			||||||
 | 
					from ..models import Invoice, Product, RemittanceType, Remittance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceViewSet(ReadProtectedModelViewSet):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    REST API View set.
 | 
				
			||||||
 | 
					    The djangorestframework plugin will get all `Invoice` objects, serialize it to JSON with the given serializer,
 | 
				
			||||||
 | 
					    then render it on /api/treasury/invoice/
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    queryset = Invoice.objects.all()
 | 
				
			||||||
 | 
					    serializer_class = InvoiceSerializer
 | 
				
			||||||
 | 
					    filter_backends = [DjangoFilterBackend]
 | 
				
			||||||
 | 
					    filterset_fields = ['bde', ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProductViewSet(ReadProtectedModelViewSet):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    REST API View set.
 | 
				
			||||||
 | 
					    The djangorestframework plugin will get all `Product` objects, serialize it to JSON with the given serializer,
 | 
				
			||||||
 | 
					    then render it on /api/treasury/product/
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    queryset = Product.objects.all()
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
							
								
								
									
										33
									
								
								apps/treasury/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								apps/treasury/apps.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.apps import AppConfig
 | 
				
			||||||
 | 
					from django.db.models import Q
 | 
				
			||||||
 | 
					from django.db.models.signals import post_save, post_migrate
 | 
				
			||||||
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TreasuryConfig(AppConfig):
 | 
				
			||||||
 | 
					    name = 'treasury'
 | 
				
			||||||
 | 
					    verbose_name = _('Treasury')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ready(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Define app internal signals to interact with other apps
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        from . import signals
 | 
				
			||||||
 | 
					        from note.models import SpecialTransaction, NoteSpecial
 | 
				
			||||||
 | 
					        from treasury.models import SpecialTransactionProxy
 | 
				
			||||||
 | 
					        post_save.connect(signals.save_special_transaction, sender=SpecialTransaction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def setup_specialtransactions_proxies(**kwargs):
 | 
				
			||||||
 | 
					            # If the treasury app was disabled for any reason during a certain amount of time,
 | 
				
			||||||
 | 
					            # we ensure that each special transaction is linked to a proxy
 | 
				
			||||||
 | 
					            for transaction in SpecialTransaction.objects.filter(
 | 
				
			||||||
 | 
					                    source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)),
 | 
				
			||||||
 | 
					                    specialtransactionproxy=None,
 | 
				
			||||||
 | 
					            ):
 | 
				
			||||||
 | 
					                SpecialTransactionProxy.objects.create(transaction=transaction, remittance=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        post_migrate.connect(setup_specialtransactions_proxies, sender=SpecialTransactionProxy)
 | 
				
			||||||
							
								
								
									
										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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										156
									
								
								apps/treasury/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								apps/treasury/forms.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from crispy_forms.helper import FormHelper
 | 
				
			||||||
 | 
					from crispy_forms.layout import Submit
 | 
				
			||||||
 | 
					from django import forms
 | 
				
			||||||
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceForm(forms.ModelForm):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Create and generate invoices.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Django forms don't support date fields. We have to add it manually
 | 
				
			||||||
 | 
					    date = forms.DateField(
 | 
				
			||||||
 | 
					        initial=datetime.date.today,
 | 
				
			||||||
 | 
					        widget=forms.TextInput(attrs={'type': 'date'})
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean_date(self):
 | 
				
			||||||
 | 
					        self.instance.date = self.data.get("date")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Invoice
 | 
				
			||||||
 | 
					        exclude = ('bde', )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add a subform per product in the invoice form, and manage correctly the link between the invoice and
 | 
				
			||||||
 | 
					# its products. The FormSet will search automatically the ForeignKey in the Product model.
 | 
				
			||||||
 | 
					ProductFormSet = forms.inlineformset_factory(
 | 
				
			||||||
 | 
					    Invoice,
 | 
				
			||||||
 | 
					    Product,
 | 
				
			||||||
 | 
					    fields='__all__',
 | 
				
			||||||
 | 
					    extra=1,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProductFormSetHelper(FormHelper):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Specify some template informations for the product form.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, form=None):
 | 
				
			||||||
 | 
					        super().__init__(form)
 | 
				
			||||||
 | 
					        self.form_tag = False
 | 
				
			||||||
 | 
					        self.form_method = 'POST'
 | 
				
			||||||
 | 
					        self.form_class = 'form-inline'
 | 
				
			||||||
 | 
					        self.template = 'bootstrap4/table_inline_formset.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemittanceForm(forms.ModelForm):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Create remittances.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.helper = FormHelper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # We can't update the type of the remittance once created.
 | 
				
			||||||
 | 
					        if self.instance.pk:
 | 
				
			||||||
 | 
					            self.fields["remittance_type"].disabled = True
 | 
				
			||||||
 | 
					            self.fields["remittance_type"].required = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # We display the submit button iff the remittance is open,
 | 
				
			||||||
 | 
					        # the close button iff it is open and has a linked transaction
 | 
				
			||||||
 | 
					        if not self.instance.closed:
 | 
				
			||||||
 | 
					            self.helper.add_input(Submit('submit', _("Submit"), attr={'class': 'btn btn-block btn-primary'}))
 | 
				
			||||||
 | 
					            if self.instance.transactions:
 | 
				
			||||||
 | 
					                self.helper.add_input(Submit("close", _("Close"), css_class='btn btn-success'))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # If the remittance is closed, we can't change anything
 | 
				
			||||||
 | 
					            self.fields["comment"].disabled = True
 | 
				
			||||||
 | 
					            self.fields["comment"].required = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean(self):
 | 
				
			||||||
 | 
					        # We can't update anything if the remittance is already closed.
 | 
				
			||||||
 | 
					        if self.instance.closed:
 | 
				
			||||||
 | 
					            self.add_error("comment", _("Remittance is already closed."))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cleaned_data = super().clean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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."))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # The close button is manually handled
 | 
				
			||||||
 | 
					        if "close" in self.data:
 | 
				
			||||||
 | 
					            self.instance.closed = True
 | 
				
			||||||
 | 
					            self.cleaned_data["closed"] = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return cleaned_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Remittance
 | 
				
			||||||
 | 
					        fields = ('remittance_type', 'comment',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LinkTransactionToRemittanceForm(forms.ModelForm):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Attach a special transaction to a remittance.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Since we use a proxy model for special transactions, we add manually the fields related to the transaction
 | 
				
			||||||
 | 
					    last_name = forms.CharField(label=_("Last name"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    first_name = forms.Field(label=_("First name"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bank = forms.Field(label=_("Bank"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    amount = forms.IntegerField(label=_("Amount"), min_value=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					        self.helper = FormHelper()
 | 
				
			||||||
 | 
					        # Add submit button
 | 
				
			||||||
 | 
					        self.helper.add_input(Submit('submit', _("Submit"), attr={'class': 'btn btn-block btn-primary'}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.fields["remittance"].queryset = Remittance.objects.filter(closed=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean_last_name(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Replace the first name in the information of the transaction.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.instance.transaction.last_name = self.data.get("last_name")
 | 
				
			||||||
 | 
					        self.instance.transaction.clean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean_first_name(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Replace the last name in the information of the transaction.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.instance.transaction.first_name = self.data.get("first_name")
 | 
				
			||||||
 | 
					        self.instance.transaction.clean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean_bank(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Replace the bank in the information of the transaction.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.instance.transaction.bank = self.data.get("bank")
 | 
				
			||||||
 | 
					        self.instance.transaction.clean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean_amount(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Replace the amount of the transaction.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.instance.transaction.amount = self.data.get("amount")
 | 
				
			||||||
 | 
					        self.instance.transaction.clean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = SpecialTransactionProxy
 | 
				
			||||||
 | 
					        fields = ('remittance', )
 | 
				
			||||||
							
								
								
									
										0
									
								
								apps/treasury/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								apps/treasury/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										189
									
								
								apps/treasury/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								apps/treasury/models.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
 | 
					from django.db import models
 | 
				
			||||||
 | 
					from django.db.models import Q
 | 
				
			||||||
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					from note.models import NoteSpecial, SpecialTransaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Invoice(models.Model):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    An invoice model that can generates a true invoice.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    id = models.PositiveIntegerField(
 | 
				
			||||||
 | 
					        primary_key=True,
 | 
				
			||||||
 | 
					        verbose_name=_("Invoice identifier"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bde = models.CharField(
 | 
				
			||||||
 | 
					        max_length=32,
 | 
				
			||||||
 | 
					        default='Saperlistpopette.png',
 | 
				
			||||||
 | 
					        choices=(
 | 
				
			||||||
 | 
					            ('Saperlistpopette.png', 'Saper[list]popette'),
 | 
				
			||||||
 | 
					            ('Finalist.png', 'Fina[list]'),
 | 
				
			||||||
 | 
					            ('Listorique.png', '[List]orique'),
 | 
				
			||||||
 | 
					            ('Satellist.png', 'Satel[list]'),
 | 
				
			||||||
 | 
					            ('Monopolist.png', 'Monopo[list]'),
 | 
				
			||||||
 | 
					            ('Kataclist.png', 'Katac[list]'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        verbose_name=_("BDE"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object = models.CharField(
 | 
				
			||||||
 | 
					        max_length=255,
 | 
				
			||||||
 | 
					        verbose_name=_("Object"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    description = models.TextField(
 | 
				
			||||||
 | 
					        verbose_name=_("Description")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = models.CharField(
 | 
				
			||||||
 | 
					        max_length=255,
 | 
				
			||||||
 | 
					        verbose_name=_("Name"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    address = models.TextField(
 | 
				
			||||||
 | 
					        verbose_name=_("Address"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    date = models.DateField(
 | 
				
			||||||
 | 
					        auto_now_add=True,
 | 
				
			||||||
 | 
					        verbose_name=_("Place"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    acquitted = models.BooleanField(
 | 
				
			||||||
 | 
					        verbose_name=_("Acquitted"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Product(models.Model):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Product that appears on an invoice.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    invoice = models.ForeignKey(
 | 
				
			||||||
 | 
					        Invoice,
 | 
				
			||||||
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    designation = models.CharField(
 | 
				
			||||||
 | 
					        max_length=255,
 | 
				
			||||||
 | 
					        verbose_name=_("Designation"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quantity = models.PositiveIntegerField(
 | 
				
			||||||
 | 
					        verbose_name=_("Quantity")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    amount = models.IntegerField(
 | 
				
			||||||
 | 
					        verbose_name=_("Unit price")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def amount_euros(self):
 | 
				
			||||||
 | 
					        return self.amount / 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def total(self):
 | 
				
			||||||
 | 
					        return self.quantity * self.amount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def total_euros(self):
 | 
				
			||||||
 | 
					        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.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    date = models.DateTimeField(
 | 
				
			||||||
 | 
					        auto_now_add=True,
 | 
				
			||||||
 | 
					        verbose_name=_("Date"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    remittance_type = models.ForeignKey(
 | 
				
			||||||
 | 
					        RemittanceType,
 | 
				
			||||||
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
 | 
					        verbose_name=_("Type"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    comment = models.CharField(
 | 
				
			||||||
 | 
					        max_length=255,
 | 
				
			||||||
 | 
					        verbose_name=_("Comment"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closed = models.BooleanField(
 | 
				
			||||||
 | 
					        default=False,
 | 
				
			||||||
 | 
					        verbose_name=_("Closed"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def transactions(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        :return: Transactions linked to this remittance.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if not self.pk:
 | 
				
			||||||
 | 
					            return SpecialTransaction.objects.none()
 | 
				
			||||||
 | 
					        return SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def count(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Linked transactions count.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.transactions.count()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def amount(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Total amount of the remittance.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return sum(transaction.total for transaction in self.transactions.all())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
 | 
				
			||||||
 | 
					        # Check if all transactions have the right type.
 | 
				
			||||||
 | 
					        if self.transactions.filter(~Q(source=self.remittance_type.note)).exists():
 | 
				
			||||||
 | 
					            raise ValidationError("All transactions in a remittance must have the same type")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return super().save(force_insert, force_update, using, update_fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return _("Remittance #{:d}: {}").format(self.id, self.comment, )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpecialTransactionProxy(models.Model):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    In order to keep modularity, we don't that the Note app depends on the treasury app.
 | 
				
			||||||
 | 
					    That's why we create a proxy in this app, to link special transactions and remittances.
 | 
				
			||||||
 | 
					    If it isn't very clean, that makes what we want.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    transaction = models.OneToOneField(
 | 
				
			||||||
 | 
					        SpecialTransaction,
 | 
				
			||||||
 | 
					        on_delete=models.CASCADE,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    remittance = models.ForeignKey(
 | 
				
			||||||
 | 
					        Remittance,
 | 
				
			||||||
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					        verbose_name=_("Remittance"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
							
								
								
									
										12
									
								
								apps/treasury/signals.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								apps/treasury/signals.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from treasury.models import SpecialTransactionProxy, RemittanceType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def save_special_transaction(instance, created, **kwargs):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    When a special transaction is created, we create its linked proxy
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    if created and RemittanceType.objects.filter(note=instance.source).exists():
 | 
				
			||||||
 | 
					        SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save()
 | 
				
			||||||
							
								
								
									
										103
									
								
								apps/treasury/tables.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								apps/treasury/tables.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django_tables2 as tables
 | 
				
			||||||
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					from django_tables2 import A
 | 
				
			||||||
 | 
					from note.models import SpecialTransaction
 | 
				
			||||||
 | 
					from note.templatetags.pretty_money import pretty_money
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .models import Invoice, Remittance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceTable(tables.Table):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    List all invoices.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    id = tables.LinkColumn("treasury:invoice_update",
 | 
				
			||||||
 | 
					                           args=[A("pk")],
 | 
				
			||||||
 | 
					                           text=lambda record: _("Invoice #{:d}").format(record.id), )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    invoice = tables.LinkColumn("treasury:invoice_render",
 | 
				
			||||||
 | 
					                                verbose_name=_("Invoice"),
 | 
				
			||||||
 | 
					                                args=[A("pk")],
 | 
				
			||||||
 | 
					                                accessor="pk",
 | 
				
			||||||
 | 
					                                text="",
 | 
				
			||||||
 | 
					                                attrs={
 | 
				
			||||||
 | 
					                                    'a': {'class': 'fa fa-file-pdf-o'},
 | 
				
			||||||
 | 
					                                    'td': {'data-turbolinks': 'false'}
 | 
				
			||||||
 | 
					                                })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        attrs = {
 | 
				
			||||||
 | 
					            'class': 'table table-condensed table-striped table-hover'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        model = Invoice
 | 
				
			||||||
 | 
					        template_name = 'django_tables2/bootstrap4.html'
 | 
				
			||||||
 | 
					        fields = ('id', 'name', 'object', 'acquitted', 'invoice',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemittanceTable(tables.Table):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    List all remittances.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    count = tables.Column(verbose_name=_("Transaction count"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    amount = tables.Column(verbose_name=_("Amount"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    view = tables.LinkColumn("treasury:remittance_update",
 | 
				
			||||||
 | 
					                             verbose_name=_("View"),
 | 
				
			||||||
 | 
					                             args=[A("pk")],
 | 
				
			||||||
 | 
					                             text=_("View"),
 | 
				
			||||||
 | 
					                             attrs={
 | 
				
			||||||
 | 
					                                 'a': {'class': 'btn btn-primary'}
 | 
				
			||||||
 | 
					                             }, )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def render_amount(self, value):
 | 
				
			||||||
 | 
					        return pretty_money(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        attrs = {
 | 
				
			||||||
 | 
					            'class': 'table table-condensed table-striped table-hover'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        model = Remittance
 | 
				
			||||||
 | 
					        template_name = 'django_tables2/bootstrap4.html'
 | 
				
			||||||
 | 
					        fields = ('id', 'date', 'remittance_type', 'comment', 'count', 'amount', 'view',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpecialTransactionTable(tables.Table):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    List special credit transactions that are (or not, following the queryset) attached to a remittance.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Display add and remove buttons. Use the `exclude` field to select what is needed.
 | 
				
			||||||
 | 
					    remittance_add = tables.LinkColumn("treasury:link_transaction",
 | 
				
			||||||
 | 
					                                       verbose_name=_("Remittance"),
 | 
				
			||||||
 | 
					                                       args=[A("specialtransactionproxy.pk")],
 | 
				
			||||||
 | 
					                                       text=_("Add"),
 | 
				
			||||||
 | 
					                                       attrs={
 | 
				
			||||||
 | 
					                                           'a': {'class': 'btn btn-primary'}
 | 
				
			||||||
 | 
					                                       }, )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    remittance_remove = tables.LinkColumn("treasury:unlink_transaction",
 | 
				
			||||||
 | 
					                                          verbose_name=_("Remittance"),
 | 
				
			||||||
 | 
					                                          args=[A("specialtransactionproxy.pk")],
 | 
				
			||||||
 | 
					                                          text=_("Remove"),
 | 
				
			||||||
 | 
					                                          attrs={
 | 
				
			||||||
 | 
					                                              'a': {'class': 'btn btn-primary btn-danger'}
 | 
				
			||||||
 | 
					                                          }, )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def render_id(self, record):
 | 
				
			||||||
 | 
					        return record.specialtransactionproxy.pk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def render_amount(self, value):
 | 
				
			||||||
 | 
					        return pretty_money(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        attrs = {
 | 
				
			||||||
 | 
					            'class': 'table table-condensed table-striped table-hover'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        model = SpecialTransaction
 | 
				
			||||||
 | 
					        template_name = 'django_tables2/bootstrap4.html'
 | 
				
			||||||
 | 
					        fields = ('id', 'source', 'destination', 'last_name', 'first_name', 'bank', 'amount', 'reason',)
 | 
				
			||||||
							
								
								
									
										24
									
								
								apps/treasury/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								apps/treasury/urls.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.urls import path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .views import InvoiceCreateView, InvoiceListView, InvoiceUpdateView, InvoiceRenderView, RemittanceListView,\
 | 
				
			||||||
 | 
					    RemittanceCreateView, RemittanceUpdateView, LinkTransactionToRemittanceView, UnlinkTransactionToRemittanceView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app_name = 'treasury'
 | 
				
			||||||
 | 
					urlpatterns = [
 | 
				
			||||||
 | 
					    # Invoice app paths
 | 
				
			||||||
 | 
					    path('invoice/', InvoiceListView.as_view(), name='invoice_list'),
 | 
				
			||||||
 | 
					    path('invoice/create/', InvoiceCreateView.as_view(), name='invoice_create'),
 | 
				
			||||||
 | 
					    path('invoice/<int:pk>/', InvoiceUpdateView.as_view(), name='invoice_update'),
 | 
				
			||||||
 | 
					    path('invoice/render/<int:pk>/', InvoiceRenderView.as_view(), name='invoice_render'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Remittance app paths
 | 
				
			||||||
 | 
					    path('remittance/', RemittanceListView.as_view(), name='remittance_list'),
 | 
				
			||||||
 | 
					    path('remittance/create/', RemittanceCreateView.as_view(), name='remittance_create'),
 | 
				
			||||||
 | 
					    path('remittance/<int:pk>/', RemittanceUpdateView.as_view(), name='remittance_update'),
 | 
				
			||||||
 | 
					    path('remittance/link_transaction/<int:pk>/', LinkTransactionToRemittanceView.as_view(), name='link_transaction'),
 | 
				
			||||||
 | 
					    path('remittance/unlink_transaction/<int:pk>/', UnlinkTransactionToRemittanceView.as_view(),
 | 
				
			||||||
 | 
					         name='unlink_transaction'),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										316
									
								
								apps/treasury/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								apps/treasury/views.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,316 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					from tempfile import mkdtemp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from crispy_forms.helper import FormHelper
 | 
				
			||||||
 | 
					from django.contrib.auth.mixins import LoginRequiredMixin
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
 | 
					from django.db.models import Q
 | 
				
			||||||
 | 
					from django.http import HttpResponse
 | 
				
			||||||
 | 
					from django.shortcuts import redirect
 | 
				
			||||||
 | 
					from django.template.loader import render_to_string
 | 
				
			||||||
 | 
					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, 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 .tables import InvoiceTable, RemittanceTable, SpecialTransactionTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceCreateView(LoginRequiredMixin, CreateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Create Invoice
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = Invoice
 | 
				
			||||||
 | 
					    form_class = InvoiceForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        form = context['form']
 | 
				
			||||||
 | 
					        form.helper = FormHelper()
 | 
				
			||||||
 | 
					        # Remove form tag on the generation of the form in the template (already present on the template)
 | 
				
			||||||
 | 
					        form.helper.form_tag = False
 | 
				
			||||||
 | 
					        # The formset handles the set of the products
 | 
				
			||||||
 | 
					        form_set = ProductFormSet(instance=form.instance)
 | 
				
			||||||
 | 
					        context['formset'] = form_set
 | 
				
			||||||
 | 
					        context['helper'] = ProductFormSetHelper()
 | 
				
			||||||
 | 
					        context['no_cache'] = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def form_valid(self, form):
 | 
				
			||||||
 | 
					        ret = super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kwargs = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # The user type amounts in cents. We convert it in euros.
 | 
				
			||||||
 | 
					        for key in self.request.POST:
 | 
				
			||||||
 | 
					            value = self.request.POST[key]
 | 
				
			||||||
 | 
					            if key.endswith("amount") and value:
 | 
				
			||||||
 | 
					                kwargs[key] = str(int(100 * float(value)))
 | 
				
			||||||
 | 
					            elif value:
 | 
				
			||||||
 | 
					                kwargs[key] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # For each product, we save it
 | 
				
			||||||
 | 
					        formset = ProductFormSet(kwargs, instance=form.instance)
 | 
				
			||||||
 | 
					        if formset.is_valid():
 | 
				
			||||||
 | 
					            for f in formset:
 | 
				
			||||||
 | 
					                # We don't save the product if the designation is not entered, ie. if the line is empty
 | 
				
			||||||
 | 
					                if f.is_valid() and f.instance.designation:
 | 
				
			||||||
 | 
					                    f.save()
 | 
				
			||||||
 | 
					                    f.instance.save()
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    f.instance = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_success_url(self):
 | 
				
			||||||
 | 
					        return reverse_lazy('treasury:invoice_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceListView(LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    List existing Invoices
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = Invoice
 | 
				
			||||||
 | 
					    table_class = InvoiceTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Create Invoice
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = Invoice
 | 
				
			||||||
 | 
					    form_class = InvoiceForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        form = context['form']
 | 
				
			||||||
 | 
					        form.helper = FormHelper()
 | 
				
			||||||
 | 
					        # Remove form tag on the generation of the form in the template (already present on the template)
 | 
				
			||||||
 | 
					        form.helper.form_tag = False
 | 
				
			||||||
 | 
					        # Fill the intial value for the date field, with the initial date of the model instance
 | 
				
			||||||
 | 
					        form.fields['date'].initial = form.instance.date
 | 
				
			||||||
 | 
					        # The formset handles the set of the products
 | 
				
			||||||
 | 
					        form_set = ProductFormSet(instance=form.instance)
 | 
				
			||||||
 | 
					        context['formset'] = form_set
 | 
				
			||||||
 | 
					        context['helper'] = ProductFormSetHelper()
 | 
				
			||||||
 | 
					        context['no_cache'] = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def form_valid(self, form):
 | 
				
			||||||
 | 
					        ret = super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kwargs = {}
 | 
				
			||||||
 | 
					        # The user type amounts in cents. We convert it in euros.
 | 
				
			||||||
 | 
					        for key in self.request.POST:
 | 
				
			||||||
 | 
					            value = self.request.POST[key]
 | 
				
			||||||
 | 
					            if key.endswith("amount") and value:
 | 
				
			||||||
 | 
					                kwargs[key] = str(int(100 * float(value)))
 | 
				
			||||||
 | 
					            elif value:
 | 
				
			||||||
 | 
					                kwargs[key] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        formset = ProductFormSet(kwargs, instance=form.instance)
 | 
				
			||||||
 | 
					        saved = []
 | 
				
			||||||
 | 
					        # For each product, we save it
 | 
				
			||||||
 | 
					        if formset.is_valid():
 | 
				
			||||||
 | 
					            for f in formset:
 | 
				
			||||||
 | 
					                # We don't save the product if the designation is not entered, ie. if the line is empty
 | 
				
			||||||
 | 
					                if f.is_valid() and f.instance.designation:
 | 
				
			||||||
 | 
					                    f.save()
 | 
				
			||||||
 | 
					                    f.instance.save()
 | 
				
			||||||
 | 
					                    saved.append(f.instance.pk)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    f.instance = None
 | 
				
			||||||
 | 
					            # Remove old products that weren't given in the form
 | 
				
			||||||
 | 
					            Product.objects.filter(~Q(pk__in=saved), invoice=form.instance).delete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_success_url(self):
 | 
				
			||||||
 | 
					        return reverse_lazy('treasury:invoice_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvoiceRenderView(LoginRequiredMixin, View):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Render Invoice as a generated PDF with the given information and a LaTeX template
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request, **kwargs):
 | 
				
			||||||
 | 
					        pk = kwargs["pk"]
 | 
				
			||||||
 | 
					        invoice = Invoice.objects.get(pk=pk)
 | 
				
			||||||
 | 
					        products = Product.objects.filter(invoice=invoice).all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Informations of the BDE. Should be updated when the school will move.
 | 
				
			||||||
 | 
					        invoice.place = "Cachan"
 | 
				
			||||||
 | 
					        invoice.my_name = "BDE ENS Cachan"
 | 
				
			||||||
 | 
					        invoice.my_address_street = "61 avenue du Président Wilson"
 | 
				
			||||||
 | 
					        invoice.my_city = "94230 Cachan"
 | 
				
			||||||
 | 
					        invoice.bank_code = 30003
 | 
				
			||||||
 | 
					        invoice.desk_code = 3894
 | 
				
			||||||
 | 
					        invoice.account_number = 37280662
 | 
				
			||||||
 | 
					        invoice.rib_key = 14
 | 
				
			||||||
 | 
					        invoice.bic = "SOGEFRPP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Replace line breaks with the LaTeX equivalent
 | 
				
			||||||
 | 
					        invoice.description = invoice.description.replace("\r", "").replace("\n", "\\\\ ")
 | 
				
			||||||
 | 
					        invoice.address = invoice.address.replace("\r", "").replace("\n", "\\\\ ")
 | 
				
			||||||
 | 
					        # Fill the template with the information
 | 
				
			||||||
 | 
					        tex = render_to_string("treasury/invoice_sample.tex", dict(obj=invoice, products=products))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            os.mkdir(BASE_DIR + "/tmp")
 | 
				
			||||||
 | 
					        except FileExistsError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        # We render the file in a temporary directory
 | 
				
			||||||
 | 
					        tmp_dir = mkdtemp(prefix=BASE_DIR + "/tmp/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            with open("{}/invoice-{:d}.tex".format(tmp_dir, pk), "wb") as f:
 | 
				
			||||||
 | 
					                f.write(tex.encode("UTF-8"))
 | 
				
			||||||
 | 
					            del tex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # The file has to be rendered twice
 | 
				
			||||||
 | 
					            for _ in range(2):
 | 
				
			||||||
 | 
					                error = subprocess.Popen(
 | 
				
			||||||
 | 
					                    ["pdflatex", "invoice-{}.tex".format(pk)],
 | 
				
			||||||
 | 
					                    cwd=tmp_dir,
 | 
				
			||||||
 | 
					                    stdin=open(os.devnull, "r"),
 | 
				
			||||||
 | 
					                    stderr=open(os.devnull, "wb"),
 | 
				
			||||||
 | 
					                    stdout=open(os.devnull, "wb"),
 | 
				
			||||||
 | 
					                ).wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if error:
 | 
				
			||||||
 | 
					                    raise IOError("An error attempted while generating a invoice (code=" + str(error) + ")")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Display the generated pdf as a HTTP Response
 | 
				
			||||||
 | 
					            pdf = open("{}/invoice-{}.pdf".format(tmp_dir, pk), 'rb').read()
 | 
				
			||||||
 | 
					            response = HttpResponse(pdf, content_type="application/pdf")
 | 
				
			||||||
 | 
					            response['Content-Disposition'] = "inline;filename=invoice-{:d}.pdf".format(pk)
 | 
				
			||||||
 | 
					        except IOError as e:
 | 
				
			||||||
 | 
					            raise e
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            # Delete all temporary files
 | 
				
			||||||
 | 
					            shutil.rmtree(tmp_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemittanceCreateView(LoginRequiredMixin, CreateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Create Remittance
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = Remittance
 | 
				
			||||||
 | 
					    form_class = RemittanceForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_success_url(self):
 | 
				
			||||||
 | 
					        return reverse_lazy('treasury:remittance_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx["table"] = RemittanceTable(data=Remittance.objects.all())
 | 
				
			||||||
 | 
					        ctx["special_transactions"] = SpecialTransactionTable(data=SpecialTransaction.objects.none())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemittanceListView(LoginRequiredMixin, TemplateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    List existing Remittances
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    template_name = "treasury/remittance_list.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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__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__in=NoteSpecial.objects.filter(~Q(remittancetype=None)),
 | 
				
			||||||
 | 
					                                                   specialtransactionproxy__remittance__closed=False).all(),
 | 
				
			||||||
 | 
					            exclude=('remittance_add', ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Update Remittance
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = Remittance
 | 
				
			||||||
 | 
					    form_class = RemittanceForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_success_url(self):
 | 
				
			||||||
 | 
					        return reverse_lazy('treasury:remittance_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx["table"] = RemittanceTable(data=Remittance.objects.all())
 | 
				
			||||||
 | 
					        data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).all()
 | 
				
			||||||
 | 
					        ctx["special_transactions"] = SpecialTransactionTable(
 | 
				
			||||||
 | 
					            data=data,
 | 
				
			||||||
 | 
					            exclude=('remittance_add', 'remittance_remove', ) if self.object.closed else ('remittance_add', ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LinkTransactionToRemittanceView(LoginRequiredMixin, UpdateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Attach a special transaction to a remittance
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    model = SpecialTransactionProxy
 | 
				
			||||||
 | 
					    form_class = LinkTransactionToRemittanceForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_success_url(self):
 | 
				
			||||||
 | 
					        return reverse_lazy('treasury:remittance_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        form = ctx["form"]
 | 
				
			||||||
 | 
					        form.fields["last_name"].initial = self.object.transaction.last_name
 | 
				
			||||||
 | 
					        form.fields["first_name"].initial = self.object.transaction.first_name
 | 
				
			||||||
 | 
					        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(remittance_type__note=self.object.transaction.source)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UnlinkTransactionToRemittanceView(LoginRequiredMixin, View):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Unlink a special transaction and its remittance
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        pk = kwargs["pk"]
 | 
				
			||||||
 | 
					        transaction = SpecialTransactionProxy.objects.get(pk=pk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # The remittance must be open (or inexistant)
 | 
				
			||||||
 | 
					        if transaction.remittance and transaction.remittance.closed:
 | 
				
			||||||
 | 
					            raise ValidationError("Remittance is already closed.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        transaction.remittance = None
 | 
				
			||||||
 | 
					        transaction.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return redirect('treasury:remittance_list')
 | 
				
			||||||
@@ -8,7 +8,7 @@ msgid ""
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
					"Project-Id-Version: PACKAGE VERSION\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: \n"
 | 
					"Report-Msgid-Bugs-To: \n"
 | 
				
			||||||
"POT-Creation-Date: 2020-03-16 11:53+0100\n"
 | 
					"POT-Creation-Date: 2020-03-26 14:40+0100\n"
 | 
				
			||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
					"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
				
			||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
					"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
				
			||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
					"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
				
			||||||
@@ -23,9 +23,9 @@ msgid "activity"
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/activity/models.py:19 apps/activity/models.py:44
 | 
					#: apps/activity/models.py:19 apps/activity/models.py:44
 | 
				
			||||||
#: apps/member/models.py:61 apps/member/models.py:112
 | 
					#: apps/member/models.py:63 apps/member/models.py:114
 | 
				
			||||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
 | 
					#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
 | 
				
			||||||
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:202
 | 
					#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
 | 
				
			||||||
#: templates/member/profile_detail.html:15
 | 
					#: templates/member/profile_detail.html:15
 | 
				
			||||||
msgid "name"
 | 
					msgid "name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -46,12 +46,13 @@ msgstr ""
 | 
				
			|||||||
msgid "activity types"
 | 
					msgid "activity types"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:69
 | 
					#: apps/activity/models.py:48 apps/note/models/transactions.py:70
 | 
				
			||||||
 | 
					#: apps/permission/models.py:91
 | 
				
			||||||
msgid "description"
 | 
					msgid "description"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/activity/models.py:54 apps/note/models/notes.py:164
 | 
					#: apps/activity/models.py:54 apps/note/models/notes.py:164
 | 
				
			||||||
#: apps/note/models/transactions.py:62 apps/note/models/transactions.py:115
 | 
					#: apps/note/models/transactions.py:63
 | 
				
			||||||
msgid "type"
 | 
					msgid "type"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,11 +120,11 @@ msgstr ""
 | 
				
			|||||||
msgid "create"
 | 
					msgid "create"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/logs/models.py:61
 | 
					#: apps/logs/models.py:61 apps/note/tables.py:147
 | 
				
			||||||
msgid "edit"
 | 
					msgid "edit"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/logs/models.py:62
 | 
					#: apps/logs/models.py:62 apps/note/tables.py:151
 | 
				
			||||||
msgid "delete"
 | 
					msgid "delete"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -143,123 +144,123 @@ msgstr ""
 | 
				
			|||||||
msgid "member"
 | 
					msgid "member"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:23
 | 
					#: apps/member/models.py:25
 | 
				
			||||||
msgid "phone number"
 | 
					msgid "phone number"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:29 templates/member/profile_detail.html:28
 | 
					#: apps/member/models.py:31 templates/member/profile_detail.html:28
 | 
				
			||||||
msgid "section"
 | 
					msgid "section"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:30
 | 
					#: apps/member/models.py:32
 | 
				
			||||||
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 | 
					msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:36 templates/member/profile_detail.html:31
 | 
					#: apps/member/models.py:38 templates/member/profile_detail.html:31
 | 
				
			||||||
msgid "address"
 | 
					msgid "address"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:42
 | 
					#: apps/member/models.py:44
 | 
				
			||||||
msgid "paid"
 | 
					msgid "paid"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:47 apps/member/models.py:48
 | 
					#: apps/member/models.py:49 apps/member/models.py:50
 | 
				
			||||||
msgid "user profile"
 | 
					msgid "user profile"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:66
 | 
					#: apps/member/models.py:68
 | 
				
			||||||
msgid "email"
 | 
					msgid "email"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:71
 | 
					#: apps/member/models.py:73
 | 
				
			||||||
msgid "membership fee"
 | 
					msgid "membership fee"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:75
 | 
					#: apps/member/models.py:77
 | 
				
			||||||
msgid "membership duration"
 | 
					msgid "membership duration"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:76
 | 
					#: apps/member/models.py:78
 | 
				
			||||||
msgid "The longest time a membership can last (NULL = infinite)."
 | 
					msgid "The longest time a membership can last (NULL = infinite)."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:81
 | 
					#: apps/member/models.py:83
 | 
				
			||||||
msgid "membership start"
 | 
					msgid "membership start"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:82
 | 
					#: apps/member/models.py:84
 | 
				
			||||||
msgid "How long after January 1st the members can renew their membership."
 | 
					msgid "How long after January 1st the members can renew their membership."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:87
 | 
					#: apps/member/models.py:89
 | 
				
			||||||
msgid "membership end"
 | 
					msgid "membership end"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:88
 | 
					#: apps/member/models.py:90
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"How long the membership can last after January 1st of the next year after "
 | 
					"How long the membership can last after January 1st of the next year after "
 | 
				
			||||||
"members can renew their membership."
 | 
					"members can renew their membership."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:94 apps/note/models/notes.py:139
 | 
					#: apps/member/models.py:96 apps/note/models/notes.py:139
 | 
				
			||||||
msgid "club"
 | 
					msgid "club"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:95
 | 
					#: apps/member/models.py:97
 | 
				
			||||||
msgid "clubs"
 | 
					msgid "clubs"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:118
 | 
					#: apps/member/models.py:120 apps/permission/models.py:276
 | 
				
			||||||
msgid "role"
 | 
					msgid "role"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:119
 | 
					#: apps/member/models.py:121
 | 
				
			||||||
msgid "roles"
 | 
					msgid "roles"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:143
 | 
					#: apps/member/models.py:145
 | 
				
			||||||
msgid "membership starts on"
 | 
					msgid "membership starts on"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:146
 | 
					#: apps/member/models.py:148
 | 
				
			||||||
msgid "membership ends on"
 | 
					msgid "membership ends on"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:150
 | 
					#: apps/member/models.py:152
 | 
				
			||||||
msgid "fee"
 | 
					msgid "fee"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:154
 | 
					#: apps/member/models.py:162
 | 
				
			||||||
msgid "membership"
 | 
					msgid "membership"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:155
 | 
					#: apps/member/models.py:163
 | 
				
			||||||
msgid "memberships"
 | 
					msgid "memberships"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:69 templates/member/profile_detail.html:46
 | 
					#: apps/member/views.py:80 templates/member/profile_detail.html:46
 | 
				
			||||||
msgid "Update Profile"
 | 
					msgid "Update Profile"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:82
 | 
					#: apps/member/views.py:93
 | 
				
			||||||
msgid "An alias with a similar name already exists."
 | 
					msgid "An alias with a similar name already exists."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:132
 | 
					#: apps/member/views.py:146
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "Account #%(id)s: %(username)s"
 | 
					msgid "Account #%(id)s: %(username)s"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:202
 | 
					#: apps/member/views.py:216
 | 
				
			||||||
msgid "Alias successfully deleted"
 | 
					msgid "Alias successfully deleted"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
 | 
					#: apps/note/admin.py:120 apps/note/models/transactions.py:95
 | 
				
			||||||
msgid "source"
 | 
					msgid "source"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/admin.py:128 apps/note/admin.py:156
 | 
					#: apps/note/admin.py:128 apps/note/admin.py:156
 | 
				
			||||||
#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:100
 | 
					#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
 | 
				
			||||||
msgid "destination"
 | 
					msgid "destination"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -309,7 +310,7 @@ msgstr ""
 | 
				
			|||||||
msgid "display image"
 | 
					msgid "display image"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:103
 | 
					#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
 | 
				
			||||||
msgid "created at"
 | 
					msgid "created at"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -383,116 +384,274 @@ msgstr ""
 | 
				
			|||||||
msgid "You can't delete your main alias."
 | 
					msgid "You can't delete your main alias."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:30
 | 
					#: apps/note/models/transactions.py:31
 | 
				
			||||||
msgid "transaction category"
 | 
					msgid "transaction category"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:31
 | 
					#: apps/note/models/transactions.py:32
 | 
				
			||||||
msgid "transaction categories"
 | 
					msgid "transaction categories"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:47
 | 
					#: apps/note/models/transactions.py:48
 | 
				
			||||||
msgid "A template with this name already exist"
 | 
					msgid "A template with this name already exist"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:111
 | 
					#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
 | 
				
			||||||
msgid "amount"
 | 
					msgid "amount"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:57
 | 
					#: apps/note/models/transactions.py:58
 | 
				
			||||||
msgid "in centimes"
 | 
					msgid "in centimes"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:75
 | 
					#: apps/note/models/transactions.py:76
 | 
				
			||||||
msgid "transaction template"
 | 
					msgid "transaction template"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:76
 | 
					#: apps/note/models/transactions.py:77
 | 
				
			||||||
msgid "transaction templates"
 | 
					msgid "transaction templates"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:107
 | 
					#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
 | 
				
			||||||
 | 
					#: apps/note/tables.py:33 apps/note/tables.py:42
 | 
				
			||||||
 | 
					msgid "used alias"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:122
 | 
				
			||||||
msgid "quantity"
 | 
					msgid "quantity"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:117 templates/note/transaction_form.html:15
 | 
					#: apps/note/models/transactions.py:130
 | 
				
			||||||
msgid "Gift"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:118 templates/base.html:90
 | 
					 | 
				
			||||||
#: templates/note/transaction_form.html:19
 | 
					 | 
				
			||||||
#: templates/note/transaction_form.html:126
 | 
					 | 
				
			||||||
msgid "Transfer"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:119
 | 
					 | 
				
			||||||
msgid "Template"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:120 templates/note/transaction_form.html:23
 | 
					 | 
				
			||||||
msgid "Credit"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:121 templates/note/transaction_form.html:27
 | 
					 | 
				
			||||||
msgid "Debit"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:122 apps/note/models/transactions.py:230
 | 
					 | 
				
			||||||
msgid "membership transaction"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:129
 | 
					 | 
				
			||||||
msgid "reason"
 | 
					msgid "reason"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:133
 | 
					#: apps/note/models/transactions.py:135
 | 
				
			||||||
msgid "valid"
 | 
					msgid "valid"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:138
 | 
					#: apps/note/models/transactions.py:140 apps/note/tables.py:95
 | 
				
			||||||
 | 
					msgid "invalidity reason"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:147
 | 
				
			||||||
msgid "transaction"
 | 
					msgid "transaction"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:139
 | 
					#: apps/note/models/transactions.py:148
 | 
				
			||||||
msgid "transactions"
 | 
					msgid "transactions"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:207
 | 
					#: apps/note/models/transactions.py:202 templates/base.html:83
 | 
				
			||||||
 | 
					#: templates/note/transaction_form.html:19
 | 
				
			||||||
 | 
					#: templates/note/transaction_form.html:145
 | 
				
			||||||
 | 
					msgid "Transfer"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:188
 | 
				
			||||||
 | 
					msgid "Template"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:203
 | 
				
			||||||
msgid "first_name"
 | 
					msgid "first_name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:212
 | 
					#: apps/note/models/transactions.py:208
 | 
				
			||||||
msgid "bank"
 | 
					msgid "bank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:24
 | 
				
			||||||
 | 
					msgid "Credit"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:28
 | 
				
			||||||
 | 
					msgid "Debit"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:230 apps/note/models/transactions.py:235
 | 
				
			||||||
 | 
					msgid "membership transaction"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:231
 | 
					#: apps/note/models/transactions.py:231
 | 
				
			||||||
msgid "membership transactions"
 | 
					msgid "membership transactions"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/views.py:31
 | 
					#: apps/note/views.py:39
 | 
				
			||||||
msgid "Transfer money"
 | 
					msgid "Transfer money"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/views.py:132 templates/base.html:78
 | 
					#: apps/note/views.py:145 templates/base.html:79
 | 
				
			||||||
msgid "Consumptions"
 | 
					msgid "Consumptions"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/__init__.py:61
 | 
					#: apps/permission/models.py:69 apps/permission/models.py:262
 | 
				
			||||||
 | 
					#, python-brace-format
 | 
				
			||||||
 | 
					msgid "Can {type} {model}.{field} in {query}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/permission/models.py:71 apps/permission/models.py:264
 | 
				
			||||||
 | 
					#, python-brace-format
 | 
				
			||||||
 | 
					msgid "Can {type} {model} in {query}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/permission/models.py:84
 | 
				
			||||||
 | 
					msgid "rank"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/permission/models.py:147
 | 
				
			||||||
 | 
					msgid "Specifying field applies only to view and change permission types."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/apps.py:11 templates/base.html:102
 | 
				
			||||||
 | 
					msgid "Treasury"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:56 apps/treasury/forms.py:95
 | 
				
			||||||
 | 
					#: templates/django_filters/rest_framework/form.html:5
 | 
				
			||||||
 | 
					#: templates/member/club_form.html:10 templates/treasury/invoice_form.html:47
 | 
				
			||||||
 | 
					msgid "Submit"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:58
 | 
				
			||||||
 | 
					msgid "Close"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:65
 | 
				
			||||||
 | 
					msgid "Remittance is already closed."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:70
 | 
				
			||||||
 | 
					msgid "You can't change the type of the remittance."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:84
 | 
				
			||||||
 | 
					msgid "Last name"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:86 templates/note/transaction_form.html:92
 | 
				
			||||||
 | 
					msgid "First name"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:88 templates/note/transaction_form.html:98
 | 
				
			||||||
 | 
					msgid "Bank"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:90 apps/treasury/tables.py:40
 | 
				
			||||||
 | 
					#: templates/note/transaction_form.html:128
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:18
 | 
				
			||||||
 | 
					msgid "Amount"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:18
 | 
				
			||||||
 | 
					msgid "Invoice identifier"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:32
 | 
				
			||||||
 | 
					msgid "BDE"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:37
 | 
				
			||||||
 | 
					msgid "Object"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:41
 | 
				
			||||||
 | 
					msgid "Description"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:46 templates/note/transaction_form.html:86
 | 
				
			||||||
 | 
					msgid "Name"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:50
 | 
				
			||||||
 | 
					msgid "Address"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:55
 | 
				
			||||||
 | 
					msgid "Place"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:59
 | 
				
			||||||
 | 
					msgid "Acquitted"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:75
 | 
				
			||||||
 | 
					msgid "Designation"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:79
 | 
				
			||||||
 | 
					msgid "Quantity"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:83
 | 
				
			||||||
 | 
					msgid "Unit price"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:120
 | 
				
			||||||
 | 
					msgid "Date"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:126
 | 
				
			||||||
 | 
					msgid "Type"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:131
 | 
				
			||||||
 | 
					msgid "Comment"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:136
 | 
				
			||||||
 | 
					msgid "Closed"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:159
 | 
				
			||||||
 | 
					msgid "Remittance #{:d}: {}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:16
 | 
				
			||||||
 | 
					msgid "Invoice #{:d}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:10
 | 
				
			||||||
 | 
					msgid "Invoice"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:38
 | 
				
			||||||
 | 
					msgid "Transaction count"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:43 apps/treasury/tables.py:45
 | 
				
			||||||
 | 
					msgid "View"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:66
 | 
				
			||||||
 | 
					msgid "Add"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:74
 | 
				
			||||||
 | 
					msgid "Remove"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: note_kfet/settings/__init__.py:63
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"The Central Authentication Service grants you access to most of our websites "
 | 
					"The Central Authentication Service grants you access to most of our websites "
 | 
				
			||||||
"by authenticating only once, so you don't need to type your credentials "
 | 
					"by authenticating only once, so you don't need to type your credentials "
 | 
				
			||||||
"again unless your session expires or you logout."
 | 
					"again unless your session expires or you logout."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/base.py:156
 | 
					#: note_kfet/settings/base.py:151
 | 
				
			||||||
msgid "German"
 | 
					msgid "German"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/base.py:157
 | 
					#: note_kfet/settings/base.py:152
 | 
				
			||||||
msgid "English"
 | 
					msgid "English"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/base.py:158
 | 
					#: note_kfet/settings/base.py:153
 | 
				
			||||||
msgid "French"
 | 
					msgid "French"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -500,18 +659,14 @@ msgstr ""
 | 
				
			|||||||
msgid "The ENS Paris-Saclay BDE note."
 | 
					msgid "The ENS Paris-Saclay BDE note."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/base.html:81
 | 
					#: templates/base.html:87
 | 
				
			||||||
msgid "Clubs"
 | 
					msgid "Clubs"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/base.html:84
 | 
					#: templates/base.html:92
 | 
				
			||||||
msgid "Activities"
 | 
					msgid "Activities"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/base.html:87
 | 
					 | 
				
			||||||
msgid "Buttons"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: templates/cas_server/base.html:7
 | 
					#: templates/cas_server/base.html:7
 | 
				
			||||||
msgid "Central Authentication Service"
 | 
					msgid "Central Authentication Service"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -567,11 +722,6 @@ msgstr ""
 | 
				
			|||||||
msgid "Field filters"
 | 
					msgid "Field filters"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/django_filters/rest_framework/form.html:5
 | 
					 | 
				
			||||||
#: templates/member/club_form.html:10
 | 
					 | 
				
			||||||
msgid "Submit"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: templates/member/club_detail.html:10
 | 
					#: templates/member/club_detail.html:10
 | 
				
			||||||
msgid "Membership starts on"
 | 
					msgid "Membership starts on"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -653,7 +803,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Sign up"
 | 
					msgid "Sign up"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:38
 | 
					#: templates/note/conso_form.html:28 templates/note/transaction_form.html:50
 | 
				
			||||||
msgid "Select emitters"
 | 
					msgid "Select emitters"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -681,49 +831,53 @@ msgstr ""
 | 
				
			|||||||
msgid "Double consumptions"
 | 
					msgid "Double consumptions"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:141
 | 
					#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152
 | 
				
			||||||
msgid "Recent transactions history"
 | 
					msgid "Recent transactions history"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:55
 | 
					#: templates/note/transaction_form.html:15
 | 
				
			||||||
 | 
					msgid "Gift"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transaction_form.html:68
 | 
				
			||||||
msgid "External payment"
 | 
					msgid "External payment"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:63
 | 
					#: templates/note/transaction_form.html:76
 | 
				
			||||||
msgid "Transfer type"
 | 
					msgid "Transfer type"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:73
 | 
					#: templates/note/transaction_form.html:86
 | 
				
			||||||
msgid "Name"
 | 
					msgid "Name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:79
 | 
					#: templates/note/transaction_form.html:92
 | 
				
			||||||
msgid "First name"
 | 
					msgid "First name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:85
 | 
					#: templates/note/transaction_form.html:98
 | 
				
			||||||
msgid "Bank"
 | 
					msgid "Bank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:97
 | 
					#: templates/note/transaction_form.html:111
 | 
				
			||||||
#: templates/note/transaction_form.html:179
 | 
					#: templates/note/transaction_form.html:169
 | 
				
			||||||
#: templates/note/transaction_form.html:186
 | 
					#: templates/note/transaction_form.html:176
 | 
				
			||||||
msgid "Select receivers"
 | 
					msgid "Select receivers"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:114
 | 
					#: templates/note/transaction_form.html:128
 | 
				
			||||||
msgid "Amount"
 | 
					msgid "Amount"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:119
 | 
					#: templates/note/transaction_form.html:138
 | 
				
			||||||
msgid "Reason"
 | 
					msgid "Reason"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:193
 | 
					#: templates/note/transaction_form.html:183
 | 
				
			||||||
msgid "Credit note"
 | 
					msgid "Credit note"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:200
 | 
					#: templates/note/transaction_form.html:190
 | 
				
			||||||
msgid "Debit note"
 | 
					msgid "Debit note"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -731,6 +885,22 @@ msgstr ""
 | 
				
			|||||||
msgid "Buttons list"
 | 
					msgid "Buttons list"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:9
 | 
				
			||||||
 | 
					msgid "search button"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:20
 | 
				
			||||||
 | 
					msgid "buttons listing "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:71
 | 
				
			||||||
 | 
					msgid "button successfully deleted "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:75
 | 
				
			||||||
 | 
					msgid "Unable to delete button "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/logged_out.html:8
 | 
					#: templates/registration/logged_out.html:8
 | 
				
			||||||
msgid "Thanks for spending some quality time with the Web site today."
 | 
					msgid "Thanks for spending some quality time with the Web site today."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -740,7 +910,7 @@ msgid "Log in again"
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/login.html:7 templates/registration/login.html:8
 | 
					#: templates/registration/login.html:7 templates/registration/login.html:8
 | 
				
			||||||
#: templates/registration/login.html:26
 | 
					#: templates/registration/login.html:28
 | 
				
			||||||
#: templates/registration/password_reset_complete.html:10
 | 
					#: templates/registration/password_reset_complete.html:10
 | 
				
			||||||
msgid "Log in"
 | 
					msgid "Log in"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -752,7 +922,15 @@ msgid ""
 | 
				
			|||||||
"page. Would you like to login to a different account?"
 | 
					"page. Would you like to login to a different account?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/login.html:27
 | 
					#: templates/registration/login.html:22
 | 
				
			||||||
 | 
					msgid "You can also register via the central authentification server "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/registration/login.html:23
 | 
				
			||||||
 | 
					msgid "using this link "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/registration/login.html:29
 | 
				
			||||||
msgid "Forgotten your password or username?"
 | 
					msgid "Forgotten your password or username?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -808,3 +986,72 @@ msgstr ""
 | 
				
			|||||||
#: templates/registration/password_reset_form.html:11
 | 
					#: templates/registration/password_reset_form.html:11
 | 
				
			||||||
msgid "Reset my password"
 | 
					msgid "Reset my password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_form.html:6
 | 
				
			||||||
 | 
					msgid "Invoices list"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_form.html:42
 | 
				
			||||||
 | 
					msgid "Add product"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_form.html:43
 | 
				
			||||||
 | 
					msgid "Remove product"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_list.html:21
 | 
				
			||||||
 | 
					msgid "New invoice"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:7
 | 
				
			||||||
 | 
					msgid "Remittance #"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:9
 | 
				
			||||||
 | 
					#: templates/treasury/specialtransactionproxy_form.html:7
 | 
				
			||||||
 | 
					msgid "Remittances list"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:12
 | 
				
			||||||
 | 
					msgid "Count"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:29
 | 
				
			||||||
 | 
					msgid "Linked transactions"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:34
 | 
				
			||||||
 | 
					msgid "There is no transaction linked with this remittance."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:19
 | 
				
			||||||
 | 
					msgid "Opened remittances"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:24
 | 
				
			||||||
 | 
					msgid "There is no opened remittance."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:28
 | 
				
			||||||
 | 
					msgid "New remittance"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:32
 | 
				
			||||||
 | 
					msgid "Transfers without remittances"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:37
 | 
				
			||||||
 | 
					msgid "There is no transaction without any linked remittance."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:43
 | 
				
			||||||
 | 
					msgid "Transfers with opened remittances"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:48
 | 
				
			||||||
 | 
					msgid "There is no transaction with an opened linked remittance."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:54
 | 
				
			||||||
 | 
					msgid "Closed remittances"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ msgid ""
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
					"Project-Id-Version: PACKAGE VERSION\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: \n"
 | 
					"Report-Msgid-Bugs-To: \n"
 | 
				
			||||||
"POT-Creation-Date: 2020-03-16 11:53+0100\n"
 | 
					"POT-Creation-Date: 2020-03-26 14:40+0100\n"
 | 
				
			||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
					"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
				
			||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
					"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
				
			||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
					"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
				
			||||||
@@ -18,9 +18,9 @@ msgid "activity"
 | 
				
			|||||||
msgstr "activité"
 | 
					msgstr "activité"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/activity/models.py:19 apps/activity/models.py:44
 | 
					#: apps/activity/models.py:19 apps/activity/models.py:44
 | 
				
			||||||
#: apps/member/models.py:61 apps/member/models.py:112
 | 
					#: apps/member/models.py:63 apps/member/models.py:114
 | 
				
			||||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
 | 
					#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
 | 
				
			||||||
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:202
 | 
					#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
 | 
				
			||||||
#: templates/member/profile_detail.html:15
 | 
					#: templates/member/profile_detail.html:15
 | 
				
			||||||
msgid "name"
 | 
					msgid "name"
 | 
				
			||||||
msgstr "nom"
 | 
					msgstr "nom"
 | 
				
			||||||
@@ -41,12 +41,13 @@ msgstr "type d'activité"
 | 
				
			|||||||
msgid "activity types"
 | 
					msgid "activity types"
 | 
				
			||||||
msgstr "types d'activité"
 | 
					msgstr "types d'activité"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:69
 | 
					#: apps/activity/models.py:48 apps/note/models/transactions.py:70
 | 
				
			||||||
 | 
					#: apps/permission/models.py:91
 | 
				
			||||||
msgid "description"
 | 
					msgid "description"
 | 
				
			||||||
msgstr "description"
 | 
					msgstr "description"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/activity/models.py:54 apps/note/models/notes.py:164
 | 
					#: apps/activity/models.py:54 apps/note/models/notes.py:164
 | 
				
			||||||
#: apps/note/models/transactions.py:62 apps/note/models/transactions.py:115
 | 
					#: apps/note/models/transactions.py:63
 | 
				
			||||||
msgid "type"
 | 
					msgid "type"
 | 
				
			||||||
msgstr "type"
 | 
					msgstr "type"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,11 +115,11 @@ msgstr "Nouvelles données"
 | 
				
			|||||||
msgid "create"
 | 
					msgid "create"
 | 
				
			||||||
msgstr "Créer"
 | 
					msgstr "Créer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/logs/models.py:61
 | 
					#: apps/logs/models.py:61 apps/note/tables.py:147
 | 
				
			||||||
msgid "edit"
 | 
					msgid "edit"
 | 
				
			||||||
msgstr "Modifier"
 | 
					msgstr "Modifier"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/logs/models.py:62
 | 
					#: apps/logs/models.py:62 apps/note/tables.py:151
 | 
				
			||||||
msgid "delete"
 | 
					msgid "delete"
 | 
				
			||||||
msgstr "Supprimer"
 | 
					msgstr "Supprimer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,61 +139,61 @@ msgstr "Les logs ne peuvent pas être détruits."
 | 
				
			|||||||
msgid "member"
 | 
					msgid "member"
 | 
				
			||||||
msgstr "adhérent"
 | 
					msgstr "adhérent"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:23
 | 
					#: apps/member/models.py:25
 | 
				
			||||||
msgid "phone number"
 | 
					msgid "phone number"
 | 
				
			||||||
msgstr "numéro de téléphone"
 | 
					msgstr "numéro de téléphone"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:29 templates/member/profile_detail.html:28
 | 
					#: apps/member/models.py:31 templates/member/profile_detail.html:28
 | 
				
			||||||
msgid "section"
 | 
					msgid "section"
 | 
				
			||||||
msgstr "section"
 | 
					msgstr "section"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:30
 | 
					#: apps/member/models.py:32
 | 
				
			||||||
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 | 
					msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 | 
				
			||||||
msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 | 
					msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:36 templates/member/profile_detail.html:31
 | 
					#: apps/member/models.py:38 templates/member/profile_detail.html:31
 | 
				
			||||||
msgid "address"
 | 
					msgid "address"
 | 
				
			||||||
msgstr "adresse"
 | 
					msgstr "adresse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:42
 | 
					#: apps/member/models.py:44
 | 
				
			||||||
msgid "paid"
 | 
					msgid "paid"
 | 
				
			||||||
msgstr "payé"
 | 
					msgstr "payé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:47 apps/member/models.py:48
 | 
					#: apps/member/models.py:49 apps/member/models.py:50
 | 
				
			||||||
msgid "user profile"
 | 
					msgid "user profile"
 | 
				
			||||||
msgstr "profil utilisateur"
 | 
					msgstr "profil utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:66
 | 
					#: apps/member/models.py:68
 | 
				
			||||||
msgid "email"
 | 
					msgid "email"
 | 
				
			||||||
msgstr "courriel"
 | 
					msgstr "courriel"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:71
 | 
					#: apps/member/models.py:73
 | 
				
			||||||
msgid "membership fee"
 | 
					msgid "membership fee"
 | 
				
			||||||
msgstr "cotisation pour adhérer"
 | 
					msgstr "cotisation pour adhérer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:75
 | 
					#: apps/member/models.py:77
 | 
				
			||||||
msgid "membership duration"
 | 
					msgid "membership duration"
 | 
				
			||||||
msgstr "durée de l'adhésion"
 | 
					msgstr "durée de l'adhésion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:76
 | 
					#: apps/member/models.py:78
 | 
				
			||||||
msgid "The longest time a membership can last (NULL = infinite)."
 | 
					msgid "The longest time a membership can last (NULL = infinite)."
 | 
				
			||||||
msgstr "La durée maximale d'une adhésion (NULL = infinie)."
 | 
					msgstr "La durée maximale d'une adhésion (NULL = infinie)."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:81
 | 
					#: apps/member/models.py:83
 | 
				
			||||||
msgid "membership start"
 | 
					msgid "membership start"
 | 
				
			||||||
msgstr "début de l'adhésion"
 | 
					msgstr "début de l'adhésion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:82
 | 
					#: apps/member/models.py:84
 | 
				
			||||||
msgid "How long after January 1st the members can renew their membership."
 | 
					msgid "How long after January 1st the members can renew their membership."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur "
 | 
					"Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur "
 | 
				
			||||||
"adhésion."
 | 
					"adhésion."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:87
 | 
					#: apps/member/models.py:89
 | 
				
			||||||
msgid "membership end"
 | 
					msgid "membership end"
 | 
				
			||||||
msgstr "fin de l'adhésion"
 | 
					msgstr "fin de l'adhésion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:88
 | 
					#: apps/member/models.py:90
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"How long the membership can last after January 1st of the next year after "
 | 
					"How long the membership can last after January 1st of the next year after "
 | 
				
			||||||
"members can renew their membership."
 | 
					"members can renew their membership."
 | 
				
			||||||
@@ -200,65 +201,65 @@ msgstr ""
 | 
				
			|||||||
"Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
 | 
					"Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
 | 
				
			||||||
"suivante avant que les adhérents peuvent renouveler leur adhésion."
 | 
					"suivante avant que les adhérents peuvent renouveler leur adhésion."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:94 apps/note/models/notes.py:139
 | 
					#: apps/member/models.py:96 apps/note/models/notes.py:139
 | 
				
			||||||
msgid "club"
 | 
					msgid "club"
 | 
				
			||||||
msgstr "club"
 | 
					msgstr "club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:95
 | 
					#: apps/member/models.py:97
 | 
				
			||||||
msgid "clubs"
 | 
					msgid "clubs"
 | 
				
			||||||
msgstr "clubs"
 | 
					msgstr "clubs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:118
 | 
					#: apps/member/models.py:120 apps/permission/models.py:276
 | 
				
			||||||
msgid "role"
 | 
					msgid "role"
 | 
				
			||||||
msgstr "rôle"
 | 
					msgstr "rôle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:119
 | 
					#: apps/member/models.py:121
 | 
				
			||||||
msgid "roles"
 | 
					msgid "roles"
 | 
				
			||||||
msgstr "rôles"
 | 
					msgstr "rôles"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:143
 | 
					#: apps/member/models.py:145
 | 
				
			||||||
msgid "membership starts on"
 | 
					msgid "membership starts on"
 | 
				
			||||||
msgstr "l'adhésion commence le"
 | 
					msgstr "l'adhésion commence le"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:146
 | 
					#: apps/member/models.py:148
 | 
				
			||||||
msgid "membership ends on"
 | 
					msgid "membership ends on"
 | 
				
			||||||
msgstr "l'adhésion finie le"
 | 
					msgstr "l'adhésion finie le"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:150
 | 
					#: apps/member/models.py:152
 | 
				
			||||||
msgid "fee"
 | 
					msgid "fee"
 | 
				
			||||||
msgstr "cotisation"
 | 
					msgstr "cotisation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:154
 | 
					#: apps/member/models.py:162
 | 
				
			||||||
msgid "membership"
 | 
					msgid "membership"
 | 
				
			||||||
msgstr "adhésion"
 | 
					msgstr "adhésion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/models.py:155
 | 
					#: apps/member/models.py:163
 | 
				
			||||||
msgid "memberships"
 | 
					msgid "memberships"
 | 
				
			||||||
msgstr "adhésions"
 | 
					msgstr "adhésions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:69 templates/member/profile_detail.html:46
 | 
					#: apps/member/views.py:80 templates/member/profile_detail.html:46
 | 
				
			||||||
msgid "Update Profile"
 | 
					msgid "Update Profile"
 | 
				
			||||||
msgstr "Modifier le profil"
 | 
					msgstr "Modifier le profil"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:82
 | 
					#: apps/member/views.py:93
 | 
				
			||||||
msgid "An alias with a similar name already exists."
 | 
					msgid "An alias with a similar name already exists."
 | 
				
			||||||
msgstr "Un alias avec un nom similaire existe déjà."
 | 
					msgstr "Un alias avec un nom similaire existe déjà."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:132
 | 
					#: apps/member/views.py:146
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "Account #%(id)s: %(username)s"
 | 
					msgid "Account #%(id)s: %(username)s"
 | 
				
			||||||
msgstr "Compte n°%(id)s : %(username)s"
 | 
					msgstr "Compte n°%(id)s : %(username)s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/member/views.py:202
 | 
					#: apps/member/views.py:216
 | 
				
			||||||
msgid "Alias successfully deleted"
 | 
					msgid "Alias successfully deleted"
 | 
				
			||||||
msgstr "L'alias a bien été supprimé"
 | 
					msgstr "L'alias a bien été supprimé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
 | 
					#: apps/note/admin.py:120 apps/note/models/transactions.py:95
 | 
				
			||||||
msgid "source"
 | 
					msgid "source"
 | 
				
			||||||
msgstr "source"
 | 
					msgstr "source"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/admin.py:128 apps/note/admin.py:156
 | 
					#: apps/note/admin.py:128 apps/note/admin.py:156
 | 
				
			||||||
#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:100
 | 
					#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
 | 
				
			||||||
msgid "destination"
 | 
					msgid "destination"
 | 
				
			||||||
msgstr "destination"
 | 
					msgstr "destination"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -309,7 +310,7 @@ msgstr ""
 | 
				
			|||||||
msgid "display image"
 | 
					msgid "display image"
 | 
				
			||||||
msgstr "image affichée"
 | 
					msgstr "image affichée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:103
 | 
					#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
 | 
				
			||||||
msgid "created at"
 | 
					msgid "created at"
 | 
				
			||||||
msgstr "créée le"
 | 
					msgstr "créée le"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -383,116 +384,270 @@ msgstr "Un alias avec un nom similaire existe déjà : {}"
 | 
				
			|||||||
msgid "You can't delete your main alias."
 | 
					msgid "You can't delete your main alias."
 | 
				
			||||||
msgstr "Vous ne pouvez pas supprimer votre alias principal."
 | 
					msgstr "Vous ne pouvez pas supprimer votre alias principal."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:30
 | 
					#: apps/note/models/transactions.py:31
 | 
				
			||||||
msgid "transaction category"
 | 
					msgid "transaction category"
 | 
				
			||||||
msgstr "catégorie de transaction"
 | 
					msgstr "catégorie de transaction"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:31
 | 
					#: apps/note/models/transactions.py:32
 | 
				
			||||||
msgid "transaction categories"
 | 
					msgid "transaction categories"
 | 
				
			||||||
msgstr "catégories de transaction"
 | 
					msgstr "catégories de transaction"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:47
 | 
					#: apps/note/models/transactions.py:48
 | 
				
			||||||
msgid "A template with this name already exist"
 | 
					msgid "A template with this name already exist"
 | 
				
			||||||
msgstr "Un modèle de transaction avec un nom similaire existe déjà."
 | 
					msgstr "Un modèle de transaction avec un nom similaire existe déjà."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:111
 | 
					#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
 | 
				
			||||||
msgid "amount"
 | 
					msgid "amount"
 | 
				
			||||||
msgstr "montant"
 | 
					msgstr "montant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:57
 | 
					#: apps/note/models/transactions.py:58
 | 
				
			||||||
msgid "in centimes"
 | 
					msgid "in centimes"
 | 
				
			||||||
msgstr "en centimes"
 | 
					msgstr "en centimes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:75
 | 
					#: apps/note/models/transactions.py:76
 | 
				
			||||||
msgid "transaction template"
 | 
					msgid "transaction template"
 | 
				
			||||||
msgstr "modèle de transaction"
 | 
					msgstr "modèle de transaction"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:76
 | 
					#: apps/note/models/transactions.py:77
 | 
				
			||||||
msgid "transaction templates"
 | 
					msgid "transaction templates"
 | 
				
			||||||
msgstr "modèles de transaction"
 | 
					msgstr "modèles de transaction"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:107
 | 
					#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
 | 
				
			||||||
 | 
					#: apps/note/tables.py:33 apps/note/tables.py:42
 | 
				
			||||||
 | 
					msgid "used alias"
 | 
				
			||||||
 | 
					msgstr "alias utilisé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:122
 | 
				
			||||||
msgid "quantity"
 | 
					msgid "quantity"
 | 
				
			||||||
msgstr "quantité"
 | 
					msgstr "quantité"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:117 templates/note/transaction_form.html:15
 | 
					#: apps/note/models/transactions.py:115
 | 
				
			||||||
msgid "Gift"
 | 
					 | 
				
			||||||
msgstr "Don"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:118 templates/base.html:90
 | 
					 | 
				
			||||||
#: templates/note/transaction_form.html:19
 | 
					 | 
				
			||||||
#: templates/note/transaction_form.html:126
 | 
					 | 
				
			||||||
msgid "Transfer"
 | 
					 | 
				
			||||||
msgstr "Virement"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:119
 | 
					 | 
				
			||||||
msgid "Template"
 | 
					 | 
				
			||||||
msgstr "Bouton"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:120 templates/note/transaction_form.html:23
 | 
					 | 
				
			||||||
msgid "Credit"
 | 
					 | 
				
			||||||
msgstr "Crédit"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:121 templates/note/transaction_form.html:27
 | 
					 | 
				
			||||||
msgid "Debit"
 | 
					 | 
				
			||||||
msgstr "Retrait"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:122 apps/note/models/transactions.py:230
 | 
					 | 
				
			||||||
msgid "membership transaction"
 | 
					 | 
				
			||||||
msgstr "transaction d'adhésion"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: apps/note/models/transactions.py:129
 | 
					 | 
				
			||||||
msgid "reason"
 | 
					msgid "reason"
 | 
				
			||||||
msgstr "raison"
 | 
					msgstr "raison"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:133
 | 
					#: apps/note/models/transactions.py:119
 | 
				
			||||||
msgid "valid"
 | 
					msgid "valid"
 | 
				
			||||||
msgstr "valide"
 | 
					msgstr "valide"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:138
 | 
					#: apps/note/models/transactions.py:124
 | 
				
			||||||
msgid "transaction"
 | 
					msgid "transaction"
 | 
				
			||||||
msgstr "transaction"
 | 
					msgstr "transaction"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:139
 | 
					#: apps/note/models/transactions.py:125
 | 
				
			||||||
msgid "transactions"
 | 
					msgid "transactions"
 | 
				
			||||||
msgstr "transactions"
 | 
					msgstr "transactions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:207
 | 
					#: apps/note/models/transactions.py:168 templates/base.html:98
 | 
				
			||||||
msgid "first_name"
 | 
					#: templates/note/transaction_form.html:19
 | 
				
			||||||
msgstr "Prénom"
 | 
					#: templates/note/transaction_form.html:145
 | 
				
			||||||
 | 
					msgid "Transfer"
 | 
				
			||||||
 | 
					msgstr "Virement"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:212
 | 
					#: apps/note/models/transactions.py:188
 | 
				
			||||||
 | 
					msgid "Template"
 | 
				
			||||||
 | 
					msgstr "Bouton"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:203
 | 
				
			||||||
 | 
					msgid "first_name"
 | 
				
			||||||
 | 
					msgstr "prénom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:208
 | 
				
			||||||
msgid "bank"
 | 
					msgid "bank"
 | 
				
			||||||
msgstr "Banque"
 | 
					msgstr "banque"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:24
 | 
				
			||||||
 | 
					msgid "Credit"
 | 
				
			||||||
 | 
					msgstr "Crédit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:28
 | 
				
			||||||
 | 
					msgid "Debit"
 | 
				
			||||||
 | 
					msgstr "Débit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/note/models/transactions.py:230 apps/note/models/transactions.py:235
 | 
				
			||||||
 | 
					msgid "membership transaction"
 | 
				
			||||||
 | 
					msgstr "transaction d'adhésion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/models/transactions.py:231
 | 
					#: apps/note/models/transactions.py:231
 | 
				
			||||||
msgid "membership transactions"
 | 
					msgid "membership transactions"
 | 
				
			||||||
msgstr "transactions d'adhésion"
 | 
					msgstr "transactions d'adhésion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/views.py:31
 | 
					#: apps/note/views.py:39
 | 
				
			||||||
msgid "Transfer money"
 | 
					msgid "Transfer money"
 | 
				
			||||||
msgstr "Transferts d'argent"
 | 
					msgstr "Transférer de l'argent"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/note/views.py:132 templates/base.html:78
 | 
					#: apps/note/views.py:145 templates/base.html:79
 | 
				
			||||||
msgid "Consumptions"
 | 
					msgid "Consumptions"
 | 
				
			||||||
msgstr "Consommations"
 | 
					msgstr "Consommations"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/__init__.py:61
 | 
					#: apps/permission/models.py:69 apps/permission/models.py:262
 | 
				
			||||||
 | 
					#, python-brace-format
 | 
				
			||||||
 | 
					msgid "Can {type} {model}.{field} in {query}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/permission/models.py:71 apps/permission/models.py:264
 | 
				
			||||||
 | 
					#, python-brace-format
 | 
				
			||||||
 | 
					msgid "Can {type} {model} in {query}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/permission/models.py:84
 | 
				
			||||||
 | 
					msgid "rank"
 | 
				
			||||||
 | 
					msgstr "Rang"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/permission/models.py:147
 | 
				
			||||||
 | 
					msgid "Specifying field applies only to view and change permission types."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/apps.py:11 templates/base.html:102
 | 
				
			||||||
 | 
					msgid "Treasury"
 | 
				
			||||||
 | 
					msgstr "Trésorerie"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:56 apps/treasury/forms.py:95
 | 
				
			||||||
 | 
					#: templates/django_filters/rest_framework/form.html:5
 | 
				
			||||||
 | 
					#: templates/member/club_form.html:10 templates/treasury/invoice_form.html:47
 | 
				
			||||||
 | 
					msgid "Submit"
 | 
				
			||||||
 | 
					msgstr "Envoyer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:58
 | 
				
			||||||
 | 
					msgid "Close"
 | 
				
			||||||
 | 
					msgstr "Fermer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:65
 | 
				
			||||||
 | 
					msgid "Remittance is already closed."
 | 
				
			||||||
 | 
					msgstr "La remise est déjà fermée."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:70
 | 
				
			||||||
 | 
					msgid "You can't change the type of the remittance."
 | 
				
			||||||
 | 
					msgstr "Vous ne pouvez pas changer le type de la remise."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:84
 | 
				
			||||||
 | 
					msgid "Last name"
 | 
				
			||||||
 | 
					msgstr "Nom de famille"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:86 templates/note/transaction_form.html:92
 | 
				
			||||||
 | 
					msgid "First name"
 | 
				
			||||||
 | 
					msgstr "Prénom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:88 templates/note/transaction_form.html:98
 | 
				
			||||||
 | 
					msgid "Bank"
 | 
				
			||||||
 | 
					msgstr "Banque"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/forms.py:90 apps/treasury/tables.py:40
 | 
				
			||||||
 | 
					#: templates/note/transaction_form.html:128
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:18
 | 
				
			||||||
 | 
					msgid "Amount"
 | 
				
			||||||
 | 
					msgstr "Montant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:18
 | 
				
			||||||
 | 
					msgid "Invoice identifier"
 | 
				
			||||||
 | 
					msgstr "Numéro de facture"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:32
 | 
				
			||||||
 | 
					msgid "BDE"
 | 
				
			||||||
 | 
					msgstr "BDE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:37
 | 
				
			||||||
 | 
					msgid "Object"
 | 
				
			||||||
 | 
					msgstr "Objet"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:41
 | 
				
			||||||
 | 
					msgid "Description"
 | 
				
			||||||
 | 
					msgstr "Description"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:46 templates/note/transaction_form.html:86
 | 
				
			||||||
 | 
					msgid "Name"
 | 
				
			||||||
 | 
					msgstr "Nom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:50
 | 
				
			||||||
 | 
					msgid "Address"
 | 
				
			||||||
 | 
					msgstr "Adresse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:55
 | 
				
			||||||
 | 
					msgid "Place"
 | 
				
			||||||
 | 
					msgstr "Lieu"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:59
 | 
				
			||||||
 | 
					msgid "Acquitted"
 | 
				
			||||||
 | 
					msgstr "Acquittée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:75
 | 
				
			||||||
 | 
					msgid "Designation"
 | 
				
			||||||
 | 
					msgstr "Désignation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:79
 | 
				
			||||||
 | 
					msgid "Quantity"
 | 
				
			||||||
 | 
					msgstr "Quantité"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:83
 | 
				
			||||||
 | 
					msgid "Unit price"
 | 
				
			||||||
 | 
					msgstr "Prix unitaire"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:120
 | 
				
			||||||
 | 
					msgid "Date"
 | 
				
			||||||
 | 
					msgstr "Date"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:126
 | 
				
			||||||
 | 
					msgid "Type"
 | 
				
			||||||
 | 
					msgstr "Type"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:131
 | 
				
			||||||
 | 
					msgid "Comment"
 | 
				
			||||||
 | 
					msgstr "Commentaire"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:136
 | 
				
			||||||
 | 
					msgid "Closed"
 | 
				
			||||||
 | 
					msgstr "Fermée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/models.py:159
 | 
				
			||||||
 | 
					msgid "Remittance #{:d}: {}"
 | 
				
			||||||
 | 
					msgstr "Remise n°{:d} : {}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:16
 | 
				
			||||||
 | 
					msgid "Invoice #{:d}"
 | 
				
			||||||
 | 
					msgstr "Facture n°{:d}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:10
 | 
				
			||||||
 | 
					msgid "Invoice"
 | 
				
			||||||
 | 
					msgstr "Facture"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:38
 | 
				
			||||||
 | 
					msgid "Transaction count"
 | 
				
			||||||
 | 
					msgstr "Nombre de transactions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:43 apps/treasury/tables.py:45
 | 
				
			||||||
 | 
					msgid "View"
 | 
				
			||||||
 | 
					msgstr "Voir"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:66
 | 
				
			||||||
 | 
					msgid "Add"
 | 
				
			||||||
 | 
					msgstr "Ajouter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/treasury/tables.py:74
 | 
				
			||||||
 | 
					msgid "Remove"
 | 
				
			||||||
 | 
					msgstr "supprimer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: note_kfet/settings/__init__.py:63
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"The Central Authentication Service grants you access to most of our websites "
 | 
					"The Central Authentication Service grants you access to most of our websites "
 | 
				
			||||||
"by authenticating only once, so you don't need to type your credentials "
 | 
					"by authenticating only once, so you don't need to type your credentials "
 | 
				
			||||||
"again unless your session expires or you logout."
 | 
					"again unless your session expires or you logout."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/base.py:156
 | 
					#: note_kfet/settings/base.py:151
 | 
				
			||||||
msgid "German"
 | 
					msgid "German"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/base.py:157
 | 
					#: note_kfet/settings/base.py:152
 | 
				
			||||||
msgid "English"
 | 
					msgid "English"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: note_kfet/settings/base.py:158
 | 
					#: note_kfet/settings/base.py:153
 | 
				
			||||||
msgid "French"
 | 
					msgid "French"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -500,18 +655,14 @@ msgstr ""
 | 
				
			|||||||
msgid "The ENS Paris-Saclay BDE note."
 | 
					msgid "The ENS Paris-Saclay BDE note."
 | 
				
			||||||
msgstr "La note du BDE de l'ENS Paris-Saclay."
 | 
					msgstr "La note du BDE de l'ENS Paris-Saclay."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/base.html:81
 | 
					#: templates/base.html:87
 | 
				
			||||||
msgid "Clubs"
 | 
					msgid "Clubs"
 | 
				
			||||||
msgstr "Clubs"
 | 
					msgstr "Clubs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/base.html:84
 | 
					#: templates/base.html:92
 | 
				
			||||||
msgid "Activities"
 | 
					msgid "Activities"
 | 
				
			||||||
msgstr "Activités"
 | 
					msgstr "Activités"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/base.html:87
 | 
					 | 
				
			||||||
msgid "Buttons"
 | 
					 | 
				
			||||||
msgstr "Boutons"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: templates/cas_server/base.html:7
 | 
					#: templates/cas_server/base.html:7
 | 
				
			||||||
msgid "Central Authentication Service"
 | 
					msgid "Central Authentication Service"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -569,11 +720,6 @@ msgstr ""
 | 
				
			|||||||
msgid "Field filters"
 | 
					msgid "Field filters"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/django_filters/rest_framework/form.html:5
 | 
					 | 
				
			||||||
#: templates/member/club_form.html:10
 | 
					 | 
				
			||||||
msgid "Submit"
 | 
					 | 
				
			||||||
msgstr "Envoyer"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: templates/member/club_detail.html:10
 | 
					#: templates/member/club_detail.html:10
 | 
				
			||||||
msgid "Membership starts on"
 | 
					msgid "Membership starts on"
 | 
				
			||||||
msgstr "L'adhésion commence le"
 | 
					msgstr "L'adhésion commence le"
 | 
				
			||||||
@@ -620,15 +766,15 @@ msgstr "Ajouter un alias"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: templates/member/profile_detail.html:15
 | 
					#: templates/member/profile_detail.html:15
 | 
				
			||||||
msgid "first name"
 | 
					msgid "first name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr "prénom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/member/profile_detail.html:18
 | 
					#: templates/member/profile_detail.html:18
 | 
				
			||||||
msgid "username"
 | 
					msgid "username"
 | 
				
			||||||
msgstr ""
 | 
					msgstr "pseudo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/member/profile_detail.html:21
 | 
					#: templates/member/profile_detail.html:21
 | 
				
			||||||
msgid "password"
 | 
					msgid "password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr "mot de passe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/member/profile_detail.html:24
 | 
					#: templates/member/profile_detail.html:24
 | 
				
			||||||
msgid "Change password"
 | 
					msgid "Change password"
 | 
				
			||||||
@@ -655,13 +801,13 @@ msgstr "Sauvegarder les changements"
 | 
				
			|||||||
msgid "Sign up"
 | 
					msgid "Sign up"
 | 
				
			||||||
msgstr "Inscription"
 | 
					msgstr "Inscription"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:38
 | 
					#: templates/note/conso_form.html:28 templates/note/transaction_form.html:50
 | 
				
			||||||
msgid "Select emitters"
 | 
					msgid "Select emitters"
 | 
				
			||||||
msgstr "Sélection des émetteurs"
 | 
					msgstr "Sélection des émetteurs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:45
 | 
					#: templates/note/conso_form.html:45
 | 
				
			||||||
msgid "Select consumptions"
 | 
					msgid "Select consumptions"
 | 
				
			||||||
msgstr "Consommations"
 | 
					msgstr "Sélection des consommations"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:51
 | 
					#: templates/note/conso_form.html:51
 | 
				
			||||||
msgid "Consume!"
 | 
					msgid "Consume!"
 | 
				
			||||||
@@ -677,55 +823,59 @@ msgstr "Éditer"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:126
 | 
					#: templates/note/conso_form.html:126
 | 
				
			||||||
msgid "Single consumptions"
 | 
					msgid "Single consumptions"
 | 
				
			||||||
msgstr "Consos simples"
 | 
					msgstr "Consommations simples"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:130
 | 
					#: templates/note/conso_form.html:130
 | 
				
			||||||
msgid "Double consumptions"
 | 
					msgid "Double consumptions"
 | 
				
			||||||
msgstr "Consos doubles"
 | 
					msgstr "Consommations doubles"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/conso_form.html:141
 | 
					#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152
 | 
				
			||||||
msgid "Recent transactions history"
 | 
					msgid "Recent transactions history"
 | 
				
			||||||
msgstr "Historique des transactions récentes"
 | 
					msgstr "Historique des transactions récentes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:55
 | 
					#: templates/note/transaction_form.html:15
 | 
				
			||||||
msgid "External payment"
 | 
					msgid "Gift"
 | 
				
			||||||
msgstr "Paiement extérieur"
 | 
					msgstr "Don"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:63
 | 
					#: templates/note/transaction_form.html:68
 | 
				
			||||||
 | 
					msgid "External payment"
 | 
				
			||||||
 | 
					msgstr "Paiement externe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transaction_form.html:76
 | 
				
			||||||
msgid "Transfer type"
 | 
					msgid "Transfer type"
 | 
				
			||||||
msgstr "Type de transfert"
 | 
					msgstr "Type de transfert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:73
 | 
					#: templates/note/transaction_form.html:86
 | 
				
			||||||
msgid "Name"
 | 
					msgid "Name"
 | 
				
			||||||
msgstr "Nom"
 | 
					msgstr "Nom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:79
 | 
					#: templates/note/transaction_form.html:92
 | 
				
			||||||
msgid "First name"
 | 
					msgid "First name"
 | 
				
			||||||
msgstr "Prénom"
 | 
					msgstr "Prénom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:85
 | 
					#: templates/note/transaction_form.html:98
 | 
				
			||||||
msgid "Bank"
 | 
					msgid "Bank"
 | 
				
			||||||
msgstr "Banque"
 | 
					msgstr "Banque"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:97
 | 
					#: templates/note/transaction_form.html:111
 | 
				
			||||||
#: templates/note/transaction_form.html:179
 | 
					#: templates/note/transaction_form.html:169
 | 
				
			||||||
#: templates/note/transaction_form.html:186
 | 
					#: templates/note/transaction_form.html:176
 | 
				
			||||||
msgid "Select receivers"
 | 
					msgid "Select receivers"
 | 
				
			||||||
msgstr "Sélection des destinataires"
 | 
					msgstr "Sélection des destinataires"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:114
 | 
					#: templates/note/transaction_form.html:128
 | 
				
			||||||
msgid "Amount"
 | 
					msgid "Amount"
 | 
				
			||||||
msgstr "Montant"
 | 
					msgstr "Montant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:119
 | 
					#: templates/note/transaction_form.html:138
 | 
				
			||||||
msgid "Reason"
 | 
					msgid "Reason"
 | 
				
			||||||
msgstr "Raison"
 | 
					msgstr "Raison"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:193
 | 
					#: templates/note/transaction_form.html:183
 | 
				
			||||||
msgid "Credit note"
 | 
					msgid "Credit note"
 | 
				
			||||||
msgstr "Note à créditer"
 | 
					msgstr "Note à recharger"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/note/transaction_form.html:200
 | 
					#: templates/note/transaction_form.html:190
 | 
				
			||||||
msgid "Debit note"
 | 
					msgid "Debit note"
 | 
				
			||||||
msgstr "Note à débiter"
 | 
					msgstr "Note à débiter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -733,6 +883,22 @@ msgstr "Note à débiter"
 | 
				
			|||||||
msgid "Buttons list"
 | 
					msgid "Buttons list"
 | 
				
			||||||
msgstr "Liste des boutons"
 | 
					msgstr "Liste des boutons"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:9
 | 
				
			||||||
 | 
					msgid "search button"
 | 
				
			||||||
 | 
					msgstr "Chercher un bouton"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:20
 | 
				
			||||||
 | 
					msgid "buttons listing "
 | 
				
			||||||
 | 
					msgstr "Liste des boutons"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:71
 | 
				
			||||||
 | 
					msgid "button successfully deleted "
 | 
				
			||||||
 | 
					msgstr "Le bouton a bien été supprimé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/note/transactiontemplate_list.html:75
 | 
				
			||||||
 | 
					msgid "Unable to delete button "
 | 
				
			||||||
 | 
					msgstr "Impossible de supprimer le bouton "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/logged_out.html:8
 | 
					#: templates/registration/logged_out.html:8
 | 
				
			||||||
msgid "Thanks for spending some quality time with the Web site today."
 | 
					msgid "Thanks for spending some quality time with the Web site today."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -742,7 +908,7 @@ msgid "Log in again"
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/login.html:7 templates/registration/login.html:8
 | 
					#: templates/registration/login.html:7 templates/registration/login.html:8
 | 
				
			||||||
#: templates/registration/login.html:26
 | 
					#: templates/registration/login.html:28
 | 
				
			||||||
#: templates/registration/password_reset_complete.html:10
 | 
					#: templates/registration/password_reset_complete.html:10
 | 
				
			||||||
msgid "Log in"
 | 
					msgid "Log in"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -754,7 +920,15 @@ msgid ""
 | 
				
			|||||||
"page. Would you like to login to a different account?"
 | 
					"page. Would you like to login to a different account?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/login.html:27
 | 
					#: templates/registration/login.html:22
 | 
				
			||||||
 | 
					msgid "You can also register via the central authentification server "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/registration/login.html:23
 | 
				
			||||||
 | 
					msgid "using this link "
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/registration/login.html:29
 | 
				
			||||||
msgid "Forgotten your password or username?"
 | 
					msgid "Forgotten your password or username?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -810,3 +984,72 @@ msgstr ""
 | 
				
			|||||||
#: templates/registration/password_reset_form.html:11
 | 
					#: templates/registration/password_reset_form.html:11
 | 
				
			||||||
msgid "Reset my password"
 | 
					msgid "Reset my password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_form.html:6
 | 
				
			||||||
 | 
					msgid "Invoices list"
 | 
				
			||||||
 | 
					msgstr "Liste des factures"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_form.html:42
 | 
				
			||||||
 | 
					msgid "Add product"
 | 
				
			||||||
 | 
					msgstr "Ajouter produit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_form.html:43
 | 
				
			||||||
 | 
					msgid "Remove product"
 | 
				
			||||||
 | 
					msgstr "Retirer produit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/invoice_list.html:21
 | 
				
			||||||
 | 
					msgid "New invoice"
 | 
				
			||||||
 | 
					msgstr "Nouvelle facture"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:7
 | 
				
			||||||
 | 
					msgid "Remittance #"
 | 
				
			||||||
 | 
					msgstr "Remise n°"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:9
 | 
				
			||||||
 | 
					#: templates/treasury/specialtransactionproxy_form.html:7
 | 
				
			||||||
 | 
					msgid "Remittances list"
 | 
				
			||||||
 | 
					msgstr "Liste des remises"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:12
 | 
				
			||||||
 | 
					msgid "Count"
 | 
				
			||||||
 | 
					msgstr "Nombre"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:29
 | 
				
			||||||
 | 
					msgid "Linked transactions"
 | 
				
			||||||
 | 
					msgstr "Transactions liées"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_form.html:34
 | 
				
			||||||
 | 
					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:19
 | 
				
			||||||
 | 
					msgid "Opened remittances"
 | 
				
			||||||
 | 
					msgstr "Remises ouvertes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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:28
 | 
				
			||||||
 | 
					msgid "New remittance"
 | 
				
			||||||
 | 
					msgstr "Nouvelle remise"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:32
 | 
				
			||||||
 | 
					msgid "Transfers without remittances"
 | 
				
			||||||
 | 
					msgstr "Transactions sans remise associée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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:43
 | 
				
			||||||
 | 
					msgid "Transfers with opened remittances"
 | 
				
			||||||
 | 
					msgstr "Transactions associées à une remise ouverte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:48
 | 
				
			||||||
 | 
					msgid "There is no transaction with an opened linked remittance."
 | 
				
			||||||
 | 
					msgstr "Il n'y a pas de transaction associée à une remise ouverte."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: templates/treasury/remittance_list.html:54
 | 
				
			||||||
 | 
					msgid "Closed remittances"
 | 
				
			||||||
 | 
					msgstr "Remises fermées"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,7 @@ INSTALLED_APPS = [
 | 
				
			|||||||
    'activity',
 | 
					    'activity',
 | 
				
			||||||
    'member',
 | 
					    'member',
 | 
				
			||||||
    'note',
 | 
					    'note',
 | 
				
			||||||
 | 
					    'treasury',
 | 
				
			||||||
    'permission',
 | 
					    'permission',
 | 
				
			||||||
    'api',
 | 
					    'api',
 | 
				
			||||||
    'logs',
 | 
					    'logs',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ urlpatterns = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    # Include project routers
 | 
					    # Include project routers
 | 
				
			||||||
    path('note/', include('note.urls')),
 | 
					    path('note/', include('note.urls')),
 | 
				
			||||||
 | 
					    path('treasury/', include('treasury.urls')),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Include Django Contrib and Core routers
 | 
					    # Include Django Contrib and Core routers
 | 
				
			||||||
    path('i18n/', include('django.conf.urls.i18n')),
 | 
					    path('i18n/', include('django.conf.urls.i18n')),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
psycopg2==2.8.4
 | 
					psycopg2-binary==2.8.4
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								static/img/Finalist.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/img/Finalist.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 752 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								static/img/Kataclist.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/img/Kataclist.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 664 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								static/img/Listorique.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/img/Listorique.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 414 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								static/img/Monopolist.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/img/Monopolist.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 375 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								static/img/Satellist.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/img/Satellist.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 202 KiB  | 
@@ -70,11 +70,12 @@ function li(id, text) {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
function displayNote(note, alias, user_note_field=null, profile_pic_field=null) {
 | 
					function displayNote(note, alias, user_note_field=null, profile_pic_field=null) {
 | 
				
			||||||
    if (!note.display_image) {
 | 
					    if (!note.display_image) {
 | 
				
			||||||
        note.display_image = 'https://nk20.ynerant.fr/media/pic/default.png';
 | 
					        note.display_image = '/media/pic/default.png';
 | 
				
			||||||
        $.getJSON("/api/note/note/" + note.id + "/?format=json", function(new_note) {
 | 
					        $.getJSON("/api/note/note/" + note.id + "/?format=json", function(new_note) {
 | 
				
			||||||
            note.display_image = new_note.display_image.replace("http:", "https:");
 | 
					            note.display_image = new_note.display_image.replace("http:", "https:");
 | 
				
			||||||
            note.name = new_note.name;
 | 
					            note.name = new_note.name;
 | 
				
			||||||
            note.balance = new_note.balance;
 | 
					            note.balance = new_note.balance;
 | 
				
			||||||
 | 
					            note.user = new_note.user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            displayNote(note, alias, user_note_field, profile_pic_field);
 | 
					            displayNote(note, alias, user_note_field, profile_pic_field);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@@ -159,10 +160,13 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let old_pattern = null;
 | 
					    let old_pattern = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // When the user type "Enter", the first alias is clicked
 | 
					    // When the user type "Enter", the first alias is clicked, and the informations are displayed
 | 
				
			||||||
    field.keypress(function(event) {
 | 
					    field.keypress(function(event) {
 | 
				
			||||||
        if (event.originalEvent.charCode === 13)
 | 
					        if (event.originalEvent.charCode === 13) {
 | 
				
			||||||
            $("#" + alias_matched_id + " li").first().trigger("click");
 | 
					            let li_obj = $("#" + alias_matched_id + " li").first();
 | 
				
			||||||
 | 
					            displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field);
 | 
				
			||||||
 | 
					            li_obj.trigger("click");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // When the user type something, the matched aliases are refreshed
 | 
					    // When the user type something, the matched aliases are refreshed
 | 
				
			||||||
@@ -269,7 +273,16 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// When a validate button is clicked, we switch the validation status
 | 
					// When a validate button is clicked, we switch the validation status
 | 
				
			||||||
function de_validate(id, validated) {
 | 
					function in_validate(id, validated) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let invalidity_reason;
 | 
				
			||||||
 | 
					    let reason_obj = $("#invalidity_reason_" + id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (validated)
 | 
				
			||||||
 | 
					        invalidity_reason = reason_obj.val();
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        invalidity_reason = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $("#validate_" + id).html("<strong style=\"font-size: 16pt;\">⟳ ...</strong>");
 | 
					    $("#validate_" + id).html("<strong style=\"font-size: 16pt;\">⟳ ...</strong>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Perform a PATCH request to the API in order to update the transaction
 | 
					    // Perform a PATCH request to the API in order to update the transaction
 | 
				
			||||||
@@ -282,12 +295,13 @@ function de_validate(id, validated) {
 | 
				
			|||||||
            "X-CSRFTOKEN": CSRF_TOKEN
 | 
					            "X-CSRFTOKEN": CSRF_TOKEN
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
            "resourcetype": "RecurrentTransaction",
 | 
					            resourcetype: "RecurrentTransaction",
 | 
				
			||||||
            valid: !validated
 | 
					            valid: !validated,
 | 
				
			||||||
 | 
					            invalidity_reason: invalidity_reason,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        success: function () {
 | 
					        success: function () {
 | 
				
			||||||
            // Refresh jQuery objects
 | 
					            // Refresh jQuery objects
 | 
				
			||||||
            $(".validate").click(de_validate);
 | 
					            $(".validate").click(in_validate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            refreshBalance();
 | 
					            refreshBalance();
 | 
				
			||||||
            // error if this method doesn't exist. Please define it.
 | 
					            // error if this method doesn't exist. Please define it.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -167,7 +167,7 @@ function reset() {
 | 
				
			|||||||
function consumeAll() {
 | 
					function consumeAll() {
 | 
				
			||||||
    notes_display.forEach(function(note_display) {
 | 
					    notes_display.forEach(function(note_display) {
 | 
				
			||||||
        buttons.forEach(function(button) {
 | 
					        buttons.forEach(function(button) {
 | 
				
			||||||
            consume(note_display.id, button.dest, button.quantity * note_display.quantity, button.amount,
 | 
					            consume(note_display.id, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount,
 | 
				
			||||||
                button.name + " (" + button.category_name + ")", button.type, button.category_id, button.id);
 | 
					                button.name + " (" + button.category_name + ")", button.type, button.category_id, button.id);
 | 
				
			||||||
       });
 | 
					       });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -176,6 +176,7 @@ function consumeAll() {
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Create a new transaction from a button through the API.
 | 
					 * Create a new transaction from a button through the API.
 | 
				
			||||||
 * @param source The note that paid the item (type: int)
 | 
					 * @param source The note that paid the item (type: int)
 | 
				
			||||||
 | 
					 * @param source_alias The alias used for the source (type: str)
 | 
				
			||||||
 * @param dest The note that sold the item (type: int)
 | 
					 * @param dest The note that sold the item (type: int)
 | 
				
			||||||
 * @param quantity The quantity sold (type: int)
 | 
					 * @param quantity The quantity sold (type: int)
 | 
				
			||||||
 * @param amount The price of one item, in cents (type: int)
 | 
					 * @param amount The price of one item, in cents (type: int)
 | 
				
			||||||
@@ -184,7 +185,7 @@ function consumeAll() {
 | 
				
			|||||||
 * @param category The category id of the button (type: int)
 | 
					 * @param category The category id of the button (type: int)
 | 
				
			||||||
 * @param template The button id (type: int)
 | 
					 * @param template The button id (type: int)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function consume(source, dest, quantity, amount, reason, type, category, template) {
 | 
					function consume(source, source_alias, dest, quantity, amount, reason, type, category, template) {
 | 
				
			||||||
    $.post("/api/note/transaction/transaction/",
 | 
					    $.post("/api/note/transaction/transaction/",
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
					            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
@@ -195,11 +196,32 @@ function consume(source, dest, quantity, amount, reason, type, category, templat
 | 
				
			|||||||
            "polymorphic_ctype": type,
 | 
					            "polymorphic_ctype": type,
 | 
				
			||||||
            "resourcetype": "RecurrentTransaction",
 | 
					            "resourcetype": "RecurrentTransaction",
 | 
				
			||||||
            "source": source,
 | 
					            "source": source,
 | 
				
			||||||
 | 
					            "source_alias": source_alias,
 | 
				
			||||||
            "destination": dest,
 | 
					            "destination": dest,
 | 
				
			||||||
            "category": category,
 | 
					            "category": category,
 | 
				
			||||||
            "template": template
 | 
					            "template": template
 | 
				
			||||||
        }, reset).fail(function (e) {
 | 
					        }, reset).fail(function (e) {
 | 
				
			||||||
 | 
					            $.post("/api/note/transaction/transaction/",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
 | 
					                "quantity": quantity,
 | 
				
			||||||
 | 
					                "amount": amount,
 | 
				
			||||||
 | 
					                "reason": reason,
 | 
				
			||||||
 | 
					                "valid": false,
 | 
				
			||||||
 | 
					                "invalidity_reason": "Solde insuffisant",
 | 
				
			||||||
 | 
					                "polymorphic_ctype": type,
 | 
				
			||||||
 | 
					                "resourcetype": "RecurrentTransaction",
 | 
				
			||||||
 | 
					                "source": source,
 | 
				
			||||||
 | 
					                "source_alias": source_alias,
 | 
				
			||||||
 | 
					                "destination": dest,
 | 
				
			||||||
 | 
					                "category": category,
 | 
				
			||||||
 | 
					                "template": template
 | 
				
			||||||
 | 
					            }).done(function() {
 | 
				
			||||||
 | 
					                reset();
 | 
				
			||||||
 | 
					                addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", "danger");
 | 
				
			||||||
 | 
					            }).fail(function () {
 | 
				
			||||||
                reset();
 | 
					                reset();
 | 
				
			||||||
                errMsg(e.responseJSON);
 | 
					                errMsg(e.responseJSON);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * jQuery Formset 1.3-pre
 | 
					 * jQuery Formset 1.5-pre
 | 
				
			||||||
 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
 | 
					 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
 | 
				
			||||||
 * @requires jQuery 1.2.6 or later
 | 
					 * @requires jQuery 1.2.6 or later
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -55,19 +55,26 @@
 | 
				
			|||||||
            insertDeleteLink = function(row) {
 | 
					            insertDeleteLink = function(row) {
 | 
				
			||||||
                var delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.'),
 | 
					                var delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.'),
 | 
				
			||||||
                    addCssSelector = $.trim(options.addCssClass).replace(/\s+/g, '.');
 | 
					                    addCssSelector = $.trim(options.addCssClass).replace(/\s+/g, '.');
 | 
				
			||||||
                if (row.is('TR')) {
 | 
					
 | 
				
			||||||
 | 
					                var delButtonHTML = '<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>';
 | 
				
			||||||
 | 
					                if (options.deleteContainerClass) {
 | 
				
			||||||
 | 
					                    // If we have a specific container for the remove button,
 | 
				
			||||||
 | 
					                    // place it as the last child of that container:
 | 
				
			||||||
 | 
					                    row.find('[class*="' + options.deleteContainerClass + '"]').append(delButtonHTML);
 | 
				
			||||||
 | 
					                } else if (row.is('TR')) {
 | 
				
			||||||
                    // If the forms are laid out in table rows, insert
 | 
					                    // If the forms are laid out in table rows, insert
 | 
				
			||||||
                    // the remove button into the last table cell:
 | 
					                    // the remove button into the last table cell:
 | 
				
			||||||
                    row.children(':last').append('<a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + '</a>');
 | 
					                    row.children('td:last').append(delButtonHTML);
 | 
				
			||||||
                } else if (row.is('UL') || row.is('OL')) {
 | 
					                } else if (row.is('UL') || row.is('OL')) {
 | 
				
			||||||
                    // If they're laid out as an ordered/unordered list,
 | 
					                    // If they're laid out as an ordered/unordered list,
 | 
				
			||||||
                    // insert an <li> after the last list item:
 | 
					                    // insert an <li> after the last list item:
 | 
				
			||||||
                    row.append('<li><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a></li>');
 | 
					                    row.append('<li>' + delButtonHTML + '</li>');
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    // Otherwise, just insert the remove button as the
 | 
					                    // Otherwise, just insert the remove button as the
 | 
				
			||||||
                    // last child element of the form's container:
 | 
					                    // last child element of the form's container:
 | 
				
			||||||
                    row.append('<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>');
 | 
					                    row.append(delButtonHTML);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Check if we're under the minimum number of forms - not to display delete link at rendering
 | 
					                // Check if we're under the minimum number of forms - not to display delete link at rendering
 | 
				
			||||||
                if (!showDeleteLinks()){
 | 
					                if (!showDeleteLinks()){
 | 
				
			||||||
                    row.find('a.' + delCssSelector).hide();
 | 
					                    row.find('a.' + delCssSelector).hide();
 | 
				
			||||||
@@ -156,6 +163,7 @@
 | 
				
			|||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // Otherwise, use the last form in the formset; this works much better if you've got
 | 
					                // Otherwise, use the last form in the formset; this works much better if you've got
 | 
				
			||||||
                // extra (>= 1) forms (thnaks to justhamade for pointing this out):
 | 
					                // extra (>= 1) forms (thnaks to justhamade for pointing this out):
 | 
				
			||||||
 | 
					                if (options.hideLastAddForm) $('.' + options.formCssClass + ':last').hide();
 | 
				
			||||||
                template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
 | 
					                template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
 | 
				
			||||||
                template.find('input:hidden[id $= "-DELETE"]').remove();
 | 
					                template.find('input:hidden[id $= "-DELETE"]').remove();
 | 
				
			||||||
                // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
 | 
					                // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
 | 
				
			||||||
@@ -173,21 +181,28 @@
 | 
				
			|||||||
            // FIXME: Perhaps using $.data would be a better idea?
 | 
					            // FIXME: Perhaps using $.data would be a better idea?
 | 
				
			||||||
            options.formTemplate = template;
 | 
					            options.formTemplate = template;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ($$.is('TR')) {
 | 
					            var addButtonHTML = '<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>';
 | 
				
			||||||
 | 
					            if (options.addContainerClass) {
 | 
				
			||||||
 | 
					                // If we have a specific container for the "add" button,
 | 
				
			||||||
 | 
					                // place it as the last child of that container:
 | 
				
			||||||
 | 
					                var addContainer = $('[class*="' + options.addContainerClass + '"');
 | 
				
			||||||
 | 
					                addContainer.append(addButtonHTML);
 | 
				
			||||||
 | 
					                addButton = addContainer.find('[class="' + options.addCssClass + '"]');
 | 
				
			||||||
 | 
					            } else if ($$.is('TR')) {
 | 
				
			||||||
                // If forms are laid out as table rows, insert the
 | 
					                // If forms are laid out as table rows, insert the
 | 
				
			||||||
                // "add" button in a new table row:
 | 
					                // "add" button in a new table row:
 | 
				
			||||||
                var numCols = $$.eq(0).children().length,   // This is a bit of an assumption :|
 | 
					                var numCols = $$.eq(0).children().length,   // This is a bit of an assumption :|
 | 
				
			||||||
                    buttonRow = $('<tr><td colspan="' + numCols + '"><a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a></tr>')
 | 
					                    buttonRow = $('<tr><td colspan="' + numCols + '">' + addButtonHTML + '</tr>').addClass(options.formCssClass + '-add');
 | 
				
			||||||
                                .addClass(options.formCssClass + '-add');
 | 
					 | 
				
			||||||
                $$.parent().append(buttonRow);
 | 
					                $$.parent().append(buttonRow);
 | 
				
			||||||
                if (hideAddButton) buttonRow.hide();
 | 
					 | 
				
			||||||
                addButton = buttonRow.find('a');
 | 
					                addButton = buttonRow.find('a');
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // Otherwise, insert it immediately after the last form:
 | 
					                // Otherwise, insert it immediately after the last form:
 | 
				
			||||||
                $$.filter(':last').after('<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>');
 | 
					                $$.filter(':last').after(addButtonHTML);
 | 
				
			||||||
                addButton = $$.filter(':last').next();
 | 
					                addButton = $$.filter(':last').next();
 | 
				
			||||||
                if (hideAddButton) addButton.hide();
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (hideAddButton) addButton.hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            addButton.click(function() {
 | 
					            addButton.click(function() {
 | 
				
			||||||
                var formCount = parseInt(totalForms.val()),
 | 
					                var formCount = parseInt(totalForms.val()),
 | 
				
			||||||
                    row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
 | 
					                    row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
 | 
				
			||||||
@@ -220,12 +235,15 @@
 | 
				
			|||||||
        formTemplate: null,              // The jQuery selection cloned to generate new form instances
 | 
					        formTemplate: null,              // The jQuery selection cloned to generate new form instances
 | 
				
			||||||
        addText: 'add another',          // Text for the add link
 | 
					        addText: 'add another',          // Text for the add link
 | 
				
			||||||
        deleteText: 'remove',            // Text for the delete link
 | 
					        deleteText: 'remove',            // Text for the delete link
 | 
				
			||||||
        addCssClass: '',          // CSS class applied to the add link
 | 
					        addContainerClass: null,         // Container CSS class for the add link
 | 
				
			||||||
        deleteCssClass: '',    // CSS class applied to the delete link
 | 
					        deleteContainerClass: null,      // Container CSS class for the delete link
 | 
				
			||||||
 | 
					        addCssClass: 'add-row',          // CSS class applied to the add link
 | 
				
			||||||
 | 
					        deleteCssClass: 'delete-row',    // CSS class applied to the delete link
 | 
				
			||||||
        formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset
 | 
					        formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset
 | 
				
			||||||
        extraClasses: [],                // Additional CSS classes, which will be applied to each form in turn
 | 
					        extraClasses: [],                // Additional CSS classes, which will be applied to each form in turn
 | 
				
			||||||
        keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned
 | 
					        keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned
 | 
				
			||||||
        added: null,                     // Function called each time a new form is added
 | 
					        added: null,                     // Function called each time a new form is added
 | 
				
			||||||
        removed: null                    // Function called each time a form is deleted
 | 
					        removed: null,                   // Function called each time a form is deleted
 | 
				
			||||||
 | 
					        hideLastAddForm: false           // When set to true, hide last empty add form (becomes visible when clicking on add button)
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
})(jQuery);
 | 
					})(jQuery);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,10 +39,21 @@ $(document).ready(function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                last.quantity = 1;
 | 
					                last.quantity = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!last.note.user) {
 | 
				
			||||||
 | 
					                    $.getJSON("/api/note/note/" + last.note.id + "/?format=json", function(note) {
 | 
				
			||||||
 | 
					                        last.note.user = note.user;
 | 
				
			||||||
                        $.getJSON("/api/user/" + last.note.user + "/", function(user) {
 | 
					                        $.getJSON("/api/user/" + last.note.user + "/", function(user) {
 | 
				
			||||||
                            $("#last_name").val(user.last_name);
 | 
					                            $("#last_name").val(user.last_name);
 | 
				
			||||||
                            $("#first_name").val(user.first_name);
 | 
					                            $("#first_name").val(user.first_name);
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    $.getJSON("/api/user/" + last.note.user + "/", function(user) {
 | 
				
			||||||
 | 
					                        $("#last_name").val(user.last_name);
 | 
				
			||||||
 | 
					                        $("#first_name").val(user.first_name);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
@@ -72,12 +83,33 @@ $("#transfer").click(function() {
 | 
				
			|||||||
                    "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
					                    "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
                    "resourcetype": "Transaction",
 | 
					                    "resourcetype": "Transaction",
 | 
				
			||||||
                    "source": user_id,
 | 
					                    "source": user_id,
 | 
				
			||||||
                    "destination": dest.id
 | 
					                    "destination": dest.id,
 | 
				
			||||||
                }, function () {
 | 
					                    "destination_alias": dest.name
 | 
				
			||||||
 | 
					                }).done(function () {
 | 
				
			||||||
                    addMsg("Le transfert de "
 | 
					                    addMsg("Le transfert de "
 | 
				
			||||||
                        + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
					                        + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
				
			||||||
                        + " vers la note " + dest.name + " a été fait avec succès !", "success");
 | 
					                        + " vers la note " + dest.name + " a été fait avec succès !", "success");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    reset();
 | 
				
			||||||
 | 
					                }).fail(function () {
 | 
				
			||||||
 | 
					                    $.post("/api/note/transaction/transaction/",
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
 | 
					                        "quantity": dest.quantity,
 | 
				
			||||||
 | 
					                        "amount": 100 * $("#amount").val(),
 | 
				
			||||||
 | 
					                        "reason": $("#reason").val(),
 | 
				
			||||||
 | 
					                        "valid": false,
 | 
				
			||||||
 | 
					                        "invalidity_reason": "Solde insuffisant",
 | 
				
			||||||
 | 
					                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
 | 
					                        "resourcetype": "Transaction",
 | 
				
			||||||
 | 
					                        "source": user_id,
 | 
				
			||||||
 | 
					                        "destination": dest.id,
 | 
				
			||||||
 | 
					                        "destination_alias": dest.name
 | 
				
			||||||
 | 
					                    }).done(function () {
 | 
				
			||||||
 | 
					                        addMsg("Le transfert de "
 | 
				
			||||||
 | 
					                            + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
				
			||||||
 | 
					                            + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        reset();
 | 
					                        reset();
 | 
				
			||||||
                    }).fail(function (err) {
 | 
					                    }).fail(function (err) {
 | 
				
			||||||
                        addMsg("Le transfert de "
 | 
					                        addMsg("Le transfert de "
 | 
				
			||||||
@@ -87,6 +119,7 @@ $("#transfer").click(function() {
 | 
				
			|||||||
                    reset();
 | 
					                    reset();
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if ($("#type_transfer").is(':checked')) {
 | 
					    else if ($("#type_transfer").is(':checked')) {
 | 
				
			||||||
        sources_notes_display.forEach(function (source) {
 | 
					        sources_notes_display.forEach(function (source) {
 | 
				
			||||||
@@ -101,12 +134,35 @@ $("#transfer").click(function() {
 | 
				
			|||||||
                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
					                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
                        "resourcetype": "Transaction",
 | 
					                        "resourcetype": "Transaction",
 | 
				
			||||||
                        "source": source.id,
 | 
					                        "source": source.id,
 | 
				
			||||||
                        "destination": dest.id
 | 
					                        "source_alias": source.name,
 | 
				
			||||||
                    }, function () {
 | 
					                        "destination": dest.id,
 | 
				
			||||||
 | 
					                        "destination_alias": dest.name
 | 
				
			||||||
 | 
					                    }).done(function () {
 | 
				
			||||||
                        addMsg("Le transfert de "
 | 
					                        addMsg("Le transfert de "
 | 
				
			||||||
                            + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
					                            + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
				
			||||||
                            + " vers la note " + dest.name + " a été fait avec succès !", "success");
 | 
					                            + " vers la note " + dest.name + " a été fait avec succès !", "success");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        reset();
 | 
				
			||||||
 | 
					                    }).fail(function (err) {
 | 
				
			||||||
 | 
					                        $.post("/api/note/transaction/transaction/",
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
 | 
					                            "quantity": source.quantity * dest.quantity,
 | 
				
			||||||
 | 
					                            "amount": 100 * $("#amount").val(),
 | 
				
			||||||
 | 
					                            "reason": $("#reason").val(),
 | 
				
			||||||
 | 
					                            "valid": false,
 | 
				
			||||||
 | 
					                            "invalidity_reason": "Solde insuffisant",
 | 
				
			||||||
 | 
					                            "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
 | 
					                            "resourcetype": "Transaction",
 | 
				
			||||||
 | 
					                            "source": source.id,
 | 
				
			||||||
 | 
					                            "source_alias": source.name,
 | 
				
			||||||
 | 
					                            "destination": dest.id,
 | 
				
			||||||
 | 
					                            "destination_alias": dest.name
 | 
				
			||||||
 | 
					                        }).done(function () {
 | 
				
			||||||
 | 
					                            addMsg("Le transfert de "
 | 
				
			||||||
 | 
					                                + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
				
			||||||
 | 
					                                + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            reset();
 | 
					                            reset();
 | 
				
			||||||
                        }).fail(function (err) {
 | 
					                        }).fail(function (err) {
 | 
				
			||||||
                            addMsg("Le transfert de "
 | 
					                            addMsg("Le transfert de "
 | 
				
			||||||
@@ -117,6 +173,7 @@ $("#transfer").click(function() {
 | 
				
			|||||||
                    });
 | 
					                    });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
 | 
					    } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
 | 
				
			||||||
        let special_note = $("#credit_type").val();
 | 
					        let special_note = $("#credit_type").val();
 | 
				
			||||||
        let user_note = dests_notes_display[0].id;
 | 
					        let user_note = dests_notes_display[0].id;
 | 
				
			||||||
@@ -146,15 +203,17 @@ $("#transfer").click(function() {
 | 
				
			|||||||
                "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
 | 
					                "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
                "resourcetype": "SpecialTransaction",
 | 
					                "resourcetype": "SpecialTransaction",
 | 
				
			||||||
                "source": source,
 | 
					                "source": source,
 | 
				
			||||||
 | 
					                "source_alias": source.name,
 | 
				
			||||||
                "destination": dest,
 | 
					                "destination": dest,
 | 
				
			||||||
 | 
					                "destination_alias": dest.name,
 | 
				
			||||||
                "last_name": $("#last_name").val(),
 | 
					                "last_name": $("#last_name").val(),
 | 
				
			||||||
                "first_name": $("#first_name").val(),
 | 
					                "first_name": $("#first_name").val(),
 | 
				
			||||||
                "bank": $("#bank").val()
 | 
					                "bank": $("#bank").val()
 | 
				
			||||||
            }, function () {
 | 
					            }).done(function () {
 | 
				
			||||||
                addMsg("Le crédit/retrait a bien été effectué !", "success");
 | 
					                addMsg("Le crédit/retrait a bien été effectué !", "success");
 | 
				
			||||||
                reset();
 | 
					                reset();
 | 
				
			||||||
            }).fail(function (err) {
 | 
					            }).fail(function (err) {
 | 
				
			||||||
                addMsg("Le crédit/transfert a échoué : " + err.responseText, "danger");
 | 
					                addMsg("Le crédit/retrait a échoué : " + err.responseText, "danger");
 | 
				
			||||||
                reset();
 | 
					                reset();
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,6 +94,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			|||||||
                        <a class="nav-link" href="#"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
 | 
					                        <a class="nav-link" href="#"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
 | 
				
			||||||
                    </li>
 | 
					                    </li>
 | 
				
			||||||
                {% endif %}
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					                {% if "treasury.invoice"|not_empty_model_change_list %}
 | 
				
			||||||
 | 
					                    <li class="nav-item active">
 | 
				
			||||||
 | 
					                        <a class="nav-link" href="{% url 'treasury:invoice_list' %}"><i class="fa fa-money"></i>{% trans 'Treasury' %} </a>
 | 
				
			||||||
 | 
					                    </li>
 | 
				
			||||||
 | 
					                {% endif %}
 | 
				
			||||||
            </ul>
 | 
					            </ul>
 | 
				
			||||||
            <ul class="navbar-nav ml-auto">
 | 
					            <ul class="navbar-nav ml-auto">
 | 
				
			||||||
                {% if user.is_authenticated %}
 | 
					                {% if user.is_authenticated %}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										107
									
								
								templates/treasury/invoice_form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								templates/treasury/invoice_form.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load crispy_forms_tags pretty_money %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					    <p><a class="btn btn-default" href="{% url 'treasury:invoice_list' %}">{% trans "Invoices list" %}</a></p>
 | 
				
			||||||
 | 
					    <form method="post" action="">
 | 
				
			||||||
 | 
					        {% csrf_token %}
 | 
				
			||||||
 | 
					        {# Render the invoice form #}
 | 
				
			||||||
 | 
					        {% crispy form %}
 | 
				
			||||||
 | 
					        {# The next part concerns the product formset #}
 | 
				
			||||||
 | 
					        {# Generate some hidden fields that manage the number of products, and make easier the parsing #}
 | 
				
			||||||
 | 
					        {{ formset.management_form }}
 | 
				
			||||||
 | 
					        <table class="table table-condensed table-striped">
 | 
				
			||||||
 | 
					            {# Fill initial data #}
 | 
				
			||||||
 | 
					            {% for form in formset %}
 | 
				
			||||||
 | 
					                {% if forloop.first %}
 | 
				
			||||||
 | 
					                    <thead>
 | 
				
			||||||
 | 
					                    <tr>
 | 
				
			||||||
 | 
					                        <th>{{ form.designation.label }}<span class="asteriskField">*</span></th>
 | 
				
			||||||
 | 
					                        <th>{{ form.quantity.label }}<span class="asteriskField">*</span></th>
 | 
				
			||||||
 | 
					                        <th>{{ form.amount.label }}<span class="asteriskField">*</span></th>
 | 
				
			||||||
 | 
					                    </tr>
 | 
				
			||||||
 | 
					                    </thead>
 | 
				
			||||||
 | 
					                    <tbody id="form_body">
 | 
				
			||||||
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					                <tr class="row-formset">
 | 
				
			||||||
 | 
					                    <td>{{ form.designation }}</td>
 | 
				
			||||||
 | 
					                    <td>{{ form.quantity }} </td>
 | 
				
			||||||
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        {# Use custom input for amount, with the € symbol #}
 | 
				
			||||||
 | 
					                        <div class="input-group">
 | 
				
			||||||
 | 
					                            <input type="number" name="product_set-{{ forloop.counter0 }}-amount" step="0.01"
 | 
				
			||||||
 | 
					                                   id="id_product_set-{{ forloop.counter0 }}-amount"
 | 
				
			||||||
 | 
					                                   value="{{ form.instance.amount|cents_to_euros }}">
 | 
				
			||||||
 | 
					                            <div class="input-group-append">
 | 
				
			||||||
 | 
					                                <span class="input-group-text">€</span>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    {# These fields are hidden but handled by the formset to link the id and the invoice id #}
 | 
				
			||||||
 | 
					                    {{ form.invoice }}
 | 
				
			||||||
 | 
					                    {{ form.id }}
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					            {% endfor %}
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {# Display buttons to add and remove products #}
 | 
				
			||||||
 | 
					        <div class="btn-group btn-block" role="group">
 | 
				
			||||||
 | 
					            <button type="button" id="add_more" class="btn btn-primary">{% trans "Add product" %}</button>
 | 
				
			||||||
 | 
					            <button type="button" id="remove_one" class="btn btn-danger">{% trans "Remove product" %}</button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="btn-block">
 | 
				
			||||||
 | 
					            <button type="submit" class="btn btn-block btn-primary">{% trans "Submit" %}</button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="empty_form" style="display: none;">
 | 
				
			||||||
 | 
					        {# Hidden div that store an empty product form, to be copied into new forms #}
 | 
				
			||||||
 | 
					        <table class='no_error'>
 | 
				
			||||||
 | 
					            <tbody id="for_real">
 | 
				
			||||||
 | 
					            <tr class="row-formset">
 | 
				
			||||||
 | 
					                <td>{{ formset.empty_form.designation }}</td>
 | 
				
			||||||
 | 
					                <td>{{ formset.empty_form.quantity }} </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <div class="input-group">
 | 
				
			||||||
 | 
					                        <input type="number" name="product_set-__prefix__-amount" step="0.01"
 | 
				
			||||||
 | 
					                               id="id_product_set-__prefix__-amount">
 | 
				
			||||||
 | 
					                        <div class="input-group-append">
 | 
				
			||||||
 | 
					                            <span class="input-group-text">€</span>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                {{ formset.empty_form.invoice }}
 | 
				
			||||||
 | 
					                {{ formset.empty_form.id }}
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block extrajavascript %}
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					        {# Script that handles add and remove lines #}
 | 
				
			||||||
 | 
					        IDS = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $("#id_product_set-TOTAL_FORMS").val($(".row-formset").length - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $('#add_more').click(function () {
 | 
				
			||||||
 | 
					            var form_idx = $('#id_product_set-TOTAL_FORMS').val();
 | 
				
			||||||
 | 
					            $('#form_body').append($('#for_real').html().replace(/__prefix__/g, form_idx));
 | 
				
			||||||
 | 
					            $('#id_product_set-TOTAL_FORMS').val(parseInt(form_idx) + 1);
 | 
				
			||||||
 | 
					            $('#id_product_set-' + parseInt(form_idx) + '-id').val(IDS[parseInt(form_idx)]);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $('#remove_one').click(function () {
 | 
				
			||||||
 | 
					            let form_idx = $('#id_product_set-TOTAL_FORMS').val();
 | 
				
			||||||
 | 
					            if (form_idx > 0) {
 | 
				
			||||||
 | 
					                IDS[parseInt(form_idx) - 1] = $('#id_product_set-' + (parseInt(form_idx) - 1) + '-id').val();
 | 
				
			||||||
 | 
					                $('#form_body tr:last-child').remove();
 | 
				
			||||||
 | 
					                $('#id_product_set-TOTAL_FORMS').val(parseInt(form_idx) - 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										23
									
								
								templates/treasury/invoice_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								templates/treasury/invoice_list.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					{% load render_table from django_tables2 %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="row">
 | 
				
			||||||
 | 
					        <div class="col-xl-12">
 | 
				
			||||||
 | 
					            <div class="btn-group btn-group-toggle" style="width: 100%; padding: 0 0 2em 0" data-toggle="buttons">
 | 
				
			||||||
 | 
					                <a href="#" class="btn btn-sm btn-outline-primary active">
 | 
				
			||||||
 | 
					                    {% trans "Invoice" %}s
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					                <a href="{% url "treasury:remittance_list" %}" class="btn btn-sm btn-outline-primary">
 | 
				
			||||||
 | 
					                    {% trans "Remittance" %}s
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% render_table table %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<a class="btn btn-primary" href="{% url 'treasury:invoice_create' %}">{% trans "New invoice" %}</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										186
									
								
								templates/treasury/invoice_sample.tex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								templates/treasury/invoice_sample.tex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
				
			|||||||
 | 
					\nonstopmode
 | 
				
			||||||
 | 
					\documentclass[11pt]{article}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\usepackage[french]{babel}
 | 
				
			||||||
 | 
					\usepackage[T1]{fontenc}
 | 
				
			||||||
 | 
					\usepackage[utf8]{inputenc}
 | 
				
			||||||
 | 
					\usepackage[a4paper]{geometry}
 | 
				
			||||||
 | 
					\usepackage{units}
 | 
				
			||||||
 | 
					\usepackage{bera}
 | 
				
			||||||
 | 
					\usepackage{graphicx}
 | 
				
			||||||
 | 
					\usepackage{fancyhdr}
 | 
				
			||||||
 | 
					\usepackage{fp}
 | 
				
			||||||
 | 
					\usepackage{transparent}
 | 
				
			||||||
 | 
					\usepackage{eso-pic}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\def\TVA{0}    % Taux de la TVA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\def\TotalHT{0}
 | 
				
			||||||
 | 
					\def\TotalTVA{0}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\newcommand{\AjouterProduit}[4]{%    Arguments : Désignation, quantité, prix unitaire HT, prix total HT
 | 
				
			||||||
 | 
					    \FPround{\prix}{#3}{2}
 | 
				
			||||||
 | 
					    \FPround{\montant}{#4}{2}
 | 
				
			||||||
 | 
					    \FPadd{\TotalHT}{\TotalHT}{\montant}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \eaddto\ListeProduits{#1    &    \prix    &    #2    &    \montant    \cr}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\newcommand{\AfficheResultat}{%
 | 
				
			||||||
 | 
					    \ListeProduits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \FPeval{\TotalTVA}{\TotalHT * \TVA / 100}
 | 
				
			||||||
 | 
					    \FPadd{\TotalTTC}{\TotalHT}{\TotalTVA}
 | 
				
			||||||
 | 
					    \FPround{\TotalHT}{\TotalHT}{2}
 | 
				
			||||||
 | 
					    \FPround{\TotalTVA}{\TotalTVA}{2}
 | 
				
			||||||
 | 
					    \FPround{\TotalTTC}{\TotalTTC}{2}
 | 
				
			||||||
 | 
					    \global\let\TotalHT\TotalHT
 | 
				
			||||||
 | 
					    \global\let\TotalTVA\TotalTVA
 | 
				
			||||||
 | 
					    \global\let\TotalTTC\TotalTTC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \cr \hline
 | 
				
			||||||
 | 
					    Total HT            & & &    \TotalHT    \cr
 | 
				
			||||||
 | 
					    TVA \TVA~\%         & & &    \TotalTVA    \cr
 | 
				
			||||||
 | 
					    \hline \hline
 | 
				
			||||||
 | 
					    \textbf{Total TTC}    & & &    \TotalTTC
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\newcommand*\eaddto[2]{% version développée de \addto
 | 
				
			||||||
 | 
					   \edef\tmp{#2}%
 | 
				
			||||||
 | 
					   \expandafter\addto
 | 
				
			||||||
 | 
					   \expandafter#1%
 | 
				
			||||||
 | 
					   \expandafter{\tmp}%
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\newcommand	{\ListeProduits}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% Logo du BDE
 | 
				
			||||||
 | 
					\AddToShipoutPicture*{
 | 
				
			||||||
 | 
					    \put(0,0){
 | 
				
			||||||
 | 
					        \parbox[b][\paperheight]{\paperwidth}{%
 | 
				
			||||||
 | 
					            \vfill
 | 
				
			||||||
 | 
					            \centering
 | 
				
			||||||
 | 
					            {\transparent{0.1}\includegraphics[width=\textwidth]{../../static/img/{{ obj.bde }}}}%
 | 
				
			||||||
 | 
					            \vfill
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%%
 | 
				
			||||||
 | 
					% Infos Association
 | 
				
			||||||
 | 
					\def\MonNom{{"{"}}{{ obj.my_name }}} % Nom de l'association
 | 
				
			||||||
 | 
					\def\MonAdresseRue{{"{"}}{{ obj.my_address_street }}} % Adresse de l'association
 | 
				
			||||||
 | 
					\def\MonAdresseVille{{"{"}}{{ obj.my_city }}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% Informations bancaires de l'association
 | 
				
			||||||
 | 
					\def\CodeBanque{{"{"}}{{ obj.bank_code|stringformat:".05d" }}}
 | 
				
			||||||
 | 
					\def\CodeGuichet{{"{"}}{{ obj.desk_code|stringformat:".05d" }}}
 | 
				
			||||||
 | 
					\def\NCompte{{"{"}}{{ obj.account_number|stringformat:".011d" }}}
 | 
				
			||||||
 | 
					\def\CleRib{{"{"}}{{ obj.rib_key|stringformat:".02d" }}}
 | 
				
			||||||
 | 
					\def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib}
 | 
				
			||||||
 | 
					\def\CodeBic{{"{"}}{{ obj.bic }}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\def\FactureNum            {{"{"}}{{obj.id}}}    % Numéro de facture
 | 
				
			||||||
 | 
					\def\FactureAcquittee    {% if obj.acquitted %} {oui} {% else %} {non} {% endif %}     % Facture acquittée : oui/non
 | 
				
			||||||
 | 
					\def\FactureLieu    {{"{"}}{{ obj.place }}}    % Lieu de l'édition de la facture
 | 
				
			||||||
 | 
					\def\FactureDate    {{"{"}}{{ obj.date }}}    % Date de l'édition de la facture
 | 
				
			||||||
 | 
					\def\FactureObjet   {{"{"}}{{ obj.object|safe }} }    % Objet du document
 | 
				
			||||||
 | 
					% Description de la facture
 | 
				
			||||||
 | 
					\def\FactureDescr   {{"{"}}{{ obj.description|safe }}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% Infos Client
 | 
				
			||||||
 | 
					\def\ClientNom{{"{"}}{{obj.name|safe}}}    % Nom du client
 | 
				
			||||||
 | 
					\def\ClientAdresse{{"{"}}{{ obj.address|safe }}} % Adresse du client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% Liste des produits facturés : Désignation, quantité, prix unitaire HT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% for product in products %}
 | 
				
			||||||
 | 
					\AjouterProduit{ {{product.designation|safe}}} { {{product.quantity|safe}}} { {{product.amount_euros|safe}}} { {{product.total_euros|safe}}}
 | 
				
			||||||
 | 
					{% endfor %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em}
 | 
				
			||||||
 | 
					\setlength{\parindent}{1pt}
 | 
				
			||||||
 | 
					\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\thispagestyle{fancy}
 | 
				
			||||||
 | 
					\pagestyle{fancy}
 | 
				
			||||||
 | 
					\setlength{\parindent}{0pt}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\renewcommand{\headrulewidth}{0pt}
 | 
				
			||||||
 | 
					\cfoot{
 | 
				
			||||||
 | 
					    \small{\MonNom  ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)6 89 88 56 50\newline
 | 
				
			||||||
 | 
					     Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00011
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{document}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% Logo de la société
 | 
				
			||||||
 | 
					% \includegraphics{logo.jpg}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% Nom et adresse de la société
 | 
				
			||||||
 | 
					\MonNom \\
 | 
				
			||||||
 | 
					\MonAdresseRue \\
 | 
				
			||||||
 | 
					\MonAdresseVille
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Facture n°\FactureNum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{\addtolength{\leftskip}{10.5cm} %in ERT
 | 
				
			||||||
 | 
					   \ClientNom    \\
 | 
				
			||||||
 | 
					    \ClientAdresse        \\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} %in ERT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\hspace*{10.5cm}
 | 
				
			||||||
 | 
					\FactureLieu, le \FactureDate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					~\\~\\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\textbf{Objet : \FactureObjet \\}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\textnormal{\FactureDescr}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					~\\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{center}
 | 
				
			||||||
 | 
					    \begin{tabular}{lrrr}
 | 
				
			||||||
 | 
					        \textbf{Désignation ~~~~~~}    & \textbf{Prix unitaire}    & \textbf{Quantité}    & \textbf{Montant (EUR)}    \\
 | 
				
			||||||
 | 
					        \hline
 | 
				
			||||||
 | 
					        \AfficheResultat{}
 | 
				
			||||||
 | 
					    \end{tabular}
 | 
				
			||||||
 | 
					\end{center}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					~\\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\ifthenelse{\equal{\FactureAcquittee}{oui}}{
 | 
				
			||||||
 | 
					    Facture acquittée.
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    À régler par chèque ou par virement bancaire :
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \begin{center}
 | 
				
			||||||
 | 
					        \begin{tabular}{|c c c c|}
 | 
				
			||||||
 | 
					            \hline
 | 
				
			||||||
 | 
					            \textbf{Code banque} & \textbf{Code guichet} & \textbf{N° de Compte} & \textbf{Clé RIB}\\
 | 
				
			||||||
 | 
					                    \CodeBanque          & \CodeGuichet        & \NCompte               & \CleRib   \\
 | 
				
			||||||
 | 
					            \hline
 | 
				
			||||||
 | 
					            \textbf{IBAN N°}        & \multicolumn{3}{|l|} \IBAN         \\
 | 
				
			||||||
 | 
					            \hline
 | 
				
			||||||
 | 
					            \textbf{Code BIC}        & \multicolumn{3}{|l|}\CodeBic         \\
 | 
				
			||||||
 | 
					            \hline
 | 
				
			||||||
 | 
					        \end{tabular}
 | 
				
			||||||
 | 
					    \end{center}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{center}
 | 
				
			||||||
 | 
					TVA non applicable, article 293 B du CGI.
 | 
				
			||||||
 | 
					\end{center}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\end{document}
 | 
				
			||||||
							
								
								
									
										37
									
								
								templates/treasury/remittance_form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								templates/treasury/remittance_form.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load crispy_forms_tags pretty_money %}
 | 
				
			||||||
 | 
					{% load render_table from django_tables2 %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					    <h1>{% trans "Remittance #" %}{{ object.pk }}</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p><a class="btn btn-default" href="{% url 'treasury:remittance_list' %}">{% trans "Remittances list" %}</a></p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {% if object.pk %}
 | 
				
			||||||
 | 
					        <div id="div_id_type" class="form-group"><label for="id_count" class="col-form-label">{% trans "Count" %}</label>
 | 
				
			||||||
 | 
					            <div class="">
 | 
				
			||||||
 | 
					                <input type="text" name="count" value="{{ object.count }}" class="textinput textInput form-control" id="id_count" disabled>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div id="div_id_type" class="form-group"><label for="id_amount" class="col-form-label">{% trans "Amount" %}</label>
 | 
				
			||||||
 | 
					            <div class="">
 | 
				
			||||||
 | 
					                <input class="textinput textInput form-control" type="text" value="{{ object.amount|pretty_money }}" id="id_amount" disabled>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {% crispy form %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <hr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>{% trans "Linked transactions" %}</h2>
 | 
				
			||||||
 | 
					    {% if special_transactions.data %}
 | 
				
			||||||
 | 
					        {% render_table special_transactions %}
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					        <div class="alert alert-warning">
 | 
				
			||||||
 | 
					            {% trans "There is no transaction linked with this remittance." %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										56
									
								
								templates/treasury/remittance_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								templates/treasury/remittance_list.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					{% load render_table from django_tables2 %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="row">
 | 
				
			||||||
 | 
					        <div class="col-xl-12">
 | 
				
			||||||
 | 
					            <div class="btn-group btn-group-toggle" style="width: 100%; padding: 0 0 2em 0" data-toggle="buttons">
 | 
				
			||||||
 | 
					                <a href="{% url "treasury:invoice_list" %}" class="btn btn-sm btn-outline-primary">
 | 
				
			||||||
 | 
					                    {% trans "Invoice" %}s
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					                <a href="#" class="btn btn-sm btn-outline-primary active">
 | 
				
			||||||
 | 
					                    {% trans "Remittance" %}s
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>{% trans "Opened remittances" %}</h2>
 | 
				
			||||||
 | 
					    {% if opened_remittances.data %}
 | 
				
			||||||
 | 
					        {% render_table opened_remittances %}
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					        <div class="alert alert-warning">
 | 
				
			||||||
 | 
					            {% trans "There is no opened remittance." %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <a class="btn btn-primary" href="{% url 'treasury:remittance_create' %}">{% trans "New remittance" %}</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <hr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>{% trans "Transfers without remittances" %}</h2>
 | 
				
			||||||
 | 
					    {% if special_transactions_no_remittance.data %}
 | 
				
			||||||
 | 
					        {% render_table special_transactions_no_remittance %}
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					        <div class="alert alert-warning">
 | 
				
			||||||
 | 
					            {% trans "There is no transaction without any linked remittance." %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <hr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>{% trans "Transfers with opened remittances" %}</h2>
 | 
				
			||||||
 | 
					    {% if special_transactions_with_remittance.data %}
 | 
				
			||||||
 | 
					        {% render_table special_transactions_with_remittance %}
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					        <div class="alert alert-warning">
 | 
				
			||||||
 | 
					            {% trans "There is no transaction with an opened linked remittance." %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <hr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>{% trans "Closed remittances" %}</h2>
 | 
				
			||||||
 | 
					    {% render_table closed_remittances %}
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										9
									
								
								templates/treasury/specialtransactionproxy_form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/treasury/specialtransactionproxy_form.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load crispy_forms_tags pretty_money %}
 | 
				
			||||||
 | 
					{% load render_table from django_tables2 %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					    <p><a class="btn btn-default" href="{% url 'treasury:remittance_list' %}">{% trans "Remittances list" %}</a></p>
 | 
				
			||||||
 | 
					    {% crispy form %}
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										2
									
								
								tox.ini
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tox.ini
									
									
									
									
									
								
							@@ -30,7 +30,7 @@ deps =
 | 
				
			|||||||
    pep8-naming
 | 
					    pep8-naming
 | 
				
			||||||
    pyflakes
 | 
					    pyflakes
 | 
				
			||||||
commands =
 | 
					commands =
 | 
				
			||||||
    flake8 apps/activity apps/api apps/logs apps/member apps/note
 | 
					    flake8 apps/activity apps/api apps/logs apps/member apps/note apps/permission apps/treasury
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[flake8]
 | 
					[flake8]
 | 
				
			||||||
# Ignore too many errors, should be reduced in the future
 | 
					# Ignore too many errors, should be reduced in the future
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user