Merge branch 'master' into 'Production'

Master

See merge request klub-dev-ens/gestioCOF!527
This commit is contained in:
Tom Hubrecht 2023-06-15 13:59:53 +02:00
commit 7460ca591f
9 changed files with 92 additions and 21 deletions

View file

@ -27,6 +27,13 @@ adhérents ni des cotisations.
## Version ??? - ??/??/???? ## Version ??? - ??/??/????
## Version 0.15.1 - 15/06/2023
### K-Fêt
- Rattrape les erreurs d'envoi de mail de négatif
- Utilise l'adresse chefs pour les envois de négatifs
## Version 0.15 - 22/05/2023 ## Version 0.15 - 22/05/2023
### K-Fêt ### K-Fêt

View file

@ -207,7 +207,8 @@ MAIL_DATA = {
}, },
"rappels": {"FROM": "Le BdA <bda@ens.fr>", "REPLYTO": "Le BdA <bda@ens.fr>"}, "rappels": {"FROM": "Le BdA <bda@ens.fr>", "REPLYTO": "Le BdA <bda@ens.fr>"},
"rappel_negatif": { "rappel_negatif": {
"FROM": "La K-Fêt <k-fet@ens.fr>", "FROM": "La K-Fêt <chefs-k-fet@ens.fr>",
"REPLYTO": "La K-Fêt <chefs-k-fet@ens.fr>",
}, },
"revente": { "revente": {
"FROM": "BdA-Revente <bda-revente@ens.fr>", "FROM": "BdA-Revente <bda-revente@ens.fr>",

View file

@ -0,0 +1,19 @@
# Generated by Django 2.2.28 on 2023-05-22 09:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gestioncof", "0018_petitscours_email"),
]
operations = [
migrations.AddField(
model_name="cofprofile",
name="date_adhesion",
field=models.DateField(
blank=True, null=True, verbose_name="Date d'adhésion"
),
),
]

View file

@ -50,6 +50,7 @@ class CofProfile(models.Model):
"Login clipper", max_length=32, blank=True, unique=True, null=True "Login clipper", max_length=32, blank=True, unique=True, null=True
) )
is_cof = models.BooleanField("Membre du COF", default=False) is_cof = models.BooleanField("Membre du COF", default=False)
date_adhesion = models.DateField("Date d'adhésion", blank=True, null=True)
phone = models.CharField("Téléphone", max_length=20, blank=True) phone = models.CharField("Téléphone", max_length=20, blank=True)
occupation = models.CharField( occupation = models.CharField(
_("Occupation"), _("Occupation"),

View file

@ -1,5 +1,5 @@
import uuid import uuid
from datetime import timedelta from datetime import date, timedelta
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
@ -484,6 +484,7 @@ class ExportMembersViewTests(CSVResponseMixin, ViewTestCaseMixin, TestCase):
u1.last_name = "last" u1.last_name = "last"
u1.email = "user@mail.net" u1.email = "user@mail.net"
u1.save() u1.save()
u1.profile.date_adhesion = date(2023, 5, 22)
u1.profile.phone = "0123456789" u1.profile.phone = "0123456789"
u1.profile.departement = "Dept" u1.profile.departement = "Dept"
u1.profile.save() u1.profile.save()
@ -505,8 +506,9 @@ class ExportMembersViewTests(CSVResponseMixin, ViewTestCaseMixin, TestCase):
"1A", "1A",
"Dept", "Dept",
"normalien", "normalien",
"2023-05-22",
], ],
[str(u2.pk), "staff", "", "", "", "", "1A", "", "normalien"], [str(u2.pk), "staff", "", "", "", "", "1A", "", "normalien", "None"],
], ],
) )

View file

@ -1,6 +1,6 @@
import csv import csv
import uuid import uuid
from datetime import timedelta from datetime import date, timedelta
from smtplib import SMTPRecipientsRefused from smtplib import SMTPRecipientsRefused
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
@ -86,6 +86,7 @@ class ResetComptes(BuroRequiredMixin, TemplateView):
nb_adherents = CofProfile.objects.filter(is_cof=True).count() nb_adherents = CofProfile.objects.filter(is_cof=True).count()
CofProfile.objects.update( CofProfile.objects.update(
is_cof=False, is_cof=False,
date_adhesion=None,
mailing_cof=False, mailing_cof=False,
mailing_bda=False, mailing_bda=False,
mailing_bda_revente=False, mailing_bda_revente=False,
@ -575,6 +576,9 @@ def registration(request):
profile = profile_form.save() profile = profile_form.save()
if profile.is_cof and not was_cof: if profile.is_cof and not was_cof:
notify_new_member(request, member) notify_new_member(request, member)
profile.date_adhesion = date.today()
profile.save()
# Enregistrement des inscriptions aux événements # Enregistrement des inscriptions aux événements
for form in event_formset: for form in event_formset:
if "status" not in form.cleaned_data: if "status" not in form.cleaned_data:
@ -715,6 +719,7 @@ def export_members(request):
profile.occupation, profile.occupation,
profile.departement, profile.departement,
profile.type_cotiz, profile.type_cotiz,
profile.date_adhesion,
] ]
writer.writerow([str(bit) for bit in bits]) writer.writerow([str(bit) for bit in bits])

