Merge remote-tracking branch 'origin/master' into beta-soon

# Conflicts:
#	apps/scripts
This commit is contained in:
Yohann D'ANELLO 2020-05-29 21:11:14 +02:00
commit c62b5f935a
8 changed files with 177 additions and 7 deletions

View File

@ -264,6 +264,17 @@ class SpecialTransaction(Transaction):
def type(self): def type(self):
return _('Credit') if isinstance(self.source, NoteSpecial) else _("Debit") return _('Credit') if isinstance(self.source, NoteSpecial) else _("Debit")
def is_credit(self):
return isinstance(self.source, NoteSpecial)
def is_debit(self):
return isinstance(self.destination, NoteSpecial)
def clean(self):
# SpecialTransaction are only possible with NoteSpecial object
if self.is_credit() == self.is_debit():
raise(ValidationError(_("A special transaction is only possible between a Note associated to a payment method and a User or a Club")))
class MembershipTransaction(Transaction): class MembershipTransaction(Transaction):
""" """

@ -1 +1 @@
Subproject commit c37a6effc9217e2ffceb631f48b371f87814c1f6 Subproject commit ee54fca89ee247a4ba4af080dd3036d92340eade

View File

@ -191,7 +191,7 @@ class SpecialTransactionProxy(models.Model):
""" """
In order to keep modularity, we don't that the Note app depends on the treasury app. 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. 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. If it isn't very clean, it does what we want.
""" """
transaction = models.OneToOneField( transaction = models.OneToOneField(

View File

@ -1,7 +1,6 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from note.models import NoteSpecial
from treasury.models import SpecialTransactionProxy, RemittanceType from treasury.models import SpecialTransactionProxy, RemittanceType
@ -9,6 +8,10 @@ def save_special_transaction(instance, created, **kwargs):
""" """
When a special transaction is created, we create its linked proxy When a special transaction is created, we create its linked proxy
""" """
if created and isinstance(instance.source, NoteSpecial) \
and RemittanceType.objects.filter(note=instance.source).exists(): if instance.is_credit():
SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save() if created and RemittanceType.objects.filter(note=instance.source).exists():
SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save()
else:
if created and RemittanceType.objects.filter(note=instance.destination).exists():
SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save()

View File

@ -0,0 +1,89 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.management import BaseCommand, CommandError
from django.db.models import Q
from django.db.models.functions import Lower
from wei.models import WEIClub, Bus, BusTeam, WEIMembership
class Command(BaseCommand):
help = "Export WEI registrations."
def add_arguments(self, parser):
parser.add_argument('--bus', '-b', choices=[bus.name for bus in Bus.objects.all()], type=str, default=None,
help='Filter by bus')
parser.add_argument('--team', '-t', choices=[team.name for team in BusTeam.objects.all()], type=str,
default=None, help='Filter by team. Type "none" if you want to select the members '
+ 'that are not in a team.')
parser.add_argument('--year', '-y', type=int, default=None,
help='Select the year of the concerned WEI. Default: last year')
parser.add_argument('--sep', type=str, default='|',
help='Select the CSV separator.')
def handle(self, *args, **options):
year = options["year"]
if year:
try:
wei = WEIClub.objects.get(year=year)
except WEIClub.DoesNotExist:
raise CommandError("The WEI of year {:d} does not exist.".format(year,))
else:
wei = WEIClub.objects.order_by('-year').first()
bus = options["bus"]
if bus:
try:
bus = Bus.objects.filter(wei=wei).get(name=bus)
except Bus.DoesNotExist:
raise CommandError("The bus {} does not exist or does not belong to the WEI {}.".format(bus, wei.name,))
team = options["team"]
if team:
if team.lower() == "none":
team = 0
else:
try:
team = BusTeam.objects.filter(Q(bus=bus) | Q(wei=wei)).get(name=team)
bus = team.bus
except BusTeam.DoesNotExist:
raise CommandError("The bus {} does not exist or does not belong to the bus {} neither the wei {}."
.format(team, bus.name if bus else "<None>", wei.name,))
qs = WEIMembership.objects
qs = qs.filter(club=wei).order_by(
Lower('bus__name'),
Lower('team__name'),
'user__profile__promotion',
Lower('user__last_name'),
Lower('user__first_name'),
).distinct()
if bus:
qs = qs.filter(bus=bus)
if team is not None:
qs = qs.filter(team=team if team else None)
sep = options["sep"]
self.stdout.write("Nom|Prénom|Date de naissance|Genre|Département|Année|Section|Bus|Équipe|Rôles"
.replace(sep, sep))
for membership in qs.all():
user = membership.user
registration = membership.registration
bus = membership.bus
team = membership.team
s = user.last_name
s += sep + user.first_name
s += sep + str(registration.birth_date)
s += sep + registration.get_gender_display()
s += sep + user.profile.get_department_display()
s += sep + str(user.profile.ens_year) + "A"
s += sep + user.profile.section_generated
s += sep + bus.name
s += sep + (team.name if team else "--")
s += sep + ", ".join(role.name for role in membership.roles.filter(~Q(name="Adhérent WEI")).all())
self.stdout.write(s)

View File

@ -0,0 +1,52 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import date
from django.core.management import BaseCommand
from django.db.models import Q
from member.models import Membership, Club
from wei.models import WEIClub
class Command(BaseCommand):
help = "Get mailing list registrations from the last wei. " \
"Usage: manage.py extract_ml_registrations -t {events,art,sport}. " \
"You can write this into a file with a pipe, then paste the document into your mail manager."
def add_arguments(self, parser):
parser.add_argument('--type', '-t', choices=["members", "clubs", "events", "art", "sport"], default="members",
help='Select the type of the mailing list (default members)')
parser.add_argument('--year', '-y', type=int, default=None,
help='Select the year of the concerned WEI. Default: last year')
def handle(self, *args, **options):
if options["type"] == "members":
for membership in Membership.objects.filter(
club__name="BDE",
date_start__lte=date.today(),
date_end__gte=date.today(),
).all():
self.stdout.write(membership.user.email)
return
if options["type"] == "clubs":
for club in Club.objects.all():
self.stdout.write(club.email)
return
if options["year"] is None:
wei = WEIClub.objects.order_by('-year').first()
else:
wei = WEIClub.objects.filter(year=options["year"])
if wei.exists():
wei = wei.get()
else:
wei = WEIClub.objects.order_by('-year').first()
self.stderr.write(self.style.WARNING("Warning: there was no WEI in year " + str(options["year"]) + ". "
+ "Assuming the last WEI (year " + str(wei.year) + ")"))
q = Q(ml_events_registration=True) if options["type"] == "events" else Q(ml_art_registration=True)\
if options["type"] == "art" else Q(ml_sport_registration=True)
registrations = wei.users.filter(q)
for registration in registrations.all():
self.stdout.write(registration.user.email)

View File

@ -0,0 +1,15 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.management import BaseCommand
from wei.forms import CurrentSurvey
class Command(BaseCommand):
help = "Attribute to each first year member a bus for the WEI"
def handle(self, *args, **options):
"""
Run the WEI algorithm to attribute a bus to each first year member.
"""
CurrentSurvey.get_algorithm_class()().run_algorithm()

View File

@ -11,7 +11,7 @@ django-tables2==2.1.0
docutils==0.14 docutils==0.14
idna==2.8 idna==2.8
oauthlib==3.1.0 oauthlib==3.1.0
Pillow==6.1.0 Pillow==7.1.2
python3-openid==3.1.0 python3-openid==3.1.0
pytz==2019.1 pytz==2019.1
requests==2.22.0 requests==2.22.0