Skip to content
Commits on Source (9)
# 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)
# 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)
......@@ -3,21 +3,30 @@
import json
import datetime
import re
import pytz
from django.core.management.base import BaseCommand
from django.core.management import call_command
import psycopg2 as pg
import psycopg2.extras as pge
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.db import transaction
from django.core.exceptions import ValidationError
from django.utils.timezone import make_aware
from django.db import IntegrityError
from django.contrib.auth.models import User
from activity.models import ActivityType, Activity, Guest, Entry, GuestTransaction
from note.models import Note
from note.models import Alias
from note.models import TemplateCategory, TransactionTemplate, \
Transaction, RecurrentTransaction, SpecialTransaction
from note.models import (
TemplateCategory,
TransactionTemplate,
Transaction,
RecurrentTransaction,
MembershipTransaction,
SpecialTransaction,
)
from member.models import Club, Membership
from treasury.models import RemittanceType, Remittance, SpecialTransactionProxy
......@@ -63,7 +72,7 @@ def import_comptes(cur):
update_line(idx, n, row["pseudo"])
if row["type"] == "personne":
# sanitize password
if row["passwd"] != "*|*":
if row["passwd"] != "*|*" and not row["deleted"]:
passwd_nk15 = "$".join(["custom_nk15", "1", row["passwd"]])
else:
passwd_nk15 = ''
......@@ -149,7 +158,7 @@ def import_boutons(cur):
qs = Club.objects.filter(note__note_ptr=MAP_IDBDE[row["destinataire"]]).values('name')
note_name = qs[0]["name"]
# rename button name
obj_dict["name"] = "{} {}".format(obj_dict["name"], note_name)
obj_dict["name"] = f"{obj_dict_name['name']} {note_name}"
button = TransactionTemplate.objects.create(**obj_dict)
else:
raise e
......@@ -159,21 +168,32 @@ def import_boutons(cur):
@transaction.atomic
def import_transaction(cur):
idmin = 58770
cur.execute("SELECT *, transactions.date AS transac_date\
FROM transactions\
LEFT JOIN adhesions ON transactions.id = adhesions.id\
WHERE transactions.id> {}\
ORDER BY transactions.id;".format(idmin))
bde = Club.objects.get(name="BDE")
kfet = Club.objects.get(name="Kfet")
cur.execute(
"SELECT t.date AS transac_date, t.type, t.emetteur,\
t.destinataire,t.quantite, t.montant, t.description,\
t.valide, t.cantinvalidate, t.categorie, \
a.idbde, a.annee, a.wei, a.date AS adh_date, a.section\
FROM transactions AS t \
LEFT JOIN adhesions AS a ON t.id = a.idtransaction \
WHERE t.id> {} \
ORDER BY t.id;".format(idmin)
)
n = cur.rowcount
for idx, row in enumerate(cur):
update_line(idx, n, row["description"])
# some date are set to None, use the previous one
date = row["transac_date"]
try:
date = make_aware(row["transac_date"])
except (pytz.NonExistentTimeError, pytz.AmbiguousTimeError):
date = make_aware(row["transac_date"] + datetime.timedelta(hours=1))
# standart transaction object
obj_dict = {
# "pk": row["id"],
"destination_id": MAP_IDBDE[row["destinataire"]],
"source_id": MAP_IDBDE[row["emetteur"]],
"created_at": make_aware(date),
"created_at": date,
"amount": row["montant"],
"quantity": row["quantite"],
"reason": row["description"],
......@@ -211,28 +231,57 @@ def import_transaction(cur):
obj_dict["first_name"] = actor.club.name
obj_dict["last_name"] = actor.club.name
else:
raise Exception("You should'nt be there")
raise Exception("Badly formatted Special Transaction You should'nt be there.")
tr = SpecialTransaction.objects.create(**obj_dict)
if "cheques" in row["description"]:
MAP_IDSPECIALTRANSACTION[row["id"]] = tr
elif ttype == "adhésion":
# Since BDE and Kfet are distinct, don't import membership transaction and use our custom transactions.
pass
montant = row["montant"]
# Create Double membership to Kfet and Bde
# sometimes montant = 0, fees are modified accordingly.
bde_dict = {
"user": MAP_IDBDE[row["idbde"]],
"club": bde,
"date_start": row["date"].date(), # Only date, not time
"fee": min(500, montant)
}
kfet_dict = {
"user": MAP_IDBDE[row["idbde"]],
"club": kfet,
"date_start": row["date"].date(), # Only date, not time
"fee": max(montant - 500, 0),
}
if row["valide"]:
with transaction.atomic():
# membership save triggers MembershipTransaction creation
bde_membership = Membership.objects.get_or_create(**bde_dict)
kfet_membership = Membership.objects.get_or_create(**kfet_dict)
bde_membership.transaction.created_at = row["transac_date"]
bde_membership.transaction.description = row["description"]
bde_membership.transaction.save()
kfet_membership.transaction.created_at = row["transac_date"]
kfet_membership.transaction.description = row["description"] + "(Kfet)"
kfet_membership.transaction.save()
else:
# don't create membership
MembershipTransaction.objects.create(**obj_dict)
elif ttype == "invitation":
m = re.search("Invitation (.*?) \((.*?)\)", row["description"])
m = re.search(r"Invitation (.*?) \((.*?)\)", row["description"])
if m is None:
raise IntegrityError("Invitation is not well formated: {} (must be 'Invitation ACTIVITY_NAME (NAME)')"
.format(row["description"]))
raise IntegrityError(f"Invitation is not well formated: {row['description']} (must be 'Invitation ACTIVITY_NAME (NAME)')")
activity_name = m.group(1)
guest_name = m.group(2)
if activity_name not in MAP_NAMEACTIVITY:
raise IntegrityError("Activity {} is not found".format(activity_name,))
raise IntegrityError(f"Activity {activity_name} is not found")
activity = MAP_NAMEACTIVITY[activity_name]
if guest_name not in MAP_NAMEGUEST:
raise IntegrityError("Guest {} is not found".format(guest_name,))
raise IntegrityError(f"Guest {guest_name} is not found")
guest = None
for g in MAP_NAMEGUEST[guest_name]:
......@@ -240,7 +289,7 @@ def import_transaction(cur):
guest = g
break
if guest is None:
raise IntegrityError("Guest {} didn't go to the activity {}".format(guest_name, activity_name,))
raise IntegrityError("Guest {guest_name} didn't go to the activity {activity_name}")
obj_dict["guest"] = guest
......@@ -254,13 +303,13 @@ def import_aliases(cur):
cur.execute("SELECT * FROM aliases ORDER by id")
n = cur.rowcount
for idx, row in enumerate(cur):
update_line(idx, n, row["titre"])
update_line(idx, n, row["alias"])
alias_name = row["alias"]
alias_name_good = (alias_name[:252] + '...') if len(alias_name) > 255 else alias_name
obj_dict = {
"note_id": MAP_IDBDE[row["idbde"]],
"name": alias_name_good,
"normalized_name": Alias.normalize(alias_name_good)
"normalized_name": Alias.normalize(alias_name_good),
}
try:
with transaction.atomic():
......@@ -284,7 +333,7 @@ def import_activities(cur):
update_line(idx, n, row["alias"])
organizer = Club.objects.filter(name=row["signature"])
if organizer.exists():
# Try to find the club that organizes the activity. If not founded, assume that is Kfet (fix manually)
# Try to find the club that organizes the activity. If not founded, assume it's Kfet (fix manually)
organizer = organizer.get()
else:
organizer = kfet
......@@ -361,38 +410,6 @@ def import_activity_entries(cur):
raise e
@transaction.atomic
def import_memberships(cur):
cur.execute("SELECT * FROM adhesions ORDER by id")
n = cur.rowcount
bde = Club.objects.get(name="BDE")
kfet = Club.objects.get(name="Kfet")
for idx, row in enumerate(cur):
update_line(idx, n, MAP_IDBDE[row["idbde"]].username)
bde_dict = {
"user": MAP_IDBDE[row["idbde"]],
"club": bde,
"date_start": row["date"][10:], # Only date, not time
"fee": 500,
}
kfet_dict = {
"user": MAP_IDBDE[row["idbde"]],
"club": kfet,
"date_start": row["date"][:10], # Only date, not time
"fee": 1500 if row["date"].month in [3, 4, 5, 6, 7] else 3500,
}
try:
with transaction.atomic():
bde_membership = Membership.objects.get_or_create(**bde_dict)
kfet_membership = Membership.objects.get_or_create(**kfet_dict)
bde_membership.transaction.created_at = row["date"]
bde_membership.transaction.save()
kfet_membership.transaction.created_at = row["date"]
kfet_membership.transaction.save()
except IntegrityError as e:
raise e
@transaction.atomic
def import_remittances(cur):
cur.execute("SELECT * FROM remises ORDER by id")
......@@ -452,7 +469,6 @@ class Command(BaseCommand):
parser.add_argument('-t', '--transactions', action='store_true', help="import transaction")
parser.add_argument('-al', '--aliases', action='store_true', help="import aliases")
parser.add_argument('-ac', '--activities', action='store_true', help="import activities")
parser.add_argument('-M', '--memberships', action='store_true', help="import memberships")
parser.add_argument('-r', '--remittances', action='store_true', help="import check remittances")
parser.add_argument('-s', '--save', action='store', help="save mapping of idbde")
parser.add_argument('-m', '--map', action='store', help="import mapping of idbde")
......@@ -498,9 +514,6 @@ class Command(BaseCommand):
if kwargs["transactions"]:
import_transaction(cur)
self.print_success("transaction imported\n")
if kwargs["memberships"]:
import_memberships(cur)
self.print_success("memberships imported\n")
if kwargs["remittances"]:
import_remittances(cur)
self.print_success("remittances imported\n")
# 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()