View file

@ -2,6 +2,7 @@
Gestion en ligne de commande des mails de rappel K-Fet. Gestion en ligne de commande des mails de rappel K-Fet.
""" """
import smtplib
from datetime import timedelta from datetime import timedelta
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
@ -10,6 +11,14 @@ from django.utils import timezone
from kfet.models import AccountNegative from kfet.models import AccountNegative
def send_mail(neg: AccountNegative, stdout) -> None:
try:
neg.send_rappel()
stdout.write(f"Mail de rappel pour {neg.account} envoyé avec succès.")
except smtplib.SMTPException:
stdout.write(f"Erreur lors de l'envoi du mail de rappel pour {neg.account}.")
class Command(BaseCommand): class Command(BaseCommand):
help = ( help = (
"Envoie un mail de rappel aux personnes en négatif.\n" "Envoie un mail de rappel aux personnes en négatif.\n"
@ -39,12 +48,10 @@ class Command(BaseCommand):
) )
for neg in accounts_first_mail: for neg in accounts_first_mail:
neg.send_rappel() send_mail(neg, self.stdout)
self.stdout.write(f"Mail de rappel pour {neg.account} envoyé avec succès.")
for neg in accounts_periodic_mail: for neg in accounts_periodic_mail:
neg.send_rappel() send_mail(neg, self.stdout)
self.stdout.write(f"Mail de rappel pour {neg.account} envoyé avec succès.")
if not (accounts_first_mail.exists() or accounts_periodic_mail.exists()): if not (accounts_first_mail.exists() or accounts_periodic_mail.exists()):
self.stdout.write("Aucun mail à envoyer.") self.stdout.write("Aucun mail à envoyer.")

View file

@ -2,7 +2,7 @@ import re
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.mail import send_mail from django.core.mail import EmailMessage
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db import models, transaction from django.db import models, transaction
from django.db.models import F from django.db.models import F
@ -298,10 +298,11 @@ class AccountNegative(models.Model):
""" """
Envoie un mail de rappel signalant que la personne est en négatif. Envoie un mail de rappel signalant que la personne est en négatif.
""" """
# On envoie le mail mail_data = settings.MAIL_DATA["rappel_negatif"]
send_mail(
"Compte K-Psul négatif", email = EmailMessage(
loader.render_to_string( subject="Compte K-Psul négatif",
body=loader.render_to_string(
"kfet/mails/rappel.txt", "kfet/mails/rappel.txt",
context={ context={
"account": self.account, "account": self.account,
@ -309,9 +310,14 @@ class AccountNegative(models.Model):
"start_date": self.start, "start_date": self.start,
}, },
), ),
settings.MAIL_DATA["rappel_negatif"]["FROM"], from_email=mail_data["FROM"],
[self.account.email], to=[self.account.email],
reply_to=[mail_data["REPLYTO"]],
) )
# On envoie le mail
email.send()
# On enregistre le fait que l'envoi a bien eu lieu # On enregistre le fait que l'envoi a bien eu lieu
self.last_rappel = timezone.now() self.last_rappel = timezone.now()
self.save() self.save()

View file

@ -1,5 +1,29 @@
{ pkgs ? import <nixpkgs> { }, ... }: { pkgs ? import <nixpkgs> { }, ... }:
let
python = pkgs.python38;
django-types = python.pkgs.buildPythonPackage rec {
pname = "django-types";
version = "0.17.0";
format = "pyproject";
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-wcQqt4h2xXxyg0LVqwYHJas3H8jcg7uFuuC+BoRqrXA=";
};
nativeBuildInputs = with python.pkgs; [ poetry-core ];
# setup.cfg tries to pull in nonexistent LICENSE.txt file
# postPatch = "rm setup.cfg";
# propagatedBuildInputs = [ django typing-extensions ];
};
in
pkgs.mkShell { pkgs.mkShell {
shellHook = '' shellHook = ''
export DJANGO_SETTINGS_MODULE=gestioasso.settings.local export DJANGO_SETTINGS_MODULE=gestioasso.settings.local
@ -10,12 +34,11 @@ pkgs.mkShell {
pip install -r requirements-devel.txt | grep -v 'Requirement already satisfied:' pip install -r requirements-devel.txt | grep -v 'Requirement already satisfied:'
''; '';
packages = with pkgs; [ packages = [ python django-types ] ++ (with python.pkgs; [
python38 pip
python38Packages.pip virtualenv
python38Packages.virtualenv python-ldap
python38Packages.python-ldap ]);
];
allowSubstitutes = false; allowSubstitutes = false;
} }