diff --git a/.gitignore b/.gitignore
index ab791b2e..2f3d166c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ venv/
media/
*.log
*.sqlite3
+.coverage
# PyCharm
.idea
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 19bcc736..95d9305d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,3 +1,5 @@
+image: "python:3.5"
+
services:
- postgres:latest
- redis:latest
@@ -10,7 +12,7 @@ variables:
REDIS_PASSWD: "dummy"
# Cached packages
- PYTHONPATH: "$CI_PROJECT_DIR/vendor/python"
+ PIP_CACHE_DIR: "$CI_PROJECT_DIR/vendor/pip"
# postgres service configuration
POSTGRES_PASSWORD: "4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4"
@@ -20,22 +22,41 @@ variables:
# psql password authentication
PGPASSWORD: $POSTGRES_PASSWORD
-cache:
- paths:
- - vendor/python
- - vendor/pip
- - vendor/apt
-
-before_script:
- - mkdir -p vendor/{python,pip,apt}
- - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client
- - sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py
- - sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' cof/settings/secret.py
- # Remove the old test database if it has not been done yet
- - psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB"
- - pip install --upgrade --cache-dir vendor/pip -t vendor/python -r requirements.txt
-
test:
stage: test
+ before_script:
+ - mkdir -p vendor/{pip,apt}
+ - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client
+ - sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py
+ - sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' cof/settings/secret.py
+ # Remove the old test database if it has not been done yet
+ - psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB"
+ - pip install --upgrade -r requirements.txt coverage
+ - python --version
script:
- - python manage.py test
+ - coverage run manage.py test
+ after_script:
+ - coverage report
+ cache:
+ key: test
+ paths:
+ - vendor/
+ # For GitLab CI to get coverage from build.
+ # Keep this disabled for now, as it may kill GitLab...
+ # coverage: '/TOTAL.*\s(\d+\.\d+)\%$/'
+
+linters:
+ image: python:3.6
+ stage: test
+ before_script:
+ - mkdir -p vendor/pip
+ - pip install --upgrade black isort flake8
+ script:
+ - black --check .
+ - isort --recursive --check-only --diff bda cof gestioncof kfet provisioning shared utils
+ # Print errors only
+ - flake8 --exit-zero bda cof gestioncof kfet provisioning shared utils
+ cache:
+ key: linters
+ paths:
+ - vendor/
diff --git a/.pre-commit.sh b/.pre-commit.sh
new file mode 100755
index 00000000..0e0e3c1a
--- /dev/null
+++ b/.pre-commit.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+# pre-commit hook for gestioCOF project.
+#
+# Run formatters first, then checkers.
+# Formatters which changed a file must set the flag 'formatter_updated'.
+
+exit_code=0
+formatter_updated=0
+checker_dirty=0
+
+# TODO(AD): We should check only staged changes.
+# Working? -> Stash unstaged changes, run it, pop stash
+STAGED_PYTHON_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".py$")
+
+
+# Formatter: black
+
+printf "> black ... "
+
+if type black &>/dev/null; then
+ if [ -z "$STAGED_PYTHON_FILES" ]; then
+ printf "OK\n"
+ else
+ BLACK_OUTPUT="/tmp/gc-black-output.log"
+ touch $BLACK_OUTPUT
+
+ if ! echo "$STAGED_PYTHON_FILES" | xargs -d'\n' black --check &>$BLACK_OUTPUT; then
+ echo "$STAGED_PYTHON_FILES" | xargs -d'\n' black &>$BLACK_OUTPUT
+ tail -1 $BLACK_OUTPUT
+ formatter_updated=1
+ else
+ printf "OK\n"
+ fi
+ fi
+else
+ printf "SKIP: program not found\n"
+ printf "HINT: Install black with 'pip3 install black' (black requires Python>=3.6)\n"
+fi
+
+# Formatter: isort
+
+printf "> isort ... "
+
+if type isort &>/dev/null; then
+ if [ -z "$STAGED_PYTHON_FILES" ]; then
+ printf "OK\n"
+ else
+ ISORT_OUTPUT="/tmp/gc-isort-output.log"
+ touch $ISORT_OUTPUT
+
+ if ! echo "$STAGED_PYTHON_FILES" | xargs -d'\n' isort --check-only &>$ISORT_OUTPUT; then
+ echo "$STAGED_PYTHON_FILES" | xargs -d'\n' isort &>$ISORT_OUTPUT
+ printf "Reformatted.\n"
+ formatter_updated=1
+ else
+ printf "OK\n"
+ fi
+ fi
+else
+ printf "SKIP: program not found\n"
+ printf "HINT: Install isort with 'pip install isort'\n"
+fi
+
+# Checker: flake8
+
+printf "> flake8 ... "
+
+if type flake8 &>/dev/null; then
+ if [ -z "$STAGED_PYTHON_FILES" ]; then
+ printf "OK\n"
+ else
+ FLAKE8_OUTPUT="/tmp/gc-flake8-output.log"
+ touch $FLAKE8_OUTPUT
+
+ if ! echo "$STAGED_PYTHON_FILES" | xargs -d'\n' flake8 &>$FLAKE8_OUTPUT; then
+ printf "FAIL\n"
+ cat $FLAKE8_OUTPUT
+ checker_dirty=1
+ else
+ printf "OK\n"
+ fi
+ fi
+else
+ printf "SKIP: program not found\n"
+ printf "HINT: Install flake8 with 'pip install flake8'\n"
+fi
+
+# End
+
+if [ $checker_dirty -ne 0 ]
+then
+ printf ">>> Checker(s) detect(s) issue(s)\n"
+ printf " You can still commit and push :)\n"
+ printf " Be warned that our CI may cause you more trouble.\n"
+fi
+
+if [ $formatter_updated -ne 0 ]
+then
+ printf ">>> Working tree updated by formatter(s)\n"
+ printf " Add changes to staging area and retry.\n"
+ exit_code=1
+fi
+
+printf "\n"
+
+exit $exit_code
diff --git a/README.md b/README.md
index a0dc5bc1..2f08f3aa 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# GestioCOF
-![build_status](https://git.eleves.ens.fr/cof-geek/gestioCOF/badges/master/build.svg)
+[![pipeline status](https://git.eleves.ens.fr/cof-geek/gestioCOF/badges/master/pipeline.svg)](https://git.eleves.ens.fr/cof-geek/gestioCOF/commits/master)
+[![coverage report](https://git.eleves.ens.fr/cof-geek/gestioCOF/badges/master/coverage.svg)](https://git.eleves.ens.fr/cof-geek/gestioCOF/commits/master)
## Installation
@@ -43,6 +44,16 @@ pour profiter de façon transparente des mises à jour du fichier:
ln -s secret_example.py cof/settings/secret.py
+Nous avons un git hook de pre-commit pour formatter et vérifier que votre code
+vérifie nos conventions. Pour bénéficier des mises à jour du hook, préférez
+encore l'installation *via* un lien symbolique:
+
+ ln -s ../../.pre-commit.sh .git/hooks/pre-commit
+
+Pour plus d'informations à ce sujet, consulter la
+[page](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/coding-style)
+du wiki gestioCOF liée aux conventions.
+
#### Fin d'installation
diff --git a/bda/__init__.py b/bda/__init__.py
index 8b137891..e69de29b 100644
--- a/bda/__init__.py
+++ b/bda/__init__.py
@@ -1 +0,0 @@
-
diff --git a/bda/admin.py b/bda/admin.py
index 485471da..b32144f1 100644
--- a/bda/admin.py
+++ b/bda/admin.py
@@ -1,16 +1,24 @@
from datetime import timedelta
-from custommail.shortcuts import send_mass_custom_mail
+from custommail.shortcuts import send_mass_custom_mail
+from dal.autocomplete import ModelSelect2
+from django import forms
from django.contrib import admin
-from django.db.models import Sum, Count
+from django.db.models import Count, Sum
from django.template.defaultfilters import pluralize
from django.utils import timezone
-from django import forms
-from dal.autocomplete import ModelSelect2
-
-from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
- Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente
+from bda.models import (
+ Attribution,
+ CategorieSpectacle,
+ ChoixSpectacle,
+ Participant,
+ Quote,
+ Salle,
+ Spectacle,
+ SpectacleRevente,
+ Tirage,
+)
class ReadOnlyMixin(object):
@@ -27,8 +35,8 @@ class ReadOnlyMixin(object):
class ChoixSpectacleAdminForm(forms.ModelForm):
class Meta:
widgets = {
- 'participant': ModelSelect2(url='bda-participant-autocomplete'),
- 'spectacle': ModelSelect2(url='bda-spectacle-autocomplete'),
+ "participant": ModelSelect2(url="bda-participant-autocomplete"),
+ "spectacle": ModelSelect2(url="bda-spectacle-autocomplete"),
}
@@ -43,10 +51,10 @@ class AttributionTabularAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- spectacles = Spectacle.objects.select_related('location')
+ spectacles = Spectacle.objects.select_related("location")
if self.listing is not None:
spectacles = spectacles.filter(listing=self.listing)
- self.fields['spectacle'].queryset = spectacles
+ self.fields["spectacle"].queryset = spectacles
class WithoutListingAttributionTabularAdminForm(AttributionTabularAdminForm):
@@ -70,7 +78,7 @@ class AttributionInline(admin.TabularInline):
class WithListingAttributionInline(AttributionInline):
- exclude = ('given', )
+ exclude = ("given",)
form = WithListingAttributionTabularAdminForm
listing = True
@@ -81,12 +89,10 @@ class WithoutListingAttributionInline(AttributionInline):
class ParticipantAdminForm(forms.ModelForm):
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['choicesrevente'].queryset = (
- Spectacle.objects
- .select_related('location')
+ self.fields["choicesrevente"].queryset = Spectacle.objects.select_related(
+ "location"
)
@@ -94,11 +100,13 @@ class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin):
inlines = [WithListingAttributionInline, WithoutListingAttributionInline]
def get_queryset(self, request):
- return Participant.objects.annotate(nb_places=Count('attributions'),
- total=Sum('attributions__price'))
+ return Participant.objects.annotate(
+ nb_places=Count("attributions"), total=Sum("attributions__price")
+ )
def nb_places(self, obj):
return obj.nb_places
+
nb_places.admin_order_field = "nb_places"
nb_places.short_description = "Nombre de places"
@@ -108,33 +116,32 @@ class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin):
return "%.02f €" % tot
else:
return "0 €"
+
total.admin_order_field = "total"
total.short_description = "Total à payer"
- list_display = ("user", "nb_places", "total", "paid", "paymenttype",
- "tirage")
+ list_display = ("user", "nb_places", "total", "paid", "paymenttype", "tirage")
list_filter = ("paid", "tirage")
- search_fields = ('user__username', 'user__first_name', 'user__last_name')
- actions = ['send_attribs', ]
+ search_fields = ("user__username", "user__first_name", "user__last_name")
+ actions = ["send_attribs"]
actions_on_bottom = True
list_per_page = 400
readonly_fields = ("total",)
- readonly_fields_update = ('user', 'tirage')
+ readonly_fields_update = ("user", "tirage")
form = ParticipantAdminForm
def send_attribs(self, request, queryset):
datatuple = []
for member in queryset.all():
attribs = member.attributions.all()
- context = {'member': member.user}
+ context = {"member": member.user}
shortname = ""
if len(attribs) == 0:
shortname = "bda-attributions-decus"
else:
shortname = "bda-attributions"
- context['places'] = attribs
+ context["places"] = attribs
print(context)
- datatuple.append((shortname, context, "bda@ens.fr",
- [member.user.email]))
+ datatuple.append((shortname, context, "bda@ens.fr", [member.user.email]))
send_mass_custom_mail(datatuple)
count = len(queryset.all())
if count == 1:
@@ -143,24 +150,23 @@ class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin):
else:
message_bit = "%d membres ont" % count
plural = "s"
- self.message_user(request, "%s été informé%s avec succès."
- % (message_bit, plural))
+ self.message_user(
+ request, "%s été informé%s avec succès." % (message_bit, plural)
+ )
+
send_attribs.short_description = "Envoyer les résultats par mail"
class AttributionAdminForm(forms.ModelForm):
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if 'spectacle' in self.fields:
- self.fields['spectacle'].queryset = (
- Spectacle.objects
- .select_related('location')
+ if "spectacle" in self.fields:
+ self.fields["spectacle"].queryset = Spectacle.objects.select_related(
+ "location"
)
- if 'participant' in self.fields:
- self.fields['participant'].queryset = (
- Participant.objects
- .select_related('user', 'tirage')
+ if "participant" in self.fields:
+ self.fields["participant"].queryset = Participant.objects.select_related(
+ "user", "tirage"
)
def clean(self):
@@ -171,21 +177,26 @@ class AttributionAdminForm(forms.ModelForm):
if participant.tirage != spectacle.tirage:
raise forms.ValidationError(
"Erreur : le participant et le spectacle n'appartiennent"
- "pas au même tirage")
+ "pas au même tirage"
+ )
return cleaned_data
class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin):
def paid(self, obj):
return obj.participant.paid
- paid.short_description = 'A payé'
+
+ paid.short_description = "A payé"
paid.boolean = True
list_display = ("id", "spectacle", "participant", "given", "paid")
- search_fields = ('spectacle__title', 'participant__user__username',
- 'participant__user__first_name',
- 'participant__user__last_name')
+ search_fields = (
+ "spectacle__title",
+ "participant__user__username",
+ "participant__user__first_name",
+ "participant__user__last_name",
+ )
form = AttributionAdminForm
- readonly_fields_update = ('spectacle', 'participant')
+ readonly_fields_update = ("spectacle", "participant")
class ChoixSpectacleAdmin(admin.ModelAdmin):
@@ -193,13 +204,15 @@ class ChoixSpectacleAdmin(admin.ModelAdmin):
def tirage(self, obj):
return obj.participant.tirage
- list_display = ("participant", "tirage", "spectacle", "priority",
- "double_choice")
+
+ list_display = ("participant", "tirage", "spectacle", "priority", "double_choice")
list_filter = ("double_choice", "participant__tirage")
- search_fields = ('participant__user__username',
- 'participant__user__first_name',
- 'participant__user__last_name',
- 'spectacle__title')
+ search_fields = (
+ "participant__user__username",
+ "participant__user__first_name",
+ "participant__user__last_name",
+ "spectacle__title",
+ )
class QuoteInline(admin.TabularInline):
@@ -209,42 +222,36 @@ class QuoteInline(admin.TabularInline):
class SpectacleAdmin(admin.ModelAdmin):
inlines = [QuoteInline]
model = Spectacle
- list_display = ("title", "date", "tirage", "location", "slots", "price",
- "listing")
- list_filter = ("location", "tirage",)
+ list_display = ("title", "date", "tirage", "location", "slots", "price", "listing")
+ list_filter = ("location", "tirage")
search_fields = ("title", "location__name")
- readonly_fields = ("rappel_sent", )
+ readonly_fields = ("rappel_sent",)
class TirageAdmin(admin.ModelAdmin):
model = Tirage
- list_display = ("title", "ouverture", "fermeture", "active",
- "enable_do_tirage")
- readonly_fields = ("tokens", )
- list_filter = ("active", )
- search_fields = ("title", )
+ list_display = ("title", "ouverture", "fermeture", "active", "enable_do_tirage")
+ readonly_fields = ("tokens",)
+ list_filter = ("active",)
+ search_fields = ("title",)
class SalleAdmin(admin.ModelAdmin):
model = Salle
- search_fields = ('name', 'address')
+ search_fields = ("name", "address")
class SpectacleReventeAdminForm(forms.ModelForm):
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['confirmed_entry'].queryset = (
- Participant.objects
- .select_related('user', 'tirage')
+ self.fields["confirmed_entry"].queryset = Participant.objects.select_related(
+ "user", "tirage"
)
- self.fields['seller'].queryset = (
- Participant.objects
- .select_related('user', 'tirage')
+ self.fields["seller"].queryset = Participant.objects.select_related(
+ "user", "tirage"
)
- self.fields['soldTo'].queryset = (
- Participant.objects
- .select_related('user', 'tirage')
+ self.fields["soldTo"].queryset = Participant.objects.select_related(
+ "user", "tirage"
)
@@ -252,6 +259,7 @@ class SpectacleReventeAdmin(admin.ModelAdmin):
"""
Administration des reventes de spectacles
"""
+
model = SpectacleRevente
def spectacle(self, obj):
@@ -263,12 +271,14 @@ class SpectacleReventeAdmin(admin.ModelAdmin):
list_display = ("spectacle", "seller", "date", "soldTo")
raw_id_fields = ("attribution",)
readonly_fields = ("date_tirage",)
- search_fields = ['attribution__spectacle__title',
- 'seller__user__username',
- 'seller__user__first_name',
- 'seller__user__last_name']
+ search_fields = [
+ "attribution__spectacle__title",
+ "seller__user__username",
+ "seller__user__first_name",
+ "seller__user__last_name",
+ ]
- actions = ['transfer', 'reinit']
+ actions = ["transfer", "reinit"]
actions_on_bottom = True
form = SpectacleReventeAdminForm
@@ -284,10 +294,10 @@ class SpectacleReventeAdmin(admin.ModelAdmin):
attrib.save()
self.message_user(
request,
- "%d attribution%s %s été transférée%s avec succès." % (
- count, pluralize(count),
- pluralize(count, "a,ont"), pluralize(count))
- )
+ "%d attribution%s %s été transférée%s avec succès."
+ % (count, pluralize(count), pluralize(count, "a,ont"), pluralize(count)),
+ )
+
transfer.short_description = "Transférer les reventes sélectionnées"
def reinit(self, request, queryset):
@@ -296,14 +306,15 @@ class SpectacleReventeAdmin(admin.ModelAdmin):
"""
count = queryset.count()
for revente in queryset.filter(
- attribution__spectacle__date__gte=timezone.now()):
+ attribution__spectacle__date__gte=timezone.now()
+ ):
revente.reset(new_date=timezone.now() - timedelta(hours=1))
self.message_user(
request,
- "%d attribution%s %s été réinitialisée%s avec succès." % (
- count, pluralize(count),
- pluralize(count, "a,ont"), pluralize(count))
- )
+ "%d attribution%s %s été réinitialisée%s avec succès."
+ % (count, pluralize(count), pluralize(count, "a,ont"), pluralize(count)),
+ )
+
reinit.short_description = "Réinitialiser les reventes sélectionnées"
diff --git a/bda/algorithm.py b/bda/algorithm.py
index f0f48ad9..add09335 100644
--- a/bda/algorithm.py
+++ b/bda/algorithm.py
@@ -1,5 +1,3 @@
-from django.db.models import Max
-
import random
@@ -16,7 +14,7 @@ class Algorithm(object):
show.requests
- on crée des tables de demandes pour chaque personne, afin de
pouvoir modifier les rankings"""
- self.max_group = 2*max(choice.priority for choice in choices)
+ self.max_group = 2 * max(choice.priority for choice in choices)
self.shows = []
showdict = {}
for show in shows:
@@ -54,16 +52,19 @@ class Algorithm(object):
self.ranks[member][show] -= increment
def appendResult(self, l, member, show):
- l.append((member,
- self.ranks[member][show],
- self.origranks[member][show],
- self.choices[member][show].double))
+ l.append(
+ (
+ member,
+ self.ranks[member][show],
+ self.origranks[member][show],
+ self.choices[member][show].double,
+ )
+ )
def __call__(self, seed):
random.seed(seed)
results = []
- shows = sorted(self.shows, key=lambda x: x.nrequests / x.slots,
- reverse=True)
+ shows = sorted(self.shows, key=lambda x: x.nrequests / x.slots, reverse=True)
for show in shows:
# On regroupe tous les gens ayant le même rang
groups = dict([(i, []) for i in range(1, self.max_group + 1)])
@@ -82,8 +83,10 @@ class Algorithm(object):
if len(winners) + 1 < show.slots:
self.appendResult(winners, member, show)
self.appendResult(winners, member, show)
- elif not self.choices[member][show].autoquit \
- and len(winners) < show.slots:
+ elif (
+ not self.choices[member][show].autoquit
+ and len(winners) < show.slots
+ ):
self.appendResult(winners, member, show)
self.appendResult(losers, member, show)
else:
diff --git a/bda/forms.py b/bda/forms.py
index 7e81587a..94a52128 100644
--- a/bda/forms.py
+++ b/bda/forms.py
@@ -6,7 +6,6 @@ from bda.models import Attribution, Spectacle, SpectacleRevente
class InscriptionInlineFormSet(BaseInlineFormSet):
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -16,9 +15,9 @@ class InscriptionInlineFormSet(BaseInlineFormSet):
# set once for all "spectacle" field choices
# - restrict choices to the spectacles of this tirage
# - force_choices avoid many db requests
- spectacles = tirage.spectacle_set.select_related('location')
+ spectacles = tirage.spectacle_set.select_related("location")
choices = [(sp.pk, str(sp)) for sp in spectacles]
- self.force_choices('spectacle', choices)
+ self.force_choices("spectacle", choices)
def force_choices(self, name, choices):
"""Set choices of a field.
@@ -30,7 +29,7 @@ class InscriptionInlineFormSet(BaseInlineFormSet):
for form in self.forms:
field = form.fields[name]
if field.empty_label is not None:
- field.choices = [('', field.empty_label)] + choices
+ field.choices = [("", field.empty_label)] + choices
else:
field.choices = choices
@@ -53,128 +52,128 @@ class ReventeModelMultipleChoiceField(forms.ModelMultipleChoiceField):
label = "{show}{suffix}"
suffix = ""
if self.own:
- # C'est notre propre revente : pas besoin de spécifier le vendeur
+ # C'est notre propre revente : informations sur le statut
if obj.soldTo is not None:
suffix = " -- Vendue à {firstname} {lastname}".format(
- firstname=obj.soldTo.user.first_name,
- lastname=obj.soldTo.user.last_name,
- )
+ firstname=obj.soldTo.user.first_name,
+ lastname=obj.soldTo.user.last_name,
+ )
+ elif obj.shotgun:
+ suffix = " -- Tirage infructueux"
+ elif obj.notif_sent:
+ suffix = " -- Inscriptions au tirage en cours"
else:
# Ce n'est pas à nous : on ne voit jamais l'acheteur
suffix = " -- Vendue par {firstname} {lastname}".format(
- firstname=obj.seller.user.first_name,
- lastname=obj.seller.user.last_name,
- )
+ firstname=obj.seller.user.first_name, lastname=obj.seller.user.last_name
+ )
- return label.format(show=str(obj.attribution.spectacle),
- suffix=suffix)
+ return label.format(show=str(obj.attribution.spectacle), suffix=suffix)
class ResellForm(forms.Form):
attributions = AttributionModelMultipleChoiceField(
- label='',
- queryset=Attribution.objects.none(),
- widget=forms.CheckboxSelectMultiple,
- required=False)
+ label="",
+ queryset=Attribution.objects.none(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
def __init__(self, participant, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['attributions'].queryset = (
- participant.attribution_set
- .filter(spectacle__date__gte=timezone.now())
+ self.fields["attributions"].queryset = (
+ participant.attribution_set.filter(spectacle__date__gte=timezone.now())
.exclude(revente__seller=participant)
- .select_related('spectacle', 'spectacle__location',
- 'participant__user')
+ .select_related("spectacle", "spectacle__location", "participant__user")
)
class AnnulForm(forms.Form):
reventes = ReventeModelMultipleChoiceField(
- own=True,
- label='',
- queryset=Attribution.objects.none(),
- widget=forms.CheckboxSelectMultiple,
- required=False)
+ own=True,
+ label="",
+ queryset=Attribution.objects.none(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
def __init__(self, participant, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['reventes'].queryset = (
- participant.original_shows
- .filter(attribution__spectacle__date__gte=timezone.now(),
- notif_sent=False,
- soldTo__isnull=True)
- .select_related('attribution__spectacle',
- 'attribution__spectacle__location')
+ self.fields["reventes"].queryset = (
+ participant.original_shows.filter(
+ attribution__spectacle__date__gte=timezone.now(), soldTo__isnull=True
+ )
+ .select_related(
+ "attribution__spectacle", "attribution__spectacle__location"
+ )
+ .order_by("-date")
)
class InscriptionReventeForm(forms.Form):
spectacles = forms.ModelMultipleChoiceField(
- queryset=Spectacle.objects.none(),
- widget=forms.CheckboxSelectMultiple,
- required=False)
+ queryset=Spectacle.objects.none(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
def __init__(self, tirage, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['spectacles'].queryset = (
- tirage.spectacle_set
- .select_related('location')
- .filter(date__gte=timezone.now())
- )
+ self.fields["spectacles"].queryset = tirage.spectacle_set.select_related(
+ "location"
+ ).filter(date__gte=timezone.now())
class ReventeTirageAnnulForm(forms.Form):
reventes = ReventeModelMultipleChoiceField(
- own=False,
- label='',
- queryset=SpectacleRevente.objects.none(),
- widget=forms.CheckboxSelectMultiple,
- required=False
- )
+ own=False,
+ label="",
+ queryset=SpectacleRevente.objects.none(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
def __init__(self, participant, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['reventes'].queryset = (
- participant.entered.filter(soldTo__isnull=True)
- .select_related('attribution__spectacle',
- 'seller__user')
- )
+ self.fields["reventes"].queryset = participant.entered.filter(
+ soldTo__isnull=True
+ ).select_related("attribution__spectacle", "seller__user")
class ReventeTirageForm(forms.Form):
reventes = ReventeModelMultipleChoiceField(
- own=False,
- label='',
- queryset=SpectacleRevente.objects.none(),
- widget=forms.CheckboxSelectMultiple,
- required=False
- )
+ own=False,
+ label="",
+ queryset=SpectacleRevente.objects.none(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
def __init__(self, participant, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['reventes'].queryset = (
+ self.fields["reventes"].queryset = (
SpectacleRevente.objects.filter(
- notif_sent=True,
- shotgun=False,
- tirage_done=False
- ).exclude(confirmed_entry=participant)
- .select_related('attribution__spectacle')
+ notif_sent=True, shotgun=False, tirage_done=False
+ )
+ .exclude(confirmed_entry=participant)
+ .select_related("attribution__spectacle")
)
class SoldForm(forms.Form):
reventes = ReventeModelMultipleChoiceField(
- own=True,
- label='',
- queryset=Attribution.objects.none(),
- widget=forms.CheckboxSelectMultiple)
+ own=True,
+ label="",
+ queryset=Attribution.objects.none(),
+ widget=forms.CheckboxSelectMultiple,
+ )
def __init__(self, participant, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['reventes'].queryset = (
- participant.original_shows
- .filter(soldTo__isnull=False)
+ self.fields["reventes"].queryset = (
+ participant.original_shows.filter(soldTo__isnull=False)
.exclude(soldTo=participant)
- .select_related('attribution__spectacle',
- 'attribution__spectacle__location')
+ .select_related(
+ "attribution__spectacle", "attribution__spectacle__location"
+ )
)
diff --git a/bda/management/commands/loadbdadevdata.py b/bda/management/commands/loadbdadevdata.py
index a8e3f298..a608db6a 100644
--- a/bda/management/commands/loadbdadevdata.py
+++ b/bda/management/commands/loadbdadevdata.py
@@ -5,17 +5,15 @@ Crée deux tirages de test et y inscrit les utilisateurs
import os
import random
-from django.utils import timezone
from django.contrib.auth.models import User
+from django.utils import timezone
-from gestioncof.management.base import MyBaseCommand
-from bda.models import Tirage, Spectacle, Salle, Participant, ChoixSpectacle
+from bda.models import ChoixSpectacle, Participant, Salle, Spectacle, Tirage
from bda.views import do_tirage
-
+from gestioncof.management.base import MyBaseCommand
# Où sont stockés les fichiers json
-DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
- 'data')
+DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
class Command(MyBaseCommand):
@@ -27,27 +25,29 @@ class Command(MyBaseCommand):
# ---
Tirage.objects.all().delete()
- Tirage.objects.bulk_create([
- Tirage(
- title="Tirage de test 1",
- ouverture=timezone.now()-timezone.timedelta(days=7),
- fermeture=timezone.now(),
- active=True
- ),
- Tirage(
- title="Tirage de test 2",
- ouverture=timezone.now(),
- fermeture=timezone.now()+timezone.timedelta(days=60),
- active=True
- )
- ])
+ Tirage.objects.bulk_create(
+ [
+ Tirage(
+ title="Tirage de test 1",
+ ouverture=timezone.now() - timezone.timedelta(days=7),
+ fermeture=timezone.now(),
+ active=True,
+ ),
+ Tirage(
+ title="Tirage de test 2",
+ ouverture=timezone.now(),
+ fermeture=timezone.now() + timezone.timedelta(days=60),
+ active=True,
+ ),
+ ]
+ )
tirages = Tirage.objects.all()
# ---
# Salles
# ---
- locations = self.from_json('locations.json', DATA_DIR, Salle)
+ locations = self.from_json("locations.json", DATA_DIR, Salle)
# ---
# Spectacles
@@ -60,15 +60,13 @@ class Command(MyBaseCommand):
"""
show.tirage = random.choice(tirages)
show.listing = bool(random.randint(0, 1))
- show.date = (
- show.tirage.fermeture
- + timezone.timedelta(days=random.randint(60, 90))
+ show.date = show.tirage.fermeture + timezone.timedelta(
+ days=random.randint(60, 90)
)
show.location = random.choice(locations)
return show
- shows = self.from_json(
- 'shows.json', DATA_DIR, Spectacle, show_callback
- )
+
+ shows = self.from_json("shows.json", DATA_DIR, Spectacle, show_callback)
# ---
# Inscriptions
@@ -79,23 +77,19 @@ class Command(MyBaseCommand):
choices = []
for user in User.objects.filter(profile__is_cof=True):
for tirage in tirages:
- part, _ = Participant.objects.get_or_create(
- user=user,
- tirage=tirage
- )
+ part, _ = Participant.objects.get_or_create(user=user, tirage=tirage)
shows = random.sample(
- list(tirage.spectacle_set.all()),
- tirage.spectacle_set.count() // 2
+ list(tirage.spectacle_set.all()), tirage.spectacle_set.count() // 2
)
for (rank, show) in enumerate(shows):
- choices.append(ChoixSpectacle(
- participant=part,
- spectacle=show,
- priority=rank + 1,
- double_choice=random.choice(
- ['1', 'double', 'autoquit']
+ choices.append(
+ ChoixSpectacle(
+ participant=part,
+ spectacle=show,
+ priority=rank + 1,
+ double_choice=random.choice(["1", "double", "autoquit"]),
)
- ))
+ )
ChoixSpectacle.objects.bulk_create(choices)
self.stdout.write("- {:d} inscriptions générées".format(len(choices)))
diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py
index 5a06d40b..bd25a28e 100644
--- a/bda/management/commands/manage_reventes.py
+++ b/bda/management/commands/manage_reventes.py
@@ -4,12 +4,14 @@ Gestion en ligne de commande des reventes.
from django.core.management import BaseCommand
from django.utils import timezone
+
from bda.models import SpectacleRevente
class Command(BaseCommand):
- help = "Envoie les mails de notification et effectue " \
- "les tirages au sort des reventes"
+ help = (
+ "Envoie les mails de notification et effectue les tirages au sort des reventes"
+ )
leave_locale_alone = True
def handle(self, *args, **options):
@@ -28,22 +30,18 @@ class Command(BaseCommand):
)
# Le spectacle est dans plus longtemps : on prévient
- elif (revente.can_notif and not revente.notif_sent):
+ elif revente.can_notif and not revente.notif_sent:
self.stdout.write(str(now))
revente.send_notif()
self.stdout.write(
- "Mails d'inscription à la revente [%s] envoyés"
- % revente
+ "Mails d'inscription à la revente [%s] envoyés" % revente
)
# On fait le tirage
- elif (now >= revente.date_tirage and not revente.tirage_done):
+ elif now >= revente.date_tirage and not revente.tirage_done:
self.stdout.write(str(now))
winner = revente.tirage()
- self.stdout.write(
- "Tirage effectué pour la revente [%s]"
- % revente
- )
+ self.stdout.write("Tirage effectué pour la revente [%s]" % revente)
if winner:
self.stdout.write("Gagnant : %s" % winner.user)
diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py
index 82889f80..65026736 100644
--- a/bda/management/commands/sendrappels.py
+++ b/bda/management/commands/sendrappels.py
@@ -3,27 +3,31 @@ Gestion en ligne de commande des mails de rappel.
"""
from datetime import timedelta
+
from django.core.management.base import BaseCommand
from django.utils import timezone
+
from bda.models import Spectacle
class Command(BaseCommand):
- help = 'Envoie les mails de rappel des spectacles dont la date ' \
- 'approche.\nNe renvoie pas les mails déjà envoyés.'
+ help = (
+ "Envoie les mails de rappel des spectacles dont la date approche.\n"
+ "Ne renvoie pas les mails déjà envoyés."
+ )
leave_locale_alone = True
def handle(self, *args, **options):
now = timezone.now()
delay = timedelta(days=4)
- shows = Spectacle.objects \
- .filter(date__range=(now, now+delay)) \
- .filter(tirage__active=True) \
- .filter(rappel_sent__isnull=True) \
+ shows = (
+ Spectacle.objects.filter(date__range=(now, now + delay))
+ .filter(tirage__active=True)
+ .filter(rappel_sent__isnull=True)
.all()
+ )
for show in shows:
show.send_rappel()
- self.stdout.write(
- 'Mails de rappels pour %s envoyés avec succès.' % show)
+ self.stdout.write("Mails de rappels pour %s envoyés avec succès." % show)
if not shows:
- self.stdout.write('Aucun mail à envoyer.')
+ self.stdout.write("Aucun mail à envoyer.")
diff --git a/bda/migrations/0001_initial.py b/bda/migrations/0001_initial.py
index c4494413..077ddd4e 100644
--- a/bda/migrations/0001_initial.py
+++ b/bda/migrations/0001_initial.py
@@ -1,108 +1,206 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ]
+ dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]
operations = [
migrations.CreateModel(
- name='Attribution',
+ name="Attribution",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('given', models.BooleanField(default=False, verbose_name='Donn\xe9e')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("given", models.BooleanField(default=False, verbose_name="Donn\xe9e")),
],
),
migrations.CreateModel(
- name='ChoixSpectacle',
+ name="ChoixSpectacle",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('priority', models.PositiveIntegerField(verbose_name=b'Priorit\xc3\xa9')),
- ('double_choice', models.CharField(default=b'1', max_length=10, verbose_name=b'Nombre de places', choices=[(b'1', b'1 place'), (b'autoquit', b'2 places si possible, 1 sinon'), (b'double', b'2 places sinon rien')])),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "priority",
+ models.PositiveIntegerField(verbose_name=b"Priorit\xc3\xa9"),
+ ),
+ (
+ "double_choice",
+ models.CharField(
+ default=b"1",
+ max_length=10,
+ verbose_name=b"Nombre de places",
+ choices=[
+ (b"1", b"1 place"),
+ (b"autoquit", b"2 places si possible, 1 sinon"),
+ (b"double", b"2 places sinon rien"),
+ ],
+ ),
+ ),
],
options={
- 'ordering': ('priority',),
- 'verbose_name': 'voeu',
- 'verbose_name_plural': 'voeux',
+ "ordering": ("priority",),
+ "verbose_name": "voeu",
+ "verbose_name_plural": "voeux",
},
),
migrations.CreateModel(
- name='Participant',
+ name="Participant",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('paid', models.BooleanField(default=False, verbose_name='A pay\xe9')),
- ('paymenttype', models.CharField(blank=True, max_length=6, verbose_name='Moyen de paiement', choices=[(b'cash', 'Cash'), (b'cb', b'CB'), (b'cheque', 'Ch\xe8que'), (b'autre', 'Autre')])),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("paid", models.BooleanField(default=False, verbose_name="A pay\xe9")),
+ (
+ "paymenttype",
+ models.CharField(
+ blank=True,
+ max_length=6,
+ verbose_name="Moyen de paiement",
+ choices=[
+ (b"cash", "Cash"),
+ (b"cb", b"CB"),
+ (b"cheque", "Ch\xe8que"),
+ (b"autre", "Autre"),
+ ],
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Salle',
+ name="Salle",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=300, verbose_name=b'Nom')),
- ('address', models.TextField(verbose_name=b'Adresse')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("name", models.CharField(max_length=300, verbose_name=b"Nom")),
+ ("address", models.TextField(verbose_name=b"Adresse")),
],
),
migrations.CreateModel(
- name='Spectacle',
+ name="Spectacle",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('title', models.CharField(max_length=300, verbose_name=b'Titre')),
- ('date', models.DateTimeField(verbose_name=b'Date & heure')),
- ('description', models.TextField(verbose_name=b'Description', blank=True)),
- ('slots_description', models.TextField(verbose_name=b'Description des places', blank=True)),
- ('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)),
- ('slots', models.IntegerField(verbose_name=b'Places')),
- ('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')),
- ('location', models.ForeignKey(to='bda.Salle', on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("title", models.CharField(max_length=300, verbose_name=b"Titre")),
+ ("date", models.DateTimeField(verbose_name=b"Date & heure")),
+ (
+ "description",
+ models.TextField(verbose_name=b"Description", blank=True),
+ ),
+ (
+ "slots_description",
+ models.TextField(
+ verbose_name=b"Description des places", blank=True
+ ),
+ ),
+ (
+ "price",
+ models.FloatField(verbose_name=b"Prix d'une place", blank=True),
+ ),
+ ("slots", models.IntegerField(verbose_name=b"Places")),
+ (
+ "priority",
+ models.IntegerField(default=1000, verbose_name=b"Priorit\xc3\xa9"),
+ ),
+ (
+ "location",
+ models.ForeignKey(to="bda.Salle", on_delete=models.CASCADE),
+ ),
],
options={
- 'ordering': ('priority', 'date', 'title'),
- 'verbose_name': 'Spectacle',
+ "ordering": ("priority", "date", "title"),
+ "verbose_name": "Spectacle",
},
),
migrations.AddField(
- model_name='participant',
- name='attributions',
- field=models.ManyToManyField(related_name='attributed_to', through='bda.Attribution', to='bda.Spectacle'),
+ model_name="participant",
+ name="attributions",
+ field=models.ManyToManyField(
+ related_name="attributed_to",
+ through="bda.Attribution",
+ to="bda.Spectacle",
+ ),
),
migrations.AddField(
- model_name='participant',
- name='choices',
- field=models.ManyToManyField(related_name='chosen_by', through='bda.ChoixSpectacle', to='bda.Spectacle'),
+ model_name="participant",
+ name="choices",
+ field=models.ManyToManyField(
+ related_name="chosen_by",
+ through="bda.ChoixSpectacle",
+ to="bda.Spectacle",
+ ),
),
migrations.AddField(
- model_name='participant',
- name='user',
- field=models.OneToOneField(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ model_name="participant",
+ name="user",
+ field=models.OneToOneField(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
),
migrations.AddField(
- model_name='choixspectacle',
- name='participant',
- field=models.ForeignKey(to='bda.Participant', on_delete=models.CASCADE),
+ model_name="choixspectacle",
+ name="participant",
+ field=models.ForeignKey(to="bda.Participant", on_delete=models.CASCADE),
),
migrations.AddField(
- model_name='choixspectacle',
- name='spectacle',
- field=models.ForeignKey(related_name='participants', to='bda.Spectacle', on_delete=models.CASCADE),
+ model_name="choixspectacle",
+ name="spectacle",
+ field=models.ForeignKey(
+ related_name="participants",
+ to="bda.Spectacle",
+ on_delete=models.CASCADE,
+ ),
),
migrations.AddField(
- model_name='attribution',
- name='participant',
- field=models.ForeignKey(to='bda.Participant', on_delete=models.CASCADE),
+ model_name="attribution",
+ name="participant",
+ field=models.ForeignKey(to="bda.Participant", on_delete=models.CASCADE),
),
migrations.AddField(
- model_name='attribution',
- name='spectacle',
- field=models.ForeignKey(related_name='attribues', to='bda.Spectacle', on_delete=models.CASCADE),
+ model_name="attribution",
+ name="spectacle",
+ field=models.ForeignKey(
+ related_name="attribues", to="bda.Spectacle", on_delete=models.CASCADE
+ ),
),
migrations.AlterUniqueTogether(
- name='choixspectacle',
- unique_together=set([('participant', 'spectacle')]),
+ name="choixspectacle", unique_together=set([("participant", "spectacle")])
),
]
diff --git a/bda/migrations/0002_add_tirage.py b/bda/migrations/0002_add_tirage.py
index 79f79a57..f4b01ed2 100644
--- a/bda/migrations/0002_add_tirage.py
+++ b/bda/migrations/0002_add_tirage.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
from django.conf import settings
+from django.db import migrations, models
from django.utils import timezone
@@ -36,49 +36,77 @@ def fill_tirage_fields(apps, schema_editor):
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0001_initial'),
- ]
+ dependencies = [("bda", "0001_initial")]
operations = [
migrations.CreateModel(
- name='Tirage',
+ name="Tirage",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('title', models.CharField(max_length=300, verbose_name=b'Titre')),
- ('ouverture', models.DateTimeField(verbose_name=b"Date et heure d'ouverture du tirage")),
- ('fermeture', models.DateTimeField(verbose_name=b'Date et heure de fermerture du tirage')),
- ('token', models.TextField(verbose_name=b'Graine du tirage', blank=True)),
- ('active', models.BooleanField(default=True, verbose_name=b'Tirage actif')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("title", models.CharField(max_length=300, verbose_name=b"Titre")),
+ (
+ "ouverture",
+ models.DateTimeField(
+ verbose_name=b"Date et heure d'ouverture du tirage"
+ ),
+ ),
+ (
+ "fermeture",
+ models.DateTimeField(
+ verbose_name=b"Date et heure de fermerture du tirage"
+ ),
+ ),
+ (
+ "token",
+ models.TextField(verbose_name=b"Graine du tirage", blank=True),
+ ),
+ (
+ "active",
+ models.BooleanField(default=True, verbose_name=b"Tirage actif"),
+ ),
],
),
migrations.AlterField(
- model_name='participant',
- name='user',
- field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ model_name="participant",
+ name="user",
+ field=models.ForeignKey(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
),
# Create fields `spectacle` for `Participant` and `Spectacle` models.
# These fields are not nullable, but we first create them as nullable
# to give a default value for existing instances of these models.
migrations.AddField(
- model_name='participant',
- name='tirage',
- field=models.ForeignKey(to='bda.Tirage', null=True, on_delete=models.CASCADE),
+ model_name="participant",
+ name="tirage",
+ field=models.ForeignKey(
+ to="bda.Tirage", null=True, on_delete=models.CASCADE
+ ),
),
migrations.AddField(
- model_name='spectacle',
- name='tirage',
- field=models.ForeignKey(to='bda.Tirage', null=True, on_delete=models.CASCADE),
+ model_name="spectacle",
+ name="tirage",
+ field=models.ForeignKey(
+ to="bda.Tirage", null=True, on_delete=models.CASCADE
+ ),
),
migrations.RunPython(fill_tirage_fields, migrations.RunPython.noop),
migrations.AlterField(
- model_name='participant',
- name='tirage',
- field=models.ForeignKey(to='bda.Tirage', on_delete=models.CASCADE),
+ model_name="participant",
+ name="tirage",
+ field=models.ForeignKey(to="bda.Tirage", on_delete=models.CASCADE),
),
migrations.AlterField(
- model_name='spectacle',
- name='tirage',
- field=models.ForeignKey(to='bda.Tirage', on_delete=models.CASCADE),
+ model_name="spectacle",
+ name="tirage",
+ field=models.ForeignKey(to="bda.Tirage", on_delete=models.CASCADE),
),
]
diff --git a/bda/migrations/0003_update_tirage_and_spectacle.py b/bda/migrations/0003_update_tirage_and_spectacle.py
index f5ca671a..3548eb88 100644
--- a/bda/migrations/0003_update_tirage_and_spectacle.py
+++ b/bda/migrations/0003_update_tirage_and_spectacle.py
@@ -6,19 +6,17 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0002_add_tirage'),
- ]
+ dependencies = [("bda", "0002_add_tirage")]
operations = [
migrations.AlterField(
- model_name='spectacle',
- name='price',
+ model_name="spectacle",
+ name="price",
field=models.FloatField(verbose_name=b"Prix d'une place"),
),
migrations.AlterField(
- model_name='tirage',
- name='active',
- field=models.BooleanField(default=False, verbose_name=b'Tirage actif'),
+ model_name="tirage",
+ name="active",
+ field=models.BooleanField(default=False, verbose_name=b"Tirage actif"),
),
]
diff --git a/bda/migrations/0004_mails-rappel.py b/bda/migrations/0004_mails-rappel.py
index f17b711f..d331568a 100644
--- a/bda/migrations/0004_mails-rappel.py
+++ b/bda/migrations/0004_mails-rappel.py
@@ -6,20 +6,22 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0003_update_tirage_and_spectacle'),
- ]
+ dependencies = [("bda", "0003_update_tirage_and_spectacle")]
operations = [
migrations.AddField(
- model_name='spectacle',
- name='listing',
- field=models.BooleanField(default=False, verbose_name=b'Les places sont sur listing'),
+ model_name="spectacle",
+ name="listing",
+ field=models.BooleanField(
+ default=False, verbose_name=b"Les places sont sur listing"
+ ),
preserve_default=False,
),
migrations.AddField(
- model_name='spectacle',
- name='rappel_sent',
- field=models.DateTimeField(null=True, verbose_name=b'Mail de rappel envoy\xc3\xa9', blank=True),
+ model_name="spectacle",
+ name="rappel_sent",
+ field=models.DateTimeField(
+ null=True, verbose_name=b"Mail de rappel envoy\xc3\xa9", blank=True
+ ),
),
]
diff --git a/bda/migrations/0005_encoding.py b/bda/migrations/0005_encoding.py
index b36113c2..eedfcee4 100644
--- a/bda/migrations/0005_encoding.py
+++ b/bda/migrations/0005_encoding.py
@@ -6,24 +6,24 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0004_mails-rappel'),
- ]
+ dependencies = [("bda", "0004_mails-rappel")]
operations = [
migrations.AlterField(
- model_name='choixspectacle',
- name='priority',
- field=models.PositiveIntegerField(verbose_name='Priorit\xe9'),
+ model_name="choixspectacle",
+ name="priority",
+ field=models.PositiveIntegerField(verbose_name="Priorit\xe9"),
),
migrations.AlterField(
- model_name='spectacle',
- name='priority',
- field=models.IntegerField(default=1000, verbose_name='Priorit\xe9'),
+ model_name="spectacle",
+ name="priority",
+ field=models.IntegerField(default=1000, verbose_name="Priorit\xe9"),
),
migrations.AlterField(
- model_name='spectacle',
- name='rappel_sent',
- field=models.DateTimeField(null=True, verbose_name='Mail de rappel envoy\xe9', blank=True),
+ model_name="spectacle",
+ name="rappel_sent",
+ field=models.DateTimeField(
+ null=True, verbose_name="Mail de rappel envoy\xe9", blank=True
+ ),
),
]
diff --git a/bda/migrations/0006_add_tirage_switch.py b/bda/migrations/0006_add_tirage_switch.py
index fc923c9a..ccfe7505 100644
--- a/bda/migrations/0006_add_tirage_switch.py
+++ b/bda/migrations/0006_add_tirage_switch.py
@@ -10,26 +10,25 @@ def forwards_func(apps, schema_editor):
db_alias = schema_editor.connection.alias
for tirage in Tirage.objects.using(db_alias).all():
if tirage.tokens:
- tirage.tokens = "Before %s\n\"\"\"%s\"\"\"\n" % (
- timezone.now().strftime("%y-%m-%d %H:%M:%S"),
- tirage.tokens)
+ tirage.tokens = 'Before %s\n"""%s"""\n' % (
+ timezone.now().strftime("%y-%m-%d %H:%M:%S"),
+ tirage.tokens,
+ )
tirage.save()
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0005_encoding'),
- ]
+ dependencies = [("bda", "0005_encoding")]
operations = [
- migrations.RenameField('tirage', 'token', 'tokens'),
+ migrations.RenameField("tirage", "token", "tokens"),
migrations.AddField(
- model_name='tirage',
- name='enable_do_tirage',
+ model_name="tirage",
+ name="enable_do_tirage",
field=models.BooleanField(
- default=False,
- verbose_name=b'Le tirage peut \xc3\xaatre lanc\xc3\xa9'),
+ default=False, verbose_name=b"Le tirage peut \xc3\xaatre lanc\xc3\xa9"
+ ),
),
migrations.RunPython(forwards_func, migrations.RunPython.noop),
]
diff --git a/bda/migrations/0007_extends_spectacle.py b/bda/migrations/0007_extends_spectacle.py
index 6ea11dc0..87182ff7 100644
--- a/bda/migrations/0007_extends_spectacle.py
+++ b/bda/migrations/0007_extends_spectacle.py
@@ -1,91 +1,100 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0006_add_tirage_switch'),
- ]
+ dependencies = [("bda", "0006_add_tirage_switch")]
operations = [
migrations.CreateModel(
- name='CategorieSpectacle',
+ name="CategorieSpectacle",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False,
- auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=100, verbose_name='Nom',
- unique=True)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "name",
+ models.CharField(max_length=100, verbose_name="Nom", unique=True),
+ ),
],
- options={
- 'verbose_name': 'Cat\xe9gorie',
- },
+ options={"verbose_name": "Cat\xe9gorie"},
),
migrations.CreateModel(
- name='Quote',
+ name="Quote",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False,
- auto_created=True, primary_key=True)),
- ('text', models.TextField(verbose_name='Citation')),
- ('author', models.CharField(max_length=200,
- verbose_name='Auteur')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("text", models.TextField(verbose_name="Citation")),
+ ("author", models.CharField(max_length=200, verbose_name="Auteur")),
],
),
migrations.AlterModelOptions(
- name='spectacle',
- options={'ordering': ('date', 'title'),
- 'verbose_name': 'Spectacle'},
- ),
- migrations.RemoveField(
- model_name='spectacle',
- name='priority',
+ name="spectacle",
+ options={"ordering": ("date", "title"), "verbose_name": "Spectacle"},
),
+ migrations.RemoveField(model_name="spectacle", name="priority"),
migrations.AddField(
- model_name='spectacle',
- name='ext_link',
+ model_name="spectacle",
+ name="ext_link",
field=models.CharField(
max_length=500,
- verbose_name='Lien vers le site du spectacle',
- blank=True),
+ verbose_name="Lien vers le site du spectacle",
+ blank=True,
+ ),
),
migrations.AddField(
- model_name='spectacle',
- name='image',
- field=models.ImageField(upload_to='imgs/shows/', null=True,
- verbose_name='Image', blank=True),
+ model_name="spectacle",
+ name="image",
+ field=models.ImageField(
+ upload_to="imgs/shows/", null=True, verbose_name="Image", blank=True
+ ),
),
migrations.AlterField(
- model_name='tirage',
- name='enable_do_tirage',
+ model_name="tirage",
+ name="enable_do_tirage",
field=models.BooleanField(
- default=False,
- verbose_name='Le tirage peut \xeatre lanc\xe9'),
+ default=False, verbose_name="Le tirage peut \xeatre lanc\xe9"
+ ),
),
migrations.AlterField(
- model_name='tirage',
- name='tokens',
- field=models.TextField(verbose_name='Graine(s) du tirage',
- blank=True),
+ model_name="tirage",
+ name="tokens",
+ field=models.TextField(verbose_name="Graine(s) du tirage", blank=True),
),
migrations.AddField(
- model_name='spectacle',
- name='category',
- field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle',
- on_delete=models.CASCADE,
- null=True),
+ model_name="spectacle",
+ name="category",
+ field=models.ForeignKey(
+ blank=True,
+ to="bda.CategorieSpectacle",
+ on_delete=models.CASCADE,
+ null=True,
+ ),
),
migrations.AddField(
- model_name='spectacle',
- name='vips',
- field=models.TextField(verbose_name='Personnalit\xe9s',
- blank=True),
+ model_name="spectacle",
+ name="vips",
+ field=models.TextField(verbose_name="Personnalit\xe9s", blank=True),
),
migrations.AddField(
- model_name='quote',
- name='spectacle',
- field=models.ForeignKey(to='bda.Spectacle',
- on_delete=models.CASCADE),
+ model_name="quote",
+ name="spectacle",
+ field=models.ForeignKey(to="bda.Spectacle", on_delete=models.CASCADE),
),
]
diff --git a/bda/migrations/0008_py3.py b/bda/migrations/0008_py3.py
index fe6a8eaf..6aa69abd 100644
--- a/bda/migrations/0008_py3.py
+++ b/bda/migrations/0008_py3.py
@@ -1,103 +1,110 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0007_extends_spectacle'),
- ]
+ dependencies = [("bda", "0007_extends_spectacle")]
operations = [
migrations.AlterField(
- model_name='choixspectacle',
- name='double_choice',
+ model_name="choixspectacle",
+ name="double_choice",
field=models.CharField(
- verbose_name='Nombre de places',
- choices=[('1', '1 place'),
- ('autoquit', '2 places si possible, 1 sinon'),
- ('double', '2 places sinon rien')],
- max_length=10, default='1'),
+ verbose_name="Nombre de places",
+ choices=[
+ ("1", "1 place"),
+ ("autoquit", "2 places si possible, 1 sinon"),
+ ("double", "2 places sinon rien"),
+ ],
+ max_length=10,
+ default="1",
+ ),
),
migrations.AlterField(
- model_name='participant',
- name='paymenttype',
+ model_name="participant",
+ name="paymenttype",
field=models.CharField(
blank=True,
- choices=[('cash', 'Cash'), ('cb', 'CB'),
- ('cheque', 'Chèque'), ('autre', 'Autre')],
- max_length=6, verbose_name='Moyen de paiement'),
+ choices=[
+ ("cash", "Cash"),
+ ("cb", "CB"),
+ ("cheque", "Chèque"),
+ ("autre", "Autre"),
+ ],
+ max_length=6,
+ verbose_name="Moyen de paiement",
+ ),
),
migrations.AlterField(
- model_name='salle',
- name='address',
- field=models.TextField(verbose_name='Adresse'),
+ model_name="salle",
+ name="address",
+ field=models.TextField(verbose_name="Adresse"),
),
migrations.AlterField(
- model_name='salle',
- name='name',
- field=models.CharField(verbose_name='Nom', max_length=300),
+ model_name="salle",
+ name="name",
+ field=models.CharField(verbose_name="Nom", max_length=300),
),
migrations.AlterField(
- model_name='spectacle',
- name='date',
- field=models.DateTimeField(verbose_name='Date & heure'),
+ model_name="spectacle",
+ name="date",
+ field=models.DateTimeField(verbose_name="Date & heure"),
),
migrations.AlterField(
- model_name='spectacle',
- name='description',
- field=models.TextField(verbose_name='Description', blank=True),
+ model_name="spectacle",
+ name="description",
+ field=models.TextField(verbose_name="Description", blank=True),
),
migrations.AlterField(
- model_name='spectacle',
- name='listing',
- field=models.BooleanField(
- verbose_name='Les places sont sur listing'),
+ model_name="spectacle",
+ name="listing",
+ field=models.BooleanField(verbose_name="Les places sont sur listing"),
),
migrations.AlterField(
- model_name='spectacle',
- name='price',
+ model_name="spectacle",
+ name="price",
field=models.FloatField(verbose_name="Prix d'une place"),
),
migrations.AlterField(
- model_name='spectacle',
- name='slots',
- field=models.IntegerField(verbose_name='Places'),
+ model_name="spectacle",
+ name="slots",
+ field=models.IntegerField(verbose_name="Places"),
),
migrations.AlterField(
- model_name='spectacle',
- name='slots_description',
- field=models.TextField(verbose_name='Description des places',
- blank=True),
+ model_name="spectacle",
+ name="slots_description",
+ field=models.TextField(verbose_name="Description des places", blank=True),
),
migrations.AlterField(
- model_name='spectacle',
- name='title',
- field=models.CharField(verbose_name='Titre', max_length=300),
+ model_name="spectacle",
+ name="title",
+ field=models.CharField(verbose_name="Titre", max_length=300),
),
migrations.AlterField(
- model_name='tirage',
- name='active',
- field=models.BooleanField(verbose_name='Tirage actif',
- default=False),
+ model_name="tirage",
+ name="active",
+ field=models.BooleanField(verbose_name="Tirage actif", default=False),
),
migrations.AlterField(
- model_name='tirage',
- name='fermeture',
+ model_name="tirage",
+ name="fermeture",
field=models.DateTimeField(
- verbose_name='Date et heure de fermerture du tirage'),
+ verbose_name="Date et heure de fermerture du tirage"
+ ),
),
migrations.AlterField(
- model_name='tirage',
- name='ouverture',
+ model_name="tirage",
+ name="ouverture",
field=models.DateTimeField(
- verbose_name="Date et heure d'ouverture du tirage"),
+ verbose_name="Date et heure d'ouverture du tirage"
+ ),
),
migrations.AlterField(
- model_name='tirage',
- name='title',
- field=models.CharField(verbose_name='Titre', max_length=300),
+ model_name="tirage",
+ name="title",
+ field=models.CharField(verbose_name="Titre", max_length=300),
),
]
diff --git a/bda/migrations/0009_revente.py b/bda/migrations/0009_revente.py
index 70d6f338..d888140f 100644
--- a/bda/migrations/0009_revente.py
+++ b/bda/migrations/0009_revente.py
@@ -1,69 +1,87 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import django.utils.timezone
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0008_py3'),
- ]
+ dependencies = [("bda", "0008_py3")]
operations = [
migrations.CreateModel(
- name='SpectacleRevente',
+ name="SpectacleRevente",
fields=[
- ('id', models.AutoField(serialize=False, primary_key=True,
- auto_created=True, verbose_name='ID')),
- ('date', models.DateTimeField(
- verbose_name='Date de mise en vente',
- default=django.utils.timezone.now)),
- ('notif_sent', models.BooleanField(
- verbose_name='Notification envoyée', default=False)),
- ('tirage_done', models.BooleanField(
- verbose_name='Tirage effectué', default=False)),
+ (
+ "id",
+ models.AutoField(
+ serialize=False,
+ primary_key=True,
+ auto_created=True,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "date",
+ models.DateTimeField(
+ verbose_name="Date de mise en vente",
+ default=django.utils.timezone.now,
+ ),
+ ),
+ (
+ "notif_sent",
+ models.BooleanField(
+ verbose_name="Notification envoyée", default=False
+ ),
+ ),
+ (
+ "tirage_done",
+ models.BooleanField(verbose_name="Tirage effectué", default=False),
+ ),
],
- options={
- 'verbose_name': 'Revente',
- },
+ options={"verbose_name": "Revente"},
),
migrations.AddField(
- model_name='participant',
- name='choicesrevente',
- field=models.ManyToManyField(to='bda.Spectacle',
- related_name='subscribed',
- blank=True),
+ model_name="participant",
+ name="choicesrevente",
+ field=models.ManyToManyField(
+ to="bda.Spectacle", related_name="subscribed", blank=True
+ ),
),
migrations.AddField(
- model_name='spectaclerevente',
- name='answered_mail',
- field=models.ManyToManyField(to='bda.Participant',
- related_name='wanted',
- blank=True),
+ model_name="spectaclerevente",
+ name="answered_mail",
+ field=models.ManyToManyField(
+ to="bda.Participant", related_name="wanted", blank=True
+ ),
),
migrations.AddField(
- model_name='spectaclerevente',
- name='attribution',
- field=models.OneToOneField(to='bda.Attribution',
- on_delete=models.CASCADE,
- related_name='revente'),
+ model_name="spectaclerevente",
+ name="attribution",
+ field=models.OneToOneField(
+ to="bda.Attribution", on_delete=models.CASCADE, related_name="revente"
+ ),
),
migrations.AddField(
- model_name='spectaclerevente',
- name='seller',
- field=models.ForeignKey(to='bda.Participant',
- on_delete=models.CASCADE,
- verbose_name='Vendeur',
- related_name='original_shows'),
+ model_name="spectaclerevente",
+ name="seller",
+ field=models.ForeignKey(
+ to="bda.Participant",
+ on_delete=models.CASCADE,
+ verbose_name="Vendeur",
+ related_name="original_shows",
+ ),
),
migrations.AddField(
- model_name='spectaclerevente',
- name='soldTo',
- field=models.ForeignKey(to='bda.Participant',
- on_delete=models.CASCADE,
- verbose_name='Vendue à', null=True,
- blank=True),
+ model_name="spectaclerevente",
+ name="soldTo",
+ field=models.ForeignKey(
+ to="bda.Participant",
+ on_delete=models.CASCADE,
+ verbose_name="Vendue à",
+ null=True,
+ blank=True,
+ ),
),
]
diff --git a/bda/migrations/0010_spectaclerevente_shotgun.py b/bda/migrations/0010_spectaclerevente_shotgun.py
index 35b4da8a..da5c014c 100644
--- a/bda/migrations/0010_spectaclerevente_shotgun.py
+++ b/bda/migrations/0010_spectaclerevente_shotgun.py
@@ -1,33 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
-from django.utils import timezone
from datetime import timedelta
+from django.db import migrations, models
+from django.utils import timezone
+
def forwards_func(apps, schema_editor):
SpectacleRevente = apps.get_model("bda", "SpectacleRevente")
for revente in SpectacleRevente.objects.all():
is_expired = timezone.now() > revente.date_tirage()
- is_direct = (revente.attribution.spectacle.date >= revente.date and
- timezone.now() > revente.date + timedelta(minutes=15))
+ is_direct = revente.attribution.spectacle.date >= revente.date and timezone.now() > revente.date + timedelta(
+ minutes=15
+ )
revente.shotgun = is_expired or is_direct
revente.save()
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0009_revente'),
- ]
+ dependencies = [("bda", "0009_revente")]
operations = [
migrations.AddField(
- model_name='spectaclerevente',
- name='shotgun',
- field=models.BooleanField(default=False, verbose_name='Disponible imm\xe9diatement'),
+ model_name="spectaclerevente",
+ name="shotgun",
+ field=models.BooleanField(
+ default=False, verbose_name="Disponible imm\xe9diatement"
+ ),
),
migrations.RunPython(forwards_func, migrations.RunPython.noop),
]
diff --git a/bda/migrations/0011_tirage_appear_catalogue.py b/bda/migrations/0011_tirage_appear_catalogue.py
index c2a2479d..446be392 100644
--- a/bda/migrations/0011_tirage_appear_catalogue.py
+++ b/bda/migrations/0011_tirage_appear_catalogue.py
@@ -6,17 +6,14 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0010_spectaclerevente_shotgun'),
- ]
+ dependencies = [("bda", "0010_spectaclerevente_shotgun")]
operations = [
migrations.AddField(
- model_name='tirage',
- name='appear_catalogue',
+ model_name="tirage",
+ name="appear_catalogue",
field=models.BooleanField(
- default=False,
- verbose_name='Tirage à afficher dans le catalogue'
+ default=False, verbose_name="Tirage à afficher dans le catalogue"
),
- ),
+ )
]
diff --git a/bda/migrations/0012_notif_time.py b/bda/migrations/0012_notif_time.py
index ee777e35..96853a24 100644
--- a/bda/migrations/0012_notif_time.py
+++ b/bda/migrations/0012_notif_time.py
@@ -6,24 +6,26 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0011_tirage_appear_catalogue'),
- ]
+ dependencies = [("bda", "0011_tirage_appear_catalogue")]
operations = [
migrations.RenameField(
- model_name='spectaclerevente',
- old_name='answered_mail',
- new_name='confirmed_entry',
+ model_name="spectaclerevente",
+ old_name="answered_mail",
+ new_name="confirmed_entry",
),
migrations.AlterField(
- model_name='spectaclerevente',
- name='confirmed_entry',
- field=models.ManyToManyField(blank=True, related_name='entered', to='bda.Participant'),
+ model_name="spectaclerevente",
+ name="confirmed_entry",
+ field=models.ManyToManyField(
+ blank=True, related_name="entered", to="bda.Participant"
+ ),
),
migrations.AddField(
- model_name='spectaclerevente',
- name='notif_time',
- field=models.DateTimeField(blank=True, verbose_name="Moment d'envoi de la notification", null=True),
+ model_name="spectaclerevente",
+ name="notif_time",
+ field=models.DateTimeField(
+ blank=True, verbose_name="Moment d'envoi de la notification", null=True
+ ),
),
]
diff --git a/bda/migrations/0012_swap_double_choice.py b/bda/migrations/0012_swap_double_choice.py
index 56f3e739..e712f2ff 100644
--- a/bda/migrations/0012_swap_double_choice.py
+++ b/bda/migrations/0012_swap_double_choice.py
@@ -14,40 +14,38 @@ def swap_double_choice(apps, schema_editor):
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0011_tirage_appear_catalogue'),
- ]
+ dependencies = [("bda", "0011_tirage_appear_catalogue")]
operations = [
# Temporarily allow an extra "tmp" value for the `double_choice` field
migrations.AlterField(
- model_name='choixspectacle',
- name='double_choice',
+ model_name="choixspectacle",
+ name="double_choice",
field=models.CharField(
- verbose_name='Nombre de places',
+ verbose_name="Nombre de places",
max_length=10,
- default='1',
+ default="1",
choices=[
- ('tmp', 'tmp'),
- ('1', '1 place'),
- ('double', '2 places si possible, 1 sinon'),
- ('autoquit', '2 places sinon rien')
- ]
+ ("tmp", "tmp"),
+ ("1", "1 place"),
+ ("double", "2 places si possible, 1 sinon"),
+ ("autoquit", "2 places sinon rien"),
+ ],
),
),
migrations.RunPython(swap_double_choice, migrations.RunPython.noop),
migrations.AlterField(
- model_name='choixspectacle',
- name='double_choice',
+ model_name="choixspectacle",
+ name="double_choice",
field=models.CharField(
- verbose_name='Nombre de places',
+ verbose_name="Nombre de places",
max_length=10,
- default='1',
+ default="1",
choices=[
- ('1', '1 place'),
- ('double', '2 places si possible, 1 sinon'),
- ('autoquit', '2 places sinon rien')
- ]
+ ("1", "1 place"),
+ ("double", "2 places si possible, 1 sinon"),
+ ("autoquit", "2 places sinon rien"),
+ ],
),
),
]
diff --git a/bda/migrations/0013_merge_20180524_2123.py b/bda/migrations/0013_merge_20180524_2123.py
index ae8b0630..8f78b6a9 100644
--- a/bda/migrations/0013_merge_20180524_2123.py
+++ b/bda/migrations/0013_merge_20180524_2123.py
@@ -7,10 +7,6 @@ from django.db import migrations
class Migration(migrations.Migration):
- dependencies = [
- ('bda', '0012_notif_time'),
- ('bda', '0012_swap_double_choice'),
- ]
+ dependencies = [("bda", "0012_notif_time"), ("bda", "0012_swap_double_choice")]
- operations = [
- ]
+ operations = []
diff --git a/bda/models.py b/bda/models.py
index 63e01e31..9ac38a41 100644
--- a/bda/models.py
+++ b/bda/models.py
@@ -1,23 +1,22 @@
import calendar
import random
from datetime import timedelta
-from custommail.shortcuts import send_mass_custom_mail
+from custommail.models import CustomMail
+from custommail.shortcuts import send_mass_custom_mail
+from django.conf import settings
+from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core import mail
from django.db import models
from django.db.models import Count
-from django.contrib.auth.models import User
-from django.conf import settings
-from django.utils import timezone, formats
-
-from custommail.models import CustomMail
+from django.utils import formats, timezone
def get_generic_user():
generic, _ = User.objects.get_or_create(
username="bda_generic",
- defaults={"email": "bda@ens.fr", "first_name": "Bureau des arts"}
+ defaults={"email": "bda@ens.fr", "first_name": "Bureau des arts"},
)
return generic
@@ -29,15 +28,15 @@ class Tirage(models.Model):
tokens = models.TextField("Graine(s) du tirage", blank=True)
active = models.BooleanField("Tirage actif", default=False)
appear_catalogue = models.BooleanField(
- "Tirage à afficher dans le catalogue",
- default=False
+ "Tirage à afficher dans le catalogue", default=False
)
- enable_do_tirage = models.BooleanField("Le tirage peut être lancé",
- default=False)
+ enable_do_tirage = models.BooleanField("Le tirage peut être lancé", default=False)
def __str__(self):
- return "%s - %s" % (self.title, formats.localize(
- timezone.template_localtime(self.fermeture)))
+ return "%s - %s" % (
+ self.title,
+ formats.localize(timezone.template_localtime(self.fermeture)),
+ )
class Salle(models.Model):
@@ -49,7 +48,7 @@ class Salle(models.Model):
class CategorieSpectacle(models.Model):
- name = models.CharField('Nom', max_length=100, unique=True)
+ name = models.CharField("Nom", max_length=100, unique=True)
def __str__(self):
return self.name
@@ -61,28 +60,26 @@ class CategorieSpectacle(models.Model):
class Spectacle(models.Model):
title = models.CharField("Titre", max_length=300)
category = models.ForeignKey(
- CategorieSpectacle, on_delete=models.CASCADE,
- blank=True, null=True,
+ CategorieSpectacle, on_delete=models.CASCADE, blank=True, null=True
)
date = models.DateTimeField("Date & heure")
location = models.ForeignKey(Salle, on_delete=models.CASCADE)
- vips = models.TextField('Personnalités', blank=True)
+ vips = models.TextField("Personnalités", blank=True)
description = models.TextField("Description", blank=True)
slots_description = models.TextField("Description des places", blank=True)
- image = models.ImageField('Image', blank=True, null=True,
- upload_to='imgs/shows/')
- ext_link = models.CharField('Lien vers le site du spectacle', blank=True,
- max_length=500)
+ image = models.ImageField("Image", blank=True, null=True, upload_to="imgs/shows/")
+ ext_link = models.CharField(
+ "Lien vers le site du spectacle", blank=True, max_length=500
+ )
price = models.FloatField("Prix d'une place")
slots = models.IntegerField("Places")
tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE)
listing = models.BooleanField("Les places sont sur listing")
- rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
- null=True)
+ rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True, null=True)
class Meta:
verbose_name = "Spectacle"
- ordering = ("date", "title",)
+ ordering = ("date", "title")
def timestamp(self):
return "%d" % calendar.timegm(self.date.utctimetuple())
@@ -92,7 +89,7 @@ class Spectacle(models.Model):
self.title,
formats.localize(timezone.template_localtime(self.date)),
self.location,
- self.price
+ self.price,
)
def getImgUrl(self):
@@ -101,7 +98,7 @@ class Spectacle(models.Model):
"""
try:
return self.image.url
- except:
+ except Exception:
return None
def send_rappel(self):
@@ -111,19 +108,21 @@ class Spectacle(models.Model):
"""
# On récupère la liste des participants + le BdA
members = list(
- User.objects
- .filter(participant__attributions=self)
- .annotate(nb_attr=Count("id")).order_by()
+ User.objects.filter(participant__attributions=self)
+ .annotate(nb_attr=Count("id"))
+ .order_by()
)
bda_generic = get_generic_user()
bda_generic.nb_attr = 1
members.append(bda_generic)
# On écrit un mail personnalisé à chaque participant
- datatuple = [(
- 'bda-rappel',
- {'member': member, "nb_attr": member.nb_attr, 'show': self},
- settings.MAIL_DATA['rappels']['FROM'],
- [member.email])
+ datatuple = [
+ (
+ "bda-rappel",
+ {"member": member, "nb_attr": member.nb_attr, "show": self},
+ settings.MAIL_DATA["rappels"]["FROM"],
+ [member.email],
+ )
for member in members
]
send_mass_custom_mail(datatuple)
@@ -140,8 +139,8 @@ class Spectacle(models.Model):
class Quote(models.Model):
spectacle = models.ForeignKey(Spectacle, on_delete=models.CASCADE)
- text = models.TextField('Citation')
- author = models.CharField('Auteur', max_length=200)
+ text = models.TextField("Citation")
+ author = models.CharField("Auteur", max_length=200)
PAYMENT_TYPES = (
@@ -154,20 +153,20 @@ PAYMENT_TYPES = (
class Participant(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
- choices = models.ManyToManyField(Spectacle,
- through="ChoixSpectacle",
- related_name="chosen_by")
- attributions = models.ManyToManyField(Spectacle,
- through="Attribution",
- related_name="attributed_to")
+ choices = models.ManyToManyField(
+ Spectacle, through="ChoixSpectacle", related_name="chosen_by"
+ )
+ attributions = models.ManyToManyField(
+ Spectacle, through="Attribution", related_name="attributed_to"
+ )
paid = models.BooleanField("A payé", default=False)
- paymenttype = models.CharField("Moyen de paiement",
- max_length=6, choices=PAYMENT_TYPES,
- blank=True)
+ paymenttype = models.CharField(
+ "Moyen de paiement", max_length=6, choices=PAYMENT_TYPES, blank=True
+ )
tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE)
- choicesrevente = models.ManyToManyField(Spectacle,
- related_name="subscribed",
- blank=True)
+ choicesrevente = models.ManyToManyField(
+ Spectacle, related_name="subscribed", blank=True
+ )
def __str__(self):
return "%s - %s" % (self.user, self.tirage.title)
@@ -183,30 +182,32 @@ DOUBLE_CHOICES = (
class ChoixSpectacle(models.Model):
participant = models.ForeignKey(Participant, on_delete=models.CASCADE)
spectacle = models.ForeignKey(
- Spectacle, on_delete=models.CASCADE,
- related_name="participants",
+ Spectacle, on_delete=models.CASCADE, related_name="participants"
)
priority = models.PositiveIntegerField("Priorité")
- double_choice = models.CharField("Nombre de places",
- default="1", choices=DOUBLE_CHOICES,
- max_length=10)
+ double_choice = models.CharField(
+ "Nombre de places", default="1", choices=DOUBLE_CHOICES, max_length=10
+ )
def get_double(self):
return self.double_choice != "1"
+
double = property(get_double)
def get_autoquit(self):
return self.double_choice == "autoquit"
+
autoquit = property(get_autoquit)
def __str__(self):
return "Vœux de %s pour %s" % (
- self.participant.user.get_full_name(),
- self.spectacle.title)
+ self.participant.user.get_full_name(),
+ self.spectacle.title,
+ )
class Meta:
ordering = ("priority",)
- unique_together = (("participant", "spectacle",),)
+ unique_together = (("participant", "spectacle"),)
verbose_name = "voeu"
verbose_name_plural = "voeux"
@@ -214,48 +215,49 @@ class ChoixSpectacle(models.Model):
class Attribution(models.Model):
participant = models.ForeignKey(Participant, on_delete=models.CASCADE)
spectacle = models.ForeignKey(
- Spectacle, on_delete=models.CASCADE,
- related_name="attribues",
+ Spectacle, on_delete=models.CASCADE, related_name="attribues"
)
given = models.BooleanField("Donnée", default=False)
def __str__(self):
- return "%s -- %s, %s" % (self.participant.user, self.spectacle.title,
- self.spectacle.date)
+ return "%s -- %s, %s" % (
+ self.participant.user,
+ self.spectacle.title,
+ self.spectacle.date,
+ )
class SpectacleRevente(models.Model):
attribution = models.OneToOneField(
- Attribution, on_delete=models.CASCADE,
- related_name="revente",
+ Attribution, on_delete=models.CASCADE, related_name="revente"
+ )
+ date = models.DateTimeField("Date de mise en vente", default=timezone.now)
+ confirmed_entry = models.ManyToManyField(
+ Participant, related_name="entered", blank=True
)
- date = models.DateTimeField("Date de mise en vente",
- default=timezone.now)
- confirmed_entry = models.ManyToManyField(Participant,
- related_name="entered",
- blank=True)
seller = models.ForeignKey(
- Participant, on_delete=models.CASCADE,
+ Participant,
+ on_delete=models.CASCADE,
verbose_name="Vendeur",
related_name="original_shows",
)
soldTo = models.ForeignKey(
- Participant, on_delete=models.CASCADE,
+ Participant,
+ on_delete=models.CASCADE,
verbose_name="Vendue à",
- blank=True, null=True,
+ blank=True,
+ null=True,
)
- notif_sent = models.BooleanField("Notification envoyée",
- default=False)
+ notif_sent = models.BooleanField("Notification envoyée", default=False)
- notif_time = models.DateTimeField("Moment d'envoi de la notification",
- blank=True, null=True)
+ notif_time = models.DateTimeField(
+ "Moment d'envoi de la notification", blank=True, null=True
+ )
- tirage_done = models.BooleanField("Tirage effectué",
- default=False)
+ tirage_done = models.BooleanField("Tirage effectué", default=False)
- shotgun = models.BooleanField("Disponible immédiatement",
- default=False)
+ shotgun = models.BooleanField("Disponible immédiatement", default=False)
####
# Some class attributes
###
@@ -282,8 +284,9 @@ class SpectacleRevente(models.Model):
def date_tirage(self):
"""Renvoie la date du tirage au sort de la revente."""
- remaining_time = (self.attribution.spectacle.date
- - self.real_notif_time - self.min_margin)
+ remaining_time = (
+ self.attribution.spectacle.date - self.real_notif_time - self.min_margin
+ )
delay = min(remaining_time, self.max_wait_time)
@@ -296,16 +299,14 @@ class SpectacleRevente(models.Model):
Plus précisément, on doit avoir min_margin + min_wait_time de marge.
"""
spectacle_date = self.attribution.spectacle.date
- return (spectacle_date <= timezone.now() + self.min_margin
- + self.min_wait_time)
+ return spectacle_date <= timezone.now() + self.min_margin + self.min_wait_time
@property
def can_notif(self):
- return (timezone.now() >= self.date + self.remorse_time)
+ return timezone.now() >= self.date + self.remorse_time
def __str__(self):
- return "%s -- %s" % (self.seller,
- self.attribution.spectacle.title)
+ return "%s -- %s" % (self.seller, self.attribution.spectacle.title)
class Meta:
verbose_name = "Revente"
@@ -327,17 +328,19 @@ class SpectacleRevente(models.Model):
Envoie une notification pour indiquer la mise en vente d'une place sur
BdA-Revente à tous les intéressés.
"""
- inscrits = self.attribution.spectacle.subscribed.select_related('user')
- datatuple = [(
- 'bda-revente',
- {
- 'member': participant.user,
- 'show': self.attribution.spectacle,
- 'revente': self,
- 'site': Site.objects.get_current()
- },
- settings.MAIL_DATA['revente']['FROM'],
- [participant.user.email])
+ inscrits = self.attribution.spectacle.subscribed.select_related("user")
+ datatuple = [
+ (
+ "bda-revente",
+ {
+ "member": participant.user,
+ "show": self.attribution.spectacle,
+ "revente": self,
+ "site": Site.objects.get_current(),
+ },
+ settings.MAIL_DATA["revente"]["FROM"],
+ [participant.user.email],
+ )
for participant in inscrits
]
send_mass_custom_mail(datatuple)
@@ -350,16 +353,18 @@ class SpectacleRevente(models.Model):
Envoie un mail à toutes les personnes intéréssées par le spectacle pour
leur indiquer qu'il est désormais disponible au shotgun.
"""
- inscrits = self.attribution.spectacle.subscribed.select_related('user')
- datatuple = [(
- 'bda-shotgun',
- {
- 'member': participant.user,
- 'show': self.attribution.spectacle,
- 'site': Site.objects.get_current(),
- },
- settings.MAIL_DATA['revente']['FROM'],
- [participant.user.email])
+ inscrits = self.attribution.spectacle.subscribed.select_related("user")
+ datatuple = [
+ (
+ "bda-shotgun",
+ {
+ "member": participant.user,
+ "show": self.attribution.spectacle,
+ "site": Site.objects.get_current(),
+ },
+ settings.MAIL_DATA["revente"]["FROM"],
+ [participant.user.email],
+ )
for participant in inscrits
]
send_mass_custom_mail(datatuple)
@@ -389,30 +394,33 @@ class SpectacleRevente(models.Model):
mails = []
context = {
- 'acheteur': winner.user,
- 'vendeur': seller.user,
- 'show': spectacle,
+ "acheteur": winner.user,
+ "vendeur": seller.user,
+ "show": spectacle,
}
- c_mails_qs = CustomMail.objects.filter(shortname__in=[
- 'bda-revente-winner', 'bda-revente-loser',
- 'bda-revente-seller',
- ])
+ c_mails_qs = CustomMail.objects.filter(
+ shortname__in=[
+ "bda-revente-winner",
+ "bda-revente-loser",
+ "bda-revente-seller",
+ ]
+ )
c_mails = {cm.shortname: cm for cm in c_mails_qs}
mails.append(
- c_mails['bda-revente-winner'].get_message(
+ c_mails["bda-revente-winner"].get_message(
context,
- from_email=settings.MAIL_DATA['revente']['FROM'],
+ from_email=settings.MAIL_DATA["revente"]["FROM"],
to=[winner.user.email],
)
)
mails.append(
- c_mails['bda-revente-seller'].get_message(
+ c_mails["bda-revente-seller"].get_message(
context,
- from_email=settings.MAIL_DATA['revente']['FROM'],
+ from_email=settings.MAIL_DATA["revente"]["FROM"],
to=[seller.user.email],
reply_to=[winner.user.email],
)
@@ -422,12 +430,12 @@ class SpectacleRevente(models.Model):
for inscrit in inscrits:
if inscrit != winner:
new_context = dict(context)
- new_context['acheteur'] = inscrit.user
+ new_context["acheteur"] = inscrit.user
mails.append(
- c_mails['bda-revente-loser'].get_message(
+ c_mails["bda-revente-loser"].get_message(
new_context,
- from_email=settings.MAIL_DATA['revente']['FROM'],
+ from_email=settings.MAIL_DATA["revente"]["FROM"],
to=[inscrit.user.email],
)
)
diff --git a/bda/templates/bda/revente/manage.html b/bda/templates/bda/revente/manage.html
index cf0ba80e..5147ff16 100644
--- a/bda/templates/bda/revente/manage.html
+++ b/bda/templates/bda/revente/manage.html
@@ -6,7 +6,7 @@
Gestion des places que je revends
{% with resell_attributions=resellform.attributions annul_reventes=annulform.reventes sold_reventes=soldform.reventes %}
-{% if resellform.attributions %}
+{% if resell_attributions %}
Places non revendues
@@ -29,34 +29,24 @@
{% endif %}
-{% if annul_reventes or overdue %}
+{% if annul_reventes %}
Places en cours de revente
@@ -82,7 +72,7 @@
Réinitialiser
{% endif %}
-{% if not resell_attributions and not annul_attributions and not overdue and not sold_reventes %}
+{% if not resell_attributions and not annul_reventes and not sold_reventes %}
Plus de reventes possibles !
{% endif %}
diff --git a/bda/tests/test_models.py b/bda/tests/test_models.py
index 95ce8646..b8a23ba7 100644
--- a/bda/tests/test_models.py
+++ b/bda/tests/test_models.py
@@ -7,28 +7,33 @@ from django.test import TestCase
from django.utils import timezone
from bda.models import (
- Attribution, Participant, Salle, Spectacle, SpectacleRevente, Tirage,
+ Attribution,
+ Participant,
+ Salle,
+ Spectacle,
+ SpectacleRevente,
+ Tirage,
)
User = get_user_model()
class SpectacleReventeTests(TestCase):
- fixtures = ['gestioncof/management/data/custommail.json']
+ fixtures = ["gestioncof/management/data/custommail.json"]
def setUp(self):
now = timezone.now()
self.t = Tirage.objects.create(
- title='Tirage',
+ title="Tirage",
ouverture=now - timedelta(days=7),
fermeture=now - timedelta(days=3),
active=True,
)
self.s = Spectacle.objects.create(
- title='Spectacle',
+ title="Spectacle",
date=now + timedelta(days=20),
- location=Salle.objects.create(name='Salle', address='Address'),
+ location=Salle.objects.create(name="Salle", address="Address"),
price=10.5,
slots=5,
tirage=self.t,
@@ -36,31 +41,28 @@ class SpectacleReventeTests(TestCase):
)
self.seller = Participant.objects.create(
- user=User.objects.create(
- username='seller', email='seller@mail.net'),
+ user=User.objects.create(username="seller", email="seller@mail.net"),
tirage=self.t,
)
self.p1 = Participant.objects.create(
- user=User.objects.create(username='part1', email='part1@mail.net'),
+ user=User.objects.create(username="part1", email="part1@mail.net"),
tirage=self.t,
)
self.p2 = Participant.objects.create(
- user=User.objects.create(username='part2', email='part2@mail.net'),
+ user=User.objects.create(username="part2", email="part2@mail.net"),
tirage=self.t,
)
self.p3 = Participant.objects.create(
- user=User.objects.create(username='part3', email='part3@mail.net'),
+ user=User.objects.create(username="part3", email="part3@mail.net"),
tirage=self.t,
)
self.attr = Attribution.objects.create(
- participant=self.seller,
- spectacle=self.s,
+ participant=self.seller, spectacle=self.s
)
self.rev = SpectacleRevente.objects.create(
- attribution=self.attr,
- seller=self.seller,
+ attribution=self.attr, seller=self.seller
)
def test_tirage(self):
@@ -69,7 +71,7 @@ class SpectacleReventeTests(TestCase):
wanted_by = [self.p1, self.p2, self.p3]
revente.confirmed_entry = wanted_by
- with mock.patch('bda.models.random.choice') as mc:
+ with mock.patch("bda.models.random.choice") as mc:
# Set winner to self.p1.
mc.return_value = self.p1
@@ -87,14 +89,14 @@ class SpectacleReventeTests(TestCase):
self.assertEqual(len(mails), 4)
- m_seller = mails['seller@mail.net']
- self.assertListEqual(m_seller.to, ['seller@mail.net'])
- self.assertListEqual(m_seller.reply_to, ['part1@mail.net'])
+ m_seller = mails["seller@mail.net"]
+ self.assertListEqual(m_seller.to, ["seller@mail.net"])
+ self.assertListEqual(m_seller.reply_to, ["part1@mail.net"])
- m_winner = mails['part1@mail.net']
- self.assertListEqual(m_winner.to, ['part1@mail.net'])
+ m_winner = mails["part1@mail.net"]
+ self.assertListEqual(m_winner.to, ["part1@mail.net"])
self.assertCountEqual(
- [mails['part2@mail.net'].to, mails['part3@mail.net'].to],
- [['part2@mail.net'], ['part3@mail.net']],
+ [mails["part2@mail.net"].to, mails["part3@mail.net"].to],
+ [["part2@mail.net"], ["part3@mail.net"]],
)
diff --git a/bda/tests/test_revente.py b/bda/tests/test_revente.py
index 8ef7be19..202e9494 100644
--- a/bda/tests/test_revente.py
+++ b/bda/tests/test_revente.py
@@ -1,60 +1,71 @@
-from django.contrib.auth.models import User
-from django.test import TestCase, Client
-from django.utils import timezone
-
from datetime import timedelta
-from bda.models import (Tirage, Spectacle, Salle, CategorieSpectacle,
- SpectacleRevente, Attribution, Participant)
+from django.contrib.auth.models import User
+from django.test import TestCase
+from django.utils import timezone
+
+from bda.models import (
+ Attribution,
+ CategorieSpectacle,
+ Participant,
+ Salle,
+ Spectacle,
+ SpectacleRevente,
+ Tirage,
+)
class TestModels(TestCase):
def setUp(self):
self.tirage = Tirage.objects.create(
- title="Tirage test",
- appear_catalogue=True,
- ouverture=timezone.now(),
- fermeture=timezone.now()
+ title="Tirage test",
+ appear_catalogue=True,
+ ouverture=timezone.now(),
+ fermeture=timezone.now(),
)
self.category = CategorieSpectacle.objects.create(name="Category")
self.location = Salle.objects.create(name="here")
self.spectacle_soon = Spectacle.objects.create(
- title="foo", date=timezone.now()+timedelta(days=1),
- location=self.location, price=0, slots=42,
- tirage=self.tirage, listing=False, category=self.category
+ title="foo",
+ date=timezone.now() + timedelta(days=1),
+ location=self.location,
+ price=0,
+ slots=42,
+ tirage=self.tirage,
+ listing=False,
+ category=self.category,
)
self.spectacle_later = Spectacle.objects.create(
- title="bar", date=timezone.now()+timedelta(days=30),
- location=self.location, price=0, slots=42,
- tirage=self.tirage, listing=False, category=self.category
+ title="bar",
+ date=timezone.now() + timedelta(days=30),
+ location=self.location,
+ price=0,
+ slots=42,
+ tirage=self.tirage,
+ listing=False,
+ category=self.category,
)
user_buyer = User.objects.create_user(
- username="bda_buyer", password="testbuyer"
+ username="bda_buyer", password="testbuyer"
)
user_seller = User.objects.create_user(
- username="bda_seller", password="testseller"
- )
- self.buyer = Participant.objects.create(
- user=user_buyer, tirage=self.tirage
- )
- self.seller = Participant.objects.create(
- user=user_seller, tirage=self.tirage
+ username="bda_seller", password="testseller"
)
+ self.buyer = Participant.objects.create(user=user_buyer, tirage=self.tirage)
+ self.seller = Participant.objects.create(user=user_seller, tirage=self.tirage)
self.attr_soon = Attribution.objects.create(
- participant=self.seller, spectacle=self.spectacle_soon
+ participant=self.seller, spectacle=self.spectacle_soon
)
self.attr_later = Attribution.objects.create(
- participant=self.seller, spectacle=self.spectacle_later
+ participant=self.seller, spectacle=self.spectacle_later
)
self.revente_soon = SpectacleRevente.objects.create(
- seller=self.seller,
- attribution=self.attr_soon
+ seller=self.seller, attribution=self.attr_soon
)
self.revente_later = SpectacleRevente.objects.create(
- seller=self.seller,
- attribution=self.attr_later
+ seller=self.seller, attribution=self.attr_later
)
def test_urgent(self):
@@ -64,6 +75,5 @@ class TestModels(TestCase):
def test_tirage(self):
self.revente_soon.confirmed_entry.add(self.buyer)
- self.assertEqual(self.revente_soon.tirage(send_mails=False),
- self.buyer)
+ self.assertEqual(self.revente_soon.tirage(send_mails=False), self.buyer)
self.assertIsNone(self.revente_later.tirage(send_mails=False))
diff --git a/bda/tests/test_views.py b/bda/tests/test_views.py
index 88dfd980..4f906f82 100644
--- a/bda/tests/test_views.py
+++ b/bda/tests/test_views.py
@@ -1,14 +1,92 @@
import json
+from datetime import timedelta
+from unittest import mock
+from urllib.parse import urlencode
from django.contrib.auth.models import User
-from django.test import TestCase, Client
+from django.test import Client, TestCase
from django.utils import timezone
-from bda.models import Tirage, Spectacle, Salle, CategorieSpectacle
+from ..models import CategorieSpectacle, Salle, Spectacle, Tirage
-class TestBdAViews(TestCase):
+def create_user(username, is_cof=False, is_buro=False):
+ user = User.objects.create_user(username=username, password=username)
+ user.profile.is_cof = is_cof
+ user.profile.is_buro = is_buro
+ user.profile.save()
+ return user
+
+
+def user_is_cof(user):
+ return (user is not None) and user.profile.is_cof
+
+
+def user_is_staff(user):
+ return (user is not None) and user.profile.is_buro
+
+
+class BdATestHelpers:
def setUp(self):
+ # Some user with different access privileges
+ staff = create_user(username="bda_staff", is_cof=True, is_buro=True)
+ staff_c = Client()
+ staff_c.force_login(staff)
+
+ member = create_user(username="bda_member", is_cof=True)
+ member_c = Client()
+ member_c.force_login(member)
+
+ other = create_user(username="bda_other")
+ other_c = Client()
+ other_c.force_login(other)
+
+ self.client_matrix = [
+ (staff, staff_c),
+ (member, member_c),
+ (other, other_c),
+ (None, Client()),
+ ]
+
+ def require_custommails(self):
+ from django.core.management import call_command
+
+ call_command("syncmails", verbosity=0)
+
+ def check_restricted_access(
+ self, url, validate_user=user_is_cof, redirect_url=None
+ ):
+ def craft_redirect_url(user):
+ if redirect_url:
+ return redirect_url
+ elif user is None:
+ # client is not logged in
+ login_url = "/login"
+ if url:
+ login_url += "?{}".format(urlencode({"next": url}, safe="/"))
+ return login_url
+ else:
+ return "/"
+
+ for (user, client) in self.client_matrix:
+ resp = client.get(url, follow=True)
+ if validate_user(user):
+ self.assertEqual(200, resp.status_code)
+ else:
+ self.assertRedirects(resp, craft_redirect_url(user))
+
+
+class TestBdAViews(BdATestHelpers, TestCase):
+ def setUp(self):
+ # Signals handlers on login/logout send messages.
+ # Due to the way the Django' test Client performs login, this raise an
+ # error. As workaround, we mock the Django' messages module.
+ patcher_messages = mock.patch("gestioncof.signals.messages")
+ patcher_messages.start()
+ self.addCleanup(patcher_messages.stop)
+ # Set up the helpers
+ super().setUp()
+ # Some BdA stuff
self.tirage = Tirage.objects.create(
title="Test tirage",
appear_catalogue=True,
@@ -17,82 +95,137 @@ class TestBdAViews(TestCase):
)
self.category = CategorieSpectacle.objects.create(name="Category")
self.location = Salle.objects.create(name="here")
- Spectacle.objects.bulk_create([
- Spectacle(
- title="foo", date=timezone.now(), location=self.location,
- price=0, slots=42, tirage=self.tirage, listing=False,
- category=self.category
- ),
- Spectacle(
- title="bar", date=timezone.now(), location=self.location,
- price=1, slots=142, tirage=self.tirage, listing=False,
- category=self.category
- ),
- Spectacle(
- title="baz", date=timezone.now(), location=self.location,
- price=2, slots=242, tirage=self.tirage, listing=False,
- category=self.category
- ),
- ])
-
- self.bda_user = User.objects.create_user(
- username="bda_user", password="bda4ever"
+ Spectacle.objects.bulk_create(
+ [
+ Spectacle(
+ title="foo",
+ date=timezone.now(),
+ location=self.location,
+ price=0,
+ slots=42,
+ tirage=self.tirage,
+ listing=False,
+ category=self.category,
+ ),
+ Spectacle(
+ title="bar",
+ date=timezone.now(),
+ location=self.location,
+ price=1,
+ slots=142,
+ tirage=self.tirage,
+ listing=False,
+ category=self.category,
+ ),
+ Spectacle(
+ title="baz",
+ date=timezone.now(),
+ location=self.location,
+ price=2,
+ slots=242,
+ tirage=self.tirage,
+ listing=False,
+ category=self.category,
+ ),
+ ]
)
- self.bda_user.profile.is_cof = True
- self.bda_user.profile.is_buro = True
- self.bda_user.profile.save()
- def bda_participants(self):
- """The BdA participants views can be queried"""
- client = Client()
+ def test_bda_inscriptions(self):
+ # TODO: test the form
+ url = "/bda/inscription/{}".format(self.tirage.id)
+ self.check_restricted_access(url)
+
+ def test_bda_places(self):
+ url = "/bda/places/{}".format(self.tirage.id)
+ self.check_restricted_access(url)
+
+ def test_etat_places(self):
+ url = "/bda/etat-places/{}".format(self.tirage.id)
+ self.check_restricted_access(url)
+
+ def test_perform_tirage(self):
+ # Only staff member can perform a tirage
+ url = "/bda/tirage/{}".format(self.tirage.id)
+ self.check_restricted_access(url, validate_user=user_is_staff)
+
+ _, staff_c = self.client_matrix[0]
+ # Cannot be performed if disabled
+ self.tirage.enable_do_tirage = False
+ self.tirage.save()
+ resp = staff_c.get(url)
+ self.assertTemplateUsed(resp, "tirage-failed.html")
+ # Cannot be performed if registrations are still open
+ self.tirage.enable_do_tirage = True
+ self.tirage.fermeture = timezone.now() + timedelta(seconds=3600)
+ self.tirage.save()
+ resp = staff_c.get(url)
+ self.assertTemplateUsed(resp, "tirage-failed.html")
+ # Otherwise, perform the tirage
+ self.tirage.fermeture = timezone.now()
+ self.tirage.save()
+ resp = staff_c.get(url)
+ self.assertTemplateNotUsed(resp, "tirage-failed.html")
+
+ def test_spectacles_list(self):
+ url = "/bda/spectacles/{}".format(self.tirage.id)
+ self.check_restricted_access(url, validate_user=user_is_staff)
+
+ def test_spectacle_detail(self):
show = self.tirage.spectacle_set.first()
+ url = "/bda/spectacles/{}/{}".format(self.tirage.id, show.id)
+ self.check_restricted_access(url, validate_user=user_is_staff)
- client.login(self.bda_user.username, "bda4ever")
- tirage_resp = client.get("/bda/spectacles/{}".format(self.tirage.id))
- show_resp = client.get(
- "/bda/spectacles/{}/{}".format(self.tirage.id, show.id)
- )
- reminder_url = "/bda/mails-rappel/{}".format(show.id)
- reminder_get_resp = client.get(reminder_url)
- reminder_post_resp = client.post(reminder_url)
- self.assertEqual(200, tirage_resp.status_code)
- self.assertEqual(200, show_resp.status_code)
- self.assertEqual(200, reminder_get_resp.status_code)
- self.assertEqual(200, reminder_post_resp.status_code)
+ def test_tirage_unpaid(self):
+ url = "/bda/spectacles/unpaid/{}".format(self.tirage.id)
+ self.check_restricted_access(url, validate_user=user_is_staff)
- def test_catalogue(self):
- """Test the catalogue JSON API"""
- client = Client()
+ def test_send_reminders(self):
+ self.require_custommails()
+ # Just get the page
+ show = self.tirage.spectacle_set.first()
+ url = "/bda/mails-rappel/{}".format(show.id)
+ self.check_restricted_access(url, validate_user=user_is_staff)
+ # Actually send the reminder emails
+ _, staff_c = self.client_matrix[0]
+ resp = staff_c.post(url)
+ self.assertEqual(200, resp.status_code)
+ # TODO: check that emails are sent
- # The `list` hook
- resp = client.get("/bda/catalogue/list")
+ def test_catalogue_api(self):
+ url_list = "/bda/catalogue/list"
+ url_details = "/bda/catalogue/details?id={}".format(self.tirage.id)
+ url_descriptions = "/bda/catalogue/descriptions?id={}".format(self.tirage.id)
+
+ # Anyone can get
+ def anyone_can_get(url):
+ self.check_restricted_access(url, validate_user=lambda user: True)
+
+ anyone_can_get(url_list)
+ anyone_can_get(url_details)
+ anyone_can_get(url_descriptions)
+
+ # The resulting JSON contains the information
+ _, client = self.client_matrix[0]
+
+ # List
+ resp = client.get(url_list)
self.assertJSONEqual(
resp.content.decode("utf-8"),
- [{"id": self.tirage.id, "title": self.tirage.title}]
+ [{"id": self.tirage.id, "title": self.tirage.title}],
)
- # The `details` hook
- resp = client.get(
- "/bda/catalogue/details?id={}".format(self.tirage.id)
- )
+ # Details
+ resp = client.get(url_details)
self.assertJSONEqual(
resp.content.decode("utf-8"),
{
- "categories": [{
- "id": self.category.id,
- "name": self.category.name
- }],
- "locations": [{
- "id": self.location.id,
- "name": self.location.name
- }],
- }
+ "categories": [{"id": self.category.id, "name": self.category.name}],
+ "locations": [{"id": self.location.id, "name": self.location.name}],
+ },
)
- # The `descriptions` hook
- resp = client.get(
- "/bda/catalogue/descriptions?id={}".format(self.tirage.id)
- )
+ # Descriptions
+ resp = client.get(url_descriptions)
raw = resp.content.decode("utf-8")
try:
results = json.loads(raw)
@@ -101,5 +234,10 @@ class TestBdAViews(TestCase):
self.assertEqual(len(results), 3)
self.assertEqual(
{(s["title"], s["price"], s["slots"]) for s in results},
- {("foo", 0, 42), ("bar", 1, 142), ("baz", 2, 242)}
+ {("foo", 0, 42), ("bar", 1, 142), ("baz", 2, 242)},
)
+
+
+class TestBdaRevente:
+ pass
+ # TODO
diff --git a/bda/urls.py b/bda/urls.py
index 7264d7b3..7ceccfe0 100644
--- a/bda/urls.py
+++ b/bda/urls.py
@@ -1,62 +1,75 @@
from django.conf.urls import url
-from gestioncof.decorators import buro_required
-from bda.views import SpectacleListView
+
from bda import views
+from bda.views import SpectacleListView
+from gestioncof.decorators import buro_required
urlpatterns = [
- url(r'^inscription/(?P\d+)$',
+ url(
+ r"^inscription/(?P\d+)$",
views.inscription,
- name='bda-tirage-inscription'),
- url(r'^places/(?P\d+)$',
- views.places,
- name="bda-places-attribuees"),
- url(r'^etat-places/(?P\d+)$',
- views.etat_places,
- name='bda-etat-places'),
- url(r'^tirage/(?P\d+)$', views.tirage),
- url(r'^spectacles/(?P\d+)$',
+ name="bda-tirage-inscription",
+ ),
+ url(r"^places/(?P\d+)$", views.places, name="bda-places-attribuees"),
+ url(r"^etat-places/(?P\d+)$", views.etat_places, name="bda-etat-places"),
+ url(r"^tirage/(?P\d+)$", views.tirage),
+ url(
+ r"^spectacles/(?P\d+)$",
buro_required(SpectacleListView.as_view()),
- name="bda-liste-spectacles"),
- url(r'^spectacles/(?P\d+)/(?P\d+)$',
+ name="bda-liste-spectacles",
+ ),
+ url(
+ r"^spectacles/(?P\d+)/(?P\d+)$",
views.spectacle,
- name="bda-spectacle"),
- url(r'^spectacles/unpaid/(?P\d+)$',
- views.unpaid,
- name="bda-unpaid"),
- url(r'^spectacles/autocomplete$',
+ name="bda-spectacle",
+ ),
+ url(r"^spectacles/unpaid/(?P\d+)$", views.unpaid, name="bda-unpaid"),
+ url(
+ r"^spectacles/autocomplete$",
views.spectacle_autocomplete,
- name="bda-spectacle-autocomplete"),
- url(r'^participants/autocomplete$',
+ name="bda-spectacle-autocomplete",
+ ),
+ url(
+ r"^participants/autocomplete$",
views.participant_autocomplete,
- name="bda-participant-autocomplete"),
-
+ name="bda-participant-autocomplete",
+ ),
# Urls BdA-Revente
-
- url(r'^revente/(?P\d+)/manage$',
+ url(
+ r"^revente/(?P\d+)/manage$",
views.revente_manage,
- name='bda-revente-manage'),
- url(r'^revente/(?P\d+)/subscribe$',
+ name="bda-revente-manage",
+ ),
+ url(
+ r"^revente/(?P\d+)/subscribe$",
views.revente_subscribe,
- name="bda-revente-subscribe"),
- url(r'^revente/(?P\d+)/tirages$',
+ name="bda-revente-subscribe",
+ ),
+ url(
+ r"^revente/(?P\d+)/tirages$",
views.revente_tirages,
- name="bda-revente-tirages"),
- url(r'^revente/(?P\d+)/buy$',
+ name="bda-revente-tirages",
+ ),
+ url(
+ r"^revente/(?P\d+)/buy$",
views.revente_buy,
- name="bda-revente-buy"),
- url(r'^revente/(?P\d+)/confirm$',
+ name="bda-revente-buy",
+ ),
+ url(
+ r"^revente/(?P\d+)/confirm$",
views.revente_confirm,
- name='bda-revente-confirm'),
- url(r'^revente/(?P\d+)/shotgun$',
+ name="bda-revente-confirm",
+ ),
+ url(
+ r"^revente/(?P\d+)/shotgun$",
views.revente_shotgun,
- name="bda-revente-shotgun"),
-
- url(r'^mails-rappel/(?P\d+)$',
- views.send_rappel,
- name="bda-rappels"
- ),
- url(r'^descriptions/(?P\d+)$', views.descriptions_spectacles,
- name='bda-descriptions'),
- url(r'^catalogue/(?P[a-z]+)$', views.catalogue,
- name='bda-catalogue'),
+ name="bda-revente-shotgun",
+ ),
+ url(r"^mails-rappel/(?P\d+)$", views.send_rappel, name="bda-rappels"),
+ url(
+ r"^descriptions/(?P\d+)$",
+ views.descriptions_spectacles,
+ name="bda-descriptions",
+ ),
+ url(r"^catalogue/(?P[a-z]+)$", views.catalogue, name="bda-catalogue"),
]
diff --git a/bda/views.py b/bda/views.py
index b49eb030..050d6851 100644
--- a/bda/views.py
+++ b/bda/views.py
@@ -1,36 +1,47 @@
-from collections import defaultdict
-import random
import hashlib
-import time
import json
-from custommail.shortcuts import send_mass_custom_mail, send_custom_mail
+import random
+import time
+from collections import defaultdict
+
from custommail.models import CustomMail
-from django.shortcuts import render, get_object_or_404
-from django.contrib.auth.decorators import login_required
-from django.contrib import messages
-from django.db import transaction
-from django.core import serializers
-from django.db.models import Count, Q, Prefetch
-from django.template.defaultfilters import pluralize
-from django.forms.models import inlineformset_factory
-from django.http import (
- HttpResponseBadRequest, HttpResponseRedirect, JsonResponse
-)
-from django.core.urlresolvers import reverse
+from custommail.shortcuts import send_custom_mail, send_mass_custom_mail
from django.conf import settings
-from django.utils import timezone, formats
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.core import serializers
+from django.core.urlresolvers import reverse
+from django.db import transaction
+from django.db.models import Count, Prefetch
+from django.forms.models import inlineformset_factory
+from django.http import HttpResponseBadRequest, HttpResponseRedirect, JsonResponse
+from django.shortcuts import get_object_or_404, render
+from django.template.defaultfilters import pluralize
+from django.utils import formats, timezone
from django.views.generic.list import ListView
-from gestioncof.decorators import cof_required, buro_required
-from bda.models import (
- Spectacle, Participant, ChoixSpectacle, Attribution, Tirage,
- SpectacleRevente, Salle, CategorieSpectacle
-)
+
from bda.algorithm import Algorithm
from bda.forms import (
- TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm,
- InscriptionInlineFormSet, ReventeTirageForm, ReventeTirageAnnulForm
+ AnnulForm,
+ InscriptionInlineFormSet,
+ InscriptionReventeForm,
+ ResellForm,
+ ReventeTirageAnnulForm,
+ ReventeTirageForm,
+ SoldForm,
+ TokenForm,
)
-
+from bda.models import (
+ Attribution,
+ CategorieSpectacle,
+ ChoixSpectacle,
+ Participant,
+ Salle,
+ Spectacle,
+ SpectacleRevente,
+ Tirage,
+)
+from gestioncof.decorators import buro_required, cof_required
from utils.views.autocomplete import Select2QuerySetView
@@ -45,7 +56,7 @@ def etat_places(request, tirage_id):
"""
tirage = get_object_or_404(Tirage, id=tirage_id)
- spectacles = tirage.spectacle_set.select_related('location')
+ spectacles = tirage.spectacle_set.select_related("location")
spectacles_dict = {} # index of spectacle by id
for spectacle in spectacles:
@@ -53,10 +64,9 @@ def etat_places(request, tirage_id):
spectacles_dict[spectacle.id] = spectacle
choices = (
- ChoixSpectacle.objects
- .filter(spectacle__in=spectacles)
- .values('spectacle')
- .annotate(total=Count('spectacle'))
+ ChoixSpectacle.objects.filter(spectacle__in=spectacles)
+ .values("spectacle")
+ .annotate(total=Count("spectacle"))
)
# choices *by spectacles* whose only 1 place is requested
@@ -65,11 +75,11 @@ def etat_places(request, tirage_id):
choices2 = choices.exclude(double_choice="1")
for spectacle in choices1:
- pk = spectacle['spectacle']
- spectacles_dict[pk].total += spectacle['total']
+ pk = spectacle["spectacle"]
+ spectacles_dict[pk].total += spectacle["total"]
for spectacle in choices2:
- pk = spectacle['spectacle']
- spectacles_dict[pk].total += 2*spectacle['total']
+ pk = spectacle["spectacle"]
+ spectacles_dict[pk].total += 2 * spectacle["total"]
# here, each spectacle.total contains the number of requests
@@ -84,13 +94,13 @@ def etat_places(request, tirage_id):
"proposed": slots,
"spectacles": spectacles,
"total": total,
- 'tirage': tirage
+ "tirage": tirage,
}
return render(request, "bda/etat-places.html", context)
def _hash_queryset(queryset):
- data = serializers.serialize("json", queryset).encode('utf-8')
+ data = serializers.serialize("json", queryset).encode("utf-8")
hasher = hashlib.sha256()
hasher.update(data)
return hasher.hexdigest()
@@ -99,15 +109,10 @@ def _hash_queryset(queryset):
@cof_required
def places(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
- participant, _ = (
- Participant.objects
- .get_or_create(user=request.user, tirage=tirage)
- )
- places = (
- participant.attribution_set
- .order_by("spectacle__date", "spectacle")
- .select_related("spectacle", "spectacle__location")
- )
+ participant, _ = Participant.objects.get_or_create(user=request.user, tirage=tirage)
+ places = participant.attribution_set.order_by(
+ "spectacle__date", "spectacle"
+ ).select_related("spectacle", "spectacle__location")
total = sum(place.spectacle.price for place in places)
filtered_places = []
places_dict = {}
@@ -129,13 +134,21 @@ def places(request, tirage_id):
dates.append(date)
# On prévient l'utilisateur s'il a deux places à la même date
if warning:
- messages.warning(request, "Attention, vous avez reçu des places pour "
- "des spectacles différents à la même date.")
- return render(request, "bda/resume_places.html",
- {"participant": participant,
- "places": filtered_places,
- "tirage": tirage,
- "total": total})
+ messages.warning(
+ request,
+ "Attention, vous avez reçu des places pour "
+ "des spectacles différents à la même date.",
+ )
+ return render(
+ request,
+ "bda/resume_places.html",
+ {
+ "participant": participant,
+ "places": filtered_places,
+ "tirage": tirage,
+ "total": total,
+ },
+ )
@cof_required
@@ -151,24 +164,24 @@ def inscription(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
if timezone.now() < tirage.ouverture:
# Le tirage n'est pas encore ouvert.
- opening = formats.localize(
- timezone.template_localtime(tirage.ouverture))
- messages.error(request, "Le tirage n'est pas encore ouvert : "
- "ouverture le {:s}".format(opening))
- return render(request, 'bda/resume-inscription-tirage.html', {})
+ opening = formats.localize(timezone.template_localtime(tirage.ouverture))
+ messages.error(
+ request,
+ "Le tirage n'est pas encore ouvert : " "ouverture le {:s}".format(opening),
+ )
+ return render(request, "bda/resume-inscription-tirage.html", {})
- participant, _ = (
- Participant.objects.select_related('tirage')
- .get_or_create(user=request.user, tirage=tirage)
+ participant, _ = Participant.objects.select_related("tirage").get_or_create(
+ user=request.user, tirage=tirage
)
if timezone.now() > tirage.fermeture:
# Le tirage est fermé.
choices = participant.choixspectacle_set.order_by("priority")
- messages.error(request,
- " C'est fini : tirage au sort dans la journée !")
- return render(request, "bda/resume-inscription-tirage.html",
- {"choices": choices})
+ messages.error(request, " C'est fini : tirage au sort dans la journée !")
+ return render(
+ request, "bda/resume-inscription-tirage.html", {"choices": choices}
+ )
BdaFormSet = inlineformset_factory(
Participant,
@@ -196,27 +209,33 @@ def inscription(request, tirage_id):
# use *this* queryset
dbstate = _hash_queryset(participant.choixspectacle_set.all())
total_price = 0
- choices = (
- participant.choixspectacle_set
- .select_related('spectacle')
- )
+ choices = participant.choixspectacle_set.select_related("spectacle")
for choice in choices:
total_price += choice.spectacle.price
if choice.double:
total_price += choice.spectacle.price
# Messages
if success:
- messages.success(request, "Votre inscription a été mise à jour avec "
- "succès !")
+ messages.success(
+ request, "Votre inscription a été mise à jour avec " "succès !"
+ )
if stateerror:
- messages.error(request, "Impossible d'enregistrer vos modifications "
- ": vous avez apporté d'autres modifications "
- "entre temps.")
- return render(request, "bda/inscription-tirage.html",
- {"formset": formset,
- "total_price": total_price,
- "dbstate": dbstate,
- 'tirage': tirage})
+ messages.error(
+ request,
+ "Impossible d'enregistrer vos modifications "
+ ": vous avez apporté d'autres modifications "
+ "entre temps.",
+ )
+ return render(
+ request,
+ "bda/inscription-tirage.html",
+ {
+ "formset": formset,
+ "total_price": total_price,
+ "dbstate": dbstate,
+ "tirage": tirage,
+ },
+ )
def do_tirage(tirage_elt, token):
@@ -229,40 +248,39 @@ def do_tirage(tirage_elt, token):
# Initialisation du dictionnaire data qui va contenir les résultats
start = time.time()
data = {
- 'shows': tirage_elt.spectacle_set.select_related('location'),
- 'token': token,
- 'members': tirage_elt.participant_set.select_related('user'),
- 'total_slots': 0,
- 'total_losers': 0,
- 'total_sold': 0,
- 'total_deficit': 0,
- 'opera_deficit': 0,
+ "shows": tirage_elt.spectacle_set.select_related("location"),
+ "token": token,
+ "members": tirage_elt.participant_set.select_related("user"),
+ "total_slots": 0,
+ "total_losers": 0,
+ "total_sold": 0,
+ "total_deficit": 0,
+ "opera_deficit": 0,
}
# On lance le tirage
choices = (
- ChoixSpectacle.objects
- .filter(spectacle__tirage=tirage_elt)
- .order_by('participant', 'priority')
- .select_related('participant', 'participant__user', 'spectacle')
+ ChoixSpectacle.objects.filter(spectacle__tirage=tirage_elt)
+ .order_by("participant", "priority")
+ .select_related("participant", "participant__user", "spectacle")
)
- results = Algorithm(data['shows'], data['members'], choices)(token)
+ results = Algorithm(data["shows"], data["members"], choices)(token)
# On compte les places attribuées et les déçus
for (_, members, losers) in results:
- data['total_slots'] += len(members)
- data['total_losers'] += len(losers)
+ data["total_slots"] += len(members)
+ data["total_losers"] += len(losers)
# On calcule le déficit et les bénéfices pour le BdA
# FIXME: le traitement de l'opéra est sale
for (show, members, _) in results:
deficit = (show.slots - len(members)) * show.price
- data['total_sold'] += show.slots * show.price
+ data["total_sold"] += show.slots * show.price
if deficit >= 0:
if "Opéra" in show.location.name:
- data['opera_deficit'] += deficit
- data['total_deficit'] += deficit
- data["total_sold"] -= data['total_deficit']
+ data["opera_deficit"] += deficit
+ data["total_deficit"] += deficit
+ data["total_sold"] -= data["total_deficit"]
# Participant objects are not shared accross spectacle results,
# so assign a single object for each Participant id
@@ -288,32 +306,30 @@ def do_tirage(tirage_elt, token):
# désactive le tirage
Attribution.objects.filter(spectacle__tirage=tirage_elt).delete()
tirage_elt.tokens += '{:s}\n"""{:s}"""\n'.format(
- timezone.now().strftime("%y-%m-%d %H:%M:%S"),
- token)
+ timezone.now().strftime("%y-%m-%d %H:%M:%S"), token
+ )
tirage_elt.enable_do_tirage = False
tirage_elt.save()
# On enregistre les nouvelles attributions
- Attribution.objects.bulk_create([
- Attribution(spectacle=show, participant=member)
- for show, members, _ in results
- for member, _, _, _ in members
- ])
+ Attribution.objects.bulk_create(
+ [
+ Attribution(spectacle=show, participant=member)
+ for show, members, _ in results
+ for member, _, _, _ in members
+ ]
+ )
# On inscrit à BdA-Revente ceux qui n'ont pas eu les places voulues
ChoixRevente = Participant.choicesrevente.through
# Suppression des reventes demandées/enregistrées
# (si le tirage est relancé)
+ (ChoixRevente.objects.filter(spectacle__tirage=tirage_elt).delete())
(
- ChoixRevente.objects
- .filter(spectacle__tirage=tirage_elt)
- .delete()
- )
- (
- SpectacleRevente.objects
- .filter(attribution__spectacle__tirage=tirage_elt)
- .delete()
+ SpectacleRevente.objects.filter(
+ attribution__spectacle__tirage=tirage_elt
+ ).delete()
)
lost_by = defaultdict(set)
@@ -335,13 +351,12 @@ def do_tirage(tirage_elt, token):
@buro_required
def tirage(request, tirage_id):
tirage_elt = get_object_or_404(Tirage, id=tirage_id)
- if not (tirage_elt.enable_do_tirage
- and tirage_elt.fermeture < timezone.now()):
- return render(request, "tirage-failed.html", {'tirage': tirage_elt})
+ if not (tirage_elt.enable_do_tirage and tirage_elt.fermeture < timezone.now()):
+ return render(request, "tirage-failed.html", {"tirage": tirage_elt})
if request.POST:
form = TokenForm(request.POST)
if form.is_valid():
- results = do_tirage(tirage_elt, form.cleaned_data['token'])
+ results = do_tirage(tirage_elt, form.cleaned_data["token"])
return render(request, "bda-attrib-extra.html", results)
else:
form = TokenForm()
@@ -360,56 +375,59 @@ def revente_manage(request, tirage_id):
"""
tirage = get_object_or_404(Tirage, id=tirage_id)
participant, created = Participant.objects.get_or_create(
- user=request.user, tirage=tirage)
+ user=request.user, tirage=tirage
+ )
if not participant.paid:
return render(request, "bda/revente/notpaid.html", {})
- resellform = ResellForm(participant, prefix='resell')
- annulform = AnnulForm(participant, prefix='annul')
- soldform = SoldForm(participant, prefix='sold')
+ resellform = ResellForm(participant, prefix="resell")
+ annulform = AnnulForm(participant, prefix="annul")
+ soldform = SoldForm(participant, prefix="sold")
- if request.method == 'POST':
+ if request.method == "POST":
# On met en vente une place
- if 'resell' in request.POST:
- resellform = ResellForm(participant, request.POST, prefix='resell')
+ if "resell" in request.POST:
+ resellform = ResellForm(participant, request.POST, prefix="resell")
if resellform.is_valid():
datatuple = []
attributions = resellform.cleaned_data["attributions"]
with transaction.atomic():
for attribution in attributions:
- revente, created = \
- SpectacleRevente.objects.get_or_create(
- attribution=attribution,
- defaults={'seller': participant})
+ revente, created = SpectacleRevente.objects.get_or_create(
+ attribution=attribution, defaults={"seller": participant}
+ )
if not created:
revente.reset()
context = {
- 'vendeur': participant.user,
- 'show': attribution.spectacle,
- 'revente': revente
+ "vendeur": participant.user,
+ "show": attribution.spectacle,
+ "revente": revente,
}
- datatuple.append((
- 'bda-revente-new', context,
- settings.MAIL_DATA['revente']['FROM'],
- [participant.user.email]
- ))
+ datatuple.append(
+ (
+ "bda-revente-new",
+ context,
+ settings.MAIL_DATA["revente"]["FROM"],
+ [participant.user.email],
+ )
+ )
revente.save()
send_mass_custom_mail(datatuple)
# On annule une revente
- elif 'annul' in request.POST:
- annulform = AnnulForm(participant, request.POST, prefix='annul')
+ elif "annul" in request.POST:
+ annulform = AnnulForm(participant, request.POST, prefix="annul")
if annulform.is_valid():
reventes = annulform.cleaned_data["reventes"]
for revente in reventes:
revente.delete()
# On confirme une vente en transférant la place à la personne qui a
# gagné le tirage
- elif 'transfer' in request.POST:
- soldform = SoldForm(participant, request.POST, prefix='sold')
+ elif "transfer" in request.POST:
+ soldform = SoldForm(participant, request.POST, prefix="sold")
if soldform.is_valid():
- reventes = soldform.cleaned_data['reventes']
+ reventes = soldform.cleaned_data["reventes"]
for revente in reventes:
revente.attribution.participant = revente.soldTo
revente.attribution.save()
@@ -417,28 +435,26 @@ def revente_manage(request, tirage_id):
# On annule la revente après le tirage au sort (par exemple si
# la personne qui a gagné le tirage ne se manifeste pas). La place est
# alors remise en vente
- elif 'reinit' in request.POST:
- soldform = SoldForm(participant, request.POST, prefix='sold')
+ elif "reinit" in request.POST:
+ soldform = SoldForm(participant, request.POST, prefix="sold")
if soldform.is_valid():
- reventes = soldform.cleaned_data['reventes']
+ reventes = soldform.cleaned_data["reventes"]
for revente in reventes:
if revente.attribution.spectacle.date > timezone.now():
# On antidate pour envoyer le mail plus vite
- new_date = (timezone.now()
- - SpectacleRevente.remorse_time)
+ new_date = timezone.now() - SpectacleRevente.remorse_time
revente.reset(new_date=new_date)
- overdue = participant.attribution_set.filter(
- spectacle__date__gte=timezone.now(),
- revente__isnull=False,
- revente__seller=participant,
- revente__notif_sent=True)\
- .filter(
- Q(revente__soldTo__isnull=True) | Q(revente__soldTo=participant))
-
- return render(request, "bda/revente/manage.html",
- {'tirage': tirage, 'overdue': overdue, "soldform": soldform,
- "annulform": annulform, "resellform": resellform})
+ return render(
+ request,
+ "bda/revente/manage.html",
+ {
+ "tirage": tirage,
+ "soldform": soldform,
+ "annulform": annulform,
+ "resellform": resellform,
+ },
+ )
@login_required
@@ -448,58 +464,64 @@ def revente_tirages(request, tirage_id):
tirage donné) et lui permet de s'inscrire et se désinscrire à ces reventes.
"""
tirage = get_object_or_404(Tirage, id=tirage_id)
- participant, _ = Participant.objects.get_or_create(
- user=request.user, tirage=tirage)
+ participant, _ = Participant.objects.get_or_create(user=request.user, tirage=tirage)
subform = ReventeTirageForm(participant, prefix="subscribe")
annulform = ReventeTirageAnnulForm(participant, prefix="annul")
- if request.method == 'POST':
+ if request.method == "POST":
if "subscribe" in request.POST:
- subform = ReventeTirageForm(participant, request.POST,
- prefix="subscribe")
+ subform = ReventeTirageForm(participant, request.POST, prefix="subscribe")
if subform.is_valid():
- reventes = subform.cleaned_data['reventes']
+ reventes = subform.cleaned_data["reventes"]
count = reventes.count()
for revente in reventes:
revente.confirmed_entry.add(participant)
if count > 0:
messages.success(
request,
- "Tu as bien été inscrit à {} revente{}"
- .format(count, pluralize(count))
+ "Tu as bien été inscrit à {} revente{}".format(
+ count, pluralize(count)
+ ),
)
elif "annul" in request.POST:
- annulform = ReventeTirageAnnulForm(participant, request.POST,
- prefix="annul")
+ annulform = ReventeTirageAnnulForm(
+ participant, request.POST, prefix="annul"
+ )
if annulform.is_valid():
- reventes = annulform.cleaned_data['reventes']
+ reventes = annulform.cleaned_data["reventes"]
count = reventes.count()
for revente in reventes:
revente.confirmed_entry.remove(participant)
if count > 0:
messages.success(
request,
- "Tu as bien été désinscrit de {} revente{}"
- .format(count, pluralize(count))
+ "Tu as bien été désinscrit de {} revente{}".format(
+ count, pluralize(count)
+ ),
)
- return render(request, "bda/revente/tirages.html",
- {"annulform": annulform, "subform": subform})
+ return render(
+ request,
+ "bda/revente/tirages.html",
+ {"annulform": annulform, "subform": subform},
+ )
@login_required
def revente_confirm(request, revente_id):
revente = get_object_or_404(SpectacleRevente, id=revente_id)
participant, _ = Participant.objects.get_or_create(
- user=request.user, tirage=revente.attribution.spectacle.tirage)
+ user=request.user, tirage=revente.attribution.spectacle.tirage
+ )
if not revente.notif_sent or revente.shotgun:
- return render(request, "bda/revente/wrongtime.html",
- {"revente": revente})
+ return render(request, "bda/revente/wrongtime.html", {"revente": revente})
revente.confirmed_entry.add(participant)
- return render(request, "bda/revente/confirmed.html",
- {"spectacle": revente.attribution.spectacle,
- "date": revente.date_tirage})
+ return render(
+ request,
+ "bda/revente/confirmed.html",
+ {"spectacle": revente.attribution.spectacle, "date": revente.date_tirage},
+ )
@login_required
@@ -511,20 +533,18 @@ def revente_subscribe(request, tirage_id):
spectacle à la liste des spectacles qui l'intéressent.
"""
tirage = get_object_or_404(Tirage, id=tirage_id)
- participant, _ = Participant.objects.get_or_create(
- user=request.user, tirage=tirage)
+ participant, _ = Participant.objects.get_or_create(user=request.user, tirage=tirage)
deja_revente = False
success = False
inscrit_revente = []
- if request.method == 'POST':
+ if request.method == "POST":
form = InscriptionReventeForm(tirage, request.POST)
if form.is_valid():
- choices = form.cleaned_data['spectacles']
+ choices = form.cleaned_data["spectacles"]
participant.choicesrevente = choices
participant.save()
for spectacle in choices:
- qset = SpectacleRevente.objects.filter(
- attribution__spectacle=spectacle)
+ qset = SpectacleRevente.objects.filter(attribution__spectacle=spectacle)
if qset.filter(shotgun=True, soldTo__isnull=True).exists():
# Une place est disponible au shotgun, on suggère à
# l'utilisateur d'aller la récupérer
@@ -535,8 +555,8 @@ def revente_subscribe(request, tirage_id):
# la revente ayant le moins d'inscrits
min_resell = (
qset.filter(shotgun=False)
- .annotate(nb_subscribers=Count('confirmed_entry'))
- .order_by('nb_subscribers')
+ .annotate(nb_subscribers=Count("confirmed_entry"))
+ .order_by("nb_subscribers")
.first()
)
if min_resell is not None:
@@ -545,21 +565,23 @@ def revente_subscribe(request, tirage_id):
success = True
else:
form = InscriptionReventeForm(
- tirage,
- initial={'spectacles': participant.choicesrevente.all()}
+ tirage, initial={"spectacles": participant.choicesrevente.all()}
)
# Messages
if success:
messages.success(request, "Ton inscription a bien été prise en compte")
if deja_revente:
- messages.info(request, "Des reventes existent déjà pour certains de "
- "ces spectacles, vérifie les places "
- "disponibles sans tirage !")
+ messages.info(
+ request,
+ "Des reventes existent déjà pour certains de "
+ "ces spectacles, vérifie les places "
+ "disponibles sans tirage !",
+ )
if inscrit_revente:
shows = map("{!s} ".format, inscrit_revente)
msg = (
"Tu as été inscrit à des reventes en cours pour les spectacles "
- "".format('\n'.join(shows))
+ "".format("\n".join(shows))
)
messages.info(request, msg, extra_tags="safe")
@@ -570,19 +592,17 @@ def revente_subscribe(request, tirage_id):
def revente_buy(request, spectacle_id):
spectacle = get_object_or_404(Spectacle, id=spectacle_id)
tirage = spectacle.tirage
- participant, _ = Participant.objects.get_or_create(
- user=request.user, tirage=tirage)
+ participant, _ = Participant.objects.get_or_create(user=request.user, tirage=tirage)
reventes = SpectacleRevente.objects.filter(
- attribution__spectacle=spectacle,
- soldTo__isnull=True)
+ attribution__spectacle=spectacle, soldTo__isnull=True
+ )
# Si l'utilisateur veut racheter une place qu'il est en train de revendre,
# on supprime la revente en question.
own_reventes = reventes.filter(seller=participant)
if len(own_reventes) > 0:
own_reventes[0].delete()
- return HttpResponseRedirect(reverse("bda-revente-shotgun",
- args=[tirage.id]))
+ return HttpResponseRedirect(reverse("bda-revente-shotgun", args=[tirage.id]))
reventes_shotgun = reventes.filter(shotgun=True)
@@ -594,94 +614,98 @@ def revente_buy(request, spectacle_id):
revente.soldTo = participant
revente.save()
context = {
- 'show': spectacle,
- 'acheteur': request.user,
- 'vendeur': revente.seller.user
+ "show": spectacle,
+ "acheteur": request.user,
+ "vendeur": revente.seller.user,
}
send_custom_mail(
- 'bda-buy-shotgun',
- 'bda@ens.fr',
+ "bda-buy-shotgun",
+ "bda@ens.fr",
[revente.seller.user.email],
context=context,
)
- return render(request, "bda/revente/mail-success.html",
- {"seller": revente.attribution.participant.user,
- "spectacle": spectacle})
+ return render(
+ request,
+ "bda/revente/mail-success.html",
+ {"seller": revente.attribution.participant.user, "spectacle": spectacle},
+ )
- return render(request, "bda/revente/confirm-shotgun.html",
- {"spectacle": spectacle,
- "user": request.user})
+ return render(
+ request,
+ "bda/revente/confirm-shotgun.html",
+ {"spectacle": spectacle, "user": request.user},
+ )
@login_required
def revente_shotgun(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
spectacles = (
- tirage.spectacle_set
- .filter(date__gte=timezone.now())
- .select_related('location')
- .prefetch_related(Prefetch(
- 'attribues',
- queryset=(
- Attribution.objects
- .filter(revente__shotgun=True,
- revente__soldTo__isnull=True)
- ),
- to_attr='shotguns',
- ))
+ tirage.spectacle_set.filter(date__gte=timezone.now())
+ .select_related("location")
+ .prefetch_related(
+ Prefetch(
+ "attribues",
+ queryset=(
+ Attribution.objects.filter(
+ revente__shotgun=True, revente__soldTo__isnull=True
+ )
+ ),
+ to_attr="shotguns",
+ )
+ )
)
shotgun = [sp for sp in spectacles if len(sp.shotguns) > 0]
- return render(request, "bda/revente/shotgun.html",
- {"shotgun": shotgun})
+ return render(request, "bda/revente/shotgun.html", {"shotgun": shotgun})
@buro_required
def spectacle(request, tirage_id, spectacle_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
spectacle = get_object_or_404(Spectacle, id=spectacle_id, tirage=tirage)
- attributions = (
- spectacle.attribues
- .select_related('participant', 'participant__user')
+ attributions = spectacle.attribues.select_related(
+ "participant", "participant__user"
)
participants = {}
for attrib in attributions:
participant = attrib.participant
- participant_info = {'lastname': participant.user.last_name,
- 'name': participant.user.get_full_name,
- 'username': participant.user.username,
- 'email': participant.user.email,
- 'given': int(attrib.given),
- 'paid': participant.paid,
- 'nb_places': 1}
+ participant_info = {
+ "lastname": participant.user.last_name,
+ "name": participant.user.get_full_name,
+ "username": participant.user.username,
+ "email": participant.user.email,
+ "given": int(attrib.given),
+ "paid": participant.paid,
+ "nb_places": 1,
+ }
if participant.id in participants:
- participants[participant.id]['nb_places'] += 1
- participants[participant.id]['given'] += attrib.given
+ participants[participant.id]["nb_places"] += 1
+ participants[participant.id]["given"] += attrib.given
else:
participants[participant.id] = participant_info
- participants_info = sorted(participants.values(),
- key=lambda part: part['lastname'])
- return render(request, "bda/participants.html",
- {"spectacle": spectacle, "participants": participants_info})
+ participants_info = sorted(participants.values(), key=lambda part: part["lastname"])
+ return render(
+ request,
+ "bda/participants.html",
+ {"spectacle": spectacle, "participants": participants_info},
+ )
class SpectacleListView(ListView):
model = Spectacle
- template_name = 'spectacle_list.html'
+ template_name = "spectacle_list.html"
def get_queryset(self):
- self.tirage = get_object_or_404(Tirage, id=self.kwargs['tirage_id'])
- categories = (
- self.tirage.spectacle_set
- .select_related('location')
- )
+ self.tirage = get_object_or_404(Tirage, id=self.kwargs["tirage_id"])
+ categories = self.tirage.spectacle_set.select_related("location")
return categories
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['tirage_id'] = self.tirage.id
- context['tirage_name'] = self.tirage.title
+ context["tirage_id"] = self.tirage.id
+ context["tirage_name"] = self.tirage.title
return context
@@ -689,10 +713,9 @@ class SpectacleListView(ListView):
def unpaid(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
unpaid = (
- tirage.participant_set
- .annotate(nb_attributions=Count('attribution'))
+ tirage.participant_set.annotate(nb_attributions=Count("attribution"))
.filter(paid=False, nb_attributions__gt=0)
- .select_related('user')
+ .select_related("user")
)
return render(request, "bda-unpaid.html", {"unpaid": unpaid})
@@ -702,51 +725,45 @@ def send_rappel(request, spectacle_id):
show = get_object_or_404(Spectacle, id=spectacle_id)
# Mails d'exemples
custommail = CustomMail.objects.get(shortname="bda-rappel")
- exemple_mail_1place = custommail.render({
- 'member': request.user,
- 'show': show,
- 'nb_attr': 1
- })
- exemple_mail_2places = custommail.render({
- 'member': request.user,
- 'show': show,
- 'nb_attr': 2
- })
+ exemple_mail_1place = custommail.render(
+ {"member": request.user, "show": show, "nb_attr": 1}
+ )
+ exemple_mail_2places = custommail.render(
+ {"member": request.user, "show": show, "nb_attr": 2}
+ )
# Contexte
ctxt = {
- 'show': show,
- 'exemple_mail_1place': exemple_mail_1place,
- 'exemple_mail_2places': exemple_mail_2places,
- 'custommail': custommail,
+ "show": show,
+ "exemple_mail_1place": exemple_mail_1place,
+ "exemple_mail_2places": exemple_mail_2places,
+ "custommail": custommail,
}
# Envoi confirmé
- if request.method == 'POST':
+ if request.method == "POST":
members = show.send_rappel()
- ctxt['sent'] = True
- ctxt['members'] = members
+ ctxt["sent"] = True
+ ctxt["members"] = members
# Demande de confirmation
else:
- ctxt['sent'] = False
+ ctxt["sent"] = False
if show.rappel_sent:
messages.warning(
request,
"Attention, un mail de rappel pour ce spectale a déjà été "
- "envoyé le {}".format(formats.localize(
- timezone.template_localtime(show.rappel_sent)
- ))
+ "envoyé le {}".format(
+ formats.localize(timezone.template_localtime(show.rappel_sent))
+ ),
)
return render(request, "bda/mails-rappel.html", ctxt)
def descriptions_spectacles(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
- shows_qs = (
- tirage.spectacle_set
- .select_related('location')
- .prefetch_related('quote_set')
+ shows_qs = tirage.spectacle_set.select_related("location").prefetch_related(
+ "quote_set"
)
- category_name = request.GET.get('category', '')
- location_id = request.GET.get('location', '')
+ category_name = request.GET.get("category", "")
+ location_id = request.GET.get("location", "")
if category_name:
shows_qs = shows_qs.filter(category__name=category_name)
if location_id:
@@ -754,8 +771,9 @@ def descriptions_spectacles(request, tirage_id):
shows_qs = shows_qs.filter(location__id=int(location_id))
except ValueError:
return HttpResponseBadRequest(
- "La variable GET 'location' doit contenir un entier")
- return render(request, 'descriptions.html', {'shows': shows_qs})
+ "La variable GET 'location' doit contenir un entier"
+ )
+ return render(request, "descriptions.html", {"shows": shows_qs})
def catalogue(request, request_type):
@@ -768,44 +786,36 @@ def catalogue(request, request_type):
if request_type == "list":
# Dans ce cas on retourne la liste des tirages et de leur id en JSON
data_return = list(
- Tirage.objects.filter(appear_catalogue=True).values('id', 'title')
+ Tirage.objects.filter(appear_catalogue=True).values("id", "title")
)
return JsonResponse(data_return, safe=False)
if request_type == "details":
# Dans ce cas on retourne une liste des catégories et des salles
- tirage_id = request.GET.get('id', None)
+ tirage_id = request.GET.get("id", None)
if tirage_id is None:
- return HttpResponseBadRequest(
- "Missing GET parameter: id "
- )
+ return HttpResponseBadRequest("Missing GET parameter: id ")
try:
tirage = get_object_or_404(Tirage, id=int(tirage_id))
except ValueError:
- return HttpResponseBadRequest(
- "Bad format: int expected for `id`"
- )
+ return HttpResponseBadRequest("Bad format: int expected for `id`")
shows = tirage.spectacle_set.values_list("id", flat=True)
categories = list(
- CategorieSpectacle.objects
- .filter(spectacle__in=shows)
+ CategorieSpectacle.objects.filter(spectacle__in=shows)
.distinct()
- .values('id', 'name')
+ .values("id", "name")
)
locations = list(
- Salle.objects
- .filter(spectacle__in=shows)
- .distinct()
- .values('id', 'name')
+ Salle.objects.filter(spectacle__in=shows).distinct().values("id", "name")
)
- data_return = {'categories': categories, 'locations': locations}
+ data_return = {"categories": categories, "locations": locations}
return JsonResponse(data_return, safe=False)
if request_type == "descriptions":
# Ici on retourne les descriptions correspondant à la catégorie et
# à la salle spécifiées
- tirage_id = request.GET.get('id', '')
- categories = request.GET.get('category', '[]')
- locations = request.GET.get('location', '[]')
+ tirage_id = request.GET.get("id", "")
+ categories = request.GET.get("category", "[]")
+ locations = request.GET.get("location", "[]")
try:
tirage_id = int(tirage_id)
categories_id = json.loads(categories)
@@ -821,17 +831,16 @@ def catalogue(request, request_type):
"following types:\n"
"id: int, category: [int], location: [int]\n"
"Data received:\n"
- "id = {}, category = {}, locations = {}"
- .format(request.GET.get('id', ''),
- request.GET.get('category', '[]'),
- request.GET.get('location', '[]'))
+ "id = {}, category = {}, locations = {}".format(
+ request.GET.get("id", ""),
+ request.GET.get("category", "[]"),
+ request.GET.get("location", "[]"),
+ )
)
tirage = get_object_or_404(Tirage, id=tirage_id)
- shows_qs = (
- tirage.spectacle_set
- .select_related('location')
- .prefetch_related('quote_set')
+ shows_qs = tirage.spectacle_set.select_related("location").prefetch_related(
+ "quote_set"
)
if categories_id and 0 not in categories_id:
shows_qs = shows_qs.filter(category__id__in=categories_id)
@@ -841,23 +850,27 @@ def catalogue(request, request_type):
# On convertit les descriptions à envoyer en une liste facilement
# JSONifiable (il devrait y avoir un moyen plus efficace en
# redéfinissant le serializer de JSON)
- data_return = [{
- 'title': spectacle.title,
- 'category': str(spectacle.category),
- 'date': str(formats.date_format(
- timezone.localtime(spectacle.date),
- "SHORT_DATETIME_FORMAT")),
- 'location': str(spectacle.location),
- 'vips': spectacle.vips,
- 'description': spectacle.description,
- 'slots_description': spectacle.slots_description,
- 'quotes': [dict(author=quote.author,
- text=quote.text)
- for quote in spectacle.quote_set.all()],
- 'image': spectacle.getImgUrl(),
- 'ext_link': spectacle.ext_link,
- 'price': spectacle.price,
- 'slots': spectacle.slots
+ data_return = [
+ {
+ "title": spectacle.title,
+ "category": str(spectacle.category),
+ "date": str(
+ formats.date_format(
+ timezone.localtime(spectacle.date), "SHORT_DATETIME_FORMAT"
+ )
+ ),
+ "location": str(spectacle.location),
+ "vips": spectacle.vips,
+ "description": spectacle.description,
+ "slots_description": spectacle.slots_description,
+ "quotes": [
+ dict(author=quote.author, text=quote.text)
+ for quote in spectacle.quote_set.all()
+ ],
+ "image": spectacle.getImgUrl(),
+ "ext_link": spectacle.ext_link,
+ "price": spectacle.price,
+ "slots": spectacle.slots,
}
for spectacle in shows_qs
]
@@ -875,7 +888,7 @@ def catalogue(request, request_type):
class ParticipantAutocomplete(Select2QuerySetView):
model = Participant
- search_fields = ('user__username', 'user__first_name', 'user__last_name')
+ search_fields = ("user__username", "user__first_name", "user__last_name")
participant_autocomplete = buro_required(ParticipantAutocomplete.as_view())
@@ -883,7 +896,7 @@ participant_autocomplete = buro_required(ParticipantAutocomplete.as_view())
class SpectacleAutocomplete(Select2QuerySetView):
model = Spectacle
- search_fields = ('title',)
+ search_fields = ("title",)
spectacle_autocomplete = buro_required(SpectacleAutocomplete.as_view())
diff --git a/cof/asgi.py b/cof/asgi.py
index a34621c7..ab4ce291 100644
--- a/cof/asgi.py
+++ b/cof/asgi.py
@@ -1,4 +1,5 @@
import os
+
from channels.asgi import get_channel_layer
if "DJANGO_SETTINGS_MODULE" not in os.environ:
diff --git a/cof/locale/fr/formats.py b/cof/locale/fr/formats.py
index 4b47ce3d..3120d5ce 100644
--- a/cof/locale/fr/formats.py
+++ b/cof/locale/fr/formats.py
@@ -2,4 +2,4 @@
Formats français.
"""
-DATETIME_FORMAT = r'l j F Y \à H:i'
+DATETIME_FORMAT = r"l j F Y \à H:i"
diff --git a/cof/routing.py b/cof/routing.py
index c604adf4..3c2e5718 100644
--- a/cof/routing.py
+++ b/cof/routing.py
@@ -1,6 +1,3 @@
from channels.routing import include
-
-routing = [
- include('kfet.routing.routing', path=r'^/ws/k-fet'),
-]
+routing = [include("kfet.routing.routing", path=r"^/ws/k-fet")]
diff --git a/cof/settings/common.py b/cof/settings/common.py
index 02c796ad..ebc7fb2a 100644
--- a/cof/settings/common.py
+++ b/cof/settings/common.py
@@ -46,112 +46,106 @@ KFETOPEN_TOKEN = import_secret("KFETOPEN_TOKEN")
LDAP_SERVER_URL = import_secret("LDAP_SERVER_URL")
-BASE_DIR = os.path.dirname(
- os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-TESTING = sys.argv[1] == 'test'
+TESTING = sys.argv[1] == "test"
# Application definition
INSTALLED_APPS = [
- 'shared',
-
- 'gestioncof',
-
+ "shared",
+ "gestioncof",
# Must be before 'django.contrib.admin'.
# https://django-autocomplete-light.readthedocs.io/en/master/install.html
- 'dal',
- 'dal_select2',
-
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.sites',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'django.contrib.admin',
- 'django.contrib.admindocs',
-
- 'bda',
- 'captcha',
- 'django_cas_ng',
- 'bootstrapform',
- 'kfet',
- 'kfet.open',
- 'channels',
- 'widget_tweaks',
- 'custommail',
- 'djconfig',
- 'wagtail.wagtailforms',
- 'wagtail.wagtailredirects',
- 'wagtail.wagtailembeds',
- 'wagtail.wagtailsites',
- 'wagtail.wagtailusers',
- 'wagtail.wagtailsnippets',
- 'wagtail.wagtaildocs',
- 'wagtail.wagtailimages',
- 'wagtail.wagtailsearch',
- 'wagtail.wagtailadmin',
- 'wagtail.wagtailcore',
- 'wagtail.contrib.modeladmin',
- 'wagtailmenus',
- 'modelcluster',
- 'taggit',
- 'kfet.auth',
- 'kfet.cms',
- 'corsheaders',
+ "dal",
+ "dal_select2",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.sites",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+ "django.contrib.admin",
+ "django.contrib.admindocs",
+ "bda",
+ "captcha",
+ "django_cas_ng",
+ "bootstrapform",
+ "kfet",
+ "kfet.open",
+ "channels",
+ "widget_tweaks",
+ "custommail",
+ "djconfig",
+ "wagtail.wagtailforms",
+ "wagtail.wagtailredirects",
+ "wagtail.wagtailembeds",
+ "wagtail.wagtailsites",
+ "wagtail.wagtailusers",
+ "wagtail.wagtailsnippets",
+ "wagtail.wagtaildocs",
+ "wagtail.wagtailimages",
+ "wagtail.wagtailsearch",
+ "wagtail.wagtailadmin",
+ "wagtail.wagtailcore",
+ "wagtail.contrib.modeladmin",
+ "wagtailmenus",
+ "modelcluster",
+ "taggit",
+ "kfet.auth",
+ "kfet.cms",
+ "corsheaders",
]
MIDDLEWARE = [
- 'corsheaders.middleware.CorsMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
- 'kfet.auth.middleware.TemporaryAuthMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
- 'django.middleware.security.SecurityMiddleware',
- 'djconfig.middleware.DjConfigMiddleware',
- 'wagtail.wagtailcore.middleware.SiteMiddleware',
- 'wagtail.wagtailredirects.middleware.RedirectMiddleware',
+ "corsheaders.middleware.CorsMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.auth.middleware.SessionAuthenticationMiddleware",
+ "kfet.auth.middleware.TemporaryAuthMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "django.middleware.security.SecurityMiddleware",
+ "djconfig.middleware.DjConfigMiddleware",
+ "wagtail.wagtailcore.middleware.SiteMiddleware",
+ "wagtail.wagtailredirects.middleware.RedirectMiddleware",
]
-ROOT_URLCONF = 'cof.urls'
+ROOT_URLCONF = "cof.urls"
TEMPLATES = [
{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- 'django.template.context_processors.i18n',
- 'django.template.context_processors.media',
- 'django.template.context_processors.static',
- 'wagtailmenus.context_processors.wagtailmenus',
- 'djconfig.context_processors.config',
- 'gestioncof.shared.context_processor',
- 'kfet.auth.context_processors.temporary_auth',
- 'kfet.context_processors.config',
- ],
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ "django.template.context_processors.i18n",
+ "django.template.context_processors.media",
+ "django.template.context_processors.static",
+ "wagtailmenus.context_processors.wagtailmenus",
+ "djconfig.context_processors.config",
+ "gestioncof.shared.context_processor",
+ "kfet.auth.context_processors.temporary_auth",
+ "kfet.context_processors.config",
+ ]
},
- },
+ }
]
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'NAME': DBNAME,
- 'USER': DBUSER,
- 'PASSWORD': DBPASSWD,
- 'HOST': os.environ.get('DBHOST', 'localhost'),
+ "default": {
+ "ENGINE": "django.db.backends.postgresql_psycopg2",
+ "NAME": DBNAME,
+ "USER": DBUSER,
+ "PASSWORD": DBPASSWD,
+ "HOST": os.environ.get("DBHOST", "localhost"),
}
}
@@ -159,9 +153,9 @@ DATABASES = {
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
-LANGUAGE_CODE = 'fr-fr'
+LANGUAGE_CODE = "fr-fr"
-TIME_ZONE = 'Europe/Paris'
+TIME_ZONE = "Europe/Paris"
USE_I18N = True
@@ -173,35 +167,35 @@ USE_TZ = True
SITE_ID = 1
GRAPPELLI_ADMIN_HEADLINE = "GestioCOF"
-GRAPPELLI_ADMIN_TITLE = "GestioCOF "
+GRAPPELLI_ADMIN_TITLE = 'GestioCOF '
MAIL_DATA = {
- 'petits_cours': {
- 'FROM': "Le COF ",
- 'BCC': "archivescof@gmail.com",
- 'REPLYTO': "cof@ens.fr"},
- 'rappels': {
- 'FROM': 'Le BdA ',
- 'REPLYTO': 'Le BdA '},
- 'revente': {
- 'FROM': 'BdA-Revente ',
- 'REPLYTO': 'BdA-Revente '},
+ "petits_cours": {
+ "FROM": "Le COF ",
+ "BCC": "archivescof@gmail.com",
+ "REPLYTO": "cof@ens.fr",
+ },
+ "rappels": {"FROM": "Le BdA ", "REPLYTO": "Le BdA "},
+ "revente": {
+ "FROM": "BdA-Revente ",
+ "REPLYTO": "BdA-Revente ",
+ },
}
LOGIN_URL = "cof-login"
LOGIN_REDIRECT_URL = "home"
-CAS_SERVER_URL = 'https://cas.eleves.ens.fr/'
-CAS_VERSION = '3'
+CAS_SERVER_URL = "https://cas.eleves.ens.fr/"
+CAS_VERSION = "3"
CAS_LOGIN_MSG = None
CAS_IGNORE_REFERER = True
-CAS_REDIRECT_URL = '/'
+CAS_REDIRECT_URL = "/"
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
AUTHENTICATION_BACKENDS = (
- 'django.contrib.auth.backends.ModelBackend',
- 'gestioncof.shared.COFCASBackend',
- 'kfet.auth.backends.GenericBackend',
+ "django.contrib.auth.backends.ModelBackend",
+ "gestioncof.shared.COFCASBackend",
+ "kfet.auth.backends.GenericBackend",
)
@@ -214,21 +208,16 @@ AUTHENTICATION_BACKENDS = (
NOCAPTCHA = True
RECAPTCHA_USE_SSL = True
-CORS_ORIGIN_WHITELIST = (
- 'bda.ens.fr',
- 'www.bda.ens.fr'
- 'cof.ens.fr',
- 'www.cof.ens.fr',
-)
+CORS_ORIGIN_WHITELIST = ("bda.ens.fr", "www.bda.ens.fr" "cof.ens.fr", "www.cof.ens.fr")
# Cache settings
CACHES = {
- 'default': {
- 'BACKEND': 'redis_cache.RedisCache',
- 'LOCATION': 'redis://:{passwd}@{host}:{port}/db'
- .format(passwd=REDIS_PASSWD, host=REDIS_HOST,
- port=REDIS_PORT, db=REDIS_DB),
+ "default": {
+ "BACKEND": "redis_cache.RedisCache",
+ "LOCATION": "redis://:{passwd}@{host}:{port}/db".format(
+ passwd=REDIS_PASSWD, host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB
+ ),
}
}
@@ -239,20 +228,25 @@ CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"CONFIG": {
- "hosts": [(
- "redis://:{passwd}@{host}:{port}/{db}"
- .format(passwd=REDIS_PASSWD, host=REDIS_HOST,
- port=REDIS_PORT, db=REDIS_DB)
- )],
+ "hosts": [
+ (
+ "redis://:{passwd}@{host}:{port}/{db}".format(
+ passwd=REDIS_PASSWD,
+ host=REDIS_HOST,
+ port=REDIS_PORT,
+ db=REDIS_DB,
+ )
+ )
+ ]
},
"ROUTING": "cof.routing.routing",
}
}
-FORMAT_MODULE_PATH = 'cof.locale'
+FORMAT_MODULE_PATH = "cof.locale"
# Wagtail settings
-WAGTAIL_SITE_NAME = 'GestioCOF'
+WAGTAIL_SITE_NAME = "GestioCOF"
WAGTAIL_ENABLE_UPDATE_CHECK = False
TAGGIT_CASE_INSENSITIVE = True
diff --git a/cof/settings/dev.py b/cof/settings/dev.py
index 114f37da..0fd367cd 100644
--- a/cof/settings/dev.py
+++ b/cof/settings/dev.py
@@ -6,32 +6,30 @@ The settings that are not listed here are imported from .common
from .common import * # NOQA
from .common import INSTALLED_APPS, MIDDLEWARE, TESTING
-
-EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
DEBUG = True
if TESTING:
- PASSWORD_HASHERS = [
- 'django.contrib.auth.hashers.MD5PasswordHasher',
- ]
+ PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
# ---
# Apache static/media config
# ---
-STATIC_URL = '/static/'
-STATIC_ROOT = '/srv/gestiocof/static/'
+STATIC_URL = "/static/"
+STATIC_ROOT = "/srv/gestiocof/static/"
-MEDIA_ROOT = '/srv/gestiocof/media/'
-MEDIA_URL = '/media/'
+MEDIA_ROOT = "/srv/gestiocof/media/"
+MEDIA_URL = "/media/"
# ---
# Debug tool bar
# ---
+
def show_toolbar(request):
"""
On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar
@@ -41,13 +39,10 @@ def show_toolbar(request):
"""
return DEBUG
+
if not TESTING:
INSTALLED_APPS += ["debug_toolbar", "debug_panel"]
- MIDDLEWARE = [
- "debug_panel.middleware.DebugPanelMiddleware"
- ] + MIDDLEWARE
+ MIDDLEWARE = ["debug_panel.middleware.DebugPanelMiddleware"] + MIDDLEWARE
- DEBUG_TOOLBAR_CONFIG = {
- 'SHOW_TOOLBAR_CALLBACK': show_toolbar,
- }
+ DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar}
diff --git a/cof/settings/local.py b/cof/settings/local.py
index 6e1f0802..06cdf4a0 100644
--- a/cof/settings/local.py
+++ b/cof/settings/local.py
@@ -8,21 +8,16 @@ import os
from .dev import * # NOQA
from .dev import BASE_DIR
-
# Use sqlite for local development
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
- "NAME": os.path.join(BASE_DIR, "db.sqlite3")
+ "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
# Use the default cache backend for local development
-CACHES = {
- "default": {
- "BACKEND": "django.core.cache.backends.locmem.LocMemCache"
- }
-}
+CACHES = {"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}}
# Use the default in memory asgi backend for local development
CHANNEL_LAYERS = {
diff --git a/cof/settings/prod.py b/cof/settings/prod.py
index fcdb3fdb..9e355ccb 100644
--- a/cof/settings/prod.py
+++ b/cof/settings/prod.py
@@ -8,21 +8,13 @@ import os
from .common import * # NOQA
from .common import BASE_DIR, import_secret
-
DEBUG = False
-ALLOWED_HOSTS = [
- "cof.ens.fr",
- "www.cof.ens.fr",
- "dev.cof.ens.fr"
-]
+ALLOWED_HOSTS = ["cof.ens.fr", "www.cof.ens.fr", "dev.cof.ens.fr"]
STATIC_ROOT = os.path.join(
- os.path.dirname(os.path.dirname(BASE_DIR)),
- "public",
- "gestion",
- "static",
+ os.path.dirname(os.path.dirname(BASE_DIR)), "public", "gestion", "static"
)
STATIC_URL = "/gestion/static/"
diff --git a/cof/settings/secret_example.py b/cof/settings/secret_example.py
index e966565a..7921d467 100644
--- a/cof/settings/secret_example.py
+++ b/cof/settings/secret_example.py
@@ -1,4 +1,4 @@
-SECRET_KEY = 'q()(zn4m63i%5cp4)f+ww4-28_w+ly3q9=6imw2ciu&_(5_4ah'
+SECRET_KEY = "q()(zn4m63i%5cp4)f+ww4-28_w+ly3q9=6imw2ciu&_(5_4ah"
ADMINS = None
SERVER_EMAIL = "root@vagrant"
EMAIL_HOST = "localhost"
diff --git a/cof/urls.py b/cof/urls.py
index a1d0c9bf..7a0bee4c 100644
--- a/cof/urls.py
+++ b/cof/urls.py
@@ -6,111 +6,130 @@ from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin
-from django.views.generic.base import TemplateView
from django.contrib.auth import views as django_views
+from django.views.generic.base import TemplateView
from django_cas_ng import views as django_cas_views
-
from wagtail.wagtailadmin import urls as wagtailadmin_urls
from wagtail.wagtailcore import urls as wagtail_urls
from wagtail.wagtaildocs import urls as wagtaildocs_urls
-from gestioncof import views as gestioncof_views, csv_views
-from gestioncof.urls import export_patterns, petitcours_patterns, \
- surveys_patterns, events_patterns, calendar_patterns, \
- clubs_patterns
+from gestioncof import csv_views, views as gestioncof_views
from gestioncof.autocomplete import autocomplete
+from gestioncof.urls import (
+ calendar_patterns,
+ clubs_patterns,
+ events_patterns,
+ export_patterns,
+ petitcours_patterns,
+ surveys_patterns,
+)
admin.autodiscover()
urlpatterns = [
# Page d'accueil
- url(r'^$', gestioncof_views.home, name='home'),
+ url(r"^$", gestioncof_views.home, name="home"),
# Le BdA
- url(r'^bda/', include('bda.urls')),
+ url(r"^bda/", include("bda.urls")),
# Les exports
- url(r'^export/', include(export_patterns)),
+ url(r"^export/", include(export_patterns)),
# Les petits cours
- url(r'^petitcours/', include(petitcours_patterns)),
+ url(r"^petitcours/", include(petitcours_patterns)),
# Les sondages
- url(r'^survey/', include(surveys_patterns)),
+ url(r"^survey/", include(surveys_patterns)),
# Evenements
- url(r'^event/', include(events_patterns)),
+ url(r"^event/", include(events_patterns)),
# Calendrier
- url(r'^calendar/', include(calendar_patterns)),
+ url(r"^calendar/", include(calendar_patterns)),
# Clubs
- url(r'^clubs/', include(clubs_patterns)),
+ url(r"^clubs/", include(clubs_patterns)),
# Authentification
- url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'),
- name="cof-denied"),
- url(r'^cas/login$', django_cas_views.login, name="cas_login_view"),
- url(r'^cas/logout$', django_cas_views.logout),
- url(r'^outsider/login$', gestioncof_views.login_ext,
- name="ext_login_view"),
- url(r'^outsider/logout$', django_views.logout, {'next_page': 'home'}),
- url(r'^login$', gestioncof_views.login, name="cof-login"),
- url(r'^logout$', gestioncof_views.logout, name="cof-logout"),
+ url(
+ r"^cof/denied$",
+ TemplateView.as_view(template_name="cof-denied.html"),
+ name="cof-denied",
+ ),
+ url(r"^cas/login$", django_cas_views.login, name="cas_login_view"),
+ url(r"^cas/logout$", django_cas_views.logout),
+ url(r"^outsider/login$", gestioncof_views.login_ext, name="ext_login_view"),
+ url(r"^outsider/logout$", django_views.logout, {"next_page": "home"}),
+ url(r"^login$", gestioncof_views.login, name="cof-login"),
+ url(r"^logout$", gestioncof_views.logout, name="cof-logout"),
# Infos persos
- url(r'^profile$', gestioncof_views.profile,
- name='profile'),
- url(r'^outsider/password-change$', django_views.password_change,
- name='password_change'),
- url(r'^outsider/password-change-done$',
+ url(r"^profile$", gestioncof_views.profile, name="profile"),
+ url(
+ r"^outsider/password-change$",
+ django_views.password_change,
+ name="password_change",
+ ),
+ url(
+ r"^outsider/password-change-done$",
django_views.password_change_done,
- name='password_change_done'),
+ name="password_change_done",
+ ),
# Inscription d'un nouveau membre
- url(r'^registration$', gestioncof_views.registration,
- name='registration'),
- url(r'^registration/clipper/(?P[\w-]+)/'
- r'(?P.*)$',
- gestioncof_views.registration_form2, name="clipper-registration"),
- url(r'^registration/user/(?P.+)$',
- gestioncof_views.registration_form2, name="user-registration"),
- url(r'^registration/empty$', gestioncof_views.registration_form2,
- name="empty-registration"),
+ url(r"^registration$", gestioncof_views.registration, name="registration"),
+ url(
+ r"^registration/clipper/(?P[\w-]+)/" r"(?P.*)$",
+ gestioncof_views.registration_form2,
+ name="clipper-registration",
+ ),
+ url(
+ r"^registration/user/(?P.+)$",
+ gestioncof_views.registration_form2,
+ name="user-registration",
+ ),
+ url(
+ r"^registration/empty$",
+ gestioncof_views.registration_form2,
+ name="empty-registration",
+ ),
# Autocompletion
- url(r'^autocomplete/registration$', autocomplete,
- name="cof.registration.autocomplete"),
- url(r'^user/autocomplete$', gestioncof_views.user_autocomplete,
- name='cof-user-autocomplete'),
+ url(
+ r"^autocomplete/registration$",
+ autocomplete,
+ name="cof.registration.autocomplete",
+ ),
+ url(
+ r"^user/autocomplete$",
+ gestioncof_views.user_autocomplete,
+ name="cof-user-autocomplete",
+ ),
# Interface admin
- url(r'^admin/logout/', gestioncof_views.logout),
- url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
- url(r'^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/',
+ url(r"^admin/logout/", gestioncof_views.logout),
+ url(r"^admin/doc/", include("django.contrib.admindocs.urls")),
+ url(
+ r"^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/",
csv_views.admin_list_export,
- {'fields': ['username', ]}),
- url(r'^admin/', include(admin.site.urls)),
+ {"fields": ["username"]},
+ ),
+ url(r"^admin/", include(admin.site.urls)),
# Liens utiles du COF et du BdA
- url(r'^utile_cof$', gestioncof_views.utile_cof,
- name='utile_cof'),
- url(r'^utile_bda$', gestioncof_views.utile_bda,
- name='utile_bda'),
- url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff,
- name="ml_diffbda"),
- url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof,
- name='ml_diffcof'),
- url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente,
- name="ml_bda_revente"),
- url(r'^k-fet/', include('kfet.urls')),
- url(r'^cms/', include(wagtailadmin_urls)),
- url(r'^documents/', include(wagtaildocs_urls)),
+ url(r"^utile_cof$", gestioncof_views.utile_cof, name="utile_cof"),
+ url(r"^utile_bda$", gestioncof_views.utile_bda, name="utile_bda"),
+ url(r"^utile_bda/bda_diff$", gestioncof_views.liste_bdadiff, name="ml_diffbda"),
+ url(r"^utile_cof/diff_cof$", gestioncof_views.liste_diffcof, name="ml_diffcof"),
+ url(
+ r"^utile_bda/bda_revente$",
+ gestioncof_views.liste_bdarevente,
+ name="ml_bda_revente",
+ ),
+ url(r"^k-fet/", include("kfet.urls")),
+ url(r"^cms/", include(wagtailadmin_urls)),
+ url(r"^documents/", include(wagtaildocs_urls)),
# djconfig
- url(r"^config", gestioncof_views.ConfigUpdate.as_view(),
- name='config.edit'),
+ url(r"^config", gestioncof_views.ConfigUpdate.as_view(), name="config.edit"),
]
-if 'debug_toolbar' in settings.INSTALLED_APPS:
+if "debug_toolbar" in settings.INSTALLED_APPS:
import debug_toolbar
- urlpatterns += [
- url(r'^__debug__/', include(debug_toolbar.urls)),
- ]
+
+ urlpatterns += [url(r"^__debug__/", include(debug_toolbar.urls))]
if settings.DEBUG:
# Si on est en production, MEDIA_ROOT est servi par Apache.
# Il faut dire à Django de servir MEDIA_ROOT lui-même en développement.
- urlpatterns += static(settings.MEDIA_URL,
- document_root=settings.MEDIA_ROOT)
+ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# Wagtail for uncatched
-urlpatterns += [
- url(r'', include(wagtail_urls)),
-]
+urlpatterns += [url(r"", include(wagtail_urls))]
diff --git a/gestioncof/__init__.py b/gestioncof/__init__.py
index b77fdb94..3bb260b9 100644
--- a/gestioncof/__init__.py
+++ b/gestioncof/__init__.py
@@ -1 +1 @@
-default_app_config = 'gestioncof.apps.GestioncofConfig'
+default_app_config = "gestioncof.apps.GestioncofConfig"
diff --git a/gestioncof/admin.py b/gestioncof/admin.py
index 54a6a5a0..e89d4271 100644
--- a/gestioncof/admin.py
+++ b/gestioncof/admin.py
@@ -1,23 +1,35 @@
+from dal.autocomplete import ModelSelect2
from django import forms
from django.contrib import admin
-from django.utils.translation import ugettext_lazy as _
-from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \
- CofProfile, EventOption, EventOptionChoice, Event, Club, \
- Survey, EventCommentField, EventRegistration
-from gestioncof.petits_cours_models import PetitCoursDemande, \
- PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
- PetitCoursAttributionCounter
-from django.contrib.auth.models import User, Group, Permission
from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.models import Group, Permission, User
from django.core.urlresolvers import reverse
-from django.utils.safestring import mark_safe
from django.db.models import Q
+from django.utils.safestring import mark_safe
+from django.utils.translation import ugettext_lazy as _
-from dal.autocomplete import ModelSelect2
+from gestioncof.models import (
+ Club,
+ CofProfile,
+ Event,
+ EventCommentField,
+ EventOption,
+ EventOptionChoice,
+ EventRegistration,
+ Survey,
+ SurveyQuestion,
+ SurveyQuestionAnswer,
+)
+from gestioncof.petits_cours_models import (
+ PetitCoursAbility,
+ PetitCoursAttribution,
+ PetitCoursAttributionCounter,
+ PetitCoursDemande,
+ PetitCoursSubject,
+)
-def add_link_field(target_model='', field='', link_text=str,
- desc_text=str):
+def add_link_field(target_model="", field="", link_text=str, desc_text=str):
def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower()
@@ -28,14 +40,14 @@ def add_link_field(target_model='', field='', link_text=str,
if not link_obj.id:
return ""
url = reverse(reverse_path, args=(link_obj.id,))
- return mark_safe("%s "
- % (url, link_text(link_obj)))
+ return mark_safe("%s " % (url, link_text(link_obj)))
+
link.allow_tags = True
- link.short_description = desc_text(reverse_name + ' link')
+ link.short_description = desc_text(reverse_name + " link")
cls.link = link
- cls.readonly_fields =\
- list(getattr(cls, 'readonly_fields', [])) + ['link']
+ cls.readonly_fields = list(getattr(cls, "readonly_fields", [])) + ["link"]
return cls
+
return add_link
@@ -43,32 +55,28 @@ class SurveyQuestionAnswerInline(admin.TabularInline):
model = SurveyQuestionAnswer
-@add_link_field(desc_text=lambda x: "Réponses",
- link_text=lambda x: "Éditer les réponses")
+@add_link_field(
+ desc_text=lambda x: "Réponses", link_text=lambda x: "Éditer les réponses"
+)
class SurveyQuestionInline(admin.TabularInline):
model = SurveyQuestion
class SurveyQuestionAdmin(admin.ModelAdmin):
- search_fields = ('survey__title', 'answer')
- inlines = [
- SurveyQuestionAnswerInline,
- ]
+ search_fields = ("survey__title", "answer")
+ inlines = [SurveyQuestionAnswerInline]
class SurveyAdmin(admin.ModelAdmin):
- search_fields = ('title', 'details')
- inlines = [
- SurveyQuestionInline,
- ]
+ search_fields = ("title", "details")
+ inlines = [SurveyQuestionInline]
class EventOptionChoiceInline(admin.TabularInline):
model = EventOptionChoice
-@add_link_field(desc_text=lambda x: "Choix",
- link_text=lambda x: "Éditer les choix")
+@add_link_field(desc_text=lambda x: "Choix", link_text=lambda x: "Éditer les choix")
class EventOptionInline(admin.TabularInline):
model = EventOption
@@ -78,18 +86,13 @@ class EventCommentFieldInline(admin.TabularInline):
class EventOptionAdmin(admin.ModelAdmin):
- search_fields = ('event__title', 'name')
- inlines = [
- EventOptionChoiceInline,
- ]
+ search_fields = ("event__title", "name")
+ inlines = [EventOptionChoiceInline]
class EventAdmin(admin.ModelAdmin):
- search_fields = ('title', 'location', 'description')
- inlines = [
- EventOptionInline,
- EventCommentFieldInline,
- ]
+ search_fields = ("title", "location", "description")
+ inlines = [EventOptionInline, EventCommentFieldInline]
class CofProfileInline(admin.StackedInline):
@@ -98,10 +101,9 @@ class CofProfileInline(admin.StackedInline):
class FkeyLookup(object):
- def __init__(self, fkeydecl, short_description=None,
- admin_order_field=None):
- self.fk, fkattrs = fkeydecl.split('__', 1)
- self.fkattrs = fkattrs.split('__')
+ def __init__(self, fkeydecl, short_description=None, admin_order_field=None):
+ self.fk, fkattrs = fkeydecl.split("__", 1)
+ self.fkattrs = fkattrs.split("__")
self.short_description = short_description or self.fkattrs[-1]
self.admin_order_field = admin_order_field or fkeydecl
@@ -126,19 +128,19 @@ def ProfileInfo(field, short_description, boolean=False):
return getattr(self.profile, field)
except CofProfile.DoesNotExist:
return ""
+
getter.short_description = short_description
getter.boolean = boolean
return getter
-User.profile_login_clipper = FkeyLookup("profile__login_clipper",
- "Login clipper")
+
+User.profile_login_clipper = FkeyLookup("profile__login_clipper", "Login clipper")
User.profile_phone = ProfileInfo("phone", "Téléphone")
User.profile_occupation = ProfileInfo("occupation", "Occupation")
User.profile_departement = ProfileInfo("departement", "Departement")
User.profile_mailing_cof = ProfileInfo("mailing_cof", "ML COF", True)
User.profile_mailing_bda = ProfileInfo("mailing_bda", "ML BdA", True)
-User.profile_mailing_bda_revente = ProfileInfo("mailing_bda_revente",
- "ML BdA-R", True)
+User.profile_mailing_bda_revente = ProfileInfo("mailing_bda_revente", "ML BdA-R", True)
class UserProfileAdmin(UserAdmin):
@@ -147,7 +149,8 @@ class UserProfileAdmin(UserAdmin):
return obj.profile.is_buro
except CofProfile.DoesNotExist:
return False
- is_buro.short_description = 'Membre du Buro'
+
+ is_buro.short_description = "Membre du Buro"
is_buro.boolean = True
def is_cof(self, obj):
@@ -155,27 +158,33 @@ class UserProfileAdmin(UserAdmin):
return obj.profile.is_cof
except CofProfile.DoesNotExist:
return False
- is_cof.short_description = 'Membre du COF'
+
+ is_cof.short_description = "Membre du COF"
is_cof.boolean = True
- list_display = (
- UserAdmin.list_display
- + ('profile_login_clipper', 'profile_phone', 'profile_occupation',
- 'profile_mailing_cof', 'profile_mailing_bda',
- 'profile_mailing_bda_revente', 'is_cof', 'is_buro', )
+ list_display = UserAdmin.list_display + (
+ "profile_login_clipper",
+ "profile_phone",
+ "profile_occupation",
+ "profile_mailing_cof",
+ "profile_mailing_bda",
+ "profile_mailing_bda_revente",
+ "is_cof",
+ "is_buro",
)
- list_display_links = ('username', 'email', 'first_name', 'last_name')
- list_filter = UserAdmin.list_filter \
- + ('profile__is_cof', 'profile__is_buro', 'profile__mailing_cof',
- 'profile__mailing_bda')
- search_fields = UserAdmin.search_fields + ('profile__phone',)
- inlines = [
- CofProfileInline,
- ]
+ list_display_links = ("username", "email", "first_name", "last_name")
+ list_filter = UserAdmin.list_filter + (
+ "profile__is_cof",
+ "profile__is_buro",
+ "profile__mailing_cof",
+ "profile__mailing_bda",
+ )
+ search_fields = UserAdmin.search_fields + ("profile__phone",)
+ inlines = [CofProfileInline]
staff_fieldsets = [
- (None, {'fields': ['username', 'password']}),
- (_('Personal info'), {'fields': ['first_name', 'last_name', 'email']}),
+ (None, {"fields": ["username", "password"]}),
+ (_("Personal info"), {"fields": ["first_name", "last_name", "email"]}),
]
def get_fieldsets(self, request, user=None):
@@ -184,15 +193,15 @@ class UserProfileAdmin(UserAdmin):
return super().get_fieldsets(request, user)
def save_model(self, request, user, form, change):
- cof_group, created = Group.objects.get_or_create(name='COF')
+ cof_group, created = Group.objects.get_or_create(name="COF")
if created:
# Si le groupe COF n'était pas déjà dans la bdd
# On lui assigne les bonnes permissions
perms = Permission.objects.filter(
- Q(content_type__app_label='gestioncof')
- | Q(content_type__app_label='bda')
- | (Q(content_type__app_label='auth')
- & Q(content_type__model='user')))
+ Q(content_type__app_label="gestioncof")
+ | Q(content_type__app_label="bda")
+ | (Q(content_type__app_label="auth") & Q(content_type__model="user"))
+ )
cof_group.permissions = perms
# On y associe les membres du Burô
cof_group.user_set = User.objects.filter(profile__is_buro=True)
@@ -214,72 +223,97 @@ def user_str(self):
return "{} ({})".format(self.get_full_name(), self.username)
else:
return self.username
+
+
User.__str__ = user_str
class EventRegistrationAdminForm(forms.ModelForm):
class Meta:
- widgets = {
- 'user': ModelSelect2(url='cof-user-autocomplete'),
- }
+ widgets = {"user": ModelSelect2(url="cof-user-autocomplete")}
class EventRegistrationAdmin(admin.ModelAdmin):
form = EventRegistrationAdminForm
- list_display = ('__str__', 'event', 'user', 'paid')
- list_filter = ('paid',)
- search_fields = ('user__username', 'user__first_name', 'user__last_name',
- 'user__email', 'event__title')
+ list_display = ("__str__", "event", "user", "paid")
+ list_filter = ("paid",)
+ search_fields = (
+ "user__username",
+ "user__first_name",
+ "user__last_name",
+ "user__email",
+ "event__title",
+ )
class PetitCoursAbilityAdmin(admin.ModelAdmin):
- list_display = ('user', 'matiere', 'niveau', 'agrege')
- search_fields = ('user__username', 'user__first_name', 'user__last_name',
- 'user__email', 'matiere__name', 'niveau')
- list_filter = ('matiere', 'niveau', 'agrege')
+ list_display = ("user", "matiere", "niveau", "agrege")
+ search_fields = (
+ "user__username",
+ "user__first_name",
+ "user__last_name",
+ "user__email",
+ "matiere__name",
+ "niveau",
+ )
+ list_filter = ("matiere", "niveau", "agrege")
class PetitCoursAttributionAdmin(admin.ModelAdmin):
- list_display = ('user', 'demande', 'matiere', 'rank', )
- search_fields = ('user__username', 'matiere__name')
+ list_display = ("user", "demande", "matiere", "rank")
+ search_fields = ("user__username", "matiere__name")
class PetitCoursAttributionCounterAdmin(admin.ModelAdmin):
- list_display = ('user', 'matiere', 'count', )
- list_filter = ('matiere',)
- search_fields = ('user__username', 'user__first_name', 'user__last_name',
- 'user__email', 'matiere__name')
- actions = ['reset', ]
+ list_display = ("user", "matiere", "count")
+ list_filter = ("matiere",)
+ search_fields = (
+ "user__username",
+ "user__first_name",
+ "user__last_name",
+ "user__email",
+ "matiere__name",
+ )
+ actions = ["reset"]
actions_on_bottom = True
def reset(self, request, queryset):
queryset.update(count=0)
+
reset.short_description = "Remise à zéro du compteur"
class PetitCoursDemandeAdmin(admin.ModelAdmin):
- list_display = ('name', 'email', 'agrege_requis', 'niveau', 'created',
- 'traitee', 'processed')
- list_filter = ('traitee', 'niveau')
- search_fields = ('name', 'email', 'phone', 'lieu', 'remarques')
+ list_display = (
+ "name",
+ "email",
+ "agrege_requis",
+ "niveau",
+ "created",
+ "traitee",
+ "processed",
+ )
+ list_filter = ("traitee", "niveau")
+ search_fields = ("name", "email", "phone", "lieu", "remarques")
class ClubAdminForm(forms.ModelForm):
def clean(self):
cleaned_data = super().clean()
- respos = cleaned_data.get('respos')
- members = cleaned_data.get('membres')
+ respos = cleaned_data.get("respos")
+ members = cleaned_data.get("membres")
for respo in respos.all():
if respo not in members:
raise forms.ValidationError(
"Erreur : le respo %s n'est pas membre du club."
- % respo.get_full_name())
+ % respo.get_full_name()
+ )
return cleaned_data
class ClubAdmin(admin.ModelAdmin):
- list_display = ['name']
+ list_display = ["name"]
form = ClubAdminForm
@@ -294,7 +328,6 @@ admin.site.register(Club, ClubAdmin)
admin.site.register(PetitCoursSubject)
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
-admin.site.register(PetitCoursAttributionCounter,
- PetitCoursAttributionCounterAdmin)
+admin.site.register(PetitCoursAttributionCounter, PetitCoursAttributionCounterAdmin)
admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin)
admin.site.register(EventRegistration, EventRegistrationAdmin)
diff --git a/gestioncof/apps.py b/gestioncof/apps.py
index 78120ef4..88e2fbfc 100644
--- a/gestioncof/apps.py
+++ b/gestioncof/apps.py
@@ -2,14 +2,16 @@ from django.apps import AppConfig
class GestioncofConfig(AppConfig):
- name = 'gestioncof'
+ name = "gestioncof"
verbose_name = "Gestion des adhérents du COF"
def ready(self):
- from . import signals
+ from . import signals # noqa
+
self.register_config()
def register_config(self):
import djconfig
from .forms import GestioncofConfigForm
+
djconfig.register(GestioncofConfigForm)
diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py
index 1d60cd78..0aa94ae9 100644
--- a/gestioncof/autocomplete.py
+++ b/gestioncof/autocomplete.py
@@ -1,13 +1,12 @@
+from django import shortcuts
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.db.models import Q
+from django.http import Http404
from ldap3 import Connection
-from django import shortcuts
-from django.http import Http404
-from django.db.models import Q
-from django.contrib.auth.models import User
-from django.conf import settings
-
-from gestioncof.models import CofProfile
from gestioncof.decorators import buro_required
+from gestioncof.models import CofProfile
class Clipper(object):
@@ -19,68 +18,71 @@ class Clipper(object):
self.clipper = clipper
self.fullname = fullname
+ def __str__(self):
+ return "{} ({})".format(self.clipper, self.fullname)
+
+ def __eq__(self, other):
+ return self.clipper == other.clipper and self.fullname == other.fullname
+
@buro_required
def autocomplete(request):
if "q" not in request.GET:
raise Http404
- q = request.GET['q']
- data = {
- 'q': q,
- }
+ q = request.GET["q"]
+ data = {"q": q}
queries = {}
bits = q.split()
# Fetching data from User and CofProfile tables
- queries['members'] = CofProfile.objects.filter(is_cof=True)
- queries['users'] = User.objects.filter(profile__is_cof=False)
+ queries["members"] = CofProfile.objects.filter(is_cof=True)
+ queries["users"] = User.objects.filter(profile__is_cof=False)
for bit in bits:
- queries['members'] = queries['members'].filter(
+ queries["members"] = queries["members"].filter(
Q(user__first_name__icontains=bit)
| Q(user__last_name__icontains=bit)
| Q(user__username__icontains=bit)
- | Q(login_clipper__icontains=bit))
- queries['users'] = queries['users'].filter(
+ | Q(login_clipper__icontains=bit)
+ )
+ queries["users"] = queries["users"].filter(
Q(first_name__icontains=bit)
| Q(last_name__icontains=bit)
- | Q(username__icontains=bit))
- queries['members'] = queries['members'].distinct()
- queries['users'] = queries['users'].distinct()
+ | Q(username__icontains=bit)
+ )
+ queries["members"] = queries["members"].distinct()
+ queries["users"] = queries["users"].distinct()
# Clearing redundancies
- usernames = (
- set(queries['members'].values_list('login_clipper', flat='True'))
- | set(queries['users'].values_list('profile__login_clipper',
- flat='True'))
+ usernames = set(queries["members"].values_list("login_clipper", flat="True")) | set(
+ queries["users"].values_list("profile__login_clipper", flat="True")
)
# Fetching data from the SPI
- if getattr(settings, 'LDAP_SERVER_URL', None):
+ if getattr(settings, "LDAP_SERVER_URL", None):
# Fetching
- ldap_query = '(&{:s})'.format(''.join(
- '(|(cn=*{bit:s}*)(uid=*{bit:s}*))'.format(bit=bit)
- for bit in bits if bit.isalnum()
- ))
+ ldap_query = "(&{:s})".format(
+ "".join(
+ "(|(cn=*{bit:s}*)(uid=*{bit:s}*))".format(bit=bit)
+ for bit in bits
+ if bit.isalnum()
+ )
+ )
if ldap_query != "(&)":
# If none of the bits were legal, we do not perform the query
entries = None
with Connection(settings.LDAP_SERVER_URL) as conn:
- conn.search(
- 'dc=spi,dc=ens,dc=fr', ldap_query,
- attributes=['uid', 'cn']
- )
+ conn.search("dc=spi,dc=ens,dc=fr", ldap_query, attributes=["uid", "cn"])
entries = conn.entries
# Clearing redundancies
- queries['clippers'] = [
+ queries["clippers"] = [
Clipper(entry.uid.value, entry.cn.value)
for entry in entries
- if entry.uid.value
- and entry.uid.value not in usernames
+ if entry.uid.value and entry.uid.value not in usernames
]
# Resulting data
data.update(queries)
- data['options'] = sum(len(query) for query in queries)
+ data["options"] = sum(len(query) for query in queries)
return shortcuts.render(request, "autocomplete_user.html", data)
diff --git a/gestioncof/csv_views.py b/gestioncof/csv_views.py
index 733768dc..e85c78b0 100644
--- a/gestioncof/csv_views.py
+++ b/gestioncof/csv_views.py
@@ -1,14 +1,16 @@
import csv
+
+from django.apps import apps
from django.http import HttpResponse, HttpResponseForbidden
from django.template.defaultfilters import slugify
-from django.apps import apps
def export(qs, fields=None):
model = qs.model
- response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment; filename=%s.csv' \
- % slugify(model.__name__)
+ response = HttpResponse(content_type="text/csv")
+ response["Content-Disposition"] = "attachment; filename=%s.csv" % slugify(
+ model.__name__
+ )
writer = csv.writer(response)
# Write headers to CSV file
if fields:
@@ -32,8 +34,9 @@ def export(qs, fields=None):
return response
-def admin_list_export(request, model_name, app_label, queryset=None,
- fields=None, list_display=True):
+def admin_list_export(
+ request, model_name, app_label, queryset=None, fields=None, list_display=True
+):
"""
Put the following line in your urls.py BEFORE your admin include
(r'^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/',
diff --git a/gestioncof/decorators.py b/gestioncof/decorators.py
index 3875b77d..ef811730 100644
--- a/gestioncof/decorators.py
+++ b/gestioncof/decorators.py
@@ -5,9 +5,10 @@ def is_cof(user):
try:
profile = user.profile
return profile.is_cof
- except:
+ except Exception:
return False
+
cof_required = user_passes_test(is_cof)
@@ -15,7 +16,8 @@ def is_buro(user):
try:
profile = user.profile
return profile.is_buro
- except:
+ except Exception:
return False
+
buro_required = user_passes_test(is_buro)
diff --git a/gestioncof/forms.py b/gestioncof/forms.py
index 4a9087fd..aec5ce24 100644
--- a/gestioncof/forms.py
+++ b/gestioncof/forms.py
@@ -1,16 +1,13 @@
from django import forms
-from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
-from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.formsets import BaseFormSet, formset_factory
-
+from django.forms.widgets import CheckboxSelectMultiple, RadioSelect
+from django.utils.translation import ugettext_lazy as _
from djconfig.forms import ConfigForm
-from gestioncof.models import CofProfile, EventCommentValue, \
- CalendarSubscription, Club
-from gestioncof.widgets import TriStateCheckbox
-
from bda.models import Spectacle
+from gestioncof.models import CalendarSubscription, Club, CofProfile, EventCommentValue
+from gestioncof.widgets import TriStateCheckbox
class EventForm(forms.Form):
@@ -28,31 +25,33 @@ class EventForm(forms.Form):
choices[choice.event_option.id].append(choice.id)
all_choices = choices
for option in event.options.all():
- choices = [(choice.id, choice.value)
- for choice in option.choices.all()]
+ choices = [(choice.id, choice.value) for choice in option.choices.all()]
if option.multi_choices:
- initial = [] if option.id not in all_choices \
- else all_choices[option.id]
+ initial = [] if option.id not in all_choices else all_choices[option.id]
field = forms.MultipleChoiceField(
label=option.name,
choices=choices,
widget=CheckboxSelectMultiple,
required=False,
- initial=initial)
+ initial=initial,
+ )
else:
- initial = None if option.id not in all_choices \
- else all_choices[option.id][0]
- field = forms.ChoiceField(label=option.name,
- choices=choices,
- widget=RadioSelect,
- required=False,
- initial=initial)
+ initial = (
+ None if option.id not in all_choices else all_choices[option.id][0]
+ )
+ field = forms.ChoiceField(
+ label=option.name,
+ choices=choices,
+ widget=RadioSelect,
+ required=False,
+ initial=initial,
+ )
field.option_id = option.id
self.fields["option_%d" % option.id] = field
def choices(self):
for name, value in self.cleaned_data.items():
- if name.startswith('option_'):
+ if name.startswith("option_"):
yield (self.fields[name].option_id, value)
@@ -69,31 +68,33 @@ class SurveyForm(forms.Form):
else:
answers[answer.survey_question.id].append(answer.id)
for question in survey.questions.all():
- choices = [(answer.id, answer.answer)
- for answer in question.answers.all()]
+ choices = [(answer.id, answer.answer) for answer in question.answers.all()]
if question.multi_answers:
- initial = [] if question.id not in answers\
- else answers[question.id]
+ initial = [] if question.id not in answers else answers[question.id]
field = forms.MultipleChoiceField(
label=question.question,
choices=choices,
widget=CheckboxSelectMultiple,
required=False,
- initial=initial)
+ initial=initial,
+ )
else:
- initial = None if question.id not in answers\
- else answers[question.id][0]
- field = forms.ChoiceField(label=question.question,
- choices=choices,
- widget=RadioSelect,
- required=False,
- initial=initial)
+ initial = (
+ None if question.id not in answers else answers[question.id][0]
+ )
+ field = forms.ChoiceField(
+ label=question.question,
+ choices=choices,
+ widget=RadioSelect,
+ required=False,
+ initial=initial,
+ )
field.question_id = question.id
self.fields["question_%d" % question.id] = field
def answers(self):
for name, value in self.cleaned_data.items():
- if name.startswith('question_'):
+ if name.startswith("question_"):
yield (self.fields[name].question_id, value)
@@ -104,8 +105,7 @@ class SurveyStatusFilterForm(forms.Form):
for question in survey.questions.all():
for answer in question.answers.all():
name = "question_%d_answer_%d" % (question.id, answer.id)
- if self.is_bound \
- and self.data.get(self.add_prefix(name), None):
+ if self.is_bound and self.data.get(self.add_prefix(name), None):
initial = self.data.get(self.add_prefix(name), None)
else:
initial = "none"
@@ -114,16 +114,20 @@ class SurveyStatusFilterForm(forms.Form):
choices=[("yes", "yes"), ("no", "no"), ("none", "none")],
widget=TriStateCheckbox,
required=False,
- initial=initial)
+ initial=initial,
+ )
field.question_id = question.id
field.answer_id = answer.id
self.fields[name] = field
def filters(self):
for name, value in self.cleaned_data.items():
- if name.startswith('question_'):
- yield (self.fields[name].question_id,
- self.fields[name].answer_id, value)
+ if name.startswith("question_"):
+ yield (
+ self.fields[name].question_id,
+ self.fields[name].answer_id,
+ value,
+ )
class EventStatusFilterForm(forms.Form):
@@ -133,8 +137,7 @@ class EventStatusFilterForm(forms.Form):
for option in event.options.all():
for choice in option.choices.all():
name = "option_%d_choice_%d" % (option.id, choice.id)
- if self.is_bound \
- and self.data.get(self.add_prefix(name), None):
+ if self.is_bound and self.data.get(self.add_prefix(name), None):
initial = self.data.get(self.add_prefix(name), None)
else:
initial = "none"
@@ -143,7 +146,8 @@ class EventStatusFilterForm(forms.Form):
choices=[("yes", "yes"), ("no", "no"), ("none", "none")],
widget=TriStateCheckbox,
required=False,
- initial=initial)
+ initial=initial,
+ )
field.option_id = option.id
field.choice_id = choice.id
self.fields[name] = field
@@ -153,48 +157,45 @@ class EventStatusFilterForm(forms.Form):
initial = self.data.get(self.add_prefix(name), None)
else:
initial = "none"
- field = forms.ChoiceField(label="Événement payé",
- choices=[("yes", "yes"), ("no", "no"),
- ("none", "none")],
- widget=TriStateCheckbox,
- required=False,
- initial=initial)
+ field = forms.ChoiceField(
+ label="Événement payé",
+ choices=[("yes", "yes"), ("no", "no"), ("none", "none")],
+ widget=TriStateCheckbox,
+ required=False,
+ initial=initial,
+ )
self.fields[name] = field
def filters(self):
for name, value in self.cleaned_data.items():
- if name.startswith('option_'):
- yield (self.fields[name].option_id,
- self.fields[name].choice_id, value)
+ if name.startswith("option_"):
+ yield (self.fields[name].option_id, self.fields[name].choice_id, value)
elif name == "event_has_paid":
yield ("has_paid", None, value)
-class UserProfileForm(forms.ModelForm):
- first_name = forms.CharField(label=_('Prénom'), max_length=30)
- last_name = forms.CharField(label=_('Nom'), max_length=30)
+class UserForm(forms.ModelForm):
+ class Meta:
+ model = User
+ fields = ["first_name", "last_name", "email"]
- def __init__(self, *args, **kw):
- super().__init__(*args, **kw)
- self.fields['first_name'].initial = self.instance.user.first_name
- self.fields['last_name'].initial = self.instance.user.last_name
-
- def save(self, *args, **kw):
- super().save(*args, **kw)
- self.instance.user.first_name = self.cleaned_data.get('first_name')
- self.instance.user.last_name = self.cleaned_data.get('last_name')
- self.instance.user.save()
+class ProfileForm(forms.ModelForm):
class Meta:
model = CofProfile
- fields = ["first_name", "last_name", "phone", "mailing_cof",
- "mailing_bda", "mailing_bda_revente"]
+ fields = [
+ "phone",
+ "mailing_cof",
+ "mailing_bda",
+ "mailing_bda_revente",
+ "mailing_unernestaparis",
+ ]
class RegistrationUserForm(forms.ModelForm):
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
- self.fields['username'].help_text = ""
+ self.fields["username"].help_text = ""
class Meta:
model = User
@@ -205,22 +206,23 @@ class RegistrationPassUserForm(RegistrationUserForm):
"""
Formulaire pour changer le mot de passe d'un utilisateur.
"""
- password1 = forms.CharField(label=_('Mot de passe'),
- widget=forms.PasswordInput)
- password2 = forms.CharField(label=_('Confirmation du mot de passe'),
- widget=forms.PasswordInput)
+
+ password1 = forms.CharField(label=_("Mot de passe"), widget=forms.PasswordInput)
+ password2 = forms.CharField(
+ label=_("Confirmation du mot de passe"), widget=forms.PasswordInput
+ )
def clean_password2(self):
- pass1 = self.cleaned_data['password1']
- pass2 = self.cleaned_data['password2']
+ pass1 = self.cleaned_data["password1"]
+ pass2 = self.cleaned_data["password2"]
if pass1 and pass2:
if pass1 != pass2:
- raise forms.ValidationError(_('Mots de passe non identiques.'))
+ raise forms.ValidationError(_("Mots de passe non identiques."))
return pass2
def save(self, commit=True, *args, **kwargs):
user = super().save(commit, *args, **kwargs)
- user.set_password(self.cleaned_data['password2'])
+ user.set_password(self.cleaned_data["password2"])
if commit:
user.save()
return user
@@ -229,44 +231,62 @@ class RegistrationPassUserForm(RegistrationUserForm):
class RegistrationProfileForm(forms.ModelForm):
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
- self.fields['mailing_cof'].initial = True
- self.fields['mailing_bda'].initial = True
- self.fields['mailing_bda_revente'].initial = True
+ self.fields["mailing_cof"].initial = True
+ self.fields["mailing_bda"].initial = True
+ self.fields["mailing_bda_revente"].initial = True
+ self.fields["mailing_unernestaparis"].initial = True
self.fields.keyOrder = [
- 'login_clipper',
- 'phone',
- 'occupation',
- 'departement',
- 'is_cof',
- 'type_cotiz',
- 'mailing_cof',
- 'mailing_bda',
- 'mailing_bda_revente',
- 'comments'
- ]
+ "login_clipper",
+ "phone",
+ "occupation",
+ "departement",
+ "is_cof",
+ "type_cotiz",
+ "mailing_cof",
+ "mailing_bda",
+ "mailing_bda_revente",
+ "mailing_unernestaparis",
+ "comments",
+ ]
class Meta:
model = CofProfile
- fields = ("login_clipper", "phone", "occupation",
- "departement", "is_cof", "type_cotiz", "mailing_cof",
- "mailing_bda", "mailing_bda_revente", "comments")
+ fields = (
+ "login_clipper",
+ "phone",
+ "occupation",
+ "departement",
+ "is_cof",
+ "type_cotiz",
+ "mailing_cof",
+ "mailing_bda",
+ "mailing_bda_revente",
+ "mailing_unernestaparis",
+ "comments",
+ )
-STATUS_CHOICES = (('no', 'Non'),
- ('wait', 'Oui mais attente paiement'),
- ('paid', 'Oui payé'),)
+
+STATUS_CHOICES = (
+ ("no", "Non"),
+ ("wait", "Oui mais attente paiement"),
+ ("paid", "Oui payé"),
+)
class AdminEventForm(forms.Form):
- status = forms.ChoiceField(label="Inscription", initial="no",
- choices=STATUS_CHOICES, widget=RadioSelect)
+ status = forms.ChoiceField(
+ label="Inscription", initial="no", choices=STATUS_CHOICES, widget=RadioSelect
+ )
def __init__(self, *args, **kwargs):
self.event = kwargs.pop("event")
registration = kwargs.pop("current_registration", None)
- current_choices, paid = \
- (registration.options.all(), registration.paid) \
- if registration is not None else ([], None)
+ current_choices, paid = (
+ (registration.options.all(), registration.paid)
+ if registration is not None
+ else ([], None)
+ )
if paid is True:
kwargs["initial"] = {"status": "paid"}
elif paid is False:
@@ -282,66 +302,69 @@ class AdminEventForm(forms.Form):
choices[choice.event_option.id].append(choice.id)
all_choices = choices
for option in self.event.options.all():
- choices = [(choice.id, choice.value)
- for choice in option.choices.all()]
+ choices = [(choice.id, choice.value) for choice in option.choices.all()]
if option.multi_choices:
- initial = [] if option.id not in all_choices\
- else all_choices[option.id]
+ initial = [] if option.id not in all_choices else all_choices[option.id]
field = forms.MultipleChoiceField(
label=option.name,
choices=choices,
widget=CheckboxSelectMultiple,
required=False,
- initial=initial)
+ initial=initial,
+ )
else:
- initial = None if option.id not in all_choices\
- else all_choices[option.id][0]
- field = forms.ChoiceField(label=option.name,
- choices=choices,
- widget=RadioSelect,
- required=False,
- initial=initial)
+ initial = (
+ None if option.id not in all_choices else all_choices[option.id][0]
+ )
+ field = forms.ChoiceField(
+ label=option.name,
+ choices=choices,
+ widget=RadioSelect,
+ required=False,
+ initial=initial,
+ )
field.option_id = option.id
self.fields["option_%d" % option.id] = field
for commentfield in self.event.commentfields.all():
initial = commentfield.default
if registration is not None:
try:
- initial = registration.comments \
- .get(commentfield=commentfield).content
+ initial = registration.comments.get(
+ commentfield=commentfield
+ ).content
except EventCommentValue.DoesNotExist:
pass
- widget = forms.Textarea if commentfield.fieldtype == "text" \
- else forms.TextInput
- field = forms.CharField(label=commentfield.name,
- widget=widget,
- required=False,
- initial=initial)
+ widget = (
+ forms.Textarea if commentfield.fieldtype == "text" else forms.TextInput
+ )
+ field = forms.CharField(
+ label=commentfield.name, widget=widget, required=False, initial=initial
+ )
field.comment_id = commentfield.id
self.fields["comment_%d" % commentfield.id] = field
def choices(self):
for name, value in self.cleaned_data.items():
- if name.startswith('option_'):
+ if name.startswith("option_"):
yield (self.fields[name].option_id, value)
def comments(self):
for name, value in self.cleaned_data.items():
- if name.startswith('comment_'):
+ if name.startswith("comment_"):
yield (self.fields[name].comment_id, value)
class BaseEventRegistrationFormset(BaseFormSet):
def __init__(self, *args, **kwargs):
- self.events = kwargs.pop('events')
- self.current_registrations = kwargs.pop('current_registrations', None)
+ self.events = kwargs.pop("events")
+ self.current_registrations = kwargs.pop("current_registrations", None)
self.extra = len(self.events)
super().__init__(*args, **kwargs)
def _construct_form(self, index, **kwargs):
- kwargs['event'] = self.events[index]
+ kwargs["event"] = self.events[index]
if self.current_registrations is not None:
- kwargs['current_registration'] = self.current_registrations[index]
+ kwargs["current_registration"] = self.current_registrations[index]
return super()._construct_form(index, **kwargs)
@@ -350,34 +373,36 @@ EventFormset = formset_factory(AdminEventForm, BaseEventRegistrationFormset)
class CalendarForm(forms.ModelForm):
subscribe_to_events = forms.BooleanField(
- initial=True,
- label="Événements du COF",
- required=False)
+ initial=True, label="Événements du COF", required=False
+ )
subscribe_to_my_shows = forms.BooleanField(
- initial=True,
- label="Les spectacles pour lesquels j'ai obtenu une place",
- required=False)
+ initial=True,
+ label="Les spectacles pour lesquels j'ai obtenu une place",
+ required=False,
+ )
other_shows = forms.ModelMultipleChoiceField(
- label="Spectacles supplémentaires",
- queryset=Spectacle.objects.filter(tirage__active=True),
- widget=forms.CheckboxSelectMultiple,
- required=False)
+ label="Spectacles supplémentaires",
+ queryset=Spectacle.objects.filter(tirage__active=True),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
class Meta:
model = CalendarSubscription
- fields = ['subscribe_to_events', 'subscribe_to_my_shows',
- 'other_shows']
+ fields = ["subscribe_to_events", "subscribe_to_my_shows", "other_shows"]
class ClubsForm(forms.Form):
"""
Formulaire d'inscription d'un membre à plusieurs clubs du COF.
"""
+
clubs = forms.ModelMultipleChoiceField(
- label="Inscriptions aux clubs du COF",
- queryset=Club.objects.all(),
- widget=forms.CheckboxSelectMultiple,
- required=False)
+ label="Inscriptions aux clubs du COF",
+ queryset=Club.objects.all(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
# ---
@@ -385,9 +410,10 @@ class ClubsForm(forms.Form):
# TODO: move this to the `gestion` app once the supportBDS branch is merged
# ---
+
class GestioncofConfigForm(ConfigForm):
gestion_banner = forms.CharField(
label=_("Announcements banner"),
help_text=_("An empty banner disables annoucements"),
- max_length=2048
+ max_length=2048,
)
diff --git a/gestioncof/management/base.py b/gestioncof/management/base.py
index ab4d1a30..7d7bcc30 100644
--- a/gestioncof/management/base.py
+++ b/gestioncof/management/base.py
@@ -2,8 +2,8 @@
Un mixin à utiliser avec BaseCommand pour charger des objets depuis un json
"""
-import os
import json
+import os
from django.core.management.base import BaseCommand
@@ -13,15 +13,14 @@ class MyBaseCommand(BaseCommand):
Ajoute une méthode ``from_json`` qui charge des objets à partir d'un json.
"""
- def from_json(self, filename, data_dir, klass,
- callback=lambda obj: obj):
+ def from_json(self, filename, data_dir, klass, callback=lambda obj: obj):
"""
Charge les objets contenus dans le fichier json référencé par
``filename`` dans la base de donnée. La fonction callback est appelées
sur chaque objet avant enregistrement.
"""
self.stdout.write("Chargement de {:s}".format(filename))
- with open(os.path.join(data_dir, filename), 'r') as file:
+ with open(os.path.join(data_dir, filename), "r") as file:
descriptions = json.load(file)
objects = []
nb_new = 0
@@ -36,6 +35,7 @@ class MyBaseCommand(BaseCommand):
objects.append(obj)
nb_new += 1
self.stdout.write("- {:d} objets créés".format(nb_new))
- self.stdout.write("- {:d} objets gardés en l'état"
- .format(len(objects)-nb_new))
+ self.stdout.write(
+ "- {:d} objets gardés en l'état".format(len(objects) - nb_new)
+ )
return objects
diff --git a/gestioncof/management/commands/loaddevdata.py b/gestioncof/management/commands/loaddevdata.py
index 7358c695..44d77065 100644
--- a/gestioncof/management/commands/loaddevdata.py
+++ b/gestioncof/management/commands/loaddevdata.py
@@ -15,13 +15,14 @@ from django.core.management import call_command
from gestioncof.management.base import MyBaseCommand
from gestioncof.petits_cours_models import (
- PetitCoursAbility, PetitCoursSubject, LEVELS_CHOICES,
- PetitCoursAttributionCounter
+ LEVELS_CHOICES,
+ PetitCoursAbility,
+ PetitCoursAttributionCounter,
+ PetitCoursSubject,
)
# Où sont stockés les fichiers json
-DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
- 'data')
+DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
class Command(MyBaseCommand):
@@ -32,11 +33,11 @@ class Command(MyBaseCommand):
Permet de ne pas créer l'utilisateur "root".
"""
parser.add_argument(
- '--no-root',
- action='store_true',
- dest='no-root',
+ "--no-root",
+ action="store_true",
+ dest="no-root",
default=False,
- help='Ne crée pas l\'utilisateur "root"'
+ help='Ne crée pas l\'utilisateur "root"',
)
def handle(self, *args, **options):
@@ -45,24 +46,25 @@ class Command(MyBaseCommand):
# ---
# Gaulois
- gaulois = self.from_json('gaulois.json', DATA_DIR, User)
+ gaulois = self.from_json("gaulois.json", DATA_DIR, User)
for user in gaulois:
user.profile.is_cof = True
user.profile.save()
# Romains
- self.from_json('romains.json', DATA_DIR, User)
+ self.from_json("romains.json", DATA_DIR, User)
# Root
- no_root = options.get('no-root', False)
+ no_root = options.get("no-root", False)
if not no_root:
self.stdout.write("Création de l'utilisateur root")
root, _ = User.objects.get_or_create(
- username='root',
- first_name='super',
- last_name='user',
- email='root@localhost')
- root.set_password('root')
+ username="root",
+ first_name="super",
+ last_name="user",
+ email="root@localhost",
+ )
+ root.set_password("root")
root.is_staff = True
root.is_superuser = True
root.profile.is_cof = True
@@ -87,18 +89,17 @@ class Command(MyBaseCommand):
# L'utilisateur est compétent dans une matière
subject = random.choice(subjects)
if not PetitCoursAbility.objects.filter(
- user=user,
- matiere=subject).exists():
+ user=user, matiere=subject
+ ).exists():
PetitCoursAbility.objects.create(
user=user,
matiere=subject,
niveau=random.choice(levels),
- agrege=bool(random.randint(0, 1))
+ agrege=bool(random.randint(0, 1)),
)
# On initialise son compteur d'attributions
PetitCoursAttributionCounter.objects.get_or_create(
- user=user,
- matiere=subject
+ user=user, matiere=subject
)
self.stdout.write("- {:d} inscriptions".format(nb_of_teachers))
@@ -106,10 +107,10 @@ class Command(MyBaseCommand):
# Le BdA
# ---
- call_command('loadbdadevdata')
+ call_command("loadbdadevdata")
# ---
# La K-Fêt
# ---
- call_command('loadkfetdevdata')
+ call_command("loadkfetdevdata")
diff --git a/gestioncof/management/commands/syncmails.py b/gestioncof/management/commands/syncmails.py
index 689da716..0dd15d34 100644
--- a/gestioncof/management/commands/syncmails.py
+++ b/gestioncof/management/commands/syncmails.py
@@ -4,84 +4,86 @@ Import des mails de GestioCOF dans la base de donnée
import json
import os
-from custommail.models import Type, CustomMail, Variable
-from django.core.management.base import BaseCommand
+from custommail.models import CustomMail, Type, Variable
from django.contrib.contenttypes.models import ContentType
+from django.core.management.base import BaseCommand
+
+DATA_LOCATION = os.path.join(os.path.dirname(__file__), "..", "data", "custommail.json")
+
+
+def dummy_log(__):
+ pass
+
+
+# XXX. this should probably be in the custommail package
+def load_from_file(log=dummy_log, verbosity=1):
+ with open(DATA_LOCATION, "r") as jsonfile:
+ mail_data = json.load(jsonfile)
+
+ # On se souvient à quel objet correspond quel pk du json
+ assoc = {"types": {}, "mails": {}}
+ status = {"synced": 0, "unchanged": 0}
+
+ for obj in mail_data:
+ fields = obj["fields"]
+
+ # Pour les trois types d'objets :
+ # - On récupère les objets référencés par les clefs étrangères
+ # - On crée l'objet si nécessaire
+ # - On le stocke éventuellement dans les deux dictionnaires définis
+ # plus haut
+
+ # Variable types
+ if obj["model"] == "custommail.variabletype":
+ fields["inner1"] = assoc["types"].get(fields["inner1"])
+ fields["inner2"] = assoc["types"].get(fields["inner2"])
+ if fields["kind"] == "model":
+ fields["content_type"] = ContentType.objects.get_by_natural_key(
+ *fields["content_type"]
+ )
+ var_type, _ = Type.objects.get_or_create(**fields)
+ assoc["types"][obj["pk"]] = var_type
+
+ # Custom mails
+ if obj["model"] == "custommail.custommail":
+ mail = None
+ try:
+ mail = CustomMail.objects.get(shortname=fields["shortname"])
+ status["unchanged"] += 1
+ except CustomMail.DoesNotExist:
+ mail = CustomMail.objects.create(**fields)
+ status["synced"] += 1
+ if verbosity:
+ log("SYNCED {:s}".format(fields["shortname"]))
+ assoc["mails"][obj["pk"]] = mail
+
+ # Variables
+ if obj["model"] == "custommail.custommailvariable":
+ fields["custommail"] = assoc["mails"].get(fields["custommail"])
+ fields["type"] = assoc["types"].get(fields["type"])
+ try:
+ Variable.objects.get(
+ custommail=fields["custommail"], name=fields["name"]
+ )
+ except Variable.DoesNotExist:
+ Variable.objects.create(**fields)
+
+ if verbosity:
+ log("{synced:d} mails synchronized {unchanged:d} unchanged".format(**status))
class Command(BaseCommand):
- help = ("Va chercher les données mails de GestioCOF stocké au format json "
- "dans /gestioncof/management/data/custommails.json. Le format des "
- "données est celui donné par la commande :"
- " `python manage.py dumpdata custommail --natural-foreign` "
- "La bonne façon de mettre à jour ce fichier est donc de le "
- "charger à l'aide de syncmails, le faire les modifications à "
- "l'aide de l'interface administration et/ou du shell puis de le "
- "remplacer par le nouveau résultat de la commande précédente.")
+ help = (
+ "Va chercher les données mails de GestioCOF stocké au format json "
+ "dans /gestioncof/management/data/custommails.json. Le format des "
+ "données est celui donné par la commande :"
+ " `python manage.py dumpdata custommail --natural-foreign` "
+ "La bonne façon de mettre à jour ce fichier est donc de le "
+ "charger à l'aide de syncmails, le faire les modifications à "
+ "l'aide de l'interface administration et/ou du shell puis de le "
+ "remplacer par le nouveau résultat de la commande précédente."
+ )
def handle(self, *args, **options):
- path = os.path.join(
- os.path.dirname(os.path.dirname(__file__)),
- 'data', 'custommail.json')
- with open(path, 'r') as jsonfile:
- mail_data = json.load(jsonfile)
-
- # On se souvient à quel objet correspond quel pk du json
- assoc = {'types': {}, 'mails': {}}
- status = {'synced': 0, 'unchanged': 0}
-
- for obj in mail_data:
- fields = obj['fields']
-
- # Pour les trois types d'objets :
- # - On récupère les objets référencés par les clefs étrangères
- # - On crée l'objet si nécessaire
- # - On le stocke éventuellement dans les deux dictionnaires définis
- # plus haut
-
- # Variable types
- if obj['model'] == 'custommail.variabletype':
- fields['inner1'] = assoc['types'].get(fields['inner1'])
- fields['inner2'] = assoc['types'].get(fields['inner2'])
- if fields['kind'] == 'model':
- fields['content_type'] = (
- ContentType.objects
- .get_by_natural_key(*fields['content_type'])
- )
- var_type, _ = Type.objects.get_or_create(**fields)
- assoc['types'][obj['pk']] = var_type
-
- # Custom mails
- if obj['model'] == 'custommail.custommail':
- mail = None
- try:
- mail = CustomMail.objects.get(
- shortname=fields['shortname'])
- status['unchanged'] += 1
- except CustomMail.DoesNotExist:
- mail = CustomMail.objects.create(**fields)
- status['synced'] += 1
- if options['verbosity']:
- self.stdout.write(
- 'SYNCED {:s}'.format(fields['shortname']))
- assoc['mails'][obj['pk']] = mail
-
- # Variables
- if obj['model'] == 'custommail.custommailvariable':
- fields['custommail'] = assoc['mails'].get(fields['custommail'])
- fields['type'] = assoc['types'].get(fields['type'])
- try:
- Variable.objects.get(
- custommail=fields['custommail'],
- name=fields['name']
- )
- except Variable.DoesNotExist:
- Variable.objects.create(**fields)
-
- if options['verbosity']:
- # C'est agréable d'avoir le résultat affiché
- self.stdout.write(
- '{synced:d} mails synchronized {unchanged:d} unchanged'
- .format(**status)
- )
+ load_from_file(log=self.stdout.write)
diff --git a/gestioncof/migrations/0001_initial.py b/gestioncof/migrations/0001_initial.py
index c6bb6151..b3c10b90 100644
--- a/gestioncof/migrations/0001_initial.py
+++ b/gestioncof/migrations/0001_initial.py
@@ -1,333 +1,856 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ]
+ dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]
operations = [
migrations.CreateModel(
- name='Clipper',
+ name="Clipper",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('username', models.CharField(max_length=20, verbose_name=b'Identifiant')),
- ('fullname', models.CharField(max_length=200, verbose_name=b'Nom complet')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "username",
+ models.CharField(max_length=20, verbose_name=b"Identifiant"),
+ ),
+ (
+ "fullname",
+ models.CharField(max_length=200, verbose_name=b"Nom complet"),
+ ),
],
),
migrations.CreateModel(
- name='Club',
+ name="Club",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=200, verbose_name=b'Nom')),
- ('description', models.TextField(verbose_name=b'Description')),
- ('membres', models.ManyToManyField(related_name='clubs', to=settings.AUTH_USER_MODEL)),
- ('respos', models.ManyToManyField(related_name='clubs_geres', to=settings.AUTH_USER_MODEL)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("name", models.CharField(max_length=200, verbose_name=b"Nom")),
+ ("description", models.TextField(verbose_name=b"Description")),
+ (
+ "membres",
+ models.ManyToManyField(
+ related_name="clubs", to=settings.AUTH_USER_MODEL
+ ),
+ ),
+ (
+ "respos",
+ models.ManyToManyField(
+ related_name="clubs_geres", to=settings.AUTH_USER_MODEL
+ ),
+ ),
],
),
migrations.CreateModel(
- name='CofProfile',
+ name="CofProfile",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('login_clipper', models.CharField(max_length=8, verbose_name=b'Login clipper', blank=True)),
- ('is_cof', models.BooleanField(default=False, verbose_name=b'Membre du COF')),
- ('num', models.IntegerField(default=0, verbose_name=b"Num\xc3\xa9ro d'adh\xc3\xa9rent", blank=True)),
- ('phone', models.CharField(max_length=20, verbose_name=b'T\xc3\xa9l\xc3\xa9phone', blank=True)),
- ('occupation', models.CharField(default=b'1A', max_length=9, verbose_name='Occupation', choices=[(b'exterieur', 'Ext\xe9rieur'), (b'1A', '1A'), (b'2A', '2A'), (b'3A', '3A'), (b'4A', '4A'), (b'archicube', 'Archicube'), (b'doctorant', 'Doctorant'), (b'CST', 'CST')])),
- ('departement', models.CharField(max_length=50, verbose_name='D\xe9partement', blank=True)),
- ('type_cotiz', models.CharField(default=b'normalien', max_length=9, verbose_name='Type de cotisation', choices=[(b'etudiant', 'Normalien \xe9tudiant'), (b'normalien', 'Normalien \xe9l\xe8ve'), (b'exterieur', 'Ext\xe9rieur')])),
- ('mailing_cof', models.BooleanField(default=False, verbose_name=b'Recevoir les mails COF')),
- ('mailing_bda', models.BooleanField(default=False, verbose_name=b'Recevoir les mails BdA')),
- ('mailing_bda_revente', models.BooleanField(default=False, verbose_name=b'Recevoir les mails de revente de places BdA')),
- ('comments', models.TextField(verbose_name=b'Commentaires visibles uniquement par le Buro', blank=True)),
- ('is_buro', models.BooleanField(default=False, verbose_name=b'Membre du Bur\xc3\xb4')),
- ('petits_cours_accept', models.BooleanField(default=False, verbose_name=b'Recevoir des petits cours')),
- ('petits_cours_remarques', models.TextField(default=b'', verbose_name='Remarques et pr\xe9cisions pour les petits cours', blank=True)),
- ('user', models.OneToOneField(related_name='profile', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "login_clipper",
+ models.CharField(
+ max_length=8, verbose_name=b"Login clipper", blank=True
+ ),
+ ),
+ (
+ "is_cof",
+ models.BooleanField(default=False, verbose_name=b"Membre du COF"),
+ ),
+ (
+ "num",
+ models.IntegerField(
+ default=0,
+ verbose_name=b"Num\xc3\xa9ro d'adh\xc3\xa9rent",
+ blank=True,
+ ),
+ ),
+ (
+ "phone",
+ models.CharField(
+ max_length=20,
+ verbose_name=b"T\xc3\xa9l\xc3\xa9phone",
+ blank=True,
+ ),
+ ),
+ (
+ "occupation",
+ models.CharField(
+ default=b"1A",
+ max_length=9,
+ verbose_name="Occupation",
+ choices=[
+ (b"exterieur", "Ext\xe9rieur"),
+ (b"1A", "1A"),
+ (b"2A", "2A"),
+ (b"3A", "3A"),
+ (b"4A", "4A"),
+ (b"archicube", "Archicube"),
+ (b"doctorant", "Doctorant"),
+ (b"CST", "CST"),
+ ],
+ ),
+ ),
+ (
+ "departement",
+ models.CharField(
+ max_length=50, verbose_name="D\xe9partement", blank=True
+ ),
+ ),
+ (
+ "type_cotiz",
+ models.CharField(
+ default=b"normalien",
+ max_length=9,
+ verbose_name="Type de cotisation",
+ choices=[
+ (b"etudiant", "Normalien \xe9tudiant"),
+ (b"normalien", "Normalien \xe9l\xe8ve"),
+ (b"exterieur", "Ext\xe9rieur"),
+ ],
+ ),
+ ),
+ (
+ "mailing_cof",
+ models.BooleanField(
+ default=False, verbose_name=b"Recevoir les mails COF"
+ ),
+ ),
+ (
+ "mailing_bda",
+ models.BooleanField(
+ default=False, verbose_name=b"Recevoir les mails BdA"
+ ),
+ ),
+ (
+ "mailing_bda_revente",
+ models.BooleanField(
+ default=False,
+ verbose_name=b"Recevoir les mails de revente de places BdA",
+ ),
+ ),
+ (
+ "comments",
+ models.TextField(
+ verbose_name=b"Commentaires visibles uniquement par le Buro",
+ blank=True,
+ ),
+ ),
+ (
+ "is_buro",
+ models.BooleanField(
+ default=False, verbose_name=b"Membre du Bur\xc3\xb4"
+ ),
+ ),
+ (
+ "petits_cours_accept",
+ models.BooleanField(
+ default=False, verbose_name=b"Recevoir des petits cours"
+ ),
+ ),
+ (
+ "petits_cours_remarques",
+ models.TextField(
+ default=b"",
+ verbose_name="Remarques et pr\xe9cisions pour les petits cours",
+ blank=True,
+ ),
+ ),
+ (
+ "user",
+ models.OneToOneField(
+ related_name="profile",
+ to=settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE,
+ ),
+ ),
],
options={
- 'verbose_name': 'Profil COF',
- 'verbose_name_plural': 'Profils COF',
+ "verbose_name": "Profil COF",
+ "verbose_name_plural": "Profils COF",
},
),
migrations.CreateModel(
- name='CustomMail',
+ name="CustomMail",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('shortname', models.SlugField()),
- ('title', models.CharField(max_length=200, verbose_name=b'Titre')),
- ('content', models.TextField(verbose_name=b'Contenu')),
- ('comments', models.TextField(verbose_name=b'Informations contextuelles sur le mail', blank=True)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("shortname", models.SlugField()),
+ ("title", models.CharField(max_length=200, verbose_name=b"Titre")),
+ ("content", models.TextField(verbose_name=b"Contenu")),
+ (
+ "comments",
+ models.TextField(
+ verbose_name=b"Informations contextuelles sur le mail",
+ blank=True,
+ ),
+ ),
],
- options={
- 'verbose_name': 'Mails personnalisables',
- },
+ options={"verbose_name": "Mails personnalisables"},
),
migrations.CreateModel(
- name='Event',
+ name="Event",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('title', models.CharField(max_length=200, verbose_name=b'Titre')),
- ('location', models.CharField(max_length=200, verbose_name=b'Lieu')),
- ('start_date', models.DateField(null=True, verbose_name=b'Date de d\xc3\xa9but', blank=True)),
- ('end_date', models.DateField(null=True, verbose_name=b'Date de fin', blank=True)),
- ('description', models.TextField(verbose_name=b'Description', blank=True)),
- ('registration_open', models.BooleanField(default=True, verbose_name=b'Inscriptions ouvertes')),
- ('old', models.BooleanField(default=False, verbose_name=b'Archiver (\xc3\xa9v\xc3\xa9nement fini)')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("title", models.CharField(max_length=200, verbose_name=b"Titre")),
+ ("location", models.CharField(max_length=200, verbose_name=b"Lieu")),
+ (
+ "start_date",
+ models.DateField(
+ null=True, verbose_name=b"Date de d\xc3\xa9but", blank=True
+ ),
+ ),
+ (
+ "end_date",
+ models.DateField(
+ null=True, verbose_name=b"Date de fin", blank=True
+ ),
+ ),
+ (
+ "description",
+ models.TextField(verbose_name=b"Description", blank=True),
+ ),
+ (
+ "registration_open",
+ models.BooleanField(
+ default=True, verbose_name=b"Inscriptions ouvertes"
+ ),
+ ),
+ (
+ "old",
+ models.BooleanField(
+ default=False,
+ verbose_name=b"Archiver (\xc3\xa9v\xc3\xa9nement fini)",
+ ),
+ ),
],
- options={
- 'verbose_name': '\xc9v\xe9nement',
- },
+ options={"verbose_name": "\xc9v\xe9nement"},
),
migrations.CreateModel(
- name='EventCommentField',
+ name="EventCommentField",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=200, verbose_name=b'Champ')),
- ('fieldtype', models.CharField(default=b'text', max_length=10, verbose_name=b'Type', choices=[(b'text', 'Texte long'), (b'char', 'Texte court')])),
- ('default', models.TextField(verbose_name=b'Valeur par d\xc3\xa9faut', blank=True)),
- ('event', models.ForeignKey(related_name='commentfields', to='gestioncof.Event', on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("name", models.CharField(max_length=200, verbose_name=b"Champ")),
+ (
+ "fieldtype",
+ models.CharField(
+ default=b"text",
+ max_length=10,
+ verbose_name=b"Type",
+ choices=[(b"text", "Texte long"), (b"char", "Texte court")],
+ ),
+ ),
+ (
+ "default",
+ models.TextField(
+ verbose_name=b"Valeur par d\xc3\xa9faut", blank=True
+ ),
+ ),
+ (
+ "event",
+ models.ForeignKey(
+ related_name="commentfields",
+ to="gestioncof.Event",
+ on_delete=models.CASCADE,
+ ),
+ ),
],
- options={
- 'verbose_name': 'Champ',
- },
+ options={"verbose_name": "Champ"},
),
migrations.CreateModel(
- name='EventCommentValue',
+ name="EventCommentValue",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('content', models.TextField(null=True, verbose_name=b'Contenu', blank=True)),
- ('commentfield', models.ForeignKey(related_name='values', to='gestioncof.EventCommentField', on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "content",
+ models.TextField(null=True, verbose_name=b"Contenu", blank=True),
+ ),
+ (
+ "commentfield",
+ models.ForeignKey(
+ related_name="values",
+ to="gestioncof.EventCommentField",
+ on_delete=models.CASCADE,
+ ),
+ ),
],
),
migrations.CreateModel(
- name='EventOption',
+ name="EventOption",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=200, verbose_name=b'Option')),
- ('multi_choices', models.BooleanField(default=False, verbose_name=b'Choix multiples')),
- ('event', models.ForeignKey(related_name='options', to='gestioncof.Event', on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("name", models.CharField(max_length=200, verbose_name=b"Option")),
+ (
+ "multi_choices",
+ models.BooleanField(default=False, verbose_name=b"Choix multiples"),
+ ),
+ (
+ "event",
+ models.ForeignKey(
+ related_name="options",
+ to="gestioncof.Event",
+ on_delete=models.CASCADE,
+ ),
+ ),
+ ],
+ options={"verbose_name": "Option"},
+ ),
+ migrations.CreateModel(
+ name="EventOptionChoice",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("value", models.CharField(max_length=200, verbose_name=b"Valeur")),
+ (
+ "event_option",
+ models.ForeignKey(
+ related_name="choices",
+ to="gestioncof.EventOption",
+ on_delete=models.CASCADE,
+ ),
+ ),
+ ],
+ options={"verbose_name": "Choix"},
+ ),
+ migrations.CreateModel(
+ name="EventRegistration",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "paid",
+ models.BooleanField(default=False, verbose_name=b"A pay\xc3\xa9"),
+ ),
+ (
+ "event",
+ models.ForeignKey(to="gestioncof.Event", on_delete=models.CASCADE),
+ ),
+ (
+ "filledcomments",
+ models.ManyToManyField(
+ to="gestioncof.EventCommentField",
+ through="gestioncof.EventCommentValue",
+ ),
+ ),
+ ("options", models.ManyToManyField(to="gestioncof.EventOptionChoice")),
+ (
+ "user",
+ models.ForeignKey(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
+ ),
+ ],
+ options={"verbose_name": "Inscription"},
+ ),
+ migrations.CreateModel(
+ name="PetitCoursAbility",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "niveau",
+ models.CharField(
+ max_length=12,
+ verbose_name="Niveau",
+ choices=[
+ (b"college", "Coll\xe8ge"),
+ (b"lycee", "Lyc\xe9e"),
+ (b"prepa1styear", "Pr\xe9pa 1\xe8re ann\xe9e / L1"),
+ (b"prepa2ndyear", "Pr\xe9pa 2\xe8me ann\xe9e / L2"),
+ (b"licence3", "Licence 3"),
+ (b"other", "Autre (pr\xe9ciser dans les commentaires)"),
+ ],
+ ),
+ ),
+ (
+ "agrege",
+ models.BooleanField(default=False, verbose_name="Agr\xe9g\xe9"),
+ ),
],
options={
- 'verbose_name': 'Option',
+ "verbose_name": "Comp\xe9tence petits cours",
+ "verbose_name_plural": "Comp\xe9tences des petits cours",
},
),
migrations.CreateModel(
- name='EventOptionChoice',
+ name="PetitCoursAttribution",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('value', models.CharField(max_length=200, verbose_name=b'Valeur')),
- ('event_option', models.ForeignKey(related_name='choices', to='gestioncof.EventOption', on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "date",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="Date d'attribution"
+ ),
+ ),
+ ("rank", models.IntegerField(verbose_name=b"Rang dans l'email")),
+ (
+ "selected",
+ models.BooleanField(
+ default=False, verbose_name="S\xe9lectionn\xe9 par le demandeur"
+ ),
+ ),
],
options={
- 'verbose_name': 'Choix',
+ "verbose_name": "Attribution de petits cours",
+ "verbose_name_plural": "Attributions de petits cours",
},
),
migrations.CreateModel(
- name='EventRegistration',
+ name="PetitCoursAttributionCounter",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('paid', models.BooleanField(default=False, verbose_name=b'A pay\xc3\xa9')),
- ('event', models.ForeignKey(to='gestioncof.Event', on_delete=models.CASCADE)),
- ('filledcomments', models.ManyToManyField(to='gestioncof.EventCommentField', through='gestioncof.EventCommentValue')),
- ('options', models.ManyToManyField(to='gestioncof.EventOptionChoice')),
- ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "count",
+ models.IntegerField(default=0, verbose_name=b"Nombre d'envois"),
+ ),
],
options={
- 'verbose_name': 'Inscription',
+ "verbose_name": "Compteur d'attribution de petits cours",
+ "verbose_name_plural": "Compteurs d'attributions de petits cours",
},
),
migrations.CreateModel(
- name='PetitCoursAbility',
+ name="PetitCoursDemande",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('niveau', models.CharField(max_length=12, verbose_name='Niveau', choices=[(b'college', 'Coll\xe8ge'), (b'lycee', 'Lyc\xe9e'), (b'prepa1styear', 'Pr\xe9pa 1\xe8re ann\xe9e / L1'), (b'prepa2ndyear', 'Pr\xe9pa 2\xe8me ann\xe9e / L2'), (b'licence3', 'Licence 3'), (b'other', 'Autre (pr\xe9ciser dans les commentaires)')])),
- ('agrege', models.BooleanField(default=False, verbose_name='Agr\xe9g\xe9')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "name",
+ models.CharField(max_length=200, verbose_name="Nom/pr\xe9nom"),
+ ),
+ (
+ "email",
+ models.CharField(max_length=300, verbose_name="Adresse email"),
+ ),
+ (
+ "phone",
+ models.CharField(
+ max_length=20,
+ verbose_name="T\xe9l\xe9phone (facultatif)",
+ blank=True,
+ ),
+ ),
+ (
+ "quand",
+ models.CharField(
+ help_text="Indiquez ici la p\xe9riode d\xe9sir\xe9e pour les petits cours (vacances scolaires, semaine, week-end).",
+ max_length=300,
+ verbose_name="Quand ?",
+ blank=True,
+ ),
+ ),
+ (
+ "freq",
+ models.CharField(
+ help_text="Indiquez ici la fr\xe9quence envisag\xe9e (hebdomadaire, 2 fois par semaine, ...)",
+ max_length=300,
+ verbose_name="Fr\xe9quence",
+ blank=True,
+ ),
+ ),
+ (
+ "lieu",
+ models.CharField(
+ help_text="Si vous avez avez une pr\xe9f\xe9rence sur le lieu.",
+ max_length=300,
+ verbose_name="Lieu (si pr\xe9f\xe9rence)",
+ blank=True,
+ ),
+ ),
+ (
+ "agrege_requis",
+ models.BooleanField(
+ default=False, verbose_name="Agr\xe9g\xe9 requis"
+ ),
+ ),
+ (
+ "niveau",
+ models.CharField(
+ default=b"",
+ max_length=12,
+ verbose_name="Niveau",
+ choices=[
+ (b"college", "Coll\xe8ge"),
+ (b"lycee", "Lyc\xe9e"),
+ (b"prepa1styear", "Pr\xe9pa 1\xe8re ann\xe9e / L1"),
+ (b"prepa2ndyear", "Pr\xe9pa 2\xe8me ann\xe9e / L2"),
+ (b"licence3", "Licence 3"),
+ (b"other", "Autre (pr\xe9ciser dans les commentaires)"),
+ ],
+ ),
+ ),
+ (
+ "remarques",
+ models.TextField(
+ verbose_name="Remarques et pr\xe9cisions", blank=True
+ ),
+ ),
+ (
+ "traitee",
+ models.BooleanField(default=False, verbose_name="Trait\xe9e"),
+ ),
+ (
+ "processed",
+ models.DateTimeField(verbose_name="Date de traitement", blank=True),
+ ),
+ (
+ "created",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="Date de cr\xe9ation"
+ ),
+ ),
],
options={
- 'verbose_name': 'Comp\xe9tence petits cours',
- 'verbose_name_plural': 'Comp\xe9tences des petits cours',
+ "verbose_name": "Demande de petits cours",
+ "verbose_name_plural": "Demandes de petits cours",
},
),
migrations.CreateModel(
- name='PetitCoursAttribution',
+ name="PetitCoursSubject",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('date', models.DateTimeField(auto_now_add=True, verbose_name="Date d'attribution")),
- ('rank', models.IntegerField(verbose_name=b"Rang dans l'email")),
- ('selected', models.BooleanField(default=False, verbose_name='S\xe9lectionn\xe9 par le demandeur')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("name", models.CharField(max_length=30, verbose_name="Mati\xe8re")),
+ (
+ "users",
+ models.ManyToManyField(
+ related_name="petits_cours_matieres",
+ through="gestioncof.PetitCoursAbility",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
],
options={
- 'verbose_name': 'Attribution de petits cours',
- 'verbose_name_plural': 'Attributions de petits cours',
+ "verbose_name": "Mati\xe8re de petits cours",
+ "verbose_name_plural": "Mati\xe8res des petits cours",
},
),
migrations.CreateModel(
- name='PetitCoursAttributionCounter',
+ name="Survey",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('count', models.IntegerField(default=0, verbose_name=b"Nombre d'envois")),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("title", models.CharField(max_length=200, verbose_name=b"Titre")),
+ (
+ "details",
+ models.TextField(verbose_name=b"D\xc3\xa9tails", blank=True),
+ ),
+ (
+ "survey_open",
+ models.BooleanField(default=True, verbose_name=b"Sondage ouvert"),
+ ),
+ (
+ "old",
+ models.BooleanField(
+ default=False, verbose_name=b"Archiver (sondage fini)"
+ ),
+ ),
],
- options={
- 'verbose_name': "Compteur d'attribution de petits cours",
- 'verbose_name_plural': "Compteurs d'attributions de petits cours",
- },
+ options={"verbose_name": "Sondage"},
),
migrations.CreateModel(
- name='PetitCoursDemande',
+ name="SurveyAnswer",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=200, verbose_name='Nom/pr\xe9nom')),
- ('email', models.CharField(max_length=300, verbose_name='Adresse email')),
- ('phone', models.CharField(max_length=20, verbose_name='T\xe9l\xe9phone (facultatif)', blank=True)),
- ('quand', models.CharField(help_text='Indiquez ici la p\xe9riode d\xe9sir\xe9e pour les petits cours (vacances scolaires, semaine, week-end).', max_length=300, verbose_name='Quand ?', blank=True)),
- ('freq', models.CharField(help_text='Indiquez ici la fr\xe9quence envisag\xe9e (hebdomadaire, 2 fois par semaine, ...)', max_length=300, verbose_name='Fr\xe9quence', blank=True)),
- ('lieu', models.CharField(help_text='Si vous avez avez une pr\xe9f\xe9rence sur le lieu.', max_length=300, verbose_name='Lieu (si pr\xe9f\xe9rence)', blank=True)),
- ('agrege_requis', models.BooleanField(default=False, verbose_name='Agr\xe9g\xe9 requis')),
- ('niveau', models.CharField(default=b'', max_length=12, verbose_name='Niveau', choices=[(b'college', 'Coll\xe8ge'), (b'lycee', 'Lyc\xe9e'), (b'prepa1styear', 'Pr\xe9pa 1\xe8re ann\xe9e / L1'), (b'prepa2ndyear', 'Pr\xe9pa 2\xe8me ann\xe9e / L2'), (b'licence3', 'Licence 3'), (b'other', 'Autre (pr\xe9ciser dans les commentaires)')])),
- ('remarques', models.TextField(verbose_name='Remarques et pr\xe9cisions', blank=True)),
- ('traitee', models.BooleanField(default=False, verbose_name='Trait\xe9e')),
- ('processed', models.DateTimeField(verbose_name='Date de traitement', blank=True)),
- ('created', models.DateTimeField(auto_now_add=True, verbose_name='Date de cr\xe9ation')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ )
],
- options={
- 'verbose_name': 'Demande de petits cours',
- 'verbose_name_plural': 'Demandes de petits cours',
- },
+ options={"verbose_name": "R\xe9ponses"},
),
migrations.CreateModel(
- name='PetitCoursSubject',
+ name="SurveyQuestion",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('name', models.CharField(max_length=30, verbose_name='Mati\xe8re')),
- ('users', models.ManyToManyField(related_name='petits_cours_matieres', through='gestioncof.PetitCoursAbility', to=settings.AUTH_USER_MODEL)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "question",
+ models.CharField(max_length=200, verbose_name=b"Question"),
+ ),
+ (
+ "multi_answers",
+ models.BooleanField(default=False, verbose_name=b"Choix multiples"),
+ ),
+ (
+ "survey",
+ models.ForeignKey(
+ related_name="questions",
+ to="gestioncof.Survey",
+ on_delete=models.CASCADE,
+ ),
+ ),
],
- options={
- 'verbose_name': 'Mati\xe8re de petits cours',
- 'verbose_name_plural': 'Mati\xe8res des petits cours',
- },
+ options={"verbose_name": "Question"},
),
migrations.CreateModel(
- name='Survey',
+ name="SurveyQuestionAnswer",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('title', models.CharField(max_length=200, verbose_name=b'Titre')),
- ('details', models.TextField(verbose_name=b'D\xc3\xa9tails', blank=True)),
- ('survey_open', models.BooleanField(default=True, verbose_name=b'Sondage ouvert')),
- ('old', models.BooleanField(default=False, verbose_name=b'Archiver (sondage fini)')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ (
+ "answer",
+ models.CharField(max_length=200, verbose_name=b"R\xc3\xa9ponse"),
+ ),
+ (
+ "survey_question",
+ models.ForeignKey(
+ related_name="answers",
+ to="gestioncof.SurveyQuestion",
+ on_delete=models.CASCADE,
+ ),
+ ),
],
- options={
- 'verbose_name': 'Sondage',
- },
- ),
- migrations.CreateModel(
- name='SurveyAnswer',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ],
- options={
- 'verbose_name': 'R\xe9ponses',
- },
- ),
- migrations.CreateModel(
- name='SurveyQuestion',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('question', models.CharField(max_length=200, verbose_name=b'Question')),
- ('multi_answers', models.BooleanField(default=False, verbose_name=b'Choix multiples')),
- ('survey', models.ForeignKey(related_name='questions', to='gestioncof.Survey', on_delete=models.CASCADE)),
- ],
- options={
- 'verbose_name': 'Question',
- },
- ),
- migrations.CreateModel(
- name='SurveyQuestionAnswer',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('answer', models.CharField(max_length=200, verbose_name=b'R\xc3\xa9ponse')),
- ('survey_question', models.ForeignKey(related_name='answers', to='gestioncof.SurveyQuestion', on_delete=models.CASCADE)),
- ],
- options={
- 'verbose_name': 'R\xe9ponse',
- },
+ options={"verbose_name": "R\xe9ponse"},
),
migrations.AddField(
- model_name='surveyanswer',
- name='answers',
- field=models.ManyToManyField(related_name='selected_by', to='gestioncof.SurveyQuestionAnswer'),
+ model_name="surveyanswer",
+ name="answers",
+ field=models.ManyToManyField(
+ related_name="selected_by", to="gestioncof.SurveyQuestionAnswer"
+ ),
),
migrations.AddField(
- model_name='surveyanswer',
- name='survey',
- field=models.ForeignKey(to='gestioncof.Survey', on_delete=models.CASCADE),
+ model_name="surveyanswer",
+ name="survey",
+ field=models.ForeignKey(to="gestioncof.Survey", on_delete=models.CASCADE),
),
migrations.AddField(
- model_name='surveyanswer',
- name='user',
- field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ model_name="surveyanswer",
+ name="user",
+ field=models.ForeignKey(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
),
migrations.AddField(
- model_name='petitcoursdemande',
- name='matieres',
- field=models.ManyToManyField(related_name='demandes', verbose_name='Mati\xe8res', to='gestioncof.PetitCoursSubject'),
+ model_name="petitcoursdemande",
+ name="matieres",
+ field=models.ManyToManyField(
+ related_name="demandes",
+ verbose_name="Mati\xe8res",
+ to="gestioncof.PetitCoursSubject",
+ ),
),
migrations.AddField(
- model_name='petitcoursdemande',
- name='traitee_par',
- field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE),
+ model_name="petitcoursdemande",
+ name="traitee_par",
+ field=models.ForeignKey(
+ blank=True,
+ to=settings.AUTH_USER_MODEL,
+ null=True,
+ on_delete=models.CASCADE,
+ ),
),
migrations.AddField(
- model_name='petitcoursattributioncounter',
- name='matiere',
- field=models.ForeignKey(verbose_name='Matiere', to='gestioncof.PetitCoursSubject', on_delete=models.CASCADE),
+ model_name="petitcoursattributioncounter",
+ name="matiere",
+ field=models.ForeignKey(
+ verbose_name="Matiere",
+ to="gestioncof.PetitCoursSubject",
+ on_delete=models.CASCADE,
+ ),
),
migrations.AddField(
- model_name='petitcoursattributioncounter',
- name='user',
- field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ model_name="petitcoursattributioncounter",
+ name="user",
+ field=models.ForeignKey(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
),
migrations.AddField(
- model_name='petitcoursattribution',
- name='demande',
- field=models.ForeignKey(verbose_name='Demande', to='gestioncof.PetitCoursDemande', on_delete=models.CASCADE),
+ model_name="petitcoursattribution",
+ name="demande",
+ field=models.ForeignKey(
+ verbose_name="Demande",
+ to="gestioncof.PetitCoursDemande",
+ on_delete=models.CASCADE,
+ ),
),
migrations.AddField(
- model_name='petitcoursattribution',
- name='matiere',
- field=models.ForeignKey(verbose_name='Mati\xe8re', to='gestioncof.PetitCoursSubject', on_delete=models.CASCADE),
+ model_name="petitcoursattribution",
+ name="matiere",
+ field=models.ForeignKey(
+ verbose_name="Mati\xe8re",
+ to="gestioncof.PetitCoursSubject",
+ on_delete=models.CASCADE,
+ ),
),
migrations.AddField(
- model_name='petitcoursattribution',
- name='user',
- field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ model_name="petitcoursattribution",
+ name="user",
+ field=models.ForeignKey(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
),
migrations.AddField(
- model_name='petitcoursability',
- name='matiere',
- field=models.ForeignKey(verbose_name='Mati\xe8re', to='gestioncof.PetitCoursSubject', on_delete=models.CASCADE),
+ model_name="petitcoursability",
+ name="matiere",
+ field=models.ForeignKey(
+ verbose_name="Mati\xe8re",
+ to="gestioncof.PetitCoursSubject",
+ on_delete=models.CASCADE,
+ ),
),
migrations.AddField(
- model_name='petitcoursability',
- name='user',
- field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
+ model_name="petitcoursability",
+ name="user",
+ field=models.ForeignKey(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
),
migrations.AddField(
- model_name='eventcommentvalue',
- name='registration',
- field=models.ForeignKey(related_name='comments', to='gestioncof.EventRegistration', on_delete=models.CASCADE),
+ model_name="eventcommentvalue",
+ name="registration",
+ field=models.ForeignKey(
+ related_name="comments",
+ to="gestioncof.EventRegistration",
+ on_delete=models.CASCADE,
+ ),
),
migrations.AlterUniqueTogether(
- name='surveyanswer',
- unique_together=set([('user', 'survey')]),
+ name="surveyanswer", unique_together=set([("user", "survey")])
),
migrations.AlterUniqueTogether(
- name='eventregistration',
- unique_together=set([('user', 'event')]),
+ name="eventregistration", unique_together=set([("user", "event")])
),
]
diff --git a/gestioncof/migrations/0002_enable_unprocessed_demandes.py b/gestioncof/migrations/0002_enable_unprocessed_demandes.py
index 18006588..d8514036 100644
--- a/gestioncof/migrations/0002_enable_unprocessed_demandes.py
+++ b/gestioncof/migrations/0002_enable_unprocessed_demandes.py
@@ -6,14 +6,14 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0001_initial'),
- ]
+ dependencies = [("gestioncof", "0001_initial")]
operations = [
migrations.AlterField(
- model_name='petitcoursdemande',
- name='processed',
- field=models.DateTimeField(null=True, verbose_name='Date de traitement', blank=True),
- ),
+ model_name="petitcoursdemande",
+ name="processed",
+ field=models.DateTimeField(
+ null=True, verbose_name="Date de traitement", blank=True
+ ),
+ )
]
diff --git a/gestioncof/migrations/0003_event_image.py b/gestioncof/migrations/0003_event_image.py
index 6d65b1a6..ac5d753b 100644
--- a/gestioncof/migrations/0003_event_image.py
+++ b/gestioncof/migrations/0003_event_image.py
@@ -6,14 +6,14 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0002_enable_unprocessed_demandes'),
- ]
+ dependencies = [("gestioncof", "0002_enable_unprocessed_demandes")]
operations = [
migrations.AddField(
- model_name='event',
- name='image',
- field=models.ImageField(upload_to=b'imgs/events/', null=True, verbose_name=b'Image', blank=True),
- ),
+ model_name="event",
+ name="image",
+ field=models.ImageField(
+ upload_to=b"imgs/events/", null=True, verbose_name=b"Image", blank=True
+ ),
+ )
]
diff --git a/gestioncof/migrations/0004_registration_mail.py b/gestioncof/migrations/0004_registration_mail.py
index d72900bf..0ceba245 100644
--- a/gestioncof/migrations/0004_registration_mail.py
+++ b/gestioncof/migrations/0004_registration_mail.py
@@ -8,27 +8,28 @@ def create_mail(apps, schema_editor):
CustomMail = apps.get_model("gestioncof", "CustomMail")
db_alias = schema_editor.connection.alias
if CustomMail.objects.filter(shortname="bienvenue").count() == 0:
- CustomMail.objects.using(db_alias).bulk_create([
- CustomMail(
- shortname="bienvenue",
- title="Bienvenue au COF",
- content="Mail de bienvenue au COF, envoyé automatiquement à " \
- + "l'inscription.\n\n" \
- + "Les balises {{ ... }} sont interprétées comme expliqué " \
+ CustomMail.objects.using(db_alias).bulk_create(
+ [
+ CustomMail(
+ shortname="bienvenue",
+ title="Bienvenue au COF",
+ content="Mail de bienvenue au COF, envoyé automatiquement à "
+ + "l'inscription.\n\n"
+ + "Les balises {{ ... }} sont interprétées comme expliqué "
+ "ci-dessous à l'envoi.",
- comments="{{ nom }} \t fullname de la personne.\n"\
- + "{{ prenom }} \t prénom de la personne.")
- ])
+ comments="{{ nom }} \t fullname de la personne.\n"
+ + "{{ prenom }} \t prénom de la personne.",
+ )
+ ]
+ )
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0003_event_image'),
- ]
+ dependencies = [("gestioncof", "0003_event_image")]
operations = [
# Pas besoin de supprimer le mail lors de la migration dans l'autre
# sens.
- migrations.RunPython(create_mail, migrations.RunPython.noop),
+ migrations.RunPython(create_mail, migrations.RunPython.noop)
]
diff --git a/gestioncof/migrations/0005_encoding.py b/gestioncof/migrations/0005_encoding.py
index 4f565a5d..33c8502a 100644
--- a/gestioncof/migrations/0005_encoding.py
+++ b/gestioncof/migrations/0005_encoding.py
@@ -6,62 +6,71 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0004_registration_mail'),
- ]
+ dependencies = [("gestioncof", "0004_registration_mail")]
operations = [
migrations.AlterModelOptions(
- name='custommail',
- options={'verbose_name': 'Mail personnalisable', 'verbose_name_plural': 'Mails personnalisables'},
+ name="custommail",
+ options={
+ "verbose_name": "Mail personnalisable",
+ "verbose_name_plural": "Mails personnalisables",
+ },
),
migrations.AlterModelOptions(
- name='eventoptionchoice',
- options={'verbose_name': 'Choix', 'verbose_name_plural': 'Choix'},
+ name="eventoptionchoice",
+ options={"verbose_name": "Choix", "verbose_name_plural": "Choix"},
),
migrations.AlterField(
- model_name='cofprofile',
- name='is_buro',
- field=models.BooleanField(default=False, verbose_name='Membre du Bur\xf4'),
+ model_name="cofprofile",
+ name="is_buro",
+ field=models.BooleanField(default=False, verbose_name="Membre du Bur\xf4"),
),
migrations.AlterField(
- model_name='cofprofile',
- name='num',
- field=models.IntegerField(default=0, verbose_name="Num\xe9ro d'adh\xe9rent", blank=True),
+ model_name="cofprofile",
+ name="num",
+ field=models.IntegerField(
+ default=0, verbose_name="Num\xe9ro d'adh\xe9rent", blank=True
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='phone',
- field=models.CharField(max_length=20, verbose_name='T\xe9l\xe9phone', blank=True),
+ model_name="cofprofile",
+ name="phone",
+ field=models.CharField(
+ max_length=20, verbose_name="T\xe9l\xe9phone", blank=True
+ ),
),
migrations.AlterField(
- model_name='event',
- name='old',
- field=models.BooleanField(default=False, verbose_name='Archiver (\xe9v\xe9nement fini)'),
+ model_name="event",
+ name="old",
+ field=models.BooleanField(
+ default=False, verbose_name="Archiver (\xe9v\xe9nement fini)"
+ ),
),
migrations.AlterField(
- model_name='event',
- name='start_date',
- field=models.DateField(null=True, verbose_name='Date de d\xe9but', blank=True),
+ model_name="event",
+ name="start_date",
+ field=models.DateField(
+ null=True, verbose_name="Date de d\xe9but", blank=True
+ ),
),
migrations.AlterField(
- model_name='eventcommentfield',
- name='default',
- field=models.TextField(verbose_name='Valeur par d\xe9faut', blank=True),
+ model_name="eventcommentfield",
+ name="default",
+ field=models.TextField(verbose_name="Valeur par d\xe9faut", blank=True),
),
migrations.AlterField(
- model_name='eventregistration',
- name='paid',
- field=models.BooleanField(default=False, verbose_name='A pay\xe9'),
+ model_name="eventregistration",
+ name="paid",
+ field=models.BooleanField(default=False, verbose_name="A pay\xe9"),
),
migrations.AlterField(
- model_name='survey',
- name='details',
- field=models.TextField(verbose_name='D\xe9tails', blank=True),
+ model_name="survey",
+ name="details",
+ field=models.TextField(verbose_name="D\xe9tails", blank=True),
),
migrations.AlterField(
- model_name='surveyquestionanswer',
- name='answer',
- field=models.CharField(max_length=200, verbose_name='R\xe9ponse'),
+ model_name="surveyquestionanswer",
+ name="answer",
+ field=models.CharField(max_length=200, verbose_name="R\xe9ponse"),
),
]
diff --git a/gestioncof/migrations/0006_add_calendar.py b/gestioncof/migrations/0006_add_calendar.py
index 27852f61..760fe56c 100644
--- a/gestioncof/migrations/0006_add_calendar.py
+++ b/gestioncof/migrations/0006_add_calendar.py
@@ -1,51 +1,66 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('bda', '0004_mails-rappel'),
+ ("bda", "0004_mails-rappel"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('gestioncof', '0005_encoding'),
+ ("gestioncof", "0005_encoding"),
]
operations = [
migrations.CreateModel(
- name='CalendarSubscription',
+ name="CalendarSubscription",
fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False,
- auto_created=True, primary_key=True)),
- ('token', models.UUIDField()),
- ('subscribe_to_events', models.BooleanField(default=True)),
- ('subscribe_to_my_shows', models.BooleanField(default=True)),
- ('other_shows', models.ManyToManyField(to='bda.Spectacle')),
- ('user', models.OneToOneField(to=settings.AUTH_USER_MODEL,
- on_delete=models.CASCADE)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ ),
+ ),
+ ("token", models.UUIDField()),
+ ("subscribe_to_events", models.BooleanField(default=True)),
+ ("subscribe_to_my_shows", models.BooleanField(default=True)),
+ ("other_shows", models.ManyToManyField(to="bda.Spectacle")),
+ (
+ "user",
+ models.OneToOneField(
+ to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ ),
+ ),
],
),
migrations.AlterModelOptions(
- name='custommail',
- options={'verbose_name': 'Mail personnalisable',
- 'verbose_name_plural': 'Mails personnalisables'},
+ name="custommail",
+ options={
+ "verbose_name": "Mail personnalisable",
+ "verbose_name_plural": "Mails personnalisables",
+ },
),
migrations.AlterModelOptions(
- name='eventoptionchoice',
- options={'verbose_name': 'Choix', 'verbose_name_plural': 'Choix'},
+ name="eventoptionchoice",
+ options={"verbose_name": "Choix", "verbose_name_plural": "Choix"},
),
migrations.AlterField(
- model_name='event',
- name='end_date',
- field=models.DateTimeField(null=True, verbose_name=b'Date de fin',
- blank=True),
- ),
- migrations.AlterField(
- model_name='event',
- name='start_date',
+ model_name="event",
+ name="end_date",
field=models.DateTimeField(
- null=True, verbose_name=b'Date de d\xc3\xa9but', blank=True),
+ null=True, verbose_name=b"Date de fin", blank=True
+ ),
+ ),
+ migrations.AlterField(
+ model_name="event",
+ name="start_date",
+ field=models.DateTimeField(
+ null=True, verbose_name=b"Date de d\xc3\xa9but", blank=True
+ ),
),
]
diff --git a/gestioncof/migrations/0007_alter_club.py b/gestioncof/migrations/0007_alter_club.py
index 324c59a6..13603370 100644
--- a/gestioncof/migrations/0007_alter_club.py
+++ b/gestioncof/migrations/0007_alter_club.py
@@ -1,47 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0006_add_calendar'),
- ]
+ dependencies = [("gestioncof", "0006_add_calendar")]
operations = [
migrations.AlterField(
- model_name='club',
- name='name',
- field=models.CharField(unique=True, max_length=200,
- verbose_name='Nom')
+ model_name="club",
+ name="name",
+ field=models.CharField(unique=True, max_length=200, verbose_name="Nom"),
),
migrations.AlterField(
- model_name='club',
- name='description',
- field=models.TextField(verbose_name='Description', blank=True)
+ model_name="club",
+ name="description",
+ field=models.TextField(verbose_name="Description", blank=True),
),
migrations.AlterField(
- model_name='club',
- name='membres',
- field=models.ManyToManyField(related_name='clubs',
- to=settings.AUTH_USER_MODEL,
- blank=True),
+ model_name="club",
+ name="membres",
+ field=models.ManyToManyField(
+ related_name="clubs", to=settings.AUTH_USER_MODEL, blank=True
+ ),
),
migrations.AlterField(
- model_name='club',
- name='respos',
- field=models.ManyToManyField(related_name='clubs_geres',
- to=settings.AUTH_USER_MODEL,
- blank=True),
+ model_name="club",
+ name="respos",
+ field=models.ManyToManyField(
+ related_name="clubs_geres", to=settings.AUTH_USER_MODEL, blank=True
+ ),
),
migrations.AlterField(
- model_name='event',
- name='start_date',
- field=models.DateTimeField(null=True,
- verbose_name='Date de d\xe9but',
- blank=True),
+ model_name="event",
+ name="start_date",
+ field=models.DateTimeField(
+ null=True, verbose_name="Date de d\xe9but", blank=True
+ ),
),
]
diff --git a/gestioncof/migrations/0008_py3.py b/gestioncof/migrations/0008_py3.py
index 7d94d7ce..f2b89aa4 100644
--- a/gestioncof/migrations/0008_py3.py
+++ b/gestioncof/migrations/0008_py3.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
def forwards(apps, schema_editor):
@@ -11,243 +11,266 @@ def forwards(apps, schema_editor):
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0007_alter_club'),
- ]
+ dependencies = [("gestioncof", "0007_alter_club")]
operations = [
migrations.AlterField(
- model_name='clipper',
- name='fullname',
- field=models.CharField(verbose_name='Nom complet', max_length=200),
+ model_name="clipper",
+ name="fullname",
+ field=models.CharField(verbose_name="Nom complet", max_length=200),
),
migrations.AlterField(
- model_name='clipper',
- name='username',
- field=models.CharField(verbose_name='Identifiant', max_length=20),
+ model_name="clipper",
+ name="username",
+ field=models.CharField(verbose_name="Identifiant", max_length=20),
),
migrations.AlterField(
- model_name='cofprofile',
- name='comments',
+ model_name="cofprofile",
+ name="comments",
field=models.TextField(
- verbose_name="Commentaires visibles par l'utilisateur",
- blank=True),
+ verbose_name="Commentaires visibles par l'utilisateur", blank=True
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='is_cof',
- field=models.BooleanField(verbose_name='Membre du COF',
- default=False),
+ model_name="cofprofile",
+ name="is_cof",
+ field=models.BooleanField(verbose_name="Membre du COF", default=False),
),
migrations.AlterField(
- model_name='cofprofile',
- name='login_clipper',
- field=models.CharField(verbose_name='Login clipper', max_length=8,
- blank=True),
+ model_name="cofprofile",
+ name="login_clipper",
+ field=models.CharField(
+ verbose_name="Login clipper", max_length=8, blank=True
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='mailing_bda',
- field=models.BooleanField(verbose_name='Recevoir les mails BdA',
- default=False),
- ),
- migrations.AlterField(
- model_name='cofprofile',
- name='mailing_bda_revente',
+ model_name="cofprofile",
+ name="mailing_bda",
field=models.BooleanField(
- verbose_name='Recevoir les mails de revente de places BdA',
- default=False),
+ verbose_name="Recevoir les mails BdA", default=False
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='mailing_cof',
- field=models.BooleanField(verbose_name='Recevoir les mails COF',
- default=False),
+ model_name="cofprofile",
+ name="mailing_bda_revente",
+ field=models.BooleanField(
+ verbose_name="Recevoir les mails de revente de places BdA",
+ default=False,
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='occupation',
- field=models.CharField(verbose_name='Occupation',
- choices=[('exterieur', 'Extérieur'),
- ('1A', '1A'),
- ('2A', '2A'),
- ('3A', '3A'),
- ('4A', '4A'),
- ('archicube', 'Archicube'),
- ('doctorant', 'Doctorant'),
- ('CST', 'CST')],
- max_length=9, default='1A'),
+ model_name="cofprofile",
+ name="mailing_cof",
+ field=models.BooleanField(
+ verbose_name="Recevoir les mails COF", default=False
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='petits_cours_accept',
- field=models.BooleanField(verbose_name='Recevoir des petits cours',
- default=False),
+ model_name="cofprofile",
+ name="occupation",
+ field=models.CharField(
+ verbose_name="Occupation",
+ choices=[
+ ("exterieur", "Extérieur"),
+ ("1A", "1A"),
+ ("2A", "2A"),
+ ("3A", "3A"),
+ ("4A", "4A"),
+ ("archicube", "Archicube"),
+ ("doctorant", "Doctorant"),
+ ("CST", "CST"),
+ ],
+ max_length=9,
+ default="1A",
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='petits_cours_remarques',
+ model_name="cofprofile",
+ name="petits_cours_accept",
+ field=models.BooleanField(
+ verbose_name="Recevoir des petits cours", default=False
+ ),
+ ),
+ migrations.AlterField(
+ model_name="cofprofile",
+ name="petits_cours_remarques",
field=models.TextField(
blank=True,
- verbose_name='Remarques et précisions pour les petits cours',
- default=''),
+ verbose_name="Remarques et précisions pour les petits cours",
+ default="",
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='type_cotiz',
+ model_name="cofprofile",
+ name="type_cotiz",
field=models.CharField(
- verbose_name='Type de cotisation',
- choices=[('etudiant', 'Normalien étudiant'),
- ('normalien', 'Normalien élève'),
- ('exterieur', 'Extérieur')],
- max_length=9, default='normalien'),
+ verbose_name="Type de cotisation",
+ choices=[
+ ("etudiant", "Normalien étudiant"),
+ ("normalien", "Normalien élève"),
+ ("exterieur", "Extérieur"),
+ ],
+ max_length=9,
+ default="normalien",
+ ),
),
migrations.AlterField(
- model_name='custommail',
- name='comments',
+ model_name="custommail",
+ name="comments",
field=models.TextField(
- verbose_name='Informations contextuelles sur le mail',
- blank=True),
+ verbose_name="Informations contextuelles sur le mail", blank=True
+ ),
),
migrations.AlterField(
- model_name='custommail',
- name='content',
- field=models.TextField(verbose_name='Contenu'),
+ model_name="custommail",
+ name="content",
+ field=models.TextField(verbose_name="Contenu"),
),
migrations.AlterField(
- model_name='custommail',
- name='title',
- field=models.CharField(verbose_name='Titre', max_length=200),
+ model_name="custommail",
+ name="title",
+ field=models.CharField(verbose_name="Titre", max_length=200),
),
migrations.AlterField(
- model_name='event',
- name='description',
- field=models.TextField(verbose_name='Description', blank=True),
+ model_name="event",
+ name="description",
+ field=models.TextField(verbose_name="Description", blank=True),
),
migrations.AlterField(
- model_name='event',
- name='end_date',
- field=models.DateTimeField(null=True, verbose_name='Date de fin',
- blank=True),
+ model_name="event",
+ name="end_date",
+ field=models.DateTimeField(
+ null=True, verbose_name="Date de fin", blank=True
+ ),
),
migrations.AlterField(
- model_name='event',
- name='image',
- field=models.ImageField(upload_to='imgs/events/', null=True,
- verbose_name='Image', blank=True),
+ model_name="event",
+ name="image",
+ field=models.ImageField(
+ upload_to="imgs/events/", null=True, verbose_name="Image", blank=True
+ ),
),
migrations.AlterField(
- model_name='event',
- name='location',
- field=models.CharField(verbose_name='Lieu', max_length=200),
+ model_name="event",
+ name="location",
+ field=models.CharField(verbose_name="Lieu", max_length=200),
),
migrations.AlterField(
- model_name='event',
- name='registration_open',
- field=models.BooleanField(verbose_name='Inscriptions ouvertes',
- default=True),
+ model_name="event",
+ name="registration_open",
+ field=models.BooleanField(
+ verbose_name="Inscriptions ouvertes", default=True
+ ),
),
migrations.AlterField(
- model_name='event',
- name='title',
- field=models.CharField(verbose_name='Titre', max_length=200),
+ model_name="event",
+ name="title",
+ field=models.CharField(verbose_name="Titre", max_length=200),
),
migrations.AlterField(
- model_name='eventcommentfield',
- name='fieldtype',
- field=models.CharField(verbose_name='Type',
- choices=[('text', 'Texte long'),
- ('char', 'Texte court')],
- max_length=10, default='text'),
- ),
- migrations.AlterField(
- model_name='eventcommentfield',
- name='name',
- field=models.CharField(verbose_name='Champ', max_length=200),
- ),
- migrations.AlterField(
- model_name='eventcommentvalue',
- name='content',
- field=models.TextField(null=True, verbose_name='Contenu',
- blank=True),
- ),
- migrations.AlterField(
- model_name='eventoption',
- name='multi_choices',
- field=models.BooleanField(verbose_name='Choix multiples',
- default=False),
- ),
- migrations.AlterField(
- model_name='eventoption',
- name='name',
- field=models.CharField(verbose_name='Option', max_length=200),
- ),
- migrations.AlterField(
- model_name='eventoptionchoice',
- name='value',
- field=models.CharField(verbose_name='Valeur', max_length=200),
- ),
- migrations.AlterField(
- model_name='petitcoursability',
- name='niveau',
+ model_name="eventcommentfield",
+ name="fieldtype",
field=models.CharField(
- choices=[('college', 'Collège'), ('lycee', 'Lycée'),
- ('prepa1styear', 'Prépa 1ère année / L1'),
- ('prepa2ndyear', 'Prépa 2ème année / L2'),
- ('licence3', 'Licence 3'),
- ('other', 'Autre (préciser dans les commentaires)')],
- max_length=12, verbose_name='Niveau'),
+ verbose_name="Type",
+ choices=[("text", "Texte long"), ("char", "Texte court")],
+ max_length=10,
+ default="text",
+ ),
),
migrations.AlterField(
- model_name='petitcoursattribution',
- name='rank',
+ model_name="eventcommentfield",
+ name="name",
+ field=models.CharField(verbose_name="Champ", max_length=200),
+ ),
+ migrations.AlterField(
+ model_name="eventcommentvalue",
+ name="content",
+ field=models.TextField(null=True, verbose_name="Contenu", blank=True),
+ ),
+ migrations.AlterField(
+ model_name="eventoption",
+ name="multi_choices",
+ field=models.BooleanField(verbose_name="Choix multiples", default=False),
+ ),
+ migrations.AlterField(
+ model_name="eventoption",
+ name="name",
+ field=models.CharField(verbose_name="Option", max_length=200),
+ ),
+ migrations.AlterField(
+ model_name="eventoptionchoice",
+ name="value",
+ field=models.CharField(verbose_name="Valeur", max_length=200),
+ ),
+ migrations.AlterField(
+ model_name="petitcoursability",
+ name="niveau",
+ field=models.CharField(
+ choices=[
+ ("college", "Collège"),
+ ("lycee", "Lycée"),
+ ("prepa1styear", "Prépa 1ère année / L1"),
+ ("prepa2ndyear", "Prépa 2ème année / L2"),
+ ("licence3", "Licence 3"),
+ ("other", "Autre (préciser dans les commentaires)"),
+ ],
+ max_length=12,
+ verbose_name="Niveau",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="petitcoursattribution",
+ name="rank",
field=models.IntegerField(verbose_name="Rang dans l'email"),
),
migrations.AlterField(
- model_name='petitcoursattributioncounter',
- name='count',
- field=models.IntegerField(verbose_name="Nombre d'envois",
- default=0),
+ model_name="petitcoursattributioncounter",
+ name="count",
+ field=models.IntegerField(verbose_name="Nombre d'envois", default=0),
),
migrations.AlterField(
- model_name='petitcoursdemande',
- name='niveau',
+ model_name="petitcoursdemande",
+ name="niveau",
field=models.CharField(
- verbose_name='Niveau',
- choices=[('college', 'Collège'), ('lycee', 'Lycée'),
- ('prepa1styear', 'Prépa 1ère année / L1'),
- ('prepa2ndyear', 'Prépa 2ème année / L2'),
- ('licence3', 'Licence 3'),
- ('other', 'Autre (préciser dans les commentaires)')],
- max_length=12, default=''),
+ verbose_name="Niveau",
+ choices=[
+ ("college", "Collège"),
+ ("lycee", "Lycée"),
+ ("prepa1styear", "Prépa 1ère année / L1"),
+ ("prepa2ndyear", "Prépa 2ème année / L2"),
+ ("licence3", "Licence 3"),
+ ("other", "Autre (préciser dans les commentaires)"),
+ ],
+ max_length=12,
+ default="",
+ ),
),
migrations.AlterField(
- model_name='survey',
- name='old',
- field=models.BooleanField(verbose_name='Archiver (sondage fini)',
- default=False),
+ model_name="survey",
+ name="old",
+ field=models.BooleanField(
+ verbose_name="Archiver (sondage fini)", default=False
+ ),
),
migrations.AlterField(
- model_name='survey',
- name='survey_open',
- field=models.BooleanField(verbose_name='Sondage ouvert',
- default=True),
+ model_name="survey",
+ name="survey_open",
+ field=models.BooleanField(verbose_name="Sondage ouvert", default=True),
),
migrations.AlterField(
- model_name='survey',
- name='title',
- field=models.CharField(verbose_name='Titre', max_length=200),
+ model_name="survey",
+ name="title",
+ field=models.CharField(verbose_name="Titre", max_length=200),
),
migrations.AlterField(
- model_name='surveyquestion',
- name='multi_answers',
- field=models.BooleanField(verbose_name='Choix multiples',
- default=False),
+ model_name="surveyquestion",
+ name="multi_answers",
+ field=models.BooleanField(verbose_name="Choix multiples", default=False),
),
migrations.AlterField(
- model_name='surveyquestion',
- name='question',
- field=models.CharField(verbose_name='Question', max_length=200),
+ model_name="surveyquestion",
+ name="question",
+ field=models.CharField(verbose_name="Question", max_length=200),
),
migrations.RunPython(forwards, migrations.RunPython.noop),
]
diff --git a/gestioncof/migrations/0009_delete_clipper.py b/gestioncof/migrations/0009_delete_clipper.py
index e537107b..35362716 100644
--- a/gestioncof/migrations/0009_delete_clipper.py
+++ b/gestioncof/migrations/0009_delete_clipper.py
@@ -6,12 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0008_py3'),
- ]
+ dependencies = [("gestioncof", "0008_py3")]
- operations = [
- migrations.DeleteModel(
- name='Clipper',
- ),
- ]
+ operations = [migrations.DeleteModel(name="Clipper")]
diff --git a/gestioncof/migrations/0010_delete_custommail.py b/gestioncof/migrations/0010_delete_custommail.py
index 63ebeca7..2434faf2 100644
--- a/gestioncof/migrations/0010_delete_custommail.py
+++ b/gestioncof/migrations/0010_delete_custommail.py
@@ -5,12 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0009_delete_clipper'),
- ]
+ dependencies = [("gestioncof", "0009_delete_clipper")]
- operations = [
- migrations.DeleteModel(
- name='CustomMail',
- ),
- ]
+ operations = [migrations.DeleteModel(name="CustomMail")]
diff --git a/gestioncof/migrations/0011_longer_clippers.py b/gestioncof/migrations/0011_longer_clippers.py
index 631d0ea8..777f79a8 100644
--- a/gestioncof/migrations/0011_longer_clippers.py
+++ b/gestioncof/migrations/0011_longer_clippers.py
@@ -6,14 +6,14 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0010_delete_custommail'),
- ]
+ dependencies = [("gestioncof", "0010_delete_custommail")]
operations = [
migrations.AlterField(
- model_name='cofprofile',
- name='login_clipper',
- field=models.CharField(verbose_name='Login clipper', blank=True, max_length=32),
- ),
+ model_name="cofprofile",
+ name="login_clipper",
+ field=models.CharField(
+ verbose_name="Login clipper", blank=True, max_length=32
+ ),
+ )
]
diff --git a/gestioncof/migrations/0011_remove_cofprofile_num.py b/gestioncof/migrations/0011_remove_cofprofile_num.py
index f39ce367..abf97768 100644
--- a/gestioncof/migrations/0011_remove_cofprofile_num.py
+++ b/gestioncof/migrations/0011_remove_cofprofile_num.py
@@ -6,13 +6,6 @@ from django.db import migrations
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0010_delete_custommail'),
- ]
+ dependencies = [("gestioncof", "0010_delete_custommail")]
- operations = [
- migrations.RemoveField(
- model_name='cofprofile',
- name='num',
- ),
- ]
+ operations = [migrations.RemoveField(model_name="cofprofile", name="num")]
diff --git a/gestioncof/migrations/0012_merge.py b/gestioncof/migrations/0012_merge.py
index 39879346..5e23119d 100644
--- a/gestioncof/migrations/0012_merge.py
+++ b/gestioncof/migrations/0012_merge.py
@@ -7,9 +7,8 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('gestioncof', '0011_remove_cofprofile_num'),
- ('gestioncof', '0011_longer_clippers'),
+ ("gestioncof", "0011_remove_cofprofile_num"),
+ ("gestioncof", "0011_longer_clippers"),
]
- operations = [
- ]
+ operations = []
diff --git a/gestioncof/migrations/0013_pei.py b/gestioncof/migrations/0013_pei.py
index 2fbddf1f..186d458d 100644
--- a/gestioncof/migrations/0013_pei.py
+++ b/gestioncof/migrations/0013_pei.py
@@ -6,42 +6,42 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0012_merge'),
- ]
+ dependencies = [("gestioncof", "0012_merge")]
operations = [
migrations.AlterField(
- model_name='cofprofile',
- name='occupation',
+ model_name="cofprofile",
+ name="occupation",
field=models.CharField(
- verbose_name='Occupation',
+ verbose_name="Occupation",
max_length=9,
- default='1A',
+ default="1A",
choices=[
- ('exterieur', 'Extérieur'),
- ('1A', '1A'),
- ('2A', '2A'),
- ('3A', '3A'),
- ('4A', '4A'),
- ('archicube', 'Archicube'),
- ('doctorant', 'Doctorant'),
- ('CST', 'CST'),
- ('PEI', 'PEI')
- ]),
+ ("exterieur", "Extérieur"),
+ ("1A", "1A"),
+ ("2A", "2A"),
+ ("3A", "3A"),
+ ("4A", "4A"),
+ ("archicube", "Archicube"),
+ ("doctorant", "Doctorant"),
+ ("CST", "CST"),
+ ("PEI", "PEI"),
+ ],
+ ),
),
migrations.AlterField(
- model_name='cofprofile',
- name='type_cotiz',
+ model_name="cofprofile",
+ name="type_cotiz",
field=models.CharField(
- verbose_name='Type de cotisation',
+ verbose_name="Type de cotisation",
max_length=9,
- default='normalien',
+ default="normalien",
choices=[
- ('etudiant', 'Normalien étudiant'),
- ('normalien', 'Normalien élève'),
- ('exterieur', 'Extérieur'),
- ('gratis', 'Gratuit')
- ]),
+ ("etudiant", "Normalien étudiant"),
+ ("normalien", "Normalien élève"),
+ ("exterieur", "Extérieur"),
+ ("gratis", "Gratuit"),
+ ],
+ ),
),
]
diff --git a/gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py b/gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py
new file mode 100644
index 00000000..b849bfca
--- /dev/null
+++ b/gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.15 on 2018-09-02 21:13
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [("gestioncof", "0013_pei")]
+
+ operations = [
+ migrations.AddField(
+ model_name="cofprofile",
+ name="mailing_unernestaparis",
+ field=models.BooleanField(
+ default=False, verbose_name="Recevoir les mails unErnestAParis"
+ ),
+ )
+ ]
diff --git a/gestioncof/models.py b/gestioncof/models.py
index 0d816155..227fa936 100644
--- a/gestioncof/models.py
+++ b/gestioncof/models.py
@@ -1,17 +1,13 @@
-from django.db import models
-from django.dispatch import receiver
from django.contrib.auth.models import User
+from django.db import models
+from django.db.models.signals import post_delete, post_save
+from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
-from django.db.models.signals import post_save, post_delete
-
-from gestioncof.petits_cours_models import choices_length
from bda.models import Spectacle
+from gestioncof.petits_cours_models import choices_length
-TYPE_COMMENT_FIELD = (
- ('text', _("Texte long")),
- ('char', _("Texte court")),
-)
+TYPE_COMMENT_FIELD = (("text", _("Texte long")), ("char", _("Texte court")))
class CofProfile(models.Model):
@@ -49,39 +45,39 @@ class CofProfile(models.Model):
(COTIZ_GRATIS, _("Gratuit")),
)
- user = models.OneToOneField(
- User, on_delete=models.CASCADE,
- related_name="profile",
- )
- login_clipper = models.CharField(
- "Login clipper", max_length=32, blank=True
- )
+ user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
+ login_clipper = models.CharField("Login clipper", max_length=32, blank=True)
is_cof = models.BooleanField("Membre du COF", default=False)
phone = models.CharField("Téléphone", max_length=20, blank=True)
- occupation = models.CharField(_("Occupation"),
- default="1A",
- choices=OCCUPATION_CHOICES,
- max_length=choices_length(
- OCCUPATION_CHOICES))
- departement = models.CharField(_("Département"), max_length=50,
- blank=True)
- type_cotiz = models.CharField(_("Type de cotisation"),
- default="normalien",
- choices=TYPE_COTIZ_CHOICES,
- max_length=choices_length(
- TYPE_COTIZ_CHOICES))
+ occupation = models.CharField(
+ _("Occupation"),
+ default="1A",
+ choices=OCCUPATION_CHOICES,
+ max_length=choices_length(OCCUPATION_CHOICES),
+ )
+ departement = models.CharField(_("Département"), max_length=50, blank=True)
+ type_cotiz = models.CharField(
+ _("Type de cotisation"),
+ default="normalien",
+ choices=TYPE_COTIZ_CHOICES,
+ max_length=choices_length(TYPE_COTIZ_CHOICES),
+ )
mailing_cof = models.BooleanField("Recevoir les mails COF", default=False)
mailing_bda = models.BooleanField("Recevoir les mails BdA", default=False)
+ mailing_unernestaparis = models.BooleanField(
+ "Recevoir les mails unErnestAParis", default=False
+ )
mailing_bda_revente = models.BooleanField(
- "Recevoir les mails de revente de places BdA", default=False)
- comments = models.TextField(
- "Commentaires visibles par l'utilisateur", blank=True)
+ "Recevoir les mails de revente de places BdA", default=False
+ )
+ comments = models.TextField("Commentaires visibles par l'utilisateur", blank=True)
is_buro = models.BooleanField("Membre du Burô", default=False)
petits_cours_accept = models.BooleanField(
- "Recevoir des petits cours", default=False)
+ "Recevoir des petits cours", default=False
+ )
petits_cours_remarques = models.TextField(
- _("Remarques et précisions pour les petits cours"),
- blank=True, default="")
+ _("Remarques et précisions pour les petits cours"), blank=True, default=""
+ )
class Meta:
verbose_name = "Profil COF"
@@ -105,8 +101,7 @@ def post_delete_user(sender, instance, *args, **kwargs):
class Club(models.Model):
name = models.CharField("Nom", max_length=200, unique=True)
description = models.TextField("Description", blank=True)
- respos = models.ManyToManyField(User, related_name="clubs_geres",
- blank=True)
+ respos = models.ManyToManyField(User, related_name="clubs_geres", blank=True)
membres = models.ManyToManyField(User, related_name="clubs", blank=True)
def __str__(self):
@@ -119,10 +114,8 @@ class Event(models.Model):
start_date = models.DateTimeField("Date de début", blank=True, null=True)
end_date = models.DateTimeField("Date de fin", blank=True, null=True)
description = models.TextField("Description", blank=True)
- image = models.ImageField("Image", blank=True, null=True,
- upload_to="imgs/events/")
- registration_open = models.BooleanField("Inscriptions ouvertes",
- default=True)
+ image = models.ImageField("Image", blank=True, null=True, upload_to="imgs/events/")
+ registration_open = models.BooleanField("Inscriptions ouvertes", default=True)
old = models.BooleanField("Archiver (événement fini)", default=False)
class Meta:
@@ -134,12 +127,12 @@ class Event(models.Model):
class EventCommentField(models.Model):
event = models.ForeignKey(
- Event, on_delete=models.CASCADE,
- related_name="commentfields",
+ Event, on_delete=models.CASCADE, related_name="commentfields"
)
name = models.CharField("Champ", max_length=200)
- fieldtype = models.CharField("Type", max_length=10,
- choices=TYPE_COMMENT_FIELD, default="text")
+ fieldtype = models.CharField(
+ "Type", max_length=10, choices=TYPE_COMMENT_FIELD, default="text"
+ )
default = models.TextField("Valeur par défaut", blank=True)
class Meta:
@@ -151,12 +144,10 @@ class EventCommentField(models.Model):
class EventCommentValue(models.Model):
commentfield = models.ForeignKey(
- EventCommentField, on_delete=models.CASCADE,
- related_name="values",
+ EventCommentField, on_delete=models.CASCADE, related_name="values"
)
registration = models.ForeignKey(
- "EventRegistration", on_delete=models.CASCADE,
- related_name="comments",
+ "EventRegistration", on_delete=models.CASCADE, related_name="comments"
)
content = models.TextField("Contenu", blank=True, null=True)
@@ -165,10 +156,7 @@ class EventCommentValue(models.Model):
class EventOption(models.Model):
- event = models.ForeignKey(
- Event, on_delete=models.CASCADE,
- related_name="options",
- )
+ event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="options")
name = models.CharField("Option", max_length=200)
multi_choices = models.BooleanField("Choix multiples", default=False)
@@ -181,8 +169,7 @@ class EventOption(models.Model):
class EventOptionChoice(models.Model):
event_option = models.ForeignKey(
- EventOption, on_delete=models.CASCADE,
- related_name="choices",
+ EventOption, on_delete=models.CASCADE, related_name="choices"
)
value = models.CharField("Valeur", max_length=200)
@@ -198,8 +185,9 @@ class EventRegistration(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
options = models.ManyToManyField(EventOptionChoice)
- filledcomments = models.ManyToManyField(EventCommentField,
- through=EventCommentValue)
+ filledcomments = models.ManyToManyField(
+ EventCommentField, through=EventCommentValue
+ )
paid = models.BooleanField("A payé", default=False)
class Meta:
@@ -225,8 +213,7 @@ class Survey(models.Model):
class SurveyQuestion(models.Model):
survey = models.ForeignKey(
- Survey, on_delete=models.CASCADE,
- related_name="questions",
+ Survey, on_delete=models.CASCADE, related_name="questions"
)
question = models.CharField("Question", max_length=200)
multi_answers = models.BooleanField("Choix multiples", default=False)
@@ -240,8 +227,7 @@ class SurveyQuestion(models.Model):
class SurveyQuestionAnswer(models.Model):
survey_question = models.ForeignKey(
- SurveyQuestion, on_delete=models.CASCADE,
- related_name="answers",
+ SurveyQuestion, on_delete=models.CASCADE, related_name="answers"
)
answer = models.CharField("Réponse", max_length=200)
@@ -255,8 +241,7 @@ class SurveyQuestionAnswer(models.Model):
class SurveyAnswer(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
- answers = models.ManyToManyField(SurveyQuestionAnswer,
- related_name="selected_by")
+ answers = models.ManyToManyField(SurveyQuestionAnswer, related_name="selected_by")
class Meta:
verbose_name = "Réponses"
@@ -264,8 +249,9 @@ class SurveyAnswer(models.Model):
def __str__(self):
return "Réponse de %s sondage %s" % (
- self.user.get_full_name(),
- self.survey.title)
+ self.user.get_full_name(),
+ self.survey.title,
+ )
class CalendarSubscription(models.Model):
diff --git a/gestioncof/petits_cours_forms.py b/gestioncof/petits_cours_forms.py
index e8f067bf..b9cfc067 100644
--- a/gestioncof/petits_cours_forms.py
+++ b/gestioncof/petits_cours_forms.py
@@ -1,11 +1,10 @@
from captcha.fields import ReCaptchaField
-
from django import forms
-from django.forms import ModelForm
-from django.forms.models import inlineformset_factory, BaseInlineFormSet
from django.contrib.auth.models import User
+from django.forms import ModelForm
+from django.forms.models import BaseInlineFormSet, inlineformset_factory
-from gestioncof.petits_cours_models import PetitCoursDemande, PetitCoursAbility
+from gestioncof.petits_cours_models import PetitCoursAbility, PetitCoursDemande
class BaseMatieresFormSet(BaseInlineFormSet):
@@ -20,33 +19,44 @@ class BaseMatieresFormSet(BaseInlineFormSet):
form = self.forms[i]
if not form.cleaned_data:
continue
- matiere = form.cleaned_data['matiere']
- niveau = form.cleaned_data['niveau']
- delete = form.cleaned_data['DELETE']
+ matiere = form.cleaned_data["matiere"]
+ niveau = form.cleaned_data["niveau"]
+ delete = form.cleaned_data["DELETE"]
if not delete and (matiere, niveau) in matieres:
raise forms.ValidationError(
"Vous ne pouvez pas vous inscrire deux fois pour la "
- "même matiere avec le même niveau.")
+ "même matiere avec le même niveau."
+ )
matieres.append((matiere, niveau))
class DemandeForm(ModelForm):
- captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'})
+ captcha = ReCaptchaField(attrs={"theme": "clean", "lang": "fr"})
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['matieres'].help_text = ''
+ self.fields["matieres"].help_text = ""
class Meta:
model = PetitCoursDemande
- fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu',
- 'matieres', 'agrege_requis', 'niveau', 'remarques')
- widgets = {'matieres': forms.CheckboxSelectMultiple}
+ fields = (
+ "name",
+ "email",
+ "phone",
+ "quand",
+ "freq",
+ "lieu",
+ "matieres",
+ "agrege_requis",
+ "niveau",
+ "remarques",
+ )
+ widgets = {"matieres": forms.CheckboxSelectMultiple}
MatieresFormSet = inlineformset_factory(
User,
PetitCoursAbility,
fields=("matiere", "niveau", "agrege"),
- formset=BaseMatieresFormSet
+ formset=BaseMatieresFormSet,
)
diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py
index 820f1292..40031877 100644
--- a/gestioncof/petits_cours_models.py
+++ b/gestioncof/petits_cours_models.py
@@ -1,28 +1,30 @@
from functools import reduce
+from django.contrib.auth.models import User
from django.db import models
from django.db.models import Min
-from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
def choices_length(choices):
return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0)
+
LEVELS_CHOICES = (
- ('college', _("Collège")),
- ('lycee', _("Lycée")),
- ('prepa1styear', _("Prépa 1ère année / L1")),
- ('prepa2ndyear', _("Prépa 2ème année / L2")),
- ('licence3', _("Licence 3")),
- ('other', _("Autre (préciser dans les commentaires)")),
+ ("college", _("Collège")),
+ ("lycee", _("Lycée")),
+ ("prepa1styear", _("Prépa 1ère année / L1")),
+ ("prepa2ndyear", _("Prépa 2ème année / L2")),
+ ("licence3", _("Licence 3")),
+ ("other", _("Autre (préciser dans les commentaires)")),
)
class PetitCoursSubject(models.Model):
name = models.CharField(_("Matière"), max_length=30)
- users = models.ManyToManyField(User, related_name="petits_cours_matieres",
- through="PetitCoursAbility")
+ users = models.ManyToManyField(
+ User, related_name="petits_cours_matieres", through="PetitCoursAbility"
+ )
class Meta:
verbose_name = "Matière de petits cours"
@@ -35,12 +37,11 @@ class PetitCoursSubject(models.Model):
class PetitCoursAbility(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
matiere = models.ForeignKey(
- PetitCoursSubject, on_delete=models.CASCADE,
- verbose_name=_("Matière"),
+ PetitCoursSubject, on_delete=models.CASCADE, verbose_name=_("Matière")
+ )
+ niveau = models.CharField(
+ _("Niveau"), choices=LEVELS_CHOICES, max_length=choices_length(LEVELS_CHOICES)
)
- niveau = models.CharField(_("Niveau"),
- choices=LEVELS_CHOICES,
- max_length=choices_length(LEVELS_CHOICES))
agrege = models.BooleanField(_("Agrégé"), default=False)
class Meta:
@@ -56,41 +57,50 @@ class PetitCoursAbility(models.Model):
class PetitCoursDemande(models.Model):
name = models.CharField(_("Nom/prénom"), max_length=200)
email = models.CharField(_("Adresse email"), max_length=300)
- phone = models.CharField(_("Téléphone (facultatif)"),
- max_length=20, blank=True)
+ phone = models.CharField(_("Téléphone (facultatif)"), max_length=20, blank=True)
quand = models.CharField(
_("Quand ?"),
- help_text=_("Indiquez ici la période désirée pour les petits"
- " cours (vacances scolaires, semaine, week-end)."),
- max_length=300, blank=True)
+ help_text=_(
+ "Indiquez ici la période désirée pour les petits"
+ " cours (vacances scolaires, semaine, week-end)."
+ ),
+ max_length=300,
+ blank=True,
+ )
freq = models.CharField(
_("Fréquence"),
- help_text=_("Indiquez ici la fréquence envisagée "
- "(hebdomadaire, 2 fois par semaine, ...)"),
- max_length=300, blank=True)
+ help_text=_(
+ "Indiquez ici la fréquence envisagée "
+ "(hebdomadaire, 2 fois par semaine, ...)"
+ ),
+ max_length=300,
+ blank=True,
+ )
lieu = models.CharField(
_("Lieu (si préférence)"),
help_text=_("Si vous avez avez une préférence sur le lieu."),
- max_length=300, blank=True)
+ max_length=300,
+ blank=True,
+ )
matieres = models.ManyToManyField(
- PetitCoursSubject, verbose_name=_("Matières"),
- related_name="demandes")
+ PetitCoursSubject, verbose_name=_("Matières"), related_name="demandes"
+ )
agrege_requis = models.BooleanField(_("Agrégé requis"), default=False)
- niveau = models.CharField(_("Niveau"),
- default="",
- choices=LEVELS_CHOICES,
- max_length=choices_length(LEVELS_CHOICES))
+ niveau = models.CharField(
+ _("Niveau"),
+ default="",
+ choices=LEVELS_CHOICES,
+ max_length=choices_length(LEVELS_CHOICES),
+ )
remarques = models.TextField(_("Remarques et précisions"), blank=True)
traitee = models.BooleanField(_("Traitée"), default=False)
traitee_par = models.ForeignKey(
- User, on_delete=models.CASCADE,
- blank=True, null=True,
+ User, on_delete=models.CASCADE, blank=True, null=True
)
- processed = models.DateTimeField(_("Date de traitement"),
- blank=True, null=True)
+ processed = models.DateTimeField(_("Date de traitement"), blank=True, null=True)
created = models.DateTimeField(_("Date de création"), auto_now_add=True)
def get_candidates(self, redo=False):
@@ -105,18 +115,15 @@ class PetitCoursDemande(models.Model):
matiere=matiere,
niveau=self.niveau,
user__profile__is_cof=True,
- user__profile__petits_cours_accept=True
+ user__profile__petits_cours_accept=True,
)
if self.agrege_requis:
candidates = candidates.filter(agrege=True)
if redo:
attrs = self.petitcoursattribution_set.filter(matiere=matiere)
- already_proposed = [
- attr.user
- for attr in attrs
- ]
+ already_proposed = [attr.user for attr in attrs]
candidates = candidates.exclude(user__in=already_proposed)
- candidates = candidates.order_by('?').select_related().all()
+ candidates = candidates.order_by("?").select_related().all()
yield (matiere, candidates)
class Meta:
@@ -124,25 +131,20 @@ class PetitCoursDemande(models.Model):
verbose_name_plural = "Demandes de petits cours"
def __str__(self):
- return "Demande {:d} du {:s}".format(
- self.id, self.created.strftime("%d %b %Y")
- )
+ return "Demande {:d} du {:s}".format(self.id, self.created.strftime("%d %b %Y"))
class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
demande = models.ForeignKey(
- PetitCoursDemande, on_delete=models.CASCADE,
- verbose_name=_("Demande"),
+ PetitCoursDemande, on_delete=models.CASCADE, verbose_name=_("Demande")
)
matiere = models.ForeignKey(
- PetitCoursSubject, on_delete=models.CASCADE,
- verbose_name=_("Matière"),
+ PetitCoursSubject, on_delete=models.CASCADE, verbose_name=_("Matière")
)
date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True)
rank = models.IntegerField("Rang dans l'email")
- selected = models.BooleanField(_("Sélectionné par le demandeur"),
- default=False)
+ selected = models.BooleanField(_("Sélectionné par le demandeur"), default=False)
class Meta:
verbose_name = "Attribution de petits cours"
@@ -157,8 +159,7 @@ class PetitCoursAttribution(models.Model):
class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
matiere = models.ForeignKey(
- PetitCoursSubject, on_delete=models.CASCADE,
- verbose_name=_("Matiere"),
+ PetitCoursSubject, on_delete=models.CASCADE, verbose_name=_("Matiere")
)
count = models.IntegerField("Nombre d'envois", default=0)
@@ -169,15 +170,12 @@ class PetitCoursAttributionCounter(models.Model):
n'existe pas encore, il est initialisé avec le minimum des valeurs des
compteurs de tout le monde.
"""
- counter, created = cls.objects.get_or_create(
- user=user,
- matiere=matiere,
- )
+ counter, created = cls.objects.get_or_create(user=user, matiere=matiere)
if created:
mincount = (
- cls.objects.filter(matiere=matiere).exclude(user=user)
- .aggregate(Min('count'))
- ['count__min']
+ cls.objects.filter(matiere=matiere)
+ .exclude(user=user)
+ .aggregate(Min("count"))["count__min"]
)
counter.count = mincount or 0
counter.save()
diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py
index 6b8c8610..d640981a 100644
--- a/gestioncof/petits_cours_views.py
+++ b/gestioncof/petits_cours_views.py
@@ -1,31 +1,31 @@
import json
+
from custommail.shortcuts import render_custom_mail
-
-from django.shortcuts import render, get_object_or_404, redirect
-from django.core import mail
-from django.contrib.auth.models import User
-from django.views.generic import ListView, DetailView
-from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
-from django.contrib.auth.decorators import login_required
from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
+from django.core import mail
from django.db import transaction
+from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
+from django.views.decorators.csrf import csrf_exempt
+from django.views.generic import DetailView, ListView
-from gestioncof.models import CofProfile
-from gestioncof.petits_cours_models import (
- PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter,
- PetitCoursAbility
-)
-from gestioncof.petits_cours_forms import DemandeForm, MatieresFormSet
from gestioncof.decorators import buro_required
+from gestioncof.models import CofProfile
+from gestioncof.petits_cours_forms import DemandeForm, MatieresFormSet
+from gestioncof.petits_cours_models import (
+ PetitCoursAbility,
+ PetitCoursAttribution,
+ PetitCoursAttributionCounter,
+ PetitCoursDemande,
+)
class DemandeListView(ListView):
- queryset = (
- PetitCoursDemande.objects
- .prefetch_related('matieres')
- .order_by('traitee', '-id')
+ queryset = PetitCoursDemande.objects.prefetch_related("matieres").order_by(
+ "traitee", "-id"
)
template_name = "petits_cours_demandes_list.html"
paginate_by = 20
@@ -33,10 +33,8 @@ class DemandeListView(ListView):
class DemandeDetailView(DetailView):
model = PetitCoursDemande
- queryset = (
- PetitCoursDemande.objects
- .prefetch_related('petitcoursattribution_set',
- 'matieres')
+ queryset = PetitCoursDemande.objects.prefetch_related(
+ "petitcoursattribution_set", "matieres"
)
template_name = "gestioncof/details_demande_petit_cours.html"
context_object_name = "demande"
@@ -44,7 +42,7 @@ class DemandeDetailView(DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = self.object
- context['attributions'] = obj.petitcoursattribution_set.all()
+ context["attributions"] = obj.petitcoursattribution_set.all()
return context
@@ -64,13 +62,15 @@ def traitement(request, demande_id, redo=False):
tuples = []
for candidate in candidates:
user = candidate.user
- tuples.append((
- candidate,
- PetitCoursAttributionCounter.get_uptodate(user, matiere)
- ))
+ tuples.append(
+ (
+ candidate,
+ PetitCoursAttributionCounter.get_uptodate(user, matiere),
+ )
+ )
tuples = sorted(tuples, key=lambda c: c[1].count)
candidates, _ = zip(*tuples)
- candidates = candidates[0:min(3, len(candidates))]
+ candidates = candidates[0 : min(3, len(candidates))]
attribdata[matiere.id] = []
proposals[matiere] = []
for candidate in candidates:
@@ -83,8 +83,9 @@ def traitement(request, demande_id, redo=False):
proposed_for[user].append(matiere)
else:
unsatisfied.append(matiere)
- return _finalize_traitement(request, demande, proposals,
- proposed_for, unsatisfied, attribdata, redo)
+ return _finalize_traitement(
+ request, demande, proposals, proposed_for, unsatisfied, attribdata, redo
+ )
@buro_required
@@ -92,43 +93,56 @@ def retraitement(request, demande_id):
return traitement(request, demande_id, redo=True)
-def _finalize_traitement(request, demande, proposals, proposed_for,
- unsatisfied, attribdata, redo=False, errors=None):
+def _finalize_traitement(
+ request,
+ demande,
+ proposals,
+ proposed_for,
+ unsatisfied,
+ attribdata,
+ redo=False,
+ errors=None,
+):
proposals = proposals.items()
proposed_for = proposed_for.items()
attribdata = list(attribdata.items())
proposed_mails = _generate_eleve_email(demande, proposed_for)
- mainmail = render_custom_mail("petits-cours-mail-demandeur", {
- "proposals": proposals,
- "unsatisfied": unsatisfied,
- "extra":
- ''
- })
+ "",
+ },
+ )
if errors is not None:
for error in errors:
messages.error(request, error)
- return render(request, "gestioncof/traitement_demande_petit_cours.html",
- {"demande": demande,
- "unsatisfied": unsatisfied,
- "proposals": proposals,
- "proposed_for": proposed_for,
- "proposed_mails": proposed_mails,
- "mainmail": mainmail,
- "attribdata": json.dumps(attribdata),
- "redo": redo,
- })
+ return render(
+ request,
+ "gestioncof/traitement_demande_petit_cours.html",
+ {
+ "demande": demande,
+ "unsatisfied": unsatisfied,
+ "proposals": proposals,
+ "proposed_for": proposed_for,
+ "proposed_mails": proposed_mails,
+ "mainmail": mainmail,
+ "attribdata": json.dumps(attribdata),
+ "redo": redo,
+ },
+ )
def _generate_eleve_email(demande, proposed_for):
return [
(
user,
- render_custom_mail('petit-cours-mail-eleve', {
- "demande": demande,
- "matieres": matieres
- })
+ render_custom_mail(
+ "petit-cours-mail-eleve", {"demande": demande, "matieres": matieres}
+ ),
)
for user, matieres in proposed_for
]
@@ -143,25 +157,30 @@ def _traitement_other_preparing(request, demande):
errors = []
for matiere, candidates in demande.get_candidates(redo):
if candidates:
- candidates = dict([(candidate.user.id, candidate.user)
- for candidate in candidates])
+ candidates = dict(
+ [(candidate.user.id, candidate.user) for candidate in candidates]
+ )
attribdata[matiere.id] = []
proposals[matiere] = []
for choice_id in range(min(3, len(candidates))):
choice = int(
- request.POST["proposal-{:d}-{:d}"
- .format(matiere.id, choice_id)]
+ request.POST["proposal-{:d}-{:d}".format(matiere.id, choice_id)]
)
if choice == -1:
continue
if choice not in candidates:
- errors.append("Choix invalide pour la proposition {:d}"
- "en {!s}".format(choice_id + 1, matiere))
+ errors.append(
+ "Choix invalide pour la proposition {:d}"
+ "en {!s}".format(choice_id + 1, matiere)
+ )
continue
user = candidates[choice]
if user in proposals[matiere]:
- errors.append("La proposition {:d} en {!s} est un doublon"
- .format(choice_id + 1, matiere))
+ errors.append(
+ "La proposition {:d} en {!s} est un doublon".format(
+ choice_id + 1, matiere
+ )
+ )
continue
proposals[matiere].append(user)
attribdata[matiere.id].append(user.id)
@@ -172,15 +191,24 @@ def _traitement_other_preparing(request, demande):
if not proposals[matiere]:
errors.append("Aucune proposition pour {!s}".format(matiere))
elif len(proposals[matiere]) < 3:
- errors.append("Seulement {:d} proposition{:s} pour {!s}"
- .format(
- len(proposals[matiere]),
- "s" if len(proposals[matiere]) > 1 else "",
- matiere))
+ errors.append(
+ "Seulement {:d} proposition{:s} pour {!s}".format(
+ len(proposals[matiere]),
+ "s" if len(proposals[matiere]) > 1 else "",
+ matiere,
+ )
+ )
else:
unsatisfied.append(matiere)
- return _finalize_traitement(request, demande, proposals, proposed_for,
- unsatisfied, attribdata, errors=errors)
+ return _finalize_traitement(
+ request,
+ demande,
+ proposals,
+ proposed_for,
+ unsatisfied,
+ attribdata,
+ errors=errors,
+ )
def _traitement_other(request, demande, redo):
@@ -198,10 +226,12 @@ def _traitement_other(request, demande, redo):
tuples = []
for candidate in candidates:
user = candidate.user
- tuples.append((
- candidate,
- PetitCoursAttributionCounter.get_uptodate(user, matiere)
- ))
+ tuples.append(
+ (
+ candidate,
+ PetitCoursAttributionCounter.get_uptodate(user, matiere),
+ )
+ )
tuples = sorted(tuples, key=lambda c: c[1].count)
candidates, _ = zip(*tuples)
attribdata[matiere.id] = []
@@ -218,13 +248,16 @@ def _traitement_other(request, demande, redo):
unsatisfied.append(matiere)
proposals = proposals.items()
proposed_for = proposed_for.items()
- return render(request,
- "gestioncof/traitement_demande_petit_cours_autre_niveau.html",
- {"demande": demande,
- "unsatisfied": unsatisfied,
- "proposals": proposals,
- "proposed_for": proposed_for,
- })
+ return render(
+ request,
+ "gestioncof/traitement_demande_petit_cours_autre_niveau.html",
+ {
+ "demande": demande,
+ "unsatisfied": unsatisfied,
+ "proposals": proposals,
+ "proposed_for": proposed_for,
+ },
+ )
def _traitement_post(request, demande):
@@ -252,24 +285,32 @@ def _traitement_post(request, demande):
proposed_mails = _generate_eleve_email(demande, proposed_for)
mainmail_object, mainmail_body = render_custom_mail(
"petits-cours-mail-demandeur",
- {
- "proposals": proposals_list,
- "unsatisfied": unsatisfied,
- "extra": extra
- }
+ {"proposals": proposals_list, "unsatisfied": unsatisfied, "extra": extra},
)
- frommail = settings.MAIL_DATA['petits_cours']['FROM']
- bccaddress = settings.MAIL_DATA['petits_cours']['BCC']
- replyto = settings.MAIL_DATA['petits_cours']['REPLYTO']
+ frommail = settings.MAIL_DATA["petits_cours"]["FROM"]
+ bccaddress = settings.MAIL_DATA["petits_cours"]["BCC"]
+ replyto = settings.MAIL_DATA["petits_cours"]["REPLYTO"]
mails_to_send = []
for (user, (mail_object, body)) in proposed_mails:
- msg = mail.EmailMessage(mail_object, body, frommail, [user.email],
- [bccaddress], headers={'Reply-To': replyto})
+ msg = mail.EmailMessage(
+ mail_object,
+ body,
+ frommail,
+ [user.email],
+ [bccaddress],
+ headers={"Reply-To": replyto},
+ )
mails_to_send.append(msg)
- mails_to_send.append(mail.EmailMessage(mainmail_object, mainmail_body,
- frommail, [demande.email],
- [bccaddress],
- headers={'Reply-To': replyto}))
+ mails_to_send.append(
+ mail.EmailMessage(
+ mainmail_object,
+ mainmail_body,
+ frommail,
+ [demande.email],
+ [bccaddress],
+ headers={"Reply-To": replyto},
+ )
+ )
connection = mail.get_connection(fail_silently=False)
connection.send_messages(mails_to_send)
with transaction.atomic():
@@ -280,18 +321,19 @@ def _traitement_post(request, demande):
)
counter.count += 1
counter.save()
- attrib = PetitCoursAttribution(user=user, matiere=matiere,
- demande=demande, rank=rank + 1)
+ attrib = PetitCoursAttribution(
+ user=user, matiere=matiere, demande=demande, rank=rank + 1
+ )
attrib.save()
demande.traitee = True
demande.traitee_par = request.user
demande.processed = timezone.now()
demande.save()
- return render(request,
- "gestioncof/traitement_demande_petit_cours_success.html",
- {"demande": demande,
- "redo": redo,
- })
+ return render(
+ request,
+ "gestioncof/traitement_demande_petit_cours_success.html",
+ {"demande": demande, "redo": redo},
+ )
@login_required
@@ -308,22 +350,25 @@ def inscription(request):
profile.petits_cours_remarques = request.POST["remarques"]
profile.save()
with transaction.atomic():
- abilities = (
- PetitCoursAbility.objects.filter(user=request.user).all()
- )
+ abilities = PetitCoursAbility.objects.filter(user=request.user).all()
for ability in abilities:
PetitCoursAttributionCounter.get_uptodate(
- ability.user,
- ability.matiere
+ ability.user, ability.matiere
)
success = True
formset = MatieresFormSet(instance=request.user)
else:
formset = MatieresFormSet(instance=request.user)
- return render(request, "inscription-petit-cours.html",
- {"formset": formset, "success": success,
- "receive_proposals": profile.petits_cours_accept,
- "remarques": profile.petits_cours_remarques})
+ return render(
+ request,
+ "inscription-petit-cours.html",
+ {
+ "formset": formset,
+ "success": success,
+ "receive_proposals": profile.petits_cours_accept,
+ "remarques": profile.petits_cours_remarques,
+ },
+ )
@csrf_exempt
@@ -336,8 +381,9 @@ def demande(request):
success = True
else:
form = DemandeForm()
- return render(request, "demande-petit-cours.html", {"form": form,
- "success": success})
+ return render(
+ request, "demande-petit-cours.html", {"form": form, "success": success}
+ )
@csrf_exempt
@@ -350,5 +396,6 @@ def demande_raw(request):
success = True
else:
form = DemandeForm()
- return render(request, "demande-petit-cours-raw.html",
- {"form": form, "success": success})
+ return render(
+ request, "demande-petit-cours-raw.html", {"form": form, "success": success}
+ )
diff --git a/gestioncof/shared.py b/gestioncof/shared.py
index fdab9a45..1a5bd32e 100644
--- a/gestioncof/shared.py
+++ b/gestioncof/shared.py
@@ -1,13 +1,9 @@
from django.conf import settings
from django.contrib.sites.models import Site
-
from django_cas_ng.backends import CASBackend
-from gestioncof.models import CofProfile
-
class COFCASBackend(CASBackend):
-
def clean_username(self, username):
# Le CAS de l'ENS accepte les logins avec des espaces au début
# et à la fin, ainsi qu’avec une casse variable. On normalise pour
@@ -24,9 +20,6 @@ class COFCASBackend(CASBackend):
def context_processor(request):
- '''Append extra data to the context of the given request'''
- data = {
- "user": request.user,
- "site": Site.objects.get_current(),
- }
+ """Append extra data to the context of the given request"""
+ data = {"user": request.user, "site": Site.objects.get_current()}
return data
diff --git a/gestioncof/signals.py b/gestioncof/signals.py
index 11cb55fc..3614b1c8 100644
--- a/gestioncof/signals.py
+++ b/gestioncof/signals.py
@@ -2,22 +2,21 @@ from django.contrib import messages
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
-
from django_cas_ng.signals import cas_user_authenticated
@receiver(user_logged_in)
def messages_on_out_login(request, user, **kwargs):
- if user.backend.startswith('django.contrib.auth'):
- msg = _('Connexion à GestioCOF réussie. Bienvenue {}.').format(
- user.get_short_name(),
+ if user.backend.startswith("django.contrib.auth"):
+ msg = _("Connexion à GestioCOF réussie. Bienvenue {}.").format(
+ user.get_short_name()
)
messages.success(request, msg)
@receiver(cas_user_authenticated)
def mesagges_on_cas_login(request, user, **kwargs):
- msg = _('Connexion à GestioCOF par CAS réussie. Bienvenue {}.').format(
- user.get_short_name(),
+ msg = _("Connexion à GestioCOF par CAS réussie. Bienvenue {}.").format(
+ user.get_short_name()
)
messages.success(request, msg)
diff --git a/gestioncof/templates/gestioncof/profile.html b/gestioncof/templates/gestioncof/profile.html
index 5decdfb3..9d418ef6 100644
--- a/gestioncof/templates/gestioncof/profile.html
+++ b/gestioncof/templates/gestioncof/profile.html
@@ -4,26 +4,23 @@
{% block page_size %}col-sm-8{%endblock%}
{% block realcontent %}
- Modifier mon profil
-
+ Modifier mon profil
+
{% endblock %}
diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py
index 2b732aec..21518614 100644
--- a/gestioncof/templatetags/utils.py
+++ b/gestioncof/templatetags/utils.py
@@ -1,8 +1,8 @@
+import re
+
from django import template
from django.utils.safestring import mark_safe
-import re
-
register = template.Library()
@@ -12,6 +12,7 @@ def key(d, key_name):
value = d[key_name]
except KeyError:
from django.conf import settings
+
value = settings.TEMPLATE_STRING_IF_INVALID
return value
@@ -19,16 +20,15 @@ def key(d, key_name):
def highlight_text(text, q):
q2 = "|".join(re.escape(word) for word in q.split())
pattern = re.compile(r"(?P%s)" % q2, re.IGNORECASE)
- return mark_safe(re.sub(pattern,
- r"\g ",
- text))
+ return mark_safe(
+ re.sub(pattern, r"\g ", text)
+ )
@register.filter
def highlight_user(user, q):
if user.first_name and user.last_name:
- text = "%s %s (%s )" % (user.first_name, user.last_name,
- user.username)
+ text = "%s %s (%s )" % (user.first_name, user.last_name, user.username)
else:
text = user.username
return highlight_text(text, q)
diff --git a/gestioncof/tests/test_legacy.py b/gestioncof/tests/test_legacy.py
index 85673edd..cc7ddbf7 100644
--- a/gestioncof/tests/test_legacy.py
+++ b/gestioncof/tests/test_legacy.py
@@ -12,17 +12,17 @@ from gestioncof.models import CofProfile, User
class SimpleTest(TestCase):
def test_delete_user(self):
- u = User(username='foo', first_name='foo', last_name='bar')
+ u = User(username="foo", first_name="foo", last_name="bar")
# to each user there's a cofprofile associated
u.save()
- self.assertTrue(CofProfile.objects.filter(user__username='foo').exists())
+ self.assertTrue(CofProfile.objects.filter(user__username="foo").exists())
# there's no point in having a cofprofile without a user associated.
u.delete()
- self.assertFalse(CofProfile.objects.filter(user__username='foo').exists())
+ self.assertFalse(CofProfile.objects.filter(user__username="foo").exists())
# there's no point in having a user without a cofprofile associated.
u.save()
- CofProfile.objects.get(user__username='foo').delete()
- self.assertFalse(User.objects.filter(username='foo').exists())
+ CofProfile.objects.get(user__username="foo").delete()
+ self.assertFalse(User.objects.filter(username="foo").exists())
diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py
index 47139327..d65247c1 100644
--- a/gestioncof/tests/test_views.py
+++ b/gestioncof/tests/test_views.py
@@ -2,26 +2,347 @@ import csv
import uuid
from datetime import timedelta
+from custommail.models import CustomMail
from django.contrib import messages
+from django.contrib.auth import get_user_model
from django.contrib.messages.api import get_messages
from django.contrib.messages.storage.base import Message
-from django.test import Client, TestCase
+from django.core import mail
+from django.core.management import call_command
+from django.test import Client, TestCase, override_settings
from django.urls import reverse
from bda.models import Salle, Tirage
-from gestioncof.models import (
- CalendarSubscription, Club, Event, Survey, SurveyAnswer
-)
+from gestioncof.autocomplete import Clipper
+from gestioncof.models import CalendarSubscription, Club, Event, Survey, SurveyAnswer
from gestioncof.tests.testcases import ViewTestCaseMixin
from .utils import create_member, create_root, create_user
+User = get_user_model()
+
+
+class RegistrationViewTests(ViewTestCaseMixin, TestCase):
+ url_name = "registration"
+ url_expected = "/registration"
+
+ http_methods = ["GET", "POST"]
+
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
+
+ def requires_mails(self):
+ call_command("syncmails", verbosity=0)
+
+ def test_get(self):
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 200)
+
+ @property
+ def _minimal_data(self):
+ return {
+ "first_name": "",
+ "last_name": "",
+ "email": "",
+ # 'is_cof': '1',
+ "login_clipper": "",
+ "phone": "",
+ "occupation": "1A",
+ "departement": "",
+ "type_cotiz": "normalien",
+ "comments": "",
+ # 'user_exists': '1',
+ "events-TOTAL_FORMS": "0",
+ "events-INITIAL_FORMS": "0",
+ "events-MIN_NUM_FORMS": "0",
+ "events-MAX_NUM_FORMS": "1000",
+ }
+
+ def test_post_new(self):
+ self.requires_mails()
+
+ r = self.client.post(
+ self.url,
+ dict(
+ self._minimal_data,
+ **{
+ "username": "username",
+ "first_name": "first",
+ "last_name": "last",
+ "email": "username@mail.net",
+ "is_cof": "1",
+ }
+ ),
+ )
+
+ self.assertEqual(r.status_code, 200)
+ u = User.objects.get(username="username")
+ expected_message = Message(
+ messages.SUCCESS,
+ (
+ "L'inscription de first last (username@mail.net ) a été "
+ "enregistrée avec succès.\n"
+ "Il est désormais membre du COF n°{} !".format(u.pk)
+ ),
+ )
+ self.assertIn(expected_message, get_messages(r.wsgi_request))
+
+ self.assertEqual(u.first_name, "first")
+ self.assertEqual(u.last_name, "last")
+ self.assertEqual(u.email, "username@mail.net")
+
+ def test_post_edit(self):
+ self.requires_mails()
+ u = self.users["user"]
+
+ r = self.client.post(
+ self.url,
+ dict(
+ self._minimal_data,
+ **{
+ "username": "user",
+ "first_name": "first",
+ "last_name": "last",
+ "email": "user@mail.net",
+ "is_cof": "1",
+ "user_exists": "1",
+ }
+ ),
+ )
+
+ self.assertEqual(r.status_code, 200)
+ u.refresh_from_db()
+ expected_message = Message(
+ messages.SUCCESS,
+ (
+ "L'inscription de first last (user@mail.net ) a été "
+ "enregistrée avec succès.\n"
+ "Il est désormais membre du COF n°{} !".format(u.pk)
+ ),
+ )
+ self.assertIn(expected_message, get_messages(r.wsgi_request))
+
+ self.assertEqual(u.first_name, "first")
+ self.assertEqual(u.last_name, "last")
+ self.assertEqual(u.email, "user@mail.net")
+
+ def _test_mail_welcome(self, was_cof, is_cof, expect_mail):
+ self.requires_mails()
+ u = self.users["member"] if was_cof else self.users["user"]
+
+ data = dict(
+ self._minimal_data,
+ **{"username": u.username, "email": "user@mail.net", "user_exists": "1"}
+ )
+ if is_cof:
+ data["is_cof"] = "1"
+ self.client.post(self.url, data)
+
+ u.refresh_from_db()
+
+ def _is_sent():
+ cm = CustomMail.objects.get(shortname="welcome")
+ welcome_msg = cm.get_message({"member": u})
+ for m in mail.outbox:
+ if m.subject == welcome_msg.subject:
+ return True
+ return False
+
+ self.assertEqual(_is_sent(), expect_mail)
+
+ def test_mail_welcome_0(self):
+ self._test_mail_welcome(was_cof=False, is_cof=False, expect_mail=False)
+
+ def test_mail_welcome_1(self):
+ self._test_mail_welcome(was_cof=False, is_cof=True, expect_mail=True)
+
+ def test_mail_welcome_2(self):
+ self._test_mail_welcome(was_cof=True, is_cof=False, expect_mail=False)
+
+ def test_mail_welcome_3(self):
+ self._test_mail_welcome(was_cof=True, is_cof=True, expect_mail=False)
+
+ def test_events(self):
+ e = Event.objects.create()
+
+ cf1 = e.commentfields.create(name="Comment Field 1")
+ cf2 = e.commentfields.create(name="Comment Field 2", fieldtype="char")
+
+ o1 = e.options.create(name="Option 1")
+ o2 = e.options.create(name="Option 2", multi_choices=True)
+
+ oc1 = o1.choices.create(value="O1 - Choice 1")
+ o1.choices.create(value="O1 - Choice 2")
+ oc3 = o2.choices.create(value="O2 - Choice 1")
+ o2.choices.create(value="O2 - Choice 2")
+
+ self.client.post(
+ self.url,
+ dict(
+ self._minimal_data,
+ **{
+ "username": "user",
+ "user_exists": "1",
+ "events-TOTAL_FORMS": "1",
+ "events-INITIAL_FORMS": "0",
+ "events-MIN_NUM_FORMS": "0",
+ "events-MAX_NUM_FORMS": "1000",
+ "events-0-status": "paid",
+ "events-0-option_{}".format(o1.pk): [str(oc1.pk)],
+ "events-0-option_{}".format(o2.pk): [str(oc3.pk)],
+ "events-0-comment_{}".format(cf1.pk): "comment 1",
+ "events-0-comment_{}".format(cf2.pk): "",
+ }
+ ),
+ )
+
+ er = e.eventregistration_set.get(user=self.users["user"])
+ self.assertQuerysetEqual(er.options.all(), map(repr, [oc1, oc3]), ordered=False)
+ self.assertCountEqual(
+ er.comments.values_list("content", flat=True), ["comment 1"]
+ )
+
+
+class RegistrationFormViewTests(ViewTestCaseMixin, TestCase):
+ urls_conf = [
+ {"name": "empty-registration", "expected": "/registration/empty"},
+ {
+ "name": "user-registration",
+ "kwargs": {"username": "user"},
+ "expected": "/registration/user/user",
+ },
+ {
+ "name": "clipper-registration",
+ "kwargs": {"login_clipper": "uid", "fullname": "First Last1 Last2"},
+ "expected": "/registration/clipper/uid/First%20Last1%20Last2",
+ },
+ ]
+
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
+
+ def test_empty(self):
+ r = self.client.get(self.t_urls[0])
+
+ self.assertIn("user_form", r.context)
+ self.assertIn("profile_form", r.context)
+ self.assertIn("event_formset", r.context)
+ self.assertIn("clubs_form", r.context)
+
+ def test_username(self):
+ u = self.users["user"]
+ u.first_name = "first"
+ u.last_name = "last"
+ u.save()
+
+ r = self.client.get(self.t_urls[1])
+
+ self.assertIn("user_form", r.context)
+ self.assertIn("profile_form", r.context)
+ self.assertIn("event_formset", r.context)
+ self.assertIn("clubs_form", r.context)
+ user_form = r.context["user_form"]
+ self.assertEqual(user_form["username"].initial, "user")
+ self.assertEqual(user_form["first_name"].initial, "first")
+ self.assertEqual(user_form["last_name"].initial, "last")
+
+ def test_clipper(self):
+ r = self.client.get(self.t_urls[2])
+
+ self.assertIn("user_form", r.context)
+ self.assertIn("profile_form", r.context)
+ self.assertIn("event_formset", r.context)
+ self.assertIn("clubs_form", r.context)
+ user_form = r.context["user_form"]
+ profile_form = r.context["profile_form"]
+ self.assertEqual(user_form["first_name"].initial, "First")
+ self.assertEqual(user_form["last_name"].initial, "Last1 Last2")
+ self.assertEqual(user_form["email"].initial, "uid@clipper.ens.fr")
+ self.assertEqual(profile_form["login_clipper"].initial, "uid")
+
+
+@override_settings(LDAP_SERVER_URL="ldap_url")
+class RegistrationAutocompleteViewTests(ViewTestCaseMixin, TestCase):
+ url_name = "cof.registration.autocomplete"
+ url_expected = "/autocomplete/registration"
+
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
+
+ def setUp(self):
+ super().setUp()
+
+ self.u1 = create_user("uu_u1", attrs={"first_name": "abc", "last_name": "xyz"})
+ self.u2 = create_user("uu_u2", attrs={"first_name": "wyz", "last_name": "abd"})
+ self.m1 = create_member(
+ "uu_m1", attrs={"first_name": "ebd", "last_name": "wyv"}
+ )
+
+ self.mockLDAP([])
+
+ def _test(self, query, expected_users, expected_members, expected_clippers):
+ r = self.client.get(self.url, {"q": query})
+
+ self.assertEqual(r.status_code, 200)
+
+ self.assertQuerysetEqual(
+ r.context["users"], map(repr, expected_users), ordered=False
+ )
+ self.assertQuerysetEqual(
+ r.context["members"],
+ map(lambda u: repr(u.profile), expected_members),
+ ordered=False,
+ )
+ self.assertCountEqual(
+ map(str, r.context.get("clippers", [])), map(str, expected_clippers)
+ )
+
+ def test_username(self):
+ self._test("uu", [self.u1, self.u2], [self.m1], [])
+
+ def test_firstname(self):
+ self._test("ab", [self.u1, self.u2], [], [])
+
+ def test_lastname(self):
+ self._test("wy", [self.u2], [self.m1], [])
+
+ def test_multi_query(self):
+ self._test("wy bd", [self.u2], [self.m1], [])
+
+ def test_clipper(self):
+ mock_ldap = self.mockLDAP([("uid", "first last")])
+
+ self._test("aa bb", [], [], [Clipper("uid", "first last")])
+
+ mock_ldap.search.assert_called_once_with(
+ "dc=spi,dc=ens,dc=fr",
+ "(&(|(cn=*aa*)(uid=*aa*))(|(cn=*bb*)(uid=*bb*)))",
+ attributes=["uid", "cn"],
+ )
+
+ def test_clipper_escaped(self):
+ mock_ldap = self.mockLDAP([])
+
+ self._test("; & | (", [], [], [])
+
+ mock_ldap.search.assert_not_called()
+
+ def test_clipper_no_duplicate(self):
+ self.mockLDAP([("uid", "uu_u1")])
+
+ self._test("uu u1", [self.u1], [], [Clipper("uid", "uu_u1")])
+
+ self.u1.profile.login_clipper = "uid"
+ self.u1.profile.save()
+
+ self._test("uu u1", [self.u1], [], [])
+
class HomeViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'home'
- url_expected = '/'
+ url_name = "home"
+ url_expected = "/"
- auth_user = 'user'
+ auth_user = "user"
auth_forbidden = [None]
def test(self):
@@ -30,49 +351,52 @@ class HomeViewTests(ViewTestCaseMixin, TestCase):
class ProfileViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'profile'
- url_expected = '/profile'
+ url_name = "profile"
+ url_expected = "/profile"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'member'
- auth_forbidden = [None, 'user']
+ auth_user = "member"
+ auth_forbidden = [None, "user"]
def test_get(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post(self):
- u = self.users['member']
+ u = self.users["member"]
- r = self.client.post(self.url, {
- 'first_name': 'First',
- 'last_name': 'Last',
- 'phone': '',
- # 'mailing_cof': '1',
- # 'mailing_bda': '1',
- # 'mailing_bda_revente': '1',
- })
+ r = self.client.post(
+ self.url,
+ {
+ "u-first_name": "First",
+ "u-last_name": "Last",
+ "p-phone": "",
+ # 'mailing_cof': '1',
+ # 'mailing_bda': '1',
+ # 'mailing_bda_revente': '1',
+ },
+ )
self.assertEqual(r.status_code, 200)
- expected_message = Message(messages.SUCCESS, (
- "Votre profil a été mis à jour avec succès !"
- ))
+ expected_message = Message(
+ messages.SUCCESS, ("Votre profil a été mis à jour avec succès !")
+ )
self.assertIn(expected_message, get_messages(r.wsgi_request))
u.refresh_from_db()
- self.assertEqual(u.first_name, 'First')
- self.assertEqual(u.last_name, 'Last')
+ self.assertEqual(u.first_name, "First")
+ self.assertEqual(u.last_name, "Last")
self.assertFalse(u.profile.mailing_cof)
self.assertFalse(u.profile.mailing_bda)
self.assertFalse(u.profile.mailing_bda_revente)
class UtilsViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'utile_cof'
- url_expected = '/utile_cof'
+ url_name = "utile_cof"
+ url_expected = "/utile_cof"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
r = self.client.get(self.url)
@@ -80,92 +404,95 @@ class UtilsViewTests(ViewTestCaseMixin, TestCase):
class MailingListDiffCof(ViewTestCaseMixin, TestCase):
- url_name = 'ml_diffcof'
- url_expected = '/utile_cof/diff_cof'
+ url_name = "ml_diffcof"
+ url_expected = "/utile_cof/diff_cof"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def setUp(self):
super().setUp()
- self.u1 = create_member('u1', attrs={'mailing_cof': True})
- self.u2 = create_member('u2', attrs={'mailing_cof': False})
- self.u3 = create_user('u3', attrs={'mailing_cof': True})
+ self.u1 = create_member("u1", attrs={"mailing_cof": True})
+ self.u2 = create_member("u2", attrs={"mailing_cof": False})
+ self.u3 = create_user("u3", attrs={"mailing_cof": True})
def test(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertEqual(r.context['personnes'].get(), self.u1.profile)
+ self.assertEqual(r.context["personnes"].get(), self.u1.profile)
class ConfigUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'config.edit'
- url_expected = '/config'
+ url_name = "config.edit"
+ url_expected = "/config"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'root'
- auth_forbidden = [None, 'user', 'member', 'staff']
+ auth_user = "root"
+ auth_forbidden = [None, "user", "member", "staff"]
def get_users_extra(self):
- return {
- 'root': create_root('root'),
- }
+ return {"root": create_root("root")}
def test_get(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post(self):
- r = self.client.post(self.url, {
- 'gestion_banner': 'Announcement !',
- })
+ r = self.client.post(self.url, {"gestion_banner": "Announcement !"})
- self.assertRedirects(r, reverse('home'))
+ self.assertRedirects(r, reverse("home"))
class UserAutocompleteViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'cof-user-autocomplete'
- url_expected = '/user/autocomplete'
+ url_name = "cof-user-autocomplete"
+ url_expected = "/user/autocomplete"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
- r = self.client.get(self.url, {'q': 'user'})
+ r = self.client.get(self.url, {"q": "user"})
self.assertEqual(r.status_code, 200)
class ExportMembersViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'cof.membres_export'
- url_expected = '/export/members'
+ url_name = "cof.membres_export"
+ url_expected = "/export/members"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
- u1, u2 = self.users['member'], self.users['staff']
- u1.first_name = 'first'
- u1.last_name = 'last'
- u1.email = 'user@mail.net'
+ u1, u2 = self.users["member"], self.users["staff"]
+ u1.first_name = "first"
+ u1.last_name = "last"
+ u1.email = "user@mail.net"
u1.save()
- u1.profile.phone = '0123456789'
- u1.profile.departement = 'Dept'
+ u1.profile.phone = "0123456789"
+ u1.profile.departement = "Dept"
u1.profile.save()
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- data = list(csv.reader(r.content.decode('utf-8').split('\n')[:-1]))
+ data = list(csv.reader(r.content.decode("utf-8").split("\n")[:-1]))
expected = [
[
- str(u1.pk), 'member', 'first', 'last', 'user@mail.net',
- '0123456789', '1A', 'Dept', 'normalien',
+ str(u1.pk),
+ "member",
+ "first",
+ "last",
+ "user@mail.net",
+ "0123456789",
+ "1A",
+ "Dept",
+ "normalien",
],
- [str(u2.pk), 'staff', '', '', '', '', '1A', '', 'normalien'],
+ [str(u2.pk), "staff", "", "", "", "", "1A", "", "normalien"],
]
# Sort before checking equality, the order of the output of csv.reader
# does not seem deterministic
@@ -178,34 +505,32 @@ class MegaHelpers:
def setUp(self):
super().setUp()
- u1 = create_user('u1')
- u1.first_name = 'first'
- u1.last_name = 'last'
- u1.email = 'user@mail.net'
+ u1 = create_user("u1")
+ u1.first_name = "first"
+ u1.last_name = "last"
+ u1.email = "user@mail.net"
u1.save()
- u1.profile.phone = '0123456789'
- u1.profile.departement = 'Dept'
- u1.profile.comments = 'profile.comments'
+ u1.profile.phone = "0123456789"
+ u1.profile.departement = "Dept"
+ u1.profile.comments = "profile.comments"
u1.profile.save()
- u2 = create_user('u2')
+ u2 = create_user("u2")
u2.profile.save()
- m = Event.objects.create(title='MEGA 2017')
+ m = Event.objects.create(title="MEGA 2018")
- cf1 = m.commentfields.create(name='Commentaire')
- cf2 = m.commentfields.create(
- name='Comment Field 2', fieldtype='char',
- )
+ cf1 = m.commentfields.create(name="Commentaires")
+ cf2 = m.commentfields.create(name="Comment Field 2", fieldtype="char")
- option_type = m.options.create(name='Conscrit/Orga ?')
- choice_orga = option_type.choices.create(value='Orga')
- choice_conscrit = option_type.choices.create(value='Conscrit')
+ option_type = m.options.create(name="Orga ? Conscrit ?")
+ choice_orga = option_type.choices.create(value="Orga")
+ choice_conscrit = option_type.choices.create(value="Conscrit")
mr1 = m.eventregistration_set.create(user=u1)
mr1.options.add(choice_orga)
- mr1.comments.create(commentfield=cf1, content='Comment 1')
- mr1.comments.create(commentfield=cf2, content='Comment 2')
+ mr1.comments.create(commentfield=cf1, content="Comment 1")
+ mr1.comments.create(commentfield=cf2, content="Comment 2")
mr2 = m.eventregistration_set.create(user=u2)
mr2.options.add(choice_conscrit)
@@ -218,96 +543,122 @@ class MegaHelpers:
class ExportMegaViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'cof.mega_export'
- url_expected = '/export/mega'
+ url_name = "cof.mega_export"
+ url_expected = "/export/mega"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertListEqual(self.load_from_csv_response(r), [
+ self.assertListEqual(
+ self.load_from_csv_response(r),
[
- 'u1', 'first', 'last', 'user@mail.net', '0123456789',
- str(self.u1.pk), 'profile.comments', 'Comment 1---Comment 2',
+ [
+ "u1",
+ "first",
+ "last",
+ "user@mail.net",
+ "0123456789",
+ str(self.u1.pk),
+ "profile.comments",
+ "Comment 1---Comment 2",
+ ],
+ ["u2", "", "", "", "", str(self.u2.pk), "", ""],
],
- ['u2', '', '', '', '', str(self.u2.pk), '', ''],
- ])
+ )
class ExportMegaOrgasViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'cof.mega_export_orgas'
- url_expected = '/export/mega/orgas'
+ url_name = "cof.mega_export_orgas"
+ url_expected = "/export/mega/orgas"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertListEqual(self.load_from_csv_response(r), [
+ self.assertListEqual(
+ self.load_from_csv_response(r),
[
- 'u1', 'first', 'last', 'user@mail.net', '0123456789',
- str(self.u1.pk), 'profile.comments', 'Comment 1---Comment 2',
+ [
+ "u1",
+ "first",
+ "last",
+ "user@mail.net",
+ "0123456789",
+ str(self.u1.pk),
+ "profile.comments",
+ "Comment 1---Comment 2",
+ ]
],
- ])
+ )
-class ExportMegaParticipantsViewTests(
- MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'cof.mega_export_participants'
- url_expected = '/export/mega/participants'
+class ExportMegaParticipantsViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
+ url_name = "cof.mega_export_participants"
+ url_expected = "/export/mega/participants"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertListEqual(self.load_from_csv_response(r), [
- ['u2', '', '', '', '', str(self.u2.pk), '', ''],
- ])
+ self.assertListEqual(
+ self.load_from_csv_response(r),
+ [["u2", "", "", "", "", str(self.u2.pk), "", ""]],
+ )
-class ExportMegaRemarksViewTests(
- MegaHelpers, ViewTestCaseMixin, TestCase):
- url_name = 'cof.mega_export_remarks'
- url_expected = '/export/mega/avecremarques'
+class ExportMegaRemarksViewTests(MegaHelpers, ViewTestCaseMixin, TestCase):
+ url_name = "cof.mega_export_remarks"
+ url_expected = "/export/mega/avecremarques"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
def test(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertListEqual(self.load_from_csv_response(r), [
+ self.assertListEqual(
+ self.load_from_csv_response(r),
[
- 'u1', 'first', 'last', 'user@mail.net', '0123456789',
- str(self.u1.pk), 'profile.comments', 'Comment 1',
+ [
+ "u1",
+ "first",
+ "last",
+ "user@mail.net",
+ "0123456789",
+ str(self.u1.pk),
+ "profile.comments",
+ "Comment 1",
+ ]
],
- ])
+ )
class ClubListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'liste-clubs'
- url_expected = '/clubs/liste'
+ url_name = "liste-clubs"
+ url_expected = "/clubs/liste"
- auth_user = 'member'
- auth_forbidden = [None, 'user']
+ auth_user = "member"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
- self.c1 = Club.objects.create(name='Club1')
- self.c2 = Club.objects.create(name='Club2')
+ self.c1 = Club.objects.create(name="Club1")
+ self.c2 = Club.objects.create(name="Club2")
- m = self.users['member']
+ m = self.users["member"]
self.c1.membres.add(m)
self.c1.respos.add(m)
@@ -315,11 +666,11 @@ class ClubListViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertEqual(r.context['owned_clubs'].get(), self.c1)
- self.assertEqual(r.context['other_clubs'].get(), self.c2)
+ self.assertEqual(r.context["owned_clubs"].get(), self.c1)
+ self.assertEqual(r.context["other_clubs"].get(), self.c2)
def test_as_staff(self):
- u = self.users['staff']
+ u = self.users["staff"]
c = Client()
c.force_login(u)
@@ -327,32 +678,31 @@ class ClubListViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['owned_clubs'], map(repr, [self.c1, self.c2]),
- ordered=False,
+ r.context["owned_clubs"], map(repr, [self.c1, self.c2]), ordered=False
)
class ClubMembersViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'membres-club'
+ url_name = "membres-club"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
@property
def url_kwargs(self):
- return {'name': self.c.name}
+ return {"name": self.c.name}
@property
def url_expected(self):
- return '/clubs/membres/{}'.format(self.c.name)
+ return "/clubs/membres/{}".format(self.c.name)
def setUp(self):
super().setUp()
- self.u1 = create_user('u1')
- self.u2 = create_user('u2')
+ self.u1 = create_user("u1")
+ self.u2 = create_user("u2")
- self.c = Club.objects.create(name='Club')
+ self.c = Club.objects.create(name="Club")
self.c.membres.add(self.u1, self.u2)
self.c.respos.add(self.u1)
@@ -360,10 +710,10 @@ class ClubMembersViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertEqual(r.context['members_no_respo'].get(), self.u2)
+ self.assertEqual(r.context["members_no_respo"].get(), self.u2)
def test_as_respo(self):
- u = self.users['user']
+ u = self.users["user"]
self.c.respos.add(u)
c = Client()
@@ -374,31 +724,27 @@ class ClubMembersViewTests(ViewTestCaseMixin, TestCase):
class ClubChangeRespoViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'change-respo'
+ url_name = "change-respo"
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
@property
def url_kwargs(self):
- return {'club_name': self.c.name, 'user_id': self.users['user'].pk}
+ return {"club_name": self.c.name, "user_id": self.users["user"].pk}
@property
def url_expected(self):
- return '/clubs/change_respo/{}/{}'.format(
- self.c.name, self.users['user'].pk,
- )
+ return "/clubs/change_respo/{}/{}".format(self.c.name, self.users["user"].pk)
def setUp(self):
super().setUp()
- self.c = Club.objects.create(name='Club')
+ self.c = Club.objects.create(name="Club")
def test(self):
- u = self.users['user']
- expected_redirect = reverse('membres-club', kwargs={
- 'name': self.c.name,
- })
+ u = self.users["user"]
+ expected_redirect = reverse("membres-club", kwargs={"name": self.c.name})
self.c.membres.add(u)
r = self.client.get(self.url)
@@ -410,40 +756,42 @@ class ClubChangeRespoViewTests(ViewTestCaseMixin, TestCase):
class CalendarViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'calendar'
- url_expected = '/calendar/subscription'
+ url_name = "calendar"
+ url_expected = "/calendar/subscription"
- auth_user = 'member'
- auth_forbidden = [None, 'user']
+ auth_user = "member"
+ auth_forbidden = [None, "user"]
post_expected_message = Message(
- messages.SUCCESS, "Calendrier mis à jour avec succès.")
+ messages.SUCCESS, "Calendrier mis à jour avec succès."
+ )
def test_get(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post_new(self):
- r = self.client.post(self.url, {
- 'subscribe_to_events': True,
- 'subscribe_to_my_shows': True,
- 'other_shows': [],
- })
+ r = self.client.post(
+ self.url,
+ {
+ "subscribe_to_events": True,
+ "subscribe_to_my_shows": True,
+ "other_shows": [],
+ },
+ )
self.assertEqual(r.status_code, 200)
self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
- cs = self.users['member'].calendarsubscription
+ cs = self.users["member"].calendarsubscription
self.assertTrue(cs.subscribe_to_events)
self.assertTrue(cs.subscribe_to_my_shows)
def test_post_edit(self):
- u = self.users['member']
+ u = self.users["member"]
token = uuid.uuid4()
cs = CalendarSubscription.objects.create(token=token, user=u)
- r = self.client.post(self.url, {
- 'other_shows': [],
- })
+ r = self.client.post(self.url, {"other_shows": []})
self.assertEqual(r.status_code, 200)
self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
@@ -453,33 +801,30 @@ class CalendarViewTests(ViewTestCaseMixin, TestCase):
self.assertFalse(cs.subscribe_to_my_shows)
def test_post_other_shows(self):
- t = Tirage.objects.create(
- ouverture=self.now,
- fermeture=self.now,
- active=True,
- )
- l = Salle.objects.create()
+ t = Tirage.objects.create(ouverture=self.now, fermeture=self.now, active=True)
+ location = Salle.objects.create()
s = t.spectacle_set.create(
- date=self.now, price=3.5, slots=20, location=l, listing=True)
+ date=self.now, price=3.5, slots=20, location=location, listing=True
+ )
- r = self.client.post(self.url, {'other_shows': [str(s.pk)]})
+ r = self.client.post(self.url, {"other_shows": [str(s.pk)]})
self.assertEqual(r.status_code, 200)
class CalendarICSViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'calendar.ics'
+ url_name = "calendar.ics"
auth_user = None
auth_forbidden = []
@property
def url_kwargs(self):
- return {'token': self.token}
+ return {"token": self.token}
@property
def url_expected(self):
- return '/calendar/{}/calendar.ics'.format(self.token)
+ return "/calendar/{}/calendar.ics".format(self.token)
def setUp(self):
super().setUp()
@@ -487,32 +832,44 @@ class CalendarICSViewTests(ViewTestCaseMixin, TestCase):
self.token = uuid.uuid4()
self.t = Tirage.objects.create(
- ouverture=self.now,
- fermeture=self.now,
- active=True,
+ ouverture=self.now, fermeture=self.now, active=True
)
- l = Salle.objects.create(name='Location')
+ location = Salle.objects.create(name="Location")
self.s1 = self.t.spectacle_set.create(
- price=1, slots=10, location=l, listing=True,
- title='Spectacle 1', date=self.now + timedelta(days=1),
+ price=1,
+ slots=10,
+ location=location,
+ listing=True,
+ title="Spectacle 1",
+ date=self.now + timedelta(days=1),
)
self.s2 = self.t.spectacle_set.create(
- price=2, slots=20, location=l, listing=True,
- title='Spectacle 2', date=self.now + timedelta(days=2),
+ price=2,
+ slots=20,
+ location=location,
+ listing=True,
+ title="Spectacle 2",
+ date=self.now + timedelta(days=2),
)
self.s3 = self.t.spectacle_set.create(
- price=3, slots=30, location=l, listing=True,
- title='Spectacle 3', date=self.now + timedelta(days=3),
+ price=3,
+ slots=30,
+ location=location,
+ listing=True,
+ title="Spectacle 3",
+ date=self.now + timedelta(days=3),
)
def test(self):
- u = self.users['user']
+ u = self.users["user"]
p = u.participant_set.create(tirage=self.t)
p.attribution_set.create(spectacle=self.s1)
self.cs = CalendarSubscription.objects.create(
- user=u, token=self.token,
- subscribe_to_my_shows=True, subscribe_to_events=True,
+ user=u,
+ token=self.token,
+ subscribe_to_my_shows=True,
+ subscribe_to_events=True,
)
self.cs.other_shows.add(self.s2)
@@ -521,91 +878,107 @@ class CalendarICSViewTests(ViewTestCaseMixin, TestCase):
def get_dt_from_ical(v):
return v.dt
- self.assertCalEqual(r.content.decode('utf-8'), [
- {
- 'summary': 'Spectacle 1',
- 'dtstart': (get_dt_from_ical, (
- (self.now + timedelta(days=1)).replace(microsecond=0)
- )),
- 'dtend': (get_dt_from_ical, (
- (self.now + timedelta(days=1, hours=2)).replace(
- microsecond=0)
- )),
- 'location': 'Location',
- 'uid': 'show-{}-{}@example.com'.format(self.s1.pk, self.t.pk),
- },
- {
- 'summary': 'Spectacle 2',
- 'dtstart': (get_dt_from_ical, (
- (self.now + timedelta(days=2)).replace(microsecond=0)
- )),
- 'dtend': (get_dt_from_ical, (
- (self.now + timedelta(days=2, hours=2)).replace(
- microsecond=0)
- )),
- 'location': 'Location',
- 'uid': 'show-{}-{}@example.com'.format(self.s2.pk, self.t.pk),
- },
- ])
+ self.assertCalEqual(
+ r.content.decode("utf-8"),
+ [
+ {
+ "summary": "Spectacle 1",
+ "dtstart": (
+ get_dt_from_ical,
+ ((self.now + timedelta(days=1)).replace(microsecond=0)),
+ ),
+ "dtend": (
+ get_dt_from_ical,
+ (
+ (self.now + timedelta(days=1, hours=2)).replace(
+ microsecond=0
+ )
+ ),
+ ),
+ "location": "Location",
+ "uid": "show-{}-{}@example.com".format(self.s1.pk, self.t.pk),
+ },
+ {
+ "summary": "Spectacle 2",
+ "dtstart": (
+ get_dt_from_ical,
+ ((self.now + timedelta(days=2)).replace(microsecond=0)),
+ ),
+ "dtend": (
+ get_dt_from_ical,
+ (
+ (self.now + timedelta(days=2, hours=2)).replace(
+ microsecond=0
+ )
+ ),
+ ),
+ "location": "Location",
+ "uid": "show-{}-{}@example.com".format(self.s2.pk, self.t.pk),
+ },
+ ],
+ )
class EventViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'event.details'
- http_methods = ['GET', 'POST']
+ url_name = "event.details"
+ http_methods = ["GET", "POST"]
- auth_user = 'user'
+ auth_user = "user"
auth_forbidden = [None]
- post_expected_message = Message(messages.SUCCESS, (
- "Votre inscription a bien été enregistrée ! Vous pouvez cependant la "
- "modifier jusqu'à la fin des inscriptions."
- ))
+ post_expected_message = Message(
+ messages.SUCCESS,
+ (
+ "Votre inscription a bien été enregistrée ! Vous pouvez cependant la "
+ "modifier jusqu'à la fin des inscriptions."
+ ),
+ )
@property
def url_kwargs(self):
- return {'event_id': self.e.pk}
+ return {"event_id": self.e.pk}
@property
def url_expected(self):
- return '/event/{}'.format(self.e.pk)
+ return "/event/{}".format(self.e.pk)
def setUp(self):
super().setUp()
self.e = Event.objects.create()
- self.ecf1 = self.e.commentfields.create(name='Comment Field 1')
+ self.ecf1 = self.e.commentfields.create(name="Comment Field 1")
self.ecf2 = self.e.commentfields.create(
- name='Comment Field 2', fieldtype='char',
+ name="Comment Field 2", fieldtype="char"
)
- self.o1 = self.e.options.create(name='Option 1')
- self.o2 = self.e.options.create(name='Option 2', multi_choices=True)
+ self.o1 = self.e.options.create(name="Option 1")
+ self.o2 = self.e.options.create(name="Option 2", multi_choices=True)
- self.oc1 = self.o1.choices.create(value='O1 - Choice 1')
- self.oc2 = self.o1.choices.create(value='O1 - Choice 2')
- self.oc3 = self.o2.choices.create(value='O2 - Choice 1')
- self.oc4 = self.o2.choices.create(value='O2 - Choice 2')
+ self.oc1 = self.o1.choices.create(value="O1 - Choice 1")
+ self.oc2 = self.o1.choices.create(value="O1 - Choice 2")
+ self.oc3 = self.o2.choices.create(value="O2 - Choice 1")
+ self.oc4 = self.o2.choices.create(value="O2 - Choice 2")
def test_get(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post_new(self):
- r = self.client.post(self.url, {
- 'option_{}'.format(self.o1.pk): [str(self.oc1.pk)],
- 'option_{}'.format(self.o2.pk): [
- str(self.oc3.pk), str(self.oc4.pk),
- ],
- })
+ r = self.client.post(
+ self.url,
+ {
+ "option_{}".format(self.o1.pk): [str(self.oc1.pk)],
+ "option_{}".format(self.o2.pk): [str(self.oc3.pk), str(self.oc4.pk)],
+ },
+ )
self.assertEqual(r.status_code, 200)
self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
- er = self.e.eventregistration_set.get(user=self.users['user'])
+ er = self.e.eventregistration_set.get(user=self.users["user"])
self.assertQuerysetEqual(
- er.options.all(), map(repr, [self.oc1, self.oc3, self.oc4]),
- ordered=False,
+ er.options.all(), map(repr, [self.oc1, self.oc3, self.oc4]), ordered=False
)
# TODO: Make the view care about comments.
# self.assertQuerysetEqual(
@@ -614,25 +987,23 @@ class EventViewTests(ViewTestCaseMixin, TestCase):
# )
def test_post_edit(self):
- er = self.e.eventregistration_set.create(user=self.users['user'])
+ er = self.e.eventregistration_set.create(user=self.users["user"])
er.options.add(self.oc1, self.oc3, self.oc4)
- er.comments.create(
- commentfield=self.ecf1, content='Comment 1',
- )
+ er.comments.create(commentfield=self.ecf1, content="Comment 1")
- r = self.client.post(self.url, {
- 'option_{}'.format(self.o1.pk): [],
- 'option_{}'.format(self.o2.pk): [str(self.oc3.pk)],
- })
+ r = self.client.post(
+ self.url,
+ {
+ "option_{}".format(self.o1.pk): [],
+ "option_{}".format(self.o2.pk): [str(self.oc3.pk)],
+ },
+ )
self.assertEqual(r.status_code, 200)
self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
er.refresh_from_db()
- self.assertQuerysetEqual(
- er.options.all(), map(repr, [self.oc3]),
- ordered=False,
- )
+ self.assertQuerysetEqual(er.options.all(), map(repr, [self.oc3]), ordered=False)
# TODO: Make the view care about comments.
# self.assertQuerysetEqual(
# er.comments.all(), map(repr, []),
@@ -641,153 +1012,149 @@ class EventViewTests(ViewTestCaseMixin, TestCase):
class EventStatusViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'event.details.status'
+ url_name = "event.details.status"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
@property
def url_kwargs(self):
- return {'event_id': self.e.pk}
+ return {"event_id": self.e.pk}
@property
def url_expected(self):
- return '/event/{}/status'.format(self.e.pk)
+ return "/event/{}/status".format(self.e.pk)
def setUp(self):
super().setUp()
self.e = Event.objects.create()
- self.cf1 = self.e.commentfields.create(name='Comment Field 1')
- self.cf2 = self.e.commentfields.create(
- name='Comment Field 2', fieldtype='char',
- )
+ self.cf1 = self.e.commentfields.create(name="Comment Field 1")
+ self.cf2 = self.e.commentfields.create(name="Comment Field 2", fieldtype="char")
- self.o1 = self.e.options.create(name='Option 1')
- self.o2 = self.e.options.create(name='Option 2', multi_choices=True)
+ self.o1 = self.e.options.create(name="Option 1")
+ self.o2 = self.e.options.create(name="Option 2", multi_choices=True)
- self.oc1 = self.o1.choices.create(value='O1 - Choice 1')
- self.oc2 = self.o1.choices.create(value='O1 - Choice 2')
- self.oc3 = self.o2.choices.create(value='O2 - Choice 1')
- self.oc4 = self.o2.choices.create(value='O2 - Choice 2')
+ self.oc1 = self.o1.choices.create(value="O1 - Choice 1")
+ self.oc2 = self.o1.choices.create(value="O1 - Choice 2")
+ self.oc3 = self.o2.choices.create(value="O2 - Choice 1")
+ self.oc4 = self.o2.choices.create(value="O2 - Choice 2")
- self.er1 = self.e.eventregistration_set.create(user=self.users['user'])
+ self.er1 = self.e.eventregistration_set.create(user=self.users["user"])
self.er1.options.add(self.oc1)
- self.er2 = self.e.eventregistration_set.create(
- user=self.users['member'],
- )
+ self.er2 = self.e.eventregistration_set.create(user=self.users["member"])
def _get_oc_filter_name(self, oc):
- return 'option_{}_choice_{}'.format(oc.event_option.pk, oc.pk)
+ return "option_{}_choice_{}".format(oc.event_option.pk, oc.pk)
def _test_filters(self, filters, expected):
- r = self.client.post(self.url, {
- self._get_oc_filter_name(oc): v for oc, v in filters
- })
+ r = self.client.post(
+ self.url, {self._get_oc_filter_name(oc): v for oc, v in filters}
+ )
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['user_choices'], map(repr, expected),
- ordered=False,
+ r.context["user_choices"], map(repr, expected), ordered=False
)
def test_filter_none(self):
- self._test_filters([(self.oc1, 'none')], [self.er1, self.er2])
+ self._test_filters([(self.oc1, "none")], [self.er1, self.er2])
def test_filter_yes(self):
- self._test_filters([(self.oc1, 'yes')], [self.er1])
+ self._test_filters([(self.oc1, "yes")], [self.er1])
def test_filter_no(self):
- self._test_filters([(self.oc1, 'no')], [self.er2])
+ self._test_filters([(self.oc1, "no")], [self.er2])
class SurveyViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'survey.details'
- http_methods = ['GET', 'POST']
+ url_name = "survey.details"
+ http_methods = ["GET", "POST"]
- auth_user = 'user'
+ auth_user = "user"
auth_forbidden = [None]
- post_expected_message = Message(messages.SUCCESS, (
- "Votre réponse a bien été enregistrée ! Vous pouvez cependant la "
- "modifier jusqu'à la fin du sondage."
- ))
+ post_expected_message = Message(
+ messages.SUCCESS,
+ (
+ "Votre réponse a bien été enregistrée ! Vous pouvez cependant la "
+ "modifier jusqu'à la fin du sondage."
+ ),
+ )
@property
def url_kwargs(self):
- return {'survey_id': self.s.pk}
+ return {"survey_id": self.s.pk}
@property
def url_expected(self):
- return '/survey/{}'.format(self.s.pk)
+ return "/survey/{}".format(self.s.pk)
def setUp(self):
super().setUp()
- self.s = Survey.objects.create(title='Title')
+ self.s = Survey.objects.create(title="Title")
- self.q1 = self.s.questions.create(question='Question 1 ?')
- self.q2 = self.s.questions.create(
- question='Question 2 ?',
- multi_answers=True,
- )
+ self.q1 = self.s.questions.create(question="Question 1 ?")
+ self.q2 = self.s.questions.create(question="Question 2 ?", multi_answers=True)
- self.qa1 = self.q1.answers.create(answer='Q1 - Answer 1')
- self.qa2 = self.q1.answers.create(answer='Q1 - Answer 2')
- self.qa3 = self.q2.answers.create(answer='Q2 - Answer 1')
- self.qa4 = self.q2.answers.create(answer='Q2 - Answer 2')
+ self.qa1 = self.q1.answers.create(answer="Q1 - Answer 1")
+ self.qa2 = self.q1.answers.create(answer="Q1 - Answer 2")
+ self.qa3 = self.q2.answers.create(answer="Q2 - Answer 1")
+ self.qa4 = self.q2.answers.create(answer="Q2 - Answer 2")
def test_get(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post_new(self):
- r = self.client.post(self.url, {
- 'question_{}'.format(self.q1.pk): [str(self.qa1.pk)],
- 'question_{}'.format(self.q2.pk): [
- str(self.qa3.pk), str(self.qa4.pk),
- ],
- })
+ r = self.client.post(
+ self.url,
+ {
+ "question_{}".format(self.q1.pk): [str(self.qa1.pk)],
+ "question_{}".format(self.q2.pk): [str(self.qa3.pk), str(self.qa4.pk)],
+ },
+ )
self.assertEqual(r.status_code, 200)
self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
- a = self.s.surveyanswer_set.get(user=self.users['user'])
+ a = self.s.surveyanswer_set.get(user=self.users["user"])
self.assertQuerysetEqual(
- a.answers.all(), map(repr, [self.qa1, self.qa3, self.qa4]),
- ordered=False,
+ a.answers.all(), map(repr, [self.qa1, self.qa3, self.qa4]), ordered=False
)
def test_post_edit(self):
- a = self.s.surveyanswer_set.create(user=self.users['user'])
+ a = self.s.surveyanswer_set.create(user=self.users["user"])
a.answers.add(self.qa1, self.qa1, self.qa4)
- r = self.client.post(self.url, {
- 'question_{}'.format(self.q1.pk): [],
- 'question_{}'.format(self.q2.pk): [str(self.qa3.pk)],
- })
+ r = self.client.post(
+ self.url,
+ {
+ "question_{}".format(self.q1.pk): [],
+ "question_{}".format(self.q2.pk): [str(self.qa3.pk)],
+ },
+ )
self.assertEqual(r.status_code, 200)
self.assertIn(self.post_expected_message, get_messages(r.wsgi_request))
a.refresh_from_db()
- self.assertQuerysetEqual(
- a.answers.all(), map(repr, [self.qa3]),
- ordered=False,
- )
+ self.assertQuerysetEqual(a.answers.all(), map(repr, [self.qa3]), ordered=False)
def test_post_delete(self):
- a = self.s.surveyanswer_set.create(user=self.users['user'])
+ a = self.s.surveyanswer_set.create(user=self.users["user"])
a.answers.add(self.qa1, self.qa4)
- r = self.client.post(self.url, {'delete': '1'})
+ r = self.client.post(self.url, {"delete": "1"})
self.assertEqual(r.status_code, 200)
expected_message = Message(
- messages.SUCCESS, "Votre réponse a bien été supprimée")
+ messages.SUCCESS, "Votre réponse a bien été supprimée"
+ )
self.assertIn(expected_message, get_messages(r.wsgi_request))
with self.assertRaises(SurveyAnswer.DoesNotExist):
@@ -811,64 +1178,60 @@ class SurveyViewTests(ViewTestCaseMixin, TestCase):
class SurveyStatusViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'survey.details.status'
+ url_name = "survey.details.status"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'staff'
- auth_forbidden = [None, 'user', 'member']
+ auth_user = "staff"
+ auth_forbidden = [None, "user", "member"]
@property
def url_kwargs(self):
- return {'survey_id': self.s.pk}
+ return {"survey_id": self.s.pk}
@property
def url_expected(self):
- return '/survey/{}/status'.format(self.s.pk)
+ return "/survey/{}/status".format(self.s.pk)
def setUp(self):
super().setUp()
- self.s = Survey.objects.create(title='Title')
+ self.s = Survey.objects.create(title="Title")
- self.q1 = self.s.questions.create(question='Question 1 ?')
- self.q2 = self.s.questions.create(
- question='Question 2 ?',
- multi_answers=True,
- )
+ self.q1 = self.s.questions.create(question="Question 1 ?")
+ self.q2 = self.s.questions.create(question="Question 2 ?", multi_answers=True)
- self.qa1 = self.q1.answers.create(answer='Q1 - Answer 1')
- self.qa2 = self.q1.answers.create(answer='Q1 - Answer 2')
- self.qa3 = self.q2.answers.create(answer='Q2 - Answer 1')
- self.qa4 = self.q2.answers.create(answer='Q2 - Answer 2')
+ self.qa1 = self.q1.answers.create(answer="Q1 - Answer 1")
+ self.qa2 = self.q1.answers.create(answer="Q1 - Answer 2")
+ self.qa3 = self.q2.answers.create(answer="Q2 - Answer 1")
+ self.qa4 = self.q2.answers.create(answer="Q2 - Answer 2")
- self.a1 = self.s.surveyanswer_set.create(user=self.users['user'])
+ self.a1 = self.s.surveyanswer_set.create(user=self.users["user"])
self.a1.answers.add(self.qa1)
- self.a2 = self.s.surveyanswer_set.create(user=self.users['member'])
+ self.a2 = self.s.surveyanswer_set.create(user=self.users["member"])
def test_get(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def _get_qa_filter_name(self, qa):
- return 'question_{}_answer_{}'.format(qa.survey_question.pk, qa.pk)
+ return "question_{}_answer_{}".format(qa.survey_question.pk, qa.pk)
def _test_filters(self, filters, expected):
- r = self.client.post(self.url, {
- self._get_qa_filter_name(qa): v for qa, v in filters
- })
+ r = self.client.post(
+ self.url, {self._get_qa_filter_name(qa): v for qa, v in filters}
+ )
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['user_answers'], map(repr, expected),
- ordered=False,
+ r.context["user_answers"], map(repr, expected), ordered=False
)
def test_filter_none(self):
- self._test_filters([(self.qa1, 'none')], [self.a1, self.a2])
+ self._test_filters([(self.qa1, "none")], [self.a1, self.a2])
def test_filter_yes(self):
- self._test_filters([(self.qa1, 'yes')], [self.a1])
+ self._test_filters([(self.qa1, "yes")], [self.a1])
def test_filter_no(self):
- self._test_filters([(self.qa1, 'no')], [self.a2])
+ self._test_filters([(self.qa1, "no")], [self.a2])
diff --git a/gestioncof/tests/testcases.py b/gestioncof/tests/testcases.py
index b53f2866..43f69bbc 100644
--- a/gestioncof/tests/testcases.py
+++ b/gestioncof/tests/testcases.py
@@ -1,6 +1,6 @@
from shared.tests.testcases import ViewTestCaseMixin as BaseViewTestCaseMixin
-from .utils import create_user, create_member, create_staff
+from .utils import create_member, create_staff, create_user
class ViewTestCaseMixin(BaseViewTestCaseMixin):
@@ -18,7 +18,7 @@ class ViewTestCaseMixin(BaseViewTestCaseMixin):
def get_users_base(self):
return {
- 'user': create_user('user'),
- 'member': create_member('member'),
- 'staff': create_staff('staff'),
+ "user": create_user("user"),
+ "member": create_member("member"),
+ "staff": create_staff("staff"),
}
diff --git a/gestioncof/tests/utils.py b/gestioncof/tests/utils.py
index 7ba361b7..7325e350 100644
--- a/gestioncof/tests/utils.py
+++ b/gestioncof/tests/utils.py
@@ -7,28 +7,35 @@ def _create_user(username, is_cof=False, is_staff=False, attrs=None):
if attrs is None:
attrs = {}
- password = attrs.pop('password', username)
+ password = attrs.pop("password", username)
- user_keys = [
- 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser',
- ]
+ user_keys = ["first_name", "last_name", "email", "is_staff", "is_superuser"]
user_attrs = {k: v for k, v in attrs.items() if k in user_keys}
profile_keys = [
- 'is_cof', 'login_clipper', 'phone', 'occupation', 'departement',
- 'type_cotiz', 'mailing_cof', 'mailing_bda', 'mailing_bda_revente',
- 'comments', 'is_buro', 'petit_cours_accept',
- 'petit_cours_remarques',
+ "is_cof",
+ "login_clipper",
+ "phone",
+ "occupation",
+ "departement",
+ "type_cotiz",
+ "mailing_cof",
+ "mailing_bda",
+ "mailing_bda_revente",
+ "comments",
+ "is_buro",
+ "petit_cours_accept",
+ "petit_cours_remarques",
]
profile_attrs = {k: v for k, v in attrs.items() if k in profile_keys}
if is_cof:
- profile_attrs['is_cof'] = True
+ profile_attrs["is_cof"] = True
if is_staff:
# At the moment, admin is accessible by COF staff.
- user_attrs['is_staff'] = True
- profile_attrs['is_buro'] = True
+ user_attrs["is_staff"] = True
+ profile_attrs["is_buro"] = True
user = User(username=username, **user_attrs)
user.set_password(password)
@@ -56,6 +63,6 @@ def create_staff(username, attrs=None):
def create_root(username, attrs=None):
if attrs is None:
attrs = {}
- attrs.setdefault('is_staff', True)
- attrs.setdefault('is_superuser', True)
+ attrs.setdefault("is_staff", True)
+ attrs.setdefault("is_superuser", True)
return _create_user(username, attrs=attrs)
diff --git a/gestioncof/urls.py b/gestioncof/urls.py
index f8ce8f6d..c4414fa5 100644
--- a/gestioncof/urls.py
+++ b/gestioncof/urls.py
@@ -1,67 +1,87 @@
from django.conf.urls import url
-from gestioncof.petits_cours_views import DemandeListView, DemandeDetailView
-from gestioncof import views, petits_cours_views
+
+from gestioncof import petits_cours_views, views
from gestioncof.decorators import buro_required
+from gestioncof.petits_cours_views import DemandeDetailView, DemandeListView
export_patterns = [
- url(r'^members$', views.export_members,
- name='cof.membres_export'),
- url(r'^mega/avecremarques$', views.export_mega_remarksonly,
- name='cof.mega_export_remarks'),
- url(r'^mega/participants$', views.export_mega_participants,
- name='cof.mega_export_participants'),
- url(r'^mega/orgas$', views.export_mega_orgas,
- name='cof.mega_export_orgas'),
+ url(r"^members$", views.export_members, name="cof.membres_export"),
+ url(
+ r"^mega/avecremarques$",
+ views.export_mega_remarksonly,
+ name="cof.mega_export_remarks",
+ ),
+ url(
+ r"^mega/participants$",
+ views.export_mega_participants,
+ name="cof.mega_export_participants",
+ ),
+ url(r"^mega/orgas$", views.export_mega_orgas, name="cof.mega_export_orgas"),
# url(r'^mega/(?P.+)$', views.export_mega_bytype),
- url(r'^mega$', views.export_mega,
- name='cof.mega_export'),
+ url(r"^mega$", views.export_mega, name="cof.mega_export"),
]
petitcours_patterns = [
- url(r'^inscription$', petits_cours_views.inscription,
- name='petits-cours-inscription'),
- url(r'^demande$', petits_cours_views.demande,
- name='petits-cours-demande'),
- url(r'^demande-raw$', petits_cours_views.demande_raw,
- name='petits-cours-demande-raw'),
- url(r'^demandes$',
+ url(
+ r"^inscription$",
+ petits_cours_views.inscription,
+ name="petits-cours-inscription",
+ ),
+ url(r"^demande$", petits_cours_views.demande, name="petits-cours-demande"),
+ url(
+ r"^demande-raw$",
+ petits_cours_views.demande_raw,
+ name="petits-cours-demande-raw",
+ ),
+ url(
+ r"^demandes$",
buro_required(DemandeListView.as_view()),
- name='petits-cours-demandes-list'),
- url(r'^demandes/(?P\d+)$',
+ name="petits-cours-demandes-list",
+ ),
+ url(
+ r"^demandes/(?P\d+)$",
buro_required(DemandeDetailView.as_view()),
- name='petits-cours-demande-details'),
- url(r'^demandes/(?P\d+)/traitement$',
+ name="petits-cours-demande-details",
+ ),
+ url(
+ r"^demandes/(?P\d+)/traitement$",
petits_cours_views.traitement,
- name='petits-cours-demande-traitement'),
- url(r'^demandes/(?P\d+)/retraitement$',
+ name="petits-cours-demande-traitement",
+ ),
+ url(
+ r"^demandes/(?P\d+)/retraitement$",
petits_cours_views.retraitement,
- name='petits-cours-demande-retraitement'),
+ name="petits-cours-demande-retraitement",
+ ),
]
surveys_patterns = [
- url(r'^(?P\d+)/status$', views.survey_status,
- name='survey.details.status'),
- url(r'^(?P\d+)$', views.survey,
- name='survey.details'),
+ url(
+ r"^(?P\d+)/status$",
+ views.survey_status,
+ name="survey.details.status",
+ ),
+ url(r"^(?P\d+)$", views.survey, name="survey.details"),
]
events_patterns = [
- url(r'^(?P\d+)$', views.event,
- name='event.details'),
- url(r'^(?P\d+)/status$', views.event_status,
- name='event.details.status'),
+ url(r"^(?P\d+)$", views.event, name="event.details"),
+ url(r"^(?P\d+)/status$", views.event_status, name="event.details.status"),
]
calendar_patterns = [
- url(r'^subscription$', views.calendar,
- name='calendar'),
- url(r'^(?P[a-z0-9-]+)/calendar.ics$', views.calendar_ics,
- name='calendar.ics'),
+ url(r"^subscription$", views.calendar, name="calendar"),
+ url(
+ r"^(?P[a-z0-9-]+)/calendar.ics$", views.calendar_ics, name="calendar.ics"
+ ),
]
clubs_patterns = [
- url(r'^membres/(?P\w+)', views.membres_club, name='membres-club'),
- url(r'^liste', views.liste_clubs, name='liste-clubs'),
- url(r'^change_respo/(?P\w+)/(?P\d+)',
- views.change_respo, name='change-respo'),
+ url(r"^membres/(?P\w+)", views.membres_club, name="membres-club"),
+ url(r"^liste", views.liste_clubs, name="liste-clubs"),
+ url(
+ r"^change_respo/(?P\w+)/(?P\d+)",
+ views.change_respo,
+ name="change-respo",
+ ),
]
diff --git a/gestioncof/views.py b/gestioncof/views.py
index 6126eb10..618fb24a 100644
--- a/gestioncof/views.py
+++ b/gestioncof/views.py
@@ -1,58 +1,74 @@
-import unicodecsv
import uuid
from datetime import timedelta
-from icalendar import Calendar, Event as Vevent
-from custommail.shortcuts import send_custom_mail
-from django.shortcuts import redirect, get_object_or_404, render
-from django.http import Http404, HttpResponse, HttpResponseForbidden
+import unicodecsv
+from custommail.shortcuts import send_custom_mail
+from django.contrib import messages
from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
from django.contrib.auth.views import (
- login as django_login_view, logout as django_logout_view,
+ login as django_login_view,
+ logout as django_logout_view,
redirect_to_login,
)
-from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse_lazy
-from django.views.generic import FormView
+from django.http import Http404, HttpResponse, HttpResponseForbidden
+from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
-from django.contrib import messages
-
+from django.views.generic import FormView
from django_cas_ng.views import logout as cas_logout_view
+from icalendar import Calendar, Event as Vevent
-from utils.views.autocomplete import Select2QuerySetView
-
-from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
- SurveyQuestionAnswer
-from gestioncof.models import Event, EventRegistration, EventOption, \
- EventOptionChoice
-from gestioncof.models import EventCommentField, EventCommentValue, \
- CalendarSubscription
-from gestioncof.models import CofProfile, Club
+from bda.models import Spectacle, Tirage
from gestioncof.decorators import buro_required, cof_required
from gestioncof.forms import (
- UserProfileForm, EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm,
- RegistrationUserForm, RegistrationProfileForm, EventForm, CalendarForm,
- EventFormset, RegistrationPassUserForm, ClubsForm, GestioncofConfigForm
+ CalendarForm,
+ ClubsForm,
+ EventForm,
+ EventFormset,
+ EventStatusFilterForm,
+ GestioncofConfigForm,
+ ProfileForm,
+ RegistrationPassUserForm,
+ RegistrationProfileForm,
+ RegistrationUserForm,
+ SurveyForm,
+ SurveyStatusFilterForm,
+ UserForm,
)
-
-from bda.models import Tirage, Spectacle
+from gestioncof.models import (
+ CalendarSubscription,
+ Club,
+ CofProfile,
+ Event,
+ EventCommentField,
+ EventCommentValue,
+ EventOption,
+ EventOptionChoice,
+ EventRegistration,
+ Survey,
+ SurveyAnswer,
+ SurveyQuestion,
+ SurveyQuestionAnswer,
+)
+from utils.views.autocomplete import Select2QuerySetView
@login_required
def home(request):
- data = {"surveys": Survey.objects.filter(old=False).all(),
- "events": Event.objects.filter(old=False).all(),
- "open_surveys":
- Survey.objects.filter(survey_open=True, old=False).all(),
- "open_events":
- Event.objects.filter(registration_open=True, old=False).all(),
- "active_tirages": Tirage.objects.filter(active=True).all(),
- "open_tirages":
- Tirage.objects.filter(active=True,
- ouverture__lte=timezone.now()).all(),
- "now": timezone.now()}
+ data = {
+ "surveys": Survey.objects.filter(old=False).all(),
+ "events": Event.objects.filter(old=False).all(),
+ "open_surveys": Survey.objects.filter(survey_open=True, old=False).all(),
+ "open_events": Event.objects.filter(registration_open=True, old=False).all(),
+ "active_tirages": Tirage.objects.filter(active=True).all(),
+ "open_tirages": Tirage.objects.filter(
+ active=True, ouverture__lte=timezone.now()
+ ).all(),
+ "now": timezone.now(),
+ }
return render(request, "home.html", data)
@@ -60,8 +76,8 @@ def login(request):
if request.user.is_authenticated:
return redirect("home")
context = {}
- if request.method == "GET" and 'next' in request.GET:
- context['next'] = request.GET['next']
+ if request.method == "GET" and "next" in request.GET:
+ context["next"] = request.GET["next"]
return render(request, "login_switch.html", context)
@@ -72,34 +88,33 @@ def login_ext(request):
if not user.has_usable_password() or user.password in ("", "!"):
profile, created = CofProfile.objects.get_or_create(user=user)
if profile.login_clipper:
- return render(request, "error.html",
- {"error_type": "use_clipper_login"})
+ return render(
+ request, "error.html", {"error_type": "use_clipper_login"}
+ )
else:
- return render(request, "error.html",
- {"error_type": "no_password"})
+ return render(request, "error.html", {"error_type": "no_password"})
except User.DoesNotExist:
pass
context = {}
- if request.method == "GET" and 'next' in request.GET:
- context['next'] = request.GET['next']
- if request.method == "POST" and 'next' in request.POST:
- context['next'] = request.POST['next']
- return django_login_view(request, template_name='login.html',
- extra_context=context)
+ if request.method == "GET" and "next" in request.GET:
+ context["next"] = request.GET["next"]
+ if request.method == "POST" and "next" in request.POST:
+ context["next"] = request.POST["next"]
+ return django_login_view(request, template_name="login.html", extra_context=context)
@login_required
def logout(request, next_page=None):
if next_page is None:
- next_page = request.GET.get('next', None)
+ next_page = request.GET.get("next", None)
- profile = getattr(request.user, 'profile', None)
+ profile = getattr(request.user, "profile", None)
if profile and profile.login_clipper:
- msg = _('Déconnexion de GestioCOF et CAS réussie. À bientôt {}.')
+ msg = _("Déconnexion de GestioCOF et CAS réussie. À bientôt {}.")
logout_view = cas_logout_view
else:
- msg = _('Déconnexion de GestioCOF réussie. À bientôt {}.')
+ msg = _("Déconnexion de GestioCOF réussie. À bientôt {}.")
logout_view = django_logout_view
messages.success(request, msg.format(request.user.get_short_name()))
@@ -109,8 +124,7 @@ def logout(request, next_page=None):
@login_required
def survey(request, survey_id):
survey = get_object_or_404(
- Survey.objects.prefetch_related('questions', 'questions__answers'),
- id=survey_id,
+ Survey.objects.prefetch_related("questions", "questions__answers"), id=survey_id
)
if not survey.survey_open or survey.old:
raise Http404
@@ -118,10 +132,11 @@ def survey(request, survey_id):
deleted = False
if request.method == "POST":
form = SurveyForm(request.POST, survey=survey)
- if request.POST.get('delete'):
+ if request.POST.get("delete"):
try:
- current_answer = SurveyAnswer.objects.get(user=request.user,
- survey=survey)
+ current_answer = SurveyAnswer.objects.get(
+ user=request.user, survey=survey
+ )
current_answer.delete()
current_answer = None
except SurveyAnswer.DoesNotExist:
@@ -133,9 +148,9 @@ def survey(request, survey_id):
if form.is_valid():
all_answers = []
for question_id, answers_ids in form.answers():
- question = get_object_or_404(SurveyQuestion,
- id=question_id,
- survey=survey)
+ question = get_object_or_404(
+ SurveyQuestion, id=question_id, survey=survey
+ )
if type(answers_ids) != list:
answers_ids = [answers_ids]
if not question.multi_answers and len(answers_ids) > 1:
@@ -145,50 +160,48 @@ def survey(request, survey_id):
continue
answer_id = int(answer_id)
answer = SurveyQuestionAnswer.objects.get(
- id=answer_id,
- survey_question=question)
+ id=answer_id, survey_question=question
+ )
all_answers.append(answer)
try:
current_answer = SurveyAnswer.objects.get(
- user=request.user, survey=survey)
+ user=request.user, survey=survey
+ )
except SurveyAnswer.DoesNotExist:
- current_answer = SurveyAnswer(user=request.user,
- survey=survey)
+ current_answer = SurveyAnswer(user=request.user, survey=survey)
current_answer.save()
current_answer.answers = all_answers
current_answer.save()
success = True
else:
try:
- current_answer = SurveyAnswer.objects.get(user=request.user,
- survey=survey)
- form = SurveyForm(survey=survey,
- current_answers=current_answer.answers)
+ current_answer = SurveyAnswer.objects.get(user=request.user, survey=survey)
+ form = SurveyForm(survey=survey, current_answers=current_answer.answers)
except SurveyAnswer.DoesNotExist:
current_answer = None
form = SurveyForm(survey=survey)
# Messages
if success:
if deleted:
- messages.success(request,
- "Votre réponse a bien été supprimée")
+ messages.success(request, "Votre réponse a bien été supprimée")
else:
- messages.success(request,
- "Votre réponse a bien été enregistrée ! Vous "
- "pouvez cependant la modifier jusqu'à la fin "
- "du sondage.")
- return render(request, "gestioncof/survey.html", {
- "survey": survey,
- "form": form,
- "current_answer": current_answer
- })
+ messages.success(
+ request,
+ "Votre réponse a bien été enregistrée ! Vous "
+ "pouvez cependant la modifier jusqu'à la fin "
+ "du sondage.",
+ )
+ return render(
+ request,
+ "gestioncof/survey.html",
+ {"survey": survey, "form": form, "current_answer": current_answer},
+ )
def get_event_form_choices(event, form):
all_choices = []
for option_id, choices_ids in form.choices():
- option = get_object_or_404(EventOption, id=option_id,
- event=event)
+ option = get_object_or_404(EventOption, id=option_id, event=event)
if type(choices_ids) != list:
choices_ids = [choices_ids]
if not option.multi_choices and len(choices_ids) > 1:
@@ -197,22 +210,19 @@ def get_event_form_choices(event, form):
if not choice_id:
continue
choice_id = int(choice_id)
- choice = EventOptionChoice.objects.get(
- id=choice_id,
- event_option=option)
+ choice = EventOptionChoice.objects.get(id=choice_id, event_option=option)
all_choices.append(choice)
return all_choices
def update_event_form_comments(event, form, registration):
for commentfield_id, value in form.comments():
- field = get_object_or_404(EventCommentField, id=commentfield_id,
- event=event)
+ field = get_object_or_404(EventCommentField, id=commentfield_id, event=event)
if value == field.default:
continue
(storage, _) = EventCommentValue.objects.get_or_create(
- commentfield=field,
- registration=registration)
+ commentfield=field, registration=registration
+ )
storage.content = value
storage.save()
@@ -227,27 +237,29 @@ def event(request, event_id):
form = EventForm(request.POST, event=event)
if form.is_valid():
all_choices = get_event_form_choices(event, form)
- (current_registration, _) = \
- EventRegistration.objects.get_or_create(user=request.user,
- event=event)
+ (current_registration, _) = EventRegistration.objects.get_or_create(
+ user=request.user, event=event
+ )
current_registration.options = all_choices
current_registration.save()
success = True
else:
try:
- current_registration = \
- EventRegistration.objects.get(user=request.user, event=event)
- form = EventForm(event=event,
- current_choices=current_registration.options)
+ current_registration = EventRegistration.objects.get(
+ user=request.user, event=event
+ )
+ form = EventForm(event=event, current_choices=current_registration.options)
except EventRegistration.DoesNotExist:
form = EventForm(event=event)
# Messages
if success:
- messages.success(request, "Votre inscription a bien été enregistrée ! "
- "Vous pouvez cependant la modifier jusqu'à "
- "la fin des inscriptions.")
- return render(request, "gestioncof/event.html",
- {"event": event, "form": form})
+ messages.success(
+ request,
+ "Votre inscription a bien été enregistrée ! "
+ "Vous pouvez cependant la modifier jusqu'à "
+ "la fin des inscriptions.",
+ )
+ return render(request, "gestioncof/event.html", {"event": event, "form": form})
def clean_post_for_status(initial):
@@ -271,19 +283,21 @@ def event_status(request, event_id):
if value == "yes":
registrations_query = registrations_query.filter(paid=True)
elif value == "no":
- registrations_query = registrations_query.filter(
- paid=False)
+ registrations_query = registrations_query.filter(paid=False)
continue
- choice = get_object_or_404(EventOptionChoice, id=choice_id,
- event_option__id=option_id)
+ choice = get_object_or_404(
+ EventOptionChoice, id=choice_id, event_option__id=option_id
+ )
if value == "none":
continue
if value == "yes":
registrations_query = registrations_query.filter(
- options__id__exact=choice.id)
+ options__id__exact=choice.id
+ )
elif value == "no":
registrations_query = registrations_query.exclude(
- options__id__exact=choice.id)
+ options__id__exact=choice.id
+ )
user_choices = registrations_query.prefetch_related("user").all()
options = EventOption.objects.filter(event=event).all()
choices_count = {}
@@ -293,10 +307,17 @@ def event_status(request, event_id):
for user_choice in user_choices:
for choice in user_choice.options.all():
choices_count[choice.id] += 1
- return render(request, "event_status.html",
- {"event": event, "user_choices": user_choices,
- "options": options, "choices_count": choices_count,
- "form": form})
+ return render(
+ request,
+ "event_status.html",
+ {
+ "event": event,
+ "user_choices": user_choices,
+ "options": options,
+ "choices_count": choices_count,
+ "form": form,
+ },
+ )
@buro_required
@@ -307,16 +328,15 @@ def survey_status(request, survey_id):
form = SurveyStatusFilterForm(post_data or None, survey=survey)
if form.is_valid():
for question_id, answer_id, value in form.filters():
- answer = get_object_or_404(SurveyQuestionAnswer, id=answer_id,
- survey_question__id=question_id)
+ answer = get_object_or_404(
+ SurveyQuestionAnswer, id=answer_id, survey_question__id=question_id
+ )
if value == "none":
continue
if value == "yes":
- answers_query = answers_query.filter(
- answers__id__exact=answer.id)
+ answers_query = answers_query.filter(answers__id__exact=answer.id)
elif value == "no":
- answers_query = answers_query.exclude(
- answers__id__exact=answer.id)
+ answers_query = answers_query.exclude(answers__id__exact=answer.id)
user_answers = answers_query.prefetch_related("user").all()
questions = SurveyQuestion.objects.filter(survey=survey).all()
answers_count = {}
@@ -326,33 +346,41 @@ def survey_status(request, survey_id):
for user_answer in user_answers:
for answer in user_answer.answers.all():
answers_count[answer.id] += 1
- return render(request, "survey_status.html",
- {"survey": survey, "user_answers": user_answers,
- "questions": questions, "answers_count": answers_count,
- "form": form})
+ return render(
+ request,
+ "survey_status.html",
+ {
+ "survey": survey,
+ "user_answers": user_answers,
+ "questions": questions,
+ "answers_count": answers_count,
+ "form": form,
+ },
+ )
@cof_required
def profile(request):
+ user = request.user
+ data = request.POST if request.method == "POST" else None
+ user_form = UserForm(data=data, instance=user, prefix="u")
+ profile_form = ProfileForm(data=data, instance=user.profile, prefix="p")
if request.method == "POST":
- form = UserProfileForm(request.POST, instance=request.user.profile)
- if form.is_valid():
- form.save()
- messages.success(request,
- "Votre profil a été mis à jour avec succès !")
- else:
- form = UserProfileForm(instance=request.user.profile)
- return render(request, "gestioncof/profile.html", {"form": form})
+ if user_form.is_valid() and profile_form.is_valid():
+ user_form.save()
+ profile_form.save()
+ messages.success(request, _("Votre profil a été mis à jour avec succès !"))
+ context = {"user_form": user_form, "profile_form": profile_form}
+ return render(request, "gestioncof/profile.html", context)
def registration_set_ro_fields(user_form, profile_form):
- user_form.fields['username'].widget.attrs['readonly'] = True
- profile_form.fields['login_clipper'].widget.attrs['readonly'] = True
+ user_form.fields["username"].widget.attrs["readonly"] = True
+ profile_form.fields["login_clipper"].widget.attrs["readonly"] = True
@buro_required
-def registration_form2(request, login_clipper=None, username=None,
- fullname=None):
+def registration_form2(request, login_clipper=None, username=None, fullname=None):
events = Event.objects.filter(old=False).all()
member = None
if login_clipper:
@@ -363,20 +391,24 @@ def registration_form2(request, login_clipper=None, username=None,
except User.DoesNotExist:
# new user, but prefill
# user
- user_form = RegistrationUserForm(initial={
- 'username': login_clipper,
- 'email': "%s@clipper.ens.fr" % login_clipper})
+ user_form = RegistrationUserForm(
+ initial={
+ "username": login_clipper,
+ "email": "%s@clipper.ens.fr" % login_clipper,
+ }
+ )
if fullname:
bits = fullname.split(" ")
- user_form.fields['first_name'].initial = bits[0]
+ user_form.fields["first_name"].initial = bits[0]
if len(bits) > 1:
- user_form.fields['last_name'].initial = " ".join(bits[1:])
+ user_form.fields["last_name"].initial = " ".join(bits[1:])
# profile
- profile_form = RegistrationProfileForm(initial={
- 'login_clipper': login_clipper})
+ profile_form = RegistrationProfileForm(
+ initial={"login_clipper": login_clipper}
+ )
registration_set_ro_fields(user_form, profile_form)
# events & clubs
- event_formset = EventFormset(events=events, prefix='events')
+ event_formset = EventFormset(events=events, prefix="events")
clubs_form = ClubsForm()
if username:
member = get_object_or_404(User, username=username)
@@ -390,26 +422,33 @@ def registration_form2(request, login_clipper=None, username=None,
for event in events:
try:
current_registrations.append(
- EventRegistration.objects.get(user=member, event=event))
+ EventRegistration.objects.get(user=member, event=event)
+ )
except EventRegistration.DoesNotExist:
current_registrations.append(None)
event_formset = EventFormset(
- events=events, prefix='events',
- current_registrations=current_registrations)
+ events=events, prefix="events", current_registrations=current_registrations
+ )
# Clubs
- clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
+ clubs_form = ClubsForm(initial={"clubs": member.clubs.all()})
elif not login_clipper:
# new user
user_form = RegistrationPassUserForm()
profile_form = RegistrationProfileForm()
- event_formset = EventFormset(events=events, prefix='events')
+ event_formset = EventFormset(events=events, prefix="events")
clubs_form = ClubsForm()
- return render(request, "gestioncof/registration_form.html",
- {"member": member, "login_clipper": login_clipper,
- "user_form": user_form,
- "profile_form": profile_form,
- "event_formset": event_formset,
- "clubs_form": clubs_form})
+ return render(
+ request,
+ "gestioncof/registration_form.html",
+ {
+ "member": member,
+ "login_clipper": login_clipper,
+ "user_form": user_form,
+ "profile_form": profile_form,
+ "event_formset": event_formset,
+ "clubs_form": clubs_form,
+ },
+ )
@buro_required
@@ -423,15 +462,14 @@ def registration(request):
# Remplissage des formulaires
# -----
- if 'password1' in request_dict or 'password2' in request_dict:
+ if "password1" in request_dict or "password2" in request_dict:
user_form = RegistrationPassUserForm(request_dict)
else:
user_form = RegistrationUserForm(request_dict)
profile_form = RegistrationProfileForm(request_dict)
clubs_form = ClubsForm(request_dict)
events = Event.objects.filter(old=False).all()
- event_formset = EventFormset(events=events, data=request_dict,
- prefix='events')
+ event_formset = EventFormset(events=events, data=request_dict, prefix="events")
if "user_exists" in request_dict and request_dict["user_exists"]:
username = request_dict["username"]
try:
@@ -453,38 +491,44 @@ def registration(request):
profile, _ = CofProfile.objects.get_or_create(user=member)
was_cof = profile.is_cof
# Maintenant on remplit le formulaire de profil
- profile_form = RegistrationProfileForm(request_dict,
- instance=profile)
- if (profile_form.is_valid() and event_formset.is_valid()
- and clubs_form.is_valid()):
+ profile_form = RegistrationProfileForm(request_dict, instance=profile)
+ if (
+ profile_form.is_valid()
+ and event_formset.is_valid()
+ and clubs_form.is_valid()
+ ):
# Enregistrement du profil
profile = profile_form.save()
if profile.is_cof and not was_cof:
send_custom_mail(
- "welcome", "cof@ens.fr", [member.email],
- context={'member': member},
+ "welcome",
+ "cof@ens.fr",
+ [member.email],
+ context={"member": member},
)
# Enregistrement des inscriptions aux événements
for form in event_formset:
- if 'status' not in form.cleaned_data:
- form.cleaned_data['status'] = 'no'
- if form.cleaned_data['status'] == 'no':
+ if "status" not in form.cleaned_data:
+ form.cleaned_data["status"] = "no"
+ if form.cleaned_data["status"] == "no":
try:
- current_registration = EventRegistration.objects \
- .get(user=member, event=form.event)
+ current_registration = EventRegistration.objects.get(
+ user=member, event=form.event
+ )
current_registration.delete()
except EventRegistration.DoesNotExist:
pass
continue
all_choices = get_event_form_choices(form.event, form)
- (current_registration, created_reg) = \
- EventRegistration.objects.get_or_create(
- user=member, event=form.event)
- update_event_form_comments(form.event, form,
- current_registration)
+ (
+ current_registration,
+ created_reg,
+ ) = EventRegistration.objects.get_or_create(
+ user=member, event=form.event
+ )
+ update_event_form_comments(form.event, form, current_registration)
current_registration.options = all_choices
- current_registration.paid = \
- (form.cleaned_data['status'] == 'paid')
+ current_registration.paid = form.cleaned_data["status"] == "paid"
current_registration.save()
# if form.event.title == "Mega 15" and created_reg:
# field = EventCommentField.objects.get(
@@ -502,7 +546,7 @@ def registration(request):
# send_custom_mail(...)
# Enregistrement des inscriptions aux clubs
member.clubs.clear()
- for club in clubs_form.cleaned_data['clubs']:
+ for club in clubs_form.cleaned_data["clubs"]:
club.membres.add(member)
club.save()
@@ -510,20 +554,29 @@ def registration(request):
# Success
# ---
- msg = ("L'inscription de {:s} ({:s} ) a été "
- "enregistrée avec succès."
- .format(member.get_full_name(), member.email))
+ msg = (
+ "L'inscription de {:s} ({:s} ) a été "
+ "enregistrée avec succès.".format(
+ member.get_full_name(), member.email
+ )
+ )
if profile.is_cof:
msg += "\nIl est désormais membre du COF n°{:d} !".format(
- member.profile.id)
- messages.success(request, msg, extra_tags='safe')
- return render(request, "gestioncof/registration_post.html",
- {"user_form": user_form,
- "profile_form": profile_form,
- "member": member,
- "login_clipper": login_clipper,
- "event_formset": event_formset,
- "clubs_form": clubs_form})
+ member.profile.id
+ )
+ messages.success(request, msg, extra_tags="safe")
+ return render(
+ request,
+ "gestioncof/registration_post.html",
+ {
+ "user_form": user_form,
+ "profile_form": profile_form,
+ "member": member,
+ "login_clipper": login_clipper,
+ "event_formset": event_formset,
+ "clubs_form": clubs_form,
+ },
+ )
else:
return render(request, "registration.html")
@@ -539,13 +592,14 @@ def membres_club(request, name):
# ou respo du club.
user = request.user
club = get_object_or_404(Club, name=name)
- if not request.user.profile.is_buro \
- and club not in user.clubs_geres.all():
- return HttpResponseForbidden('Permission denied ')
+ if not request.user.profile.is_buro and club not in user.clubs_geres.all():
+ return HttpResponseForbidden("Permission denied ")
members_no_respo = club.membres.exclude(clubs_geres=club).all()
- return render(request, 'membres_clubs.html',
- {'club': club,
- 'members_no_respo': members_no_respo})
+ return render(
+ request,
+ "membres_clubs.html",
+ {"club": club, "members_no_respo": members_no_respo},
+ )
@buro_required
@@ -558,49 +612,78 @@ def change_respo(request, club_name, user_id):
club.respos.add(user)
else:
raise Http404
- return redirect('membres-club', name=club_name)
+ return redirect("membres-club", name=club_name)
@cof_required
def liste_clubs(request):
clubs = Club.objects
if request.user.profile.is_buro:
- data = {'owned_clubs': clubs.all()}
+ data = {"owned_clubs": clubs.all()}
else:
- data = {'owned_clubs': request.user.clubs_geres.all(),
- 'other_clubs': clubs.exclude(respos=request.user)}
- return render(request, 'liste_clubs.html', data)
+ data = {
+ "owned_clubs": request.user.clubs_geres.all(),
+ "other_clubs": clubs.exclude(respos=request.user),
+ }
+ return render(request, "liste_clubs.html", data)
@buro_required
def export_members(request):
- response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment; filename=membres_cof.csv'
+ response = HttpResponse(content_type="text/csv")
+ response["Content-Disposition"] = "attachment; filename=membres_cof.csv"
writer = unicodecsv.writer(response)
for profile in CofProfile.objects.filter(is_cof=True).all():
user = profile.user
- bits = [user.id, user.username, user.first_name, user.last_name,
- user.email, profile.phone, profile.occupation,
- profile.departement, profile.type_cotiz]
+ bits = [
+ user.id,
+ user.username,
+ user.first_name,
+ user.last_name,
+ user.email,
+ profile.phone,
+ profile.occupation,
+ profile.departement,
+ profile.type_cotiz,
+ ]
writer.writerow([str(bit) for bit in bits])
return response
+# ----------------------------------------
+# Début des exports Mega machins hardcodés
+# ----------------------------------------
+
+
+MEGA_YEAR = 2018
+MEGA_EVENT_NAME = "MEGA 2018"
+MEGA_COMMENTFIELD_NAME = "Commentaires"
+MEGA_CONSCRITORGAFIELD_NAME = "Orga ? Conscrit ?"
+MEGA_CONSCRIT = "Conscrit"
+MEGA_ORGA = "Orga"
+
+
def csv_export_mega(filename, qs):
- response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment; filename=' + filename
+ response = HttpResponse(content_type="text/csv")
+ response["Content-Disposition"] = "attachment; filename=" + filename
writer = unicodecsv.writer(response)
for reg in qs.all():
user = reg.user
profile = user.profile
- comments = "---".join(
- [comment.content for comment in reg.comments.all()])
- bits = [user.username, user.first_name, user.last_name, user.email,
- profile.phone, user.id,
- profile.comments if profile.comments else "", comments]
+ comments = "---".join([comment.content for comment in reg.comments.all()])
+ bits = [
+ user.username,
+ user.first_name,
+ user.last_name,
+ user.email,
+ profile.phone,
+ user.id,
+ profile.comments if profile.comments else "",
+ comments,
+ ]
writer.writerow([str(bit) for bit in bits])
@@ -609,19 +692,27 @@ def csv_export_mega(filename, qs):
@buro_required
def export_mega_remarksonly(request):
- filename = 'remarques_mega_2017.csv'
- response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment; filename=' + filename
+ filename = "remarques_mega_{}.csv".format(MEGA_YEAR)
+ response = HttpResponse(content_type="text/csv")
+ response["Content-Disposition"] = "attachment; filename=" + filename
writer = unicodecsv.writer(response)
- event = Event.objects.get(title="MEGA 2017")
- commentfield = event.commentfields.get(name="Commentaire")
+ event = Event.objects.get(title=MEGA_EVENT_NAME)
+ commentfield = event.commentfields.get(name=MEGA_COMMENTFIELD_NAME)
for val in commentfield.values.all():
reg = val.registration
user = reg.user
profile = user.profile
- bits = [user.username, user.first_name, user.last_name, user.email,
- profile.phone, profile.id, profile.comments, val.content]
+ bits = [
+ user.username,
+ user.first_name,
+ user.last_name,
+ user.email,
+ profile.phone,
+ profile.id,
+ profile.comments,
+ val.content,
+ ]
writer.writerow([str(bit) for bit in bits])
return response
@@ -647,32 +738,36 @@ def export_mega_remarksonly(request):
@buro_required
def export_mega_orgas(request):
- event = Event.objects.get(title="MEGA 2017")
- type_option = event.options.get(name="Conscrit/Orga ?")
- participant_type = type_option.choices.get(value="Orga").id
+ event = Event.objects.get(title=MEGA_EVENT_NAME)
+ type_option = event.options.get(name=MEGA_CONSCRITORGAFIELD_NAME)
+ participant_type = type_option.choices.get(value=MEGA_ORGA).id
qs = EventRegistration.objects.filter(event=event).filter(
options__id=participant_type
)
- return csv_export_mega('orgas_mega_2017.csv', qs)
+ return csv_export_mega("orgas_mega_{}.csv".format(MEGA_YEAR), qs)
@buro_required
def export_mega_participants(request):
- event = Event.objects.get(title="MEGA 2017")
- type_option = event.options.get(name="Conscrit/Orga ?")
- participant_type = type_option.choices.get(value="Conscrit").id
+ event = Event.objects.get(title=MEGA_EVENT_NAME)
+ type_option = event.options.get(name=MEGA_CONSCRITORGAFIELD_NAME)
+ participant_type = type_option.choices.get(value=MEGA_CONSCRIT).id
qs = EventRegistration.objects.filter(event=event).filter(
options__id=participant_type
)
- return csv_export_mega('participants_mega_2017.csv', qs)
+ return csv_export_mega("conscrits_mega_{}.csv".format(MEGA_YEAR), qs)
@buro_required
def export_mega(request):
- event = Event.objects.filter(title="MEGA 2017")
- qs = EventRegistration.objects.filter(event=event) \
- .order_by("user__username")
- return csv_export_mega('all_mega_2017.csv', qs)
+ event = Event.objects.filter(title=MEGA_EVENT_NAME)
+ qs = EventRegistration.objects.filter(event=event).order_by("user__username")
+ return csv_export_mega("all_mega_{}.csv".format(MEGA_YEAR), qs)
+
+
+# ------------------------------
+# Fin des exports Mega hardcodés
+# ------------------------------
@buro_required
@@ -683,32 +778,28 @@ def utile_cof(request):
@buro_required
def utile_bda(request):
tirages = Tirage.objects.all()
- return render(request, "utile_bda.html", {'tirages': tirages})
+ return render(request, "utile_bda.html", {"tirages": tirages})
@buro_required
def liste_bdadiff(request):
titre = "BdA diffusion"
personnes = CofProfile.objects.filter(mailing_bda=True, is_cof=True).all()
- return render(request, "liste_mails.html",
- {"titre": titre, "personnes": personnes})
+ return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes})
@buro_required
def liste_bdarevente(request):
titre = "BdA revente"
- personnes = CofProfile.objects.filter(mailing_bda_revente=True,
- is_cof=True).all()
- return render(request, "liste_mails.html", {"titre": titre,
- "personnes": personnes})
+ personnes = CofProfile.objects.filter(mailing_bda_revente=True, is_cof=True).all()
+ return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes})
@buro_required
def liste_diffcof(request):
titre = "Diffusion COF"
personnes = CofProfile.objects.filter(mailing_cof=True, is_cof=True).all()
- return render(request, "liste_mails.html", {"titre": titre,
- "personnes": personnes})
+ return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes})
@cof_required
@@ -717,7 +808,7 @@ def calendar(request):
instance = CalendarSubscription.objects.get(user=request.user)
except CalendarSubscription.DoesNotExist:
instance = None
- if request.method == 'POST':
+ if request.method == "POST":
form = CalendarForm(request.POST, instance=instance)
if form.is_valid():
subscription = form.save(commit=False)
@@ -726,19 +817,26 @@ def calendar(request):
subscription.token = uuid.uuid4()
subscription.save()
form.save_m2m()
- messages.success(request,
- "Calendrier mis à jour avec succès.")
- return render(request, "gestioncof/calendar_subscription.html",
- {'form': form,
- 'token': str(subscription.token)})
+ messages.success(request, "Calendrier mis à jour avec succès.")
+ return render(
+ request,
+ "gestioncof/calendar_subscription.html",
+ {"form": form, "token": str(subscription.token)},
+ )
else:
messages.error(request, "Formulaire incorrect.")
- return render(request, "gestioncof/calendar_subscription.html",
- {'form': form})
+ return render(
+ request, "gestioncof/calendar_subscription.html", {"form": form}
+ )
else:
- return render(request, "gestioncof/calendar_subscription.html",
- {'form': CalendarForm(instance=instance),
- 'token': instance.token if instance else None})
+ return render(
+ request,
+ "gestioncof/calendar_subscription.html",
+ {
+ "form": CalendarForm(instance=instance),
+ "token": instance.token if instance else None,
+ },
+ )
def calendar_ics(request, token):
@@ -746,33 +844,33 @@ def calendar_ics(request, token):
shows = subscription.other_shows.all()
if subscription.subscribe_to_my_shows:
shows |= Spectacle.objects.filter(
- attribues__participant__user=subscription.user,
- tirage__active=True)
+ attribues__participant__user=subscription.user, tirage__active=True
+ )
shows = shows.distinct()
vcal = Calendar()
site = Site.objects.get_current()
for show in shows:
vevent = Vevent()
- vevent.add('dtstart', show.date)
- vevent.add('dtend', show.date + timedelta(seconds=7200))
- vevent.add('summary', show.title)
- vevent.add('location', show.location.name)
- vevent.add('uid', 'show-{:d}-{:d}@{:s}'.format(
- show.pk, show.tirage_id, site.domain))
+ vevent.add("dtstart", show.date)
+ vevent.add("dtend", show.date + timedelta(seconds=7200))
+ vevent.add("summary", show.title)
+ vevent.add("location", show.location.name)
+ vevent.add(
+ "uid", "show-{:d}-{:d}@{:s}".format(show.pk, show.tirage_id, site.domain)
+ )
vcal.add_component(vevent)
if subscription.subscribe_to_events:
for event in Event.objects.filter(old=False).all():
vevent = Vevent()
- vevent.add('dtstart', event.start_date)
- vevent.add('dtend', event.end_date)
- vevent.add('summary', event.title)
- vevent.add('location', event.location)
- vevent.add('description', event.description)
- vevent.add('uid', 'event-{:d}@{:s}'.format(
- event.pk, site.domain))
+ vevent.add("dtstart", event.start_date)
+ vevent.add("dtend", event.end_date)
+ vevent.add("summary", event.title)
+ vevent.add("location", event.location)
+ vevent.add("description", event.description)
+ vevent.add("uid", "event-{:d}@{:s}".format(event.pk, site.domain))
vcal.add_component(vevent)
response = HttpResponse(content=vcal.to_ical())
- response['Content-Type'] = "text/calendar"
+ response["Content-Type"] = "text/calendar"
return response
@@ -800,7 +898,7 @@ class ConfigUpdate(FormView):
class UserAutocomplete(Select2QuerySetView):
model = User
- search_fields = ('username', 'first_name', 'last_name')
+ search_fields = ("username", "first_name", "last_name")
user_autocomplete = buro_required(UserAutocomplete.as_view())
diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py
index 906f7b15..49125896 100644
--- a/gestioncof/widgets.py
+++ b/gestioncof/widgets.py
@@ -1,5 +1,5 @@
-from django.forms.widgets import Widget
from django.forms.utils import flatatt
+from django.forms.widgets import Widget
from django.utils.safestring import mark_safe
@@ -13,8 +13,8 @@ class TriStateCheckbox(Widget):
def render(self, name, value, attrs=None, choices=()):
if value is None:
- value = 'none'
- attrs['value'] = value
+ value = "none"
+ attrs["value"] = value
final_attrs = self.build_attrs(self.attrs, attrs)
- output = [" " % flatatt(final_attrs)]
- return mark_safe('\n'.join(output))
+ output = [' ' % flatatt(final_attrs)]
+ return mark_safe("\n".join(output))
diff --git a/kfet/__init__.py b/kfet/__init__.py
index 5d6c8f97..42ea33b1 100644
--- a/kfet/__init__.py
+++ b/kfet/__init__.py
@@ -1 +1 @@
-default_app_config = 'kfet.apps.KFetConfig'
+default_app_config = "kfet.apps.KFetConfig"
diff --git a/kfet/admin.py b/kfet/admin.py
deleted file mode 100644
index 8c38f3f3..00000000
--- a/kfet/admin.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.
diff --git a/kfet/apps.py b/kfet/apps.py
index 7a6c97a2..f3c7b07b 100644
--- a/kfet/apps.py
+++ b/kfet/apps.py
@@ -2,7 +2,7 @@ from django.apps import AppConfig
class KFetConfig(AppConfig):
- name = 'kfet'
+ name = "kfet"
verbose_name = "Application K-Fêt"
def ready(self):
@@ -11,4 +11,5 @@ class KFetConfig(AppConfig):
def register_config(self):
import djconfig
from kfet.forms import KFetConfigForm
+
djconfig.register(KFetConfigForm)
diff --git a/kfet/auth/__init__.py b/kfet/auth/__init__.py
index 00926030..ef2486a7 100644
--- a/kfet/auth/__init__.py
+++ b/kfet/auth/__init__.py
@@ -1,4 +1,4 @@
-default_app_config = 'kfet.auth.apps.KFetAuthConfig'
+default_app_config = "kfet.auth.apps.KFetAuthConfig"
-KFET_GENERIC_USERNAME = 'kfet_genericteam'
-KFET_GENERIC_TRIGRAMME = 'GNR'
+KFET_GENERIC_USERNAME = "kfet_genericteam"
+KFET_GENERIC_TRIGRAMME = "GNR"
diff --git a/kfet/auth/apps.py b/kfet/auth/apps.py
index d91931f5..5b4fe7fd 100644
--- a/kfet/auth/apps.py
+++ b/kfet/auth/apps.py
@@ -4,11 +4,12 @@ from django.utils.translation import ugettext_lazy as _
class KFetAuthConfig(AppConfig):
- name = 'kfet.auth'
- label = 'kfetauth'
+ name = "kfet.auth"
+ label = "kfetauth"
verbose_name = _("K-Fêt - Authentification et Autorisation")
def ready(self):
from . import signals # noqa
from .utils import setup_kfet_generic_user
+
post_migrate.connect(setup_kfet_generic_user, sender=self)
diff --git a/kfet/auth/backends.py b/kfet/auth/backends.py
index d8ef3001..55e18458 100644
--- a/kfet/auth/backends.py
+++ b/kfet/auth/backends.py
@@ -1,4 +1,5 @@
from django.contrib.auth import get_user_model
+
from kfet.models import Account, GenericTeamToken
from .utils import get_kfet_generic_user
@@ -12,11 +13,7 @@ class BaseKFetBackend:
Add extra select related up to Account.
"""
try:
- return (
- User.objects
- .select_related('profile__account_kfet')
- .get(pk=user_id)
- )
+ return User.objects.select_related("profile__account_kfet").get(pk=user_id)
except User.DoesNotExist:
return None
diff --git a/kfet/auth/context_processors.py b/kfet/auth/context_processors.py
index 7b59b88b..183cc56a 100644
--- a/kfet/auth/context_processors.py
+++ b/kfet/auth/context_processors.py
@@ -2,9 +2,6 @@ from django.contrib.auth.context_processors import PermWrapper
def temporary_auth(request):
- if hasattr(request, 'real_user'):
- return {
- 'user': request.real_user,
- 'perms': PermWrapper(request.real_user),
- }
+ if hasattr(request, "real_user"):
+ return {"user": request.real_user, "perms": PermWrapper(request.real_user)}
return {}
diff --git a/kfet/auth/fields.py b/kfet/auth/fields.py
index 28ba1c9e..a5544787 100644
--- a/kfet/auth/fields.py
+++ b/kfet/auth/fields.py
@@ -5,15 +5,12 @@ from django.forms import widgets
class KFetPermissionsField(forms.ModelMultipleChoiceField):
-
def __init__(self, *args, **kwargs):
queryset = Permission.objects.filter(
- content_type__in=ContentType.objects.filter(app_label="kfet"),
+ content_type__in=ContentType.objects.filter(app_label="kfet")
)
super().__init__(
- queryset=queryset,
- widget=widgets.CheckboxSelectMultiple,
- *args, **kwargs
+ queryset=queryset, widget=widgets.CheckboxSelectMultiple, *args, **kwargs
)
def label_from_instance(self, obj):
diff --git a/kfet/auth/forms.py b/kfet/auth/forms.py
index 876e8814..b1628af0 100644
--- a/kfet/auth/forms.py
+++ b/kfet/auth/forms.py
@@ -8,11 +8,11 @@ class GroupForm(forms.ModelForm):
permissions = KFetPermissionsField()
def clean_name(self):
- name = self.cleaned_data['name']
- return 'K-Fêt %s' % name
+ name = self.cleaned_data["name"]
+ return "K-Fêt %s" % name
def clean_permissions(self):
- kfet_perms = self.cleaned_data['permissions']
+ kfet_perms = self.cleaned_data["permissions"]
# TODO: With Django >=1.11, the QuerySet method 'difference' can be
# used.
# other_groups = self.instance.permissions.difference(
@@ -21,28 +21,29 @@ class GroupForm(forms.ModelForm):
if self.instance.pk is None:
return kfet_perms
other_perms = self.instance.permissions.exclude(
- pk__in=[p.pk for p in self.fields['permissions'].queryset],
+ pk__in=[p.pk for p in self.fields["permissions"].queryset]
)
return list(kfet_perms) + list(other_perms)
class Meta:
model = Group
- fields = ['name', 'permissions']
+ fields = ["name", "permissions"]
class UserGroupForm(forms.ModelForm):
groups = forms.ModelMultipleChoiceField(
- Group.objects.filter(name__icontains='K-Fêt'),
- label='Statut équipe',
- required=False)
+ Group.objects.filter(name__icontains="K-Fêt"),
+ label="Statut équipe",
+ required=False,
+ )
def clean_groups(self):
- kfet_groups = self.cleaned_data.get('groups')
+ kfet_groups = self.cleaned_data.get("groups")
if self.instance.pk is None:
return kfet_groups
- other_groups = self.instance.groups.exclude(name__icontains='K-Fêt')
+ other_groups = self.instance.groups.exclude(name__icontains="K-Fêt")
return list(kfet_groups) + list(other_groups)
class Meta:
model = User
- fields = ['groups']
+ fields = ["groups"]
diff --git a/kfet/auth/middleware.py b/kfet/auth/middleware.py
index 2f3bd33b..43a920e1 100644
--- a/kfet/auth/middleware.py
+++ b/kfet/auth/middleware.py
@@ -12,21 +12,19 @@ class TemporaryAuthMiddleware:
values from CofProfile and Account of this user.
"""
+
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
# avoid multiple db accesses in views and templates
- request.user = (
- User.objects
- .select_related('profile__account_kfet')
- .get(pk=request.user.pk)
+ request.user = User.objects.select_related("profile__account_kfet").get(
+ pk=request.user.pk
)
temp_request_user = AccountBackend().authenticate(
- request,
- kfet_password=self.get_kfet_password(request),
+ request, kfet_password=self.get_kfet_password(request)
)
if temp_request_user:
@@ -36,7 +34,4 @@ class TemporaryAuthMiddleware:
return self.get_response(request)
def get_kfet_password(self, request):
- return (
- request.META.get('HTTP_KFETPASSWORD') or
- request.POST.get('KFETPASSWORD')
- )
+ return request.META.get("HTTP_KFETPASSWORD") or request.POST.get("KFETPASSWORD")
diff --git a/kfet/auth/migrations/0001_initial.py b/kfet/auth/migrations/0001_initial.py
index 061570a8..caf5d786 100644
--- a/kfet/auth/migrations/0001_initial.py
+++ b/kfet/auth/migrations/0001_initial.py
@@ -7,18 +7,26 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('auth', '0006_require_contenttypes_0002'),
+ ("auth", "0006_require_contenttypes_0002"),
# Following dependency allows using Account model to set up the kfet
# generic user in post_migrate receiver.
- ('kfet', '0058_delete_genericteamtoken'),
+ ("kfet", "0058_delete_genericteamtoken"),
]
operations = [
migrations.CreateModel(
- name='GenericTeamToken',
+ name="GenericTeamToken",
fields=[
- ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)),
- ('token', models.CharField(unique=True, max_length=50)),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ auto_created=True,
+ serialize=False,
+ primary_key=True,
+ ),
+ ),
+ ("token", models.CharField(unique=True, max_length=50)),
],
- ),
+ )
]
diff --git a/kfet/auth/models.py b/kfet/auth/models.py
index ecd40091..73a70c22 100644
--- a/kfet/auth/models.py
+++ b/kfet/auth/models.py
@@ -3,7 +3,6 @@ from django.utils.crypto import get_random_string
class GenericTeamTokenManager(models.Manager):
-
def create_token(self):
token = get_random_string(50)
while self.filter(token=token).exists():
diff --git a/kfet/auth/signals.py b/kfet/auth/signals.py
index 3d7af18b..c13cde09 100644
--- a/kfet/auth/signals.py
+++ b/kfet/auth/signals.py
@@ -19,22 +19,26 @@ def suggest_auth_generic(sender, request, user, **kwargs):
- logged in user is a kfet staff member (except the generic user).
"""
# Filter against the next page.
- if not(hasattr(request, 'GET') and 'next' in request.GET):
+ if not (hasattr(request, "GET") and "next" in request.GET):
return
- next_page = request.GET['next']
- generic_url = reverse('kfet.login.generic')
+ next_page = request.GET["next"]
+ generic_url = reverse("kfet.login.generic")
- if not('k-fet' in next_page and not next_page.startswith(generic_url)):
+ if not ("k-fet" in next_page and not next_page.startswith(generic_url)):
return
# Filter against the logged in user.
- if not(user.has_perm('kfet.is_team') and user != get_kfet_generic_user()):
+ if not (user.has_perm("kfet.is_team") and user != get_kfet_generic_user()):
return
# Seems legit to add message.
text = _("K-Fêt — Ouvrir une session partagée ?")
- messages.info(request, mark_safe(
- '{} '
- .format(generic_url, text)
- ))
+ messages.info(
+ request,
+ mark_safe(
+ '{} '.format(
+ generic_url, text
+ )
+ ),
+ )
diff --git a/kfet/auth/tests.py b/kfet/auth/tests.py
index 62f870e8..e4330eef 100644
--- a/kfet/auth/tests.py
+++ b/kfet/auth/tests.py
@@ -1,8 +1,8 @@
from unittest import mock
+from django.contrib.auth.models import AnonymousUser, Group, Permission, User
from django.core import signing
from django.core.urlresolvers import reverse
-from django.contrib.auth.models import AnonymousUser, Group, Permission, User
from django.test import RequestFactory, TestCase
from kfet.forms import UserGroupForm
@@ -15,11 +15,11 @@ from .models import GenericTeamToken
from .utils import get_kfet_generic_user
from .views import GenericLoginView
-
##
# Forms
##
+
class UserGroupFormTests(TestCase):
"""Test suite for UserGroupForm."""
@@ -31,8 +31,7 @@ class UserGroupFormTests(TestCase):
prefix_name = "K-Fêt "
names = ["Group 1", "Group 2", "Group 3"]
self.kfet_groups = [
- Group.objects.create(name=prefix_name+name)
- for name in names
+ Group.objects.create(name=prefix_name + name) for name in names
]
# create a non-K-Fêt group
@@ -41,11 +40,9 @@ class UserGroupFormTests(TestCase):
def test_choices(self):
"""Only K-Fêt groups are selectable."""
form = UserGroupForm(instance=self.user)
- groups_field = form.fields['groups']
+ groups_field = form.fields["groups"]
self.assertQuerysetEqual(
- groups_field.queryset,
- [repr(g) for g in self.kfet_groups],
- ordered=False,
+ groups_field.queryset, [repr(g) for g in self.kfet_groups], ordered=False
)
def test_keep_others(self):
@@ -56,9 +53,7 @@ class UserGroupFormTests(TestCase):
user.groups.add(self.other_group)
# add user to some K-Fêt groups through UserGroupForm
- data = {
- 'groups': [group.pk for group in self.kfet_groups],
- }
+ data = {"groups": [group.pk for group in self.kfet_groups]}
form = UserGroupForm(data, instance=user)
form.is_valid()
@@ -71,7 +66,6 @@ class UserGroupFormTests(TestCase):
class KFetGenericUserTests(TestCase):
-
def test_exists(self):
"""
The account is set up when app is ready, so it should exist.
@@ -86,44 +80,39 @@ class KFetGenericUserTests(TestCase):
# Backends
##
-class AccountBackendTests(TestCase):
+class AccountBackendTests(TestCase):
def setUp(self):
- self.request = RequestFactory().get('/')
+ self.request = RequestFactory().get("/")
def test_valid(self):
- acc = Account(trigramme='000')
- acc.change_pwd('valid')
- acc.save({'username': 'user'})
+ acc = Account(trigramme="000")
+ acc.change_pwd("valid")
+ acc.save({"username": "user"})
- auth = AccountBackend().authenticate(
- self.request, kfet_password='valid')
+ auth = AccountBackend().authenticate(self.request, kfet_password="valid")
self.assertEqual(auth, acc.user)
def test_invalid(self):
- auth = AccountBackend().authenticate(
- self.request, kfet_password='invalid')
+ auth = AccountBackend().authenticate(self.request, kfet_password="invalid")
self.assertIsNone(auth)
class GenericBackendTests(TestCase):
-
def setUp(self):
- self.request = RequestFactory().get('/')
+ self.request = RequestFactory().get("/")
def test_valid(self):
token = GenericTeamToken.objects.create_token()
- auth = GenericBackend().authenticate(
- self.request, kfet_token=token.token)
+ auth = GenericBackend().authenticate(self.request, kfet_token=token.token)
self.assertEqual(auth, get_kfet_generic_user())
self.assertEqual(GenericTeamToken.objects.all().count(), 0)
def test_invalid(self):
- auth = GenericBackend().authenticate(
- self.request, kfet_token='invalid')
+ auth = GenericBackend().authenticate(self.request, kfet_token="invalid")
self.assertIsNone(auth)
@@ -131,78 +120,74 @@ class GenericBackendTests(TestCase):
# Views
##
-class GenericLoginViewTests(TestCase):
+class GenericLoginViewTests(TestCase):
def setUp(self):
- patcher_messages = mock.patch('gestioncof.signals.messages')
+ patcher_messages = mock.patch("gestioncof.signals.messages")
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
- user_acc = Account(trigramme='000')
- user_acc.save({'username': 'user'})
+ user_acc = Account(trigramme="000")
+ user_acc.save({"username": "user"})
self.user = user_acc.user
- self.user.set_password('user')
+ self.user.set_password("user")
self.user.save()
- team_acc = Account(trigramme='100')
- team_acc.save({'username': 'team'})
+ team_acc = Account(trigramme="100")
+ team_acc.save({"username": "team"})
self.team = team_acc.user
- self.team.set_password('team')
+ self.team.set_password("team")
self.team.save()
self.team.user_permissions.add(
- Permission.objects.get(
- content_type__app_label='kfet', codename='is_team'),
+ Permission.objects.get(content_type__app_label="kfet", codename="is_team")
)
- self.url = reverse('kfet.login.generic')
+ self.url = reverse("kfet.login.generic")
self.generic_user = get_kfet_generic_user()
def test_url(self):
- self.assertEqual(self.url, '/k-fet/login/generic')
+ self.assertEqual(self.url, "/k-fet/login/generic")
def test_notoken_get(self):
"""
Send confirmation for user to emit POST request, instead of GET.
"""
- self.client.login(username='team', password='team')
+ self.client.login(username="team", password="team")
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertTemplateUsed(r, 'kfet/confirm_form.html')
+ self.assertTemplateUsed(r, "kfet/confirm_form.html")
def test_notoken_post(self):
"""
POST request without token in COOKIES sets a token and redirects to
logout url.
"""
- self.client.login(username='team', password='team')
+ self.client.login(username="team", password="team")
r = self.client.post(self.url)
self.assertRedirects(
- r, '/logout?next={}'.format(self.url),
- fetch_redirect_response=False,
+ r, "/logout?next={}".format(self.url), fetch_redirect_response=False
)
def test_notoken_not_team(self):
"""
Logged in user must be a team user to initiate login as generic user.
"""
- self.client.login(username='user', password='user')
+ self.client.login(username="user", password="user")
# With GET.
r = self.client.get(self.url)
self.assertRedirects(
- r, '/login?next={}'.format(self.url),
- fetch_redirect_response=False,
+ r, "/login?next={}".format(self.url), fetch_redirect_response=False
)
# Also with POST.
r = self.client.post(self.url)
self.assertRedirects(
- r, '/login?next={}'.format(self.url),
- fetch_redirect_response=False,
+ r, "/login?next={}".format(self.url), fetch_redirect_response=False
)
def _set_signed_cookie(self, client, key, value):
@@ -216,10 +201,9 @@ class GenericLoginViewTests(TestCase):
try:
cookie = client.cookies[key]
# It also can be emptied.
- self.assertEqual(cookie.value, '')
- self.assertEqual(
- cookie['expires'], 'Thu, 01-Jan-1970 00:00:00 GMT')
- self.assertEqual(cookie['max-age'], 0)
+ self.assertEqual(cookie.value, "")
+ self.assertEqual(cookie["expires"], "Thu, 01-Jan-1970 00:00:00 GMT")
+ self.assertEqual(cookie["max-age"], 0)
except AssertionError:
raise AssertionError("The cookie '%s' still exists." % key)
@@ -227,16 +211,16 @@ class GenericLoginViewTests(TestCase):
"""
The kfet generic user is logged in.
"""
- token = GenericTeamToken.objects.create(token='valid')
+ token = GenericTeamToken.objects.create(token="valid")
self._set_signed_cookie(
- self.client, GenericLoginView.TOKEN_COOKIE_NAME, 'valid')
+ self.client, GenericLoginView.TOKEN_COOKIE_NAME, "valid"
+ )
r = self.client.get(self.url)
- self.assertRedirects(r, reverse('kfet.kpsul'))
+ self.assertRedirects(r, reverse("kfet.kpsul"))
self.assertEqual(r.wsgi_request.user, self.generic_user)
- self._is_cookie_deleted(
- self.client, GenericLoginView.TOKEN_COOKIE_NAME)
+ self._is_cookie_deleted(self.client, GenericLoginView.TOKEN_COOKIE_NAME)
with self.assertRaises(GenericTeamToken.DoesNotExist):
token.refresh_from_db()
@@ -245,27 +229,26 @@ class GenericLoginViewTests(TestCase):
If token is invalid, delete it and try again.
"""
self._set_signed_cookie(
- self.client, GenericLoginView.TOKEN_COOKIE_NAME, 'invalid')
+ self.client, GenericLoginView.TOKEN_COOKIE_NAME, "invalid"
+ )
r = self.client.get(self.url)
self.assertRedirects(r, self.url, fetch_redirect_response=False)
self.assertEqual(r.wsgi_request.user, AnonymousUser())
- self._is_cookie_deleted(
- self.client, GenericLoginView.TOKEN_COOKIE_NAME)
+ self._is_cookie_deleted(self.client, GenericLoginView.TOKEN_COOKIE_NAME)
def test_flow_ok(self):
"""
A team user is logged in as the kfet generic user.
"""
- self.client.login(username='team', password='team')
- next_url = '/k-fet/'
+ self.client.login(username="team", password="team")
+ next_url = "/k-fet/"
- r = self.client.post(
- '{}?next={}'.format(self.url, next_url), follow=True)
+ r = self.client.post("{}?next={}".format(self.url, next_url), follow=True)
self.assertEqual(r.wsgi_request.user, self.generic_user)
- self.assertEqual(r.wsgi_request.path, '/k-fet/')
+ self.assertEqual(r.wsgi_request.path, "/k-fet/")
##
@@ -276,10 +259,10 @@ class GenericLoginViewTests(TestCase):
# - temporary_auth context processor
##
-class TemporaryAuthTests(TestCase):
+class TemporaryAuthTests(TestCase):
def setUp(self):
- patcher_messages = mock.patch('gestioncof.signals.messages')
+ patcher_messages = mock.patch("gestioncof.signals.messages")
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
@@ -287,22 +270,23 @@ class TemporaryAuthTests(TestCase):
self.middleware = TemporaryAuthMiddleware(mock.Mock())
- user1_acc = Account(trigramme='000')
- user1_acc.change_pwd('kfet_user1')
- user1_acc.save({'username': 'user1'})
+ user1_acc = Account(trigramme="000")
+ user1_acc.change_pwd("kfet_user1")
+ user1_acc.save({"username": "user1"})
self.user1 = user1_acc.user
- self.user1.set_password('user1')
+ self.user1.set_password("user1")
self.user1.save()
- user2_acc = Account(trigramme='100')
- user2_acc.change_pwd('kfet_user2')
- user2_acc.save({'username': 'user2'})
+ user2_acc = Account(trigramme="100")
+ user2_acc.change_pwd("kfet_user2")
+ user2_acc.save({"username": "user2"})
self.user2 = user2_acc.user
- self.user2.set_password('user2')
+ self.user2.set_password("user2")
self.user2.save()
self.perm = Permission.objects.get(
- content_type__app_label='kfet', codename='is_team')
+ content_type__app_label="kfet", codename="is_team"
+ )
self.user2.user_permissions.add(self.perm)
def test_middleware_header(self):
@@ -310,7 +294,7 @@ class TemporaryAuthTests(TestCase):
A user can be authenticated if ``HTTP_KFETPASSWORD`` header of a
request contains a valid kfet password.
"""
- request = self.factory.get('/', HTTP_KFETPASSWORD='kfet_user2')
+ request = self.factory.get("/", HTTP_KFETPASSWORD="kfet_user2")
request.user = self.user1
self.middleware(request)
@@ -323,7 +307,7 @@ class TemporaryAuthTests(TestCase):
A user can be authenticated if ``KFETPASSWORD`` of POST data contains
a valid kfet password.
"""
- request = self.factory.post('/', {'KFETPASSWORD': 'kfet_user2'})
+ request = self.factory.post("/", {"KFETPASSWORD": "kfet_user2"})
request.user = self.user1
self.middleware(request)
@@ -335,34 +319,33 @@ class TemporaryAuthTests(TestCase):
"""
The given password must be a password of an Account.
"""
- request = self.factory.post('/', {'KFETPASSWORD': 'invalid'})
+ request = self.factory.post("/", {"KFETPASSWORD": "invalid"})
request.user = self.user1
self.middleware(request)
self.assertEqual(request.user, self.user1)
- self.assertFalse(hasattr(request, 'real_user'))
+ self.assertFalse(hasattr(request, "real_user"))
def test_context_processor(self):
"""
Context variables give the real authenticated user and his permissions.
"""
- self.client.login(username='user1', password='user1')
+ self.client.login(username="user1", password="user1")
- r = self.client.get('/k-fet/accounts/', HTTP_KFETPASSWORD='kfet_user2')
+ r = self.client.get("/k-fet/accounts/", HTTP_KFETPASSWORD="kfet_user2")
- self.assertEqual(r.context['user'], self.user1)
- self.assertNotIn('kfet.is_team', r.context['perms'])
+ self.assertEqual(r.context["user"], self.user1)
+ self.assertNotIn("kfet.is_team", r.context["perms"])
def test_auth_not_persistent(self):
"""
The authentication is temporary, i.e. for one request.
"""
- self.client.login(username='user1', password='user1')
+ self.client.login(username="user1", password="user1")
- r1 = self.client.get(
- '/k-fet/accounts/', HTTP_KFETPASSWORD='kfet_user2')
+ r1 = self.client.get("/k-fet/accounts/", HTTP_KFETPASSWORD="kfet_user2")
self.assertEqual(r1.wsgi_request.user, self.user2)
- r2 = self.client.get('/k-fet/accounts/')
+ r2 = self.client.get("/k-fet/accounts/")
self.assertEqual(r2.wsgi_request.user, self.user1)
diff --git a/kfet/auth/utils.py b/kfet/auth/utils.py
index 0edc555d..ed63bb67 100644
--- a/kfet/auth/utils.py
+++ b/kfet/auth/utils.py
@@ -23,12 +23,9 @@ def setup_kfet_generic_user(**kwargs):
"""
generic = get_kfet_generic_user()
generic.user_permissions.add(
- Permission.objects.get(
- content_type__app_label='kfet',
- codename='is_team',
- )
+ Permission.objects.get(content_type__app_label="kfet", codename="is_team")
)
def hash_password(password):
- return hashlib.sha256(password.encode('utf-8')).hexdigest()
+ return hashlib.sha256(password.encode("utf-8")).hexdigest()
diff --git a/kfet/auth/views.py b/kfet/auth/views.py
index 7b9f4099..35a6eedf 100644
--- a/kfet/auth/views.py
+++ b/kfet/auth/views.py
@@ -1,17 +1,17 @@
from django.contrib import messages
-from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import Group, User
from django.contrib.auth.views import redirect_to_login
+from django.contrib.messages.views import SuccessMessageMixin
from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import Prefetch
from django.http import QueryDict
from django.shortcuts import redirect, render
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
-from django.views.generic import View
from django.views.decorators.http import require_http_methods
+from django.views.generic import View
from django.views.generic.edit import CreateView, UpdateView
from .forms import GroupForm
@@ -30,28 +30,33 @@ class GenericLoginView(View):
provider, which can be external. Session is unusable as it will be cleared
on logout.
"""
- TOKEN_COOKIE_NAME = 'kfettoken'
- @method_decorator(require_http_methods(['GET', 'POST']))
+ TOKEN_COOKIE_NAME = "kfettoken"
+
+ @method_decorator(require_http_methods(["GET", "POST"]))
def dispatch(self, request, *args, **kwargs):
token = request.get_signed_cookie(self.TOKEN_COOKIE_NAME, None)
if not token:
- if not request.user.has_perm('kfet.is_team'):
+ if not request.user.has_perm("kfet.is_team"):
return redirect_to_login(request.get_full_path())
- if request.method == 'POST':
+ if request.method == "POST":
# Step 1: set token and logout user.
return self.prepare_auth()
else:
# GET request should not change server/client states. Send a
# confirmation template to emit a POST request.
- return render(request, 'kfet/confirm_form.html', {
- 'title': _("Ouvrir une session partagée"),
- 'text': _(
- "Êtes-vous sûr·e de vouloir ouvrir une session "
- "partagée ?"
- ),
- })
+ return render(
+ request,
+ "kfet/confirm_form.html",
+ {
+ "title": _("Ouvrir une session partagée"),
+ "text": _(
+ "Êtes-vous sûr·e de vouloir ouvrir une session "
+ "partagée ?"
+ ),
+ },
+ )
else:
# Step 2: validate token.
return self.validate_auth(token)
@@ -62,20 +67,19 @@ class GenericLoginView(View):
# Prepare callback of logout.
here_url = reverse(login_generic)
- if 'next' in self.request.GET:
+ if "next" in self.request.GET:
# Keep given next page.
here_qd = QueryDict(mutable=True)
- here_qd['next'] = self.request.GET['next']
- here_url += '?{}'.format(here_qd.urlencode())
+ here_qd["next"] = self.request.GET["next"]
+ here_url += "?{}".format(here_qd.urlencode())
- logout_url = reverse('cof-logout')
+ logout_url = reverse("cof-logout")
logout_qd = QueryDict(mutable=True)
- logout_qd['next'] = here_url
- logout_url += '?{}'.format(logout_qd.urlencode(safe='/'))
+ logout_qd["next"] = here_url
+ logout_url += "?{}".format(logout_qd.urlencode(safe="/"))
resp = redirect(logout_url)
- resp.set_signed_cookie(
- self.TOKEN_COOKIE_NAME, token.token, httponly=True)
+ resp.set_signed_cookie(self.TOKEN_COOKIE_NAME, token.token, httponly=True)
return resp
def validate_auth(self, token):
@@ -85,9 +89,9 @@ class GenericLoginView(View):
if user:
# Log in generic user.
login(self.request, user)
- messages.success(self.request, _(
- "K-Fêt — Ouverture d'une session partagée."
- ))
+ messages.success(
+ self.request, _("K-Fêt — Ouverture d'une session partagée.")
+ )
resp = redirect(self.get_next_url())
else:
# Try again.
@@ -98,39 +102,34 @@ class GenericLoginView(View):
return resp
def get_next_url(self):
- return self.request.GET.get('next', reverse('kfet.kpsul'))
+ return self.request.GET.get("next", reverse("kfet.kpsul"))
login_generic = GenericLoginView.as_view()
-@permission_required('kfet.manage_perms')
+@permission_required("kfet.manage_perms")
def account_group(request):
user_pre = Prefetch(
- 'user_set',
- queryset=User.objects.select_related('profile__account_kfet'),
+ "user_set", queryset=User.objects.select_related("profile__account_kfet")
)
- groups = (
- Group.objects
- .filter(name__icontains='K-Fêt')
- .prefetch_related('permissions', user_pre)
+ groups = Group.objects.filter(name__icontains="K-Fêt").prefetch_related(
+ "permissions", user_pre
)
- return render(request, 'kfet/account_group.html', {
- 'groups': groups,
- })
+ return render(request, "kfet/account_group.html", {"groups": groups})
class AccountGroupCreate(SuccessMessageMixin, CreateView):
model = Group
- template_name = 'kfet/account_group_form.html'
+ template_name = "kfet/account_group_form.html"
form_class = GroupForm
- success_message = 'Nouveau groupe : %(name)s'
- success_url = reverse_lazy('kfet.account.group')
+ success_message = "Nouveau groupe : %(name)s"
+ success_url = reverse_lazy("kfet.account.group")
class AccountGroupUpdate(SuccessMessageMixin, UpdateView):
- queryset = Group.objects.filter(name__icontains='K-Fêt')
- template_name = 'kfet/account_group_form.html'
+ queryset = Group.objects.filter(name__icontains="K-Fêt")
+ template_name = "kfet/account_group_form.html"
form_class = GroupForm
- success_message = 'Groupe modifié : %(name)s'
- success_url = reverse_lazy('kfet.account.group')
+ success_message = "Groupe modifié : %(name)s"
+ success_url = reverse_lazy("kfet.account.group")
diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py
index 0d1904d6..d7448194 100644
--- a/kfet/autocomplete.py
+++ b/kfet/autocomplete.py
@@ -1,8 +1,8 @@
-from ldap3 import Connection
-from django.shortcuts import render
-from django.http import Http404
-from django.db.models import Q
from django.conf import settings
+from django.db.models import Q
+from django.http import Http404
+from django.shortcuts import render
+from ldap3 import Connection
from gestioncof.models import User
from kfet.decorators import teamkfet_required
@@ -25,81 +25,80 @@ def account_create(request):
raise Http404
q = request.GET.get("q")
- if (len(q) == 0):
+ if len(q) == 0:
return render(request, "kfet/account_create_autocomplete.html")
- data = {'q': q}
+ data = {"q": q}
queries = {}
search_words = q.split()
# Fetching data from User, CofProfile and Account tables
- queries['kfet'] = Account.objects
- queries['users_cof'] = User.objects.filter(profile__is_cof=True)
- queries['users_notcof'] = User.objects.filter(profile__is_cof=False)
+ queries["kfet"] = Account.objects
+ queries["users_cof"] = User.objects.filter(profile__is_cof=True)
+ queries["users_notcof"] = User.objects.filter(profile__is_cof=False)
for word in search_words:
- queries['kfet'] = queries['kfet'].filter(
+ queries["kfet"] = queries["kfet"].filter(
Q(cofprofile__user__username__icontains=word)
| Q(cofprofile__user__first_name__icontains=word)
| Q(cofprofile__user__last_name__icontains=word)
)
- queries['users_cof'] = queries['users_cof'].filter(
+ queries["users_cof"] = queries["users_cof"].filter(
Q(username__icontains=word)
| Q(first_name__icontains=word)
| Q(last_name__icontains=word)
)
- queries['users_notcof'] = queries['users_notcof'].filter(
+ queries["users_notcof"] = queries["users_notcof"].filter(
Q(username__icontains=word)
| Q(first_name__icontains=word)
| Q(last_name__icontains=word)
)
# Clearing redundancies
- queries['kfet'] = queries['kfet'].distinct()
+ queries["kfet"] = queries["kfet"].distinct()
usernames = set(
- queries['kfet'].values_list('cofprofile__user__username', flat=True))
- queries['kfet'] = [
- (account, account.cofprofile.user)
- for account in queries['kfet']
+ queries["kfet"].values_list("cofprofile__user__username", flat=True)
+ )
+ queries["kfet"] = [
+ (account, account.cofprofile.user) for account in queries["kfet"]
]
- queries['users_cof'] = \
- queries['users_cof'].exclude(username__in=usernames).distinct()
- queries['users_notcof'] = \
- queries['users_notcof'].exclude(username__in=usernames).distinct()
- usernames |= set(
- queries['users_cof'].values_list('username', flat=True))
- usernames |= set(
- queries['users_notcof'].values_list('username', flat=True))
+ queries["users_cof"] = (
+ queries["users_cof"].exclude(username__in=usernames).distinct()
+ )
+ queries["users_notcof"] = (
+ queries["users_notcof"].exclude(username__in=usernames).distinct()
+ )
+ usernames |= set(queries["users_cof"].values_list("username", flat=True))
+ usernames |= set(queries["users_notcof"].values_list("username", flat=True))
# Fetching data from the SPI
- if getattr(settings, 'LDAP_SERVER_URL', None):
+ if getattr(settings, "LDAP_SERVER_URL", None):
# Fetching
- ldap_query = '(&{:s})'.format(''.join(
- '(|(cn=*{bit:s}*)(uid=*{bit:s}*))'.format(bit=word)
- for word in search_words if word.isalnum()
- ))
+ ldap_query = "(&{:s})".format(
+ "".join(
+ "(|(cn=*{bit:s}*)(uid=*{bit:s}*))".format(bit=word)
+ for word in search_words
+ if word.isalnum()
+ )
+ )
if ldap_query != "(&)":
# If none of the bits were legal, we do not perform the query
entries = None
with Connection(settings.LDAP_SERVER_URL) as conn:
- conn.search(
- 'dc=spi,dc=ens,dc=fr', ldap_query,
- attributes=['uid', 'cn']
- )
+ conn.search("dc=spi,dc=ens,dc=fr", ldap_query, attributes=["uid", "cn"])
entries = conn.entries
# Clearing redundancies
- queries['clippers'] = [
+ queries["clippers"] = [
Clipper(entry.uid.value, entry.cn.value)
for entry in entries
- if entry.uid.value
- and entry.uid.value not in usernames
+ if entry.uid.value and entry.uid.value not in usernames
]
# Resulting data
data.update(queries)
- data['options'] = sum([len(query) for query in queries])
+ data["options"] = sum([len(query) for query in queries])
return render(request, "kfet/account_create_autocomplete.html", data)
@@ -111,17 +110,19 @@ def account_search(request):
q = request.GET.get("q")
words = q.split()
- data = {'q': q}
+ data = {"q": q}
for word in words:
query = Account.objects.filter(
- Q(cofprofile__user__username__icontains=word) |
- Q(cofprofile__user__first_name__icontains=word) |
- Q(cofprofile__user__last_name__icontains=word)
- ).distinct()
+ Q(cofprofile__user__username__icontains=word)
+ | Q(cofprofile__user__first_name__icontains=word)
+ | Q(cofprofile__user__last_name__icontains=word)
+ ).distinct()
- query = [(account.trigramme, account.cofprofile.user.get_full_name())
- for account in query]
+ query = [
+ (account.trigramme, account.cofprofile.user.get_full_name())
+ for account in query
+ ]
- data['accounts'] = query
- return render(request, 'kfet/account_search_autocomplete.html', data)
+ data["accounts"] = query
+ return render(request, "kfet/account_search_autocomplete.html", data)
diff --git a/kfet/cms/__init__.py b/kfet/cms/__init__.py
index 0f6cab45..f6aabddc 100644
--- a/kfet/cms/__init__.py
+++ b/kfet/cms/__init__.py
@@ -1 +1 @@
-default_app_config = 'kfet.cms.apps.KFetCMSAppConfig'
+default_app_config = "kfet.cms.apps.KFetCMSAppConfig"
diff --git a/kfet/cms/apps.py b/kfet/cms/apps.py
index 1db0e043..d675cbb5 100644
--- a/kfet/cms/apps.py
+++ b/kfet/cms/apps.py
@@ -2,9 +2,9 @@ from django.apps import AppConfig
class KFetCMSAppConfig(AppConfig):
- name = 'kfet.cms'
- label = 'kfetcms'
- verbose_name = 'CMS K-Fêt'
+ name = "kfet.cms"
+ label = "kfetcms"
+ verbose_name = "CMS K-Fêt"
def ready(self):
- from . import hooks
+ from . import hooks # noqa
diff --git a/kfet/cms/context_processors.py b/kfet/cms/context_processors.py
index 34f175d1..700170ee 100644
--- a/kfet/cms/context_processors.py
+++ b/kfet/cms/context_processors.py
@@ -3,18 +3,14 @@ from kfet.models import Article
def get_articles(request=None):
articles = (
- Article.objects
- .filter(is_sold=True, hidden=False)
- .select_related('category')
- .order_by('category__name', 'name')
+ Article.objects.filter(is_sold=True, hidden=False)
+ .select_related("category")
+ .order_by("category__name", "name")
)
pressions, others = [], []
for article in articles:
- if article.category.name == 'Pression':
+ if article.category.name == "Pression":
pressions.append(article)
else:
others.append(article)
- return {
- 'pressions': pressions,
- 'articles': others,
- }
+ return {"pressions": pressions, "articles": others}
diff --git a/kfet/cms/hooks.py b/kfet/cms/hooks.py
index e58aeef5..a3070cfb 100644
--- a/kfet/cms/hooks.py
+++ b/kfet/cms/hooks.py
@@ -1,12 +1,10 @@
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.utils.html import format_html
-
from wagtail.wagtailcore import hooks
-@hooks.register('insert_editor_css')
+@hooks.register("insert_editor_css")
def editor_css():
return format_html(
- ' ',
- static('kfetcms/css/editor.css'),
+ ' ', static("kfetcms/css/editor.css")
)
diff --git a/kfet/cms/management/commands/kfet_loadwagtail.py b/kfet/cms/management/commands/kfet_loadwagtail.py
index 86b94d3e..566cca43 100644
--- a/kfet/cms/management/commands/kfet_loadwagtail.py
+++ b/kfet/cms/management/commands/kfet_loadwagtail.py
@@ -1,7 +1,6 @@
from django.contrib.auth.models import Group
from django.core.management import call_command
from django.core.management.base import BaseCommand
-
from wagtail.wagtailcore.models import Page, Site
@@ -9,7 +8,7 @@ class Command(BaseCommand):
help = "Importe des données pour Wagtail"
def add_arguments(self, parser):
- parser.add_argument('--file', default='kfet_wagtail_17_05')
+ parser.add_argument("--file", default="kfet_wagtail_17_05")
def handle(self, *args, **options):
@@ -18,12 +17,10 @@ class Command(BaseCommand):
# Nettoyage des données initiales posées par Wagtail dans la migration
# wagtailcore/0002
- Group.objects.filter(name__in=('Moderators', 'Editors')).delete()
+ Group.objects.filter(name__in=("Moderators", "Editors")).delete()
try:
- homepage = Page.objects.get(
- title="Welcome to your new Wagtail site!"
- )
+ homepage = Page.objects.get(title="Welcome to your new Wagtail site!")
homepage.delete()
Site.objects.filter(root_page=homepage).delete()
except Page.DoesNotExist:
@@ -32,4 +29,4 @@ class Command(BaseCommand):
# Import des données
# Par défaut, il s'agit d'une copie du site K-Fêt (17-05)
- call_command('loaddata', options['file'])
+ call_command("loaddata", options["file"])
diff --git a/kfet/cms/migrations/0001_initial.py b/kfet/cms/migrations/0001_initial.py
index ed0b0948..8c075903 100644
--- a/kfet/cms/migrations/0001_initial.py
+++ b/kfet/cms/migrations/0001_initial.py
@@ -1,49 +1,214 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
-import wagtail.wagtailsnippets.blocks
+import django.db.models.deletion
import wagtail.wagtailcore.blocks
import wagtail.wagtailcore.fields
-import django.db.models.deletion
+import wagtail.wagtailsnippets.blocks
+from django.db import migrations, models
+
import kfet.cms.models
class Migration(migrations.Migration):
dependencies = [
- ('wagtailcore', '0033_remove_golive_expiry_help_text'),
- ('wagtailimages', '0019_delete_filter'),
+ ("wagtailcore", "0033_remove_golive_expiry_help_text"),
+ ("wagtailimages", "0019_delete_filter"),
]
operations = [
migrations.CreateModel(
- name='KFetPage',
+ name="KFetPage",
fields=[
- ('page_ptr', models.OneToOneField(serialize=False, primary_key=True, parent_link=True, auto_created=True, to='wagtailcore.Page', on_delete=models.CASCADE)),
- ('no_header', models.BooleanField(verbose_name='Sans en-tête', help_text="Coché, l'en-tête (avec le titre) de la page n'est pas affiché.", default=False)),
- ('content', wagtail.wagtailcore.fields.StreamField((('rich', wagtail.wagtailcore.blocks.RichTextBlock(label='Éditeur')), ('carte', kfet.cms.models.MenuBlock()), ('group_team', wagtail.wagtailcore.blocks.StructBlock((('show_only', wagtail.wagtailcore.blocks.IntegerBlock(help_text='Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.', required=False, label='Montrer seulement')), ('members', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailsnippets.blocks.SnippetChooserBlock(kfet.cms.models.MemberTeam), classname='team-group', label='K-Fêt-eux-ses'))))), ('group', wagtail.wagtailcore.blocks.StreamBlock((('rich', wagtail.wagtailcore.blocks.RichTextBlock(label='Éditeur')), ('carte', kfet.cms.models.MenuBlock()), ('group_team', wagtail.wagtailcore.blocks.StructBlock((('show_only', wagtail.wagtailcore.blocks.IntegerBlock(help_text='Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.', required=False, label='Montrer seulement')), ('members', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailsnippets.blocks.SnippetChooserBlock(kfet.cms.models.MemberTeam), classname='team-group', label='K-Fêt-eux-ses')))))), label='Contenu groupé'))), verbose_name='Contenu')),
- ('layout', models.CharField(max_length=255, choices=[('kfet/base_col_1.html', 'Une colonne : centrée sur la page'), ('kfet/base_col_2.html', 'Deux colonnes : fixe à gauche, contenu à droite'), ('kfet/base_col_mult.html', 'Contenu scindé sur plusieurs colonnes')], help_text='Comment cette page devrait être affichée ?', verbose_name='Template', default='kfet/base_col_mult.html')),
- ('main_size', models.CharField(max_length=255, blank=True, verbose_name='Taille de la colonne de contenu')),
- ('col_count', models.CharField(max_length=255, blank=True, verbose_name='Nombre de colonnes', help_text="S'applique au page dont le contenu est scindé sur plusieurs colonnes")),
+ (
+ "page_ptr",
+ models.OneToOneField(
+ serialize=False,
+ primary_key=True,
+ parent_link=True,
+ auto_created=True,
+ to="wagtailcore.Page",
+ on_delete=models.CASCADE,
+ ),
+ ),
+ (
+ "no_header",
+ models.BooleanField(
+ verbose_name="Sans en-tête",
+ help_text="Coché, l'en-tête (avec le titre) de la page n'est pas affiché.",
+ default=False,
+ ),
+ ),
+ (
+ "content",
+ wagtail.wagtailcore.fields.StreamField(
+ (
+ (
+ "rich",
+ wagtail.wagtailcore.blocks.RichTextBlock(
+ label="Éditeur"
+ ),
+ ),
+ ("carte", kfet.cms.models.MenuBlock()),
+ (
+ "group_team",
+ wagtail.wagtailcore.blocks.StructBlock(
+ (
+ (
+ "show_only",
+ wagtail.wagtailcore.blocks.IntegerBlock(
+ help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",
+ required=False,
+ label="Montrer seulement",
+ ),
+ ),
+ (
+ "members",
+ wagtail.wagtailcore.blocks.ListBlock(
+ wagtail.wagtailsnippets.blocks.SnippetChooserBlock(
+ kfet.cms.models.MemberTeam
+ ),
+ classname="team-group",
+ label="K-Fêt-eux-ses",
+ ),
+ ),
+ )
+ ),
+ ),
+ (
+ "group",
+ wagtail.wagtailcore.blocks.StreamBlock(
+ (
+ (
+ "rich",
+ wagtail.wagtailcore.blocks.RichTextBlock(
+ label="Éditeur"
+ ),
+ ),
+ ("carte", kfet.cms.models.MenuBlock()),
+ (
+ "group_team",
+ wagtail.wagtailcore.blocks.StructBlock(
+ (
+ (
+ "show_only",
+ wagtail.wagtailcore.blocks.IntegerBlock(
+ help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",
+ required=False,
+ label="Montrer seulement",
+ ),
+ ),
+ (
+ "members",
+ wagtail.wagtailcore.blocks.ListBlock(
+ wagtail.wagtailsnippets.blocks.SnippetChooserBlock(
+ kfet.cms.models.MemberTeam
+ ),
+ classname="team-group",
+ label="K-Fêt-eux-ses",
+ ),
+ ),
+ )
+ ),
+ ),
+ ),
+ label="Contenu groupé",
+ ),
+ ),
+ ),
+ verbose_name="Contenu",
+ ),
+ ),
+ (
+ "layout",
+ models.CharField(
+ max_length=255,
+ choices=[
+ (
+ "kfet/base_col_1.html",
+ "Une colonne : centrée sur la page",
+ ),
+ (
+ "kfet/base_col_2.html",
+ "Deux colonnes : fixe à gauche, contenu à droite",
+ ),
+ (
+ "kfet/base_col_mult.html",
+ "Contenu scindé sur plusieurs colonnes",
+ ),
+ ],
+ help_text="Comment cette page devrait être affichée ?",
+ verbose_name="Template",
+ default="kfet/base_col_mult.html",
+ ),
+ ),
+ (
+ "main_size",
+ models.CharField(
+ max_length=255,
+ blank=True,
+ verbose_name="Taille de la colonne de contenu",
+ ),
+ ),
+ (
+ "col_count",
+ models.CharField(
+ max_length=255,
+ blank=True,
+ verbose_name="Nombre de colonnes",
+ help_text="S'applique au page dont le contenu est scindé sur plusieurs colonnes",
+ ),
+ ),
],
options={
- 'verbose_name': 'page K-Fêt',
- 'verbose_name_plural': 'pages K-Fêt',
+ "verbose_name": "page K-Fêt",
+ "verbose_name_plural": "pages K-Fêt",
},
- bases=('wagtailcore.page',),
+ bases=("wagtailcore.page",),
),
migrations.CreateModel(
- name='MemberTeam',
+ name="MemberTeam",
fields=[
- ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)),
- ('first_name', models.CharField(blank=True, max_length=255, verbose_name='Prénom', default='')),
- ('last_name', models.CharField(blank=True, max_length=255, verbose_name='Nom', default='')),
- ('nick_name', models.CharField(verbose_name='Alias', blank=True, default='', max_length=255)),
- ('photo', models.ForeignKey(null=True, related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='Photo', blank=True, to='wagtailimages.Image')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ auto_created=True,
+ serialize=False,
+ primary_key=True,
+ ),
+ ),
+ (
+ "first_name",
+ models.CharField(
+ blank=True, max_length=255, verbose_name="Prénom", default=""
+ ),
+ ),
+ (
+ "last_name",
+ models.CharField(
+ blank=True, max_length=255, verbose_name="Nom", default=""
+ ),
+ ),
+ (
+ "nick_name",
+ models.CharField(
+ verbose_name="Alias", blank=True, default="", max_length=255
+ ),
+ ),
+ (
+ "photo",
+ models.ForeignKey(
+ null=True,
+ related_name="+",
+ on_delete=django.db.models.deletion.SET_NULL,
+ verbose_name="Photo",
+ blank=True,
+ to="wagtailimages.Image",
+ ),
+ ),
],
- options={
- 'verbose_name': 'K-Fêt-eux-se',
- },
+ options={"verbose_name": "K-Fêt-eux-se"},
),
]
diff --git a/kfet/cms/migrations/0002_alter_kfetpage_colcount.py b/kfet/cms/migrations/0002_alter_kfetpage_colcount.py
index fe91d3e6..4eace262 100644
--- a/kfet/cms/migrations/0002_alter_kfetpage_colcount.py
+++ b/kfet/cms/migrations/0002_alter_kfetpage_colcount.py
@@ -6,14 +6,17 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfetcms', '0001_initial'),
- ]
+ dependencies = [("kfetcms", "0001_initial")]
operations = [
migrations.AlterField(
- model_name='kfetpage',
- name='col_count',
- field=models.CharField(blank=True, max_length=255, verbose_name='Nombre de colonnes', help_text="S'applique au page dont le contenu est scindé sur plusieurs colonnes."),
- ),
+ model_name="kfetpage",
+ name="col_count",
+ field=models.CharField(
+ blank=True,
+ max_length=255,
+ verbose_name="Nombre de colonnes",
+ help_text="S'applique au page dont le contenu est scindé sur plusieurs colonnes.",
+ ),
+ )
]
diff --git a/kfet/cms/models.py b/kfet/cms/models.py
index 0dff183f..6d108f31 100644
--- a/kfet/cms/models.py
+++ b/kfet/cms/models.py
@@ -1,8 +1,10 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
-
from wagtail.wagtailadmin.edit_handlers import (
- FieldPanel, FieldRowPanel, MultiFieldPanel, StreamFieldPanel
+ FieldPanel,
+ FieldRowPanel,
+ MultiFieldPanel,
+ StreamFieldPanel,
)
from wagtail.wagtailcore import blocks
from wagtail.wagtailcore.fields import StreamField
@@ -17,47 +19,45 @@ from kfet.cms.context_processors import get_articles
@register_snippet
class MemberTeam(models.Model):
first_name = models.CharField(
- verbose_name=_('Prénom'),
- blank=True, default='', max_length=255,
+ verbose_name=_("Prénom"), blank=True, default="", max_length=255
)
last_name = models.CharField(
- verbose_name=_('Nom'),
- blank=True, default='', max_length=255,
+ verbose_name=_("Nom"), blank=True, default="", max_length=255
)
nick_name = models.CharField(
- verbose_name=_('Alias'),
- blank=True, default='', max_length=255,
+ verbose_name=_("Alias"), blank=True, default="", max_length=255
)
photo = models.ForeignKey(
- 'wagtailimages.Image',
- verbose_name=_('Photo'),
+ "wagtailimages.Image",
+ verbose_name=_("Photo"),
on_delete=models.SET_NULL,
- null=True, blank=True,
- related_name='+',
+ null=True,
+ blank=True,
+ related_name="+",
)
class Meta:
- verbose_name = _('K-Fêt-eux-se')
+ verbose_name = _("K-Fêt-eux-se")
panels = [
- FieldPanel('first_name'),
- FieldPanel('last_name'),
- FieldPanel('nick_name'),
- ImageChooserPanel('photo'),
+ FieldPanel("first_name"),
+ FieldPanel("last_name"),
+ FieldPanel("nick_name"),
+ ImageChooserPanel("photo"),
]
def __str__(self):
return self.get_full_name()
def get_full_name(self):
- return '{} {}'.format(self.first_name, self.last_name).strip()
+ return "{} {}".format(self.first_name, self.last_name).strip()
class MenuBlock(blocks.StaticBlock):
class Meta:
- icon = 'list-ul'
- label = _('Carte')
- template = 'kfetcms/block_menu.html'
+ icon = "list-ul"
+ label = _("Carte")
+ template = "kfetcms/block_menu.html"
def get_context(self, *args, **kwargs):
context = super().get_context(*args, **kwargs)
@@ -67,71 +67,68 @@ class MenuBlock(blocks.StaticBlock):
class GroupTeamBlock(blocks.StructBlock):
show_only = blocks.IntegerBlock(
- label=_('Montrer seulement'),
+ label=_("Montrer seulement"),
required=False,
help_text=_(
- 'Nombre initial de membres affichés. Laisser vide pour tou-te-s '
- 'les afficher.'
+ "Nombre initial de membres affichés. Laisser vide pour tou-te-s "
+ "les afficher."
),
)
members = blocks.ListBlock(
SnippetChooserBlock(MemberTeam),
- label=_('K-Fêt-eux-ses'),
- classname='team-group',
+ label=_("K-Fêt-eux-ses"),
+ classname="team-group",
)
class Meta:
- icon = 'group'
- label = _('Groupe de K-Fêt-eux-ses')
- template = 'kfetcms/block_teamgroup.html'
+ icon = "group"
+ label = _("Groupe de K-Fêt-eux-ses")
+ template = "kfetcms/block_teamgroup.html"
class ChoicesStreamBlock(blocks.StreamBlock):
- rich = blocks.RichTextBlock(label=_('Éditeur'))
+ rich = blocks.RichTextBlock(label=_("Éditeur"))
carte = MenuBlock()
group_team = GroupTeamBlock()
class KFetStreamBlock(ChoicesStreamBlock):
- group = ChoicesStreamBlock(label=_('Contenu groupé'))
+ group = ChoicesStreamBlock(label=_("Contenu groupé"))
class KFetPage(Page):
- content = StreamField(KFetStreamBlock, verbose_name=_('Contenu'))
+ content = StreamField(KFetStreamBlock, verbose_name=_("Contenu"))
# Layout fields
- TEMPLATE_COL_1 = 'kfet/base_col_1.html'
- TEMPLATE_COL_2 = 'kfet/base_col_2.html'
- TEMPLATE_COL_MULT = 'kfet/base_col_mult.html'
+ TEMPLATE_COL_1 = "kfet/base_col_1.html"
+ TEMPLATE_COL_2 = "kfet/base_col_2.html"
+ TEMPLATE_COL_MULT = "kfet/base_col_mult.html"
no_header = models.BooleanField(
- verbose_name=_('Sans en-tête'),
+ verbose_name=_("Sans en-tête"),
default=False,
- help_text=_(
- "Coché, l'en-tête (avec le titre) de la page n'est pas affiché."
- ),
+ help_text=_("Coché, l'en-tête (avec le titre) de la page n'est pas affiché."),
)
layout = models.CharField(
- verbose_name=_('Template'),
+ verbose_name=_("Template"),
choices=[
- (TEMPLATE_COL_1, _('Une colonne : centrée sur la page')),
- (TEMPLATE_COL_2, _('Deux colonnes : fixe à gauche, contenu à droite')),
- (TEMPLATE_COL_MULT, _('Contenu scindé sur plusieurs colonnes')),
+ (TEMPLATE_COL_1, _("Une colonne : centrée sur la page")),
+ (TEMPLATE_COL_2, _("Deux colonnes : fixe à gauche, contenu à droite")),
+ (TEMPLATE_COL_MULT, _("Contenu scindé sur plusieurs colonnes")),
],
- default=TEMPLATE_COL_MULT, max_length=255,
- help_text=_(
- "Comment cette page devrait être affichée ?"
- ),
+ default=TEMPLATE_COL_MULT,
+ max_length=255,
+ help_text=_("Comment cette page devrait être affichée ?"),
)
main_size = models.CharField(
- verbose_name=_('Taille de la colonne de contenu'),
- blank=True, max_length=255,
+ verbose_name=_("Taille de la colonne de contenu"), blank=True, max_length=255
)
col_count = models.CharField(
- verbose_name=_('Nombre de colonnes'),
- blank=True, max_length=255,
+ verbose_name=_("Nombre de colonnes"),
+ blank=True,
+ max_length=255,
help_text=_(
"S'applique au page dont le contenu est scindé sur plusieurs colonnes."
),
@@ -139,34 +136,29 @@ class KFetPage(Page):
# Panels
- content_panels = Page.content_panels + [
- StreamFieldPanel('content'),
- ]
+ content_panels = Page.content_panels + [StreamFieldPanel("content")]
layout_panel = [
- FieldPanel('no_header'),
- FieldPanel('layout'),
- FieldRowPanel([
- FieldPanel('main_size'),
- FieldPanel('col_count'),
- ]),
+ FieldPanel("no_header"),
+ FieldPanel("layout"),
+ FieldRowPanel([FieldPanel("main_size"), FieldPanel("col_count")]),
]
settings_panels = [
- MultiFieldPanel(layout_panel, _('Affichage'))
+ MultiFieldPanel(layout_panel, _("Affichage"))
] + Page.settings_panels
# Base template
template = "kfetcms/base.html"
class Meta:
- verbose_name = _('page K-Fêt')
- verbose_name_plural = _('pages K-Fêt')
+ verbose_name = _("page K-Fêt")
+ verbose_name_plural = _("pages K-Fêt")
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
- page = context['page']
+ page = context["page"]
if not page.seo_title:
page.seo_title = page.title
diff --git a/kfet/config.py b/kfet/config.py
index f248b370..a8f7f0eb 100644
--- a/kfet/config.py
+++ b/kfet/config.py
@@ -1,25 +1,39 @@
+import djconfig
from django.core.exceptions import ValidationError
from django.db import models
-from djconfig import config
-
class KFetConfig(object):
"""kfet app configuration.
Enhance isolation with backend used to store config.
- Usable after DjConfig middleware was called.
"""
- prefix = 'kfet_'
+
+ prefix = "kfet_"
+
+ def __init__(self):
+ # Set this to False again to reload the config, e.g for testing
+ # purposes.
+ self._conf_init = False
+
+ def _check_init(self):
+ # For initialization purposes, we call 'reload_maybe' directly
+ # (normaly done once per request in middleware).
+ # Note it should be called only once across requests, if you use
+ # kfet_config instance below.
+ if not self._conf_init:
+ djconfig.reload_maybe()
+ self._conf_init = True
def __getattr__(self, key):
- if key == 'subvention_cof':
+ self._check_init()
+ if key == "subvention_cof":
# Allows accessing to the reduction as a subvention
# Other reason: backward compatibility
- reduction_mult = 1 - self.reduction_cof/100
- return (1/reduction_mult - 1) * 100
- return getattr(config, self._get_dj_key(key))
+ reduction_mult = 1 - self.reduction_cof / 100
+ return (1 / reduction_mult - 1) * 100
+ return getattr(djconfig.config, self._get_dj_key(key))
def list(self):
"""Get list of kfet app configuration.
@@ -30,11 +44,15 @@ class KFetConfig(object):
"""
# prevent circular imports
from kfet.forms import KFetConfigForm
- return [(field.label, getattr(config, name), )
- for name, field in KFetConfigForm.base_fields.items()]
+
+ self._check_init()
+ return [
+ (field.label, getattr(djconfig.config, name))
+ for name, field in KFetConfigForm.base_fields.items()
+ ]
def _get_dj_key(self, key):
- return '{}{}'.format(self.prefix, key)
+ return "{}{}".format(self.prefix, key)
def set(self, **kwargs):
"""Update configuration value(s).
@@ -47,6 +65,7 @@ class KFetConfig(object):
# prevent circular imports
from kfet.forms import KFetConfigForm
+ self._check_init()
# get old config
new_cfg = KFetConfigForm().initial
# update to new config
@@ -62,8 +81,9 @@ class KFetConfig(object):
cfg_form.save()
else:
raise ValidationError(
- 'Invalid values in kfet_config.set: %(fields)s',
- params={'fields': list(cfg_form.errors)})
+ "Invalid values in kfet_config.set: %(fields)s",
+ params={"fields": list(cfg_form.errors)},
+ )
kfet_config = KFetConfig()
diff --git a/kfet/consumers.py b/kfet/consumers.py
index a53bbb72..2655c86b 100644
--- a/kfet/consumers.py
+++ b/kfet/consumers.py
@@ -2,5 +2,5 @@ from .utils import DjangoJsonWebsocketConsumer, PermConsumerMixin
class KPsul(PermConsumerMixin, DjangoJsonWebsocketConsumer):
- groups = ['kfet.kpsul']
- perms_connect = ['kfet.is_team']
+ groups = ["kfet.kpsul"]
+ perms_connect = ["kfet.is_team"]
diff --git a/kfet/context_processors.py b/kfet/context_processors.py
index 89678f62..6668eebf 100644
--- a/kfet/context_processors.py
+++ b/kfet/context_processors.py
@@ -2,4 +2,4 @@ from kfet.config import kfet_config
def config(request):
- return {'kfet_config': kfet_config}
+ return {"kfet_config": kfet_config}
diff --git a/kfet/decorators.py b/kfet/decorators.py
index 66c9d71c..70848820 100644
--- a/kfet/decorators.py
+++ b/kfet/decorators.py
@@ -2,6 +2,7 @@ from django.contrib.auth.decorators import user_passes_test
def kfet_is_team(user):
- return user.has_perm('kfet.is_team')
+ return user.has_perm("kfet.is_team")
+
teamkfet_required = user_passes_test(kfet_is_team)
diff --git a/kfet/forms.py b/kfet/forms.py
index 522f20de..e314d80c 100644
--- a/kfet/forms.py
+++ b/kfet/forms.py
@@ -2,78 +2,87 @@ from datetime import timedelta
from decimal import Decimal
from django import forms
-from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
+from django.core import validators
+from django.core.exceptions import ValidationError
from django.forms import modelformset_factory
from django.utils import timezone
-
from djconfig.forms import ConfigForm
-from kfet.models import (
- Account, Checkout, Article, OperationGroup, Operation,
- CheckoutStatement, ArticleCategory, AccountNegative, Transfer,
- TransferGroup, Supplier)
from gestioncof.models import CofProfile
+from kfet.models import (
+ Account,
+ AccountNegative,
+ Article,
+ ArticleCategory,
+ Checkout,
+ CheckoutStatement,
+ Operation,
+ OperationGroup,
+ Supplier,
+ Transfer,
+ TransferGroup,
+)
from .auth.forms import UserGroupForm # noqa
-
# -----
# Widgets
# -----
+
class DateTimeWidget(forms.DateTimeInput):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.attrs['format'] = '%Y-%m-%d %H:%M'
+ self.attrs["format"] = "%Y-%m-%d %H:%M"
class Media:
- css = {
- 'all': ('kfet/css/bootstrap-datetimepicker.min.css',)
- }
- js = ('kfet/js/bootstrap-datetimepicker.min.js',)
+ css = {"all": ("kfet/css/bootstrap-datetimepicker.min.css",)}
+ js = ("kfet/js/bootstrap-datetimepicker.min.js",)
# -----
# Account forms
# -----
+
class AccountForm(forms.ModelForm):
# Surcharge pour passer data à Account.save()
- def save(self, data = {}, *args, **kwargs):
- obj = super().save(commit = False, *args, **kwargs)
- obj.save(data = data)
+ def save(self, data={}, *args, **kwargs):
+ obj = super().save(commit=False, *args, **kwargs)
+ obj.save(data=data)
return obj
class Meta:
- model = Account
- fields = ['trigramme', 'promo', 'nickname', 'is_frozen']
- widgets = {
- 'trigramme': forms.TextInput(attrs={'autocomplete': 'off'}),
- }
+ model = Account
+ fields = ["trigramme", "promo", "nickname", "is_frozen"]
+ widgets = {"trigramme": forms.TextInput(attrs={"autocomplete": "off"})}
+
class AccountBalanceForm(forms.ModelForm):
class Meta:
model = Account
- fields = ['balance']
+ fields = ["balance"]
+
class AccountTriForm(AccountForm):
-
def clean_trigramme(self):
- trigramme = self.cleaned_data['trigramme']
+ trigramme = self.cleaned_data["trigramme"]
return trigramme.upper()
class Meta(AccountForm.Meta):
- fields = ['trigramme']
+ fields = ["trigramme"]
+
class AccountNoTriForm(AccountForm):
class Meta(AccountForm.Meta):
- exclude = ['trigramme']
+ exclude = ["trigramme"]
+
class AccountRestrictForm(AccountForm):
class Meta(AccountForm.Meta):
- fields = ['is_frozen']
+ fields = ["is_frozen"]
class AccountPwdForm(forms.Form):
@@ -84,14 +93,12 @@ class AccountPwdForm(forms.Form):
widget=forms.PasswordInput,
)
pwd2 = forms.CharField(
- label="Confirmer le mot de passe",
- required=False,
- widget=forms.PasswordInput,
+ label="Confirmer le mot de passe", required=False, widget=forms.PasswordInput
)
def clean(self):
- pwd1 = self.cleaned_data.get('pwd1', '')
- pwd2 = self.cleaned_data.get('pwd2', '')
+ pwd1 = self.cleaned_data.get("pwd1", "")
+ pwd2 = self.cleaned_data.get("pwd2", "")
if len(pwd1) < 8:
raise ValidationError("Mot de passe trop court")
if pwd1 != pwd2:
@@ -101,63 +108,66 @@ class AccountPwdForm(forms.Form):
class CofForm(forms.ModelForm):
def clean_is_cof(self):
- instance = getattr(self, 'instance', None)
+ instance = getattr(self, "instance", None)
if instance and instance.pk:
return instance.is_cof
else:
return False
+
class Meta:
- model = CofProfile
- fields = ['login_clipper', 'is_cof', 'departement']
+ model = CofProfile
+ fields = ["login_clipper", "is_cof", "departement"]
+
class CofRestrictForm(CofForm):
class Meta(CofForm.Meta):
- fields = ['departement']
+ fields = ["departement"]
class UserForm(forms.ModelForm):
class Meta:
model = User
- fields = ['username', 'first_name', 'last_name', 'email']
- help_texts = {
- 'username': ''
- }
+ fields = ["username", "first_name", "last_name", "email"]
+ help_texts = {"username": ""}
class UserRestrictForm(UserForm):
class Meta(UserForm.Meta):
- fields = ['first_name', 'last_name']
+ fields = ["first_name", "last_name"]
+
class UserRestrictTeamForm(UserForm):
class Meta(UserForm.Meta):
- fields = ['first_name', 'last_name', 'email']
+ fields = ["first_name", "last_name", "email"]
class AccountNegativeForm(forms.ModelForm):
class Meta:
- model = AccountNegative
- fields = ['authz_overdraft_amount', 'authz_overdraft_until',
- 'balance_offset', 'comment']
- widgets = {
- 'authz_overdraft_until': DateTimeWidget(),
- }
+ model = AccountNegative
+ fields = [
+ "authz_overdraft_amount",
+ "authz_overdraft_until",
+ "balance_offset",
+ "comment",
+ ]
+ widgets = {"authz_overdraft_until": DateTimeWidget()}
+
# -----
# Checkout forms
# -----
+
class CheckoutForm(forms.ModelForm):
class Meta:
- model = Checkout
- fields = ['name', 'valid_from', 'valid_to', 'balance', 'is_protected']
- widgets = {
- 'valid_from': DateTimeWidget(),
- 'valid_to' : DateTimeWidget(),
- }
+ model = Checkout
+ fields = ["name", "valid_from", "valid_to", "balance", "is_protected"]
+ widgets = {"valid_from": DateTimeWidget(), "valid_to": DateTimeWidget()}
+
class CheckoutRestrictForm(CheckoutForm):
class Meta(CheckoutForm.Meta):
- fields = ['name', 'valid_from', 'valid_to']
+ fields = ["name", "valid_from", "valid_to"]
class CheckoutStatementCreateForm(forms.ModelForm):
@@ -179,197 +189,246 @@ class CheckoutStatementCreateForm(forms.ModelForm):
class Meta:
model = CheckoutStatement
- exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken',
- 'balance_old', 'balance_new']
+ exclude = [
+ "by",
+ "at",
+ "checkout",
+ "amount_error",
+ "amount_taken",
+ "balance_old",
+ "balance_new",
+ ]
def clean(self):
- not_count = self.cleaned_data['not_count']
+ not_count = self.cleaned_data["not_count"]
if not not_count and (
- self.cleaned_data['balance_001'] is None
- or self.cleaned_data['balance_002'] is None
- or self.cleaned_data['balance_005'] is None
- or self.cleaned_data['balance_01'] is None
- or self.cleaned_data['balance_02'] is None
- or self.cleaned_data['balance_05'] is None
- or self.cleaned_data['balance_1'] is None
- or self.cleaned_data['balance_2'] is None
- or self.cleaned_data['balance_5'] is None
- or self.cleaned_data['balance_10'] is None
- or self.cleaned_data['balance_20'] is None
- or self.cleaned_data['balance_50'] is None
- or self.cleaned_data['balance_100'] is None
- or self.cleaned_data['balance_200'] is None
- or self.cleaned_data['balance_500'] is None):
- raise ValidationError("Y'a un problème. Si tu comptes la caisse, mets au moins des 0 stp (et t'as pas idée de comment c'est long de vérifier que t'as mis des valeurs de partout...)")
+ self.cleaned_data["balance_001"] is None
+ or self.cleaned_data["balance_002"] is None
+ or self.cleaned_data["balance_005"] is None
+ or self.cleaned_data["balance_01"] is None
+ or self.cleaned_data["balance_02"] is None
+ or self.cleaned_data["balance_05"] is None
+ or self.cleaned_data["balance_1"] is None
+ or self.cleaned_data["balance_2"] is None
+ or self.cleaned_data["balance_5"] is None
+ or self.cleaned_data["balance_10"] is None
+ or self.cleaned_data["balance_20"] is None
+ or self.cleaned_data["balance_50"] is None
+ or self.cleaned_data["balance_100"] is None
+ or self.cleaned_data["balance_200"] is None
+ or self.cleaned_data["balance_500"] is None
+ ):
+ raise ValidationError(
+ "Y'a un problème. Si tu comptes la caisse, mets au moins des 0 stp."
+ )
super().clean()
+
class CheckoutStatementUpdateForm(forms.ModelForm):
class Meta:
model = CheckoutStatement
- exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken']
+ exclude = ["by", "at", "checkout", "amount_error", "amount_taken"]
# -----
# Category
# -----
+
class CategoryForm(forms.ModelForm):
class Meta:
model = ArticleCategory
- fields = ['name', 'has_addcost']
+ fields = ["name", "has_addcost"]
+
# -----
# Article forms
# -----
+
class ArticleForm(forms.ModelForm):
category_new = forms.CharField(
- label="Créer une catégorie",
- max_length=45,
- required = False)
+ label="Créer une catégorie", max_length=45, required=False
+ )
category = forms.ModelChoiceField(
- label="Catégorie",
- queryset = ArticleCategory.objects.all(),
- required = False)
+ label="Catégorie", queryset=ArticleCategory.objects.all(), required=False
+ )
suppliers = forms.ModelMultipleChoiceField(
- label="Fournisseurs",
- queryset = Supplier.objects.all(),
- required = False)
+ label="Fournisseurs", queryset=Supplier.objects.all(), required=False
+ )
supplier_new = forms.CharField(
- label="Créer un fournisseur",
- max_length = 45,
- required = False)
+ label="Créer un fournisseur", max_length=45, required=False
+ )
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.pk:
- self.initial['suppliers'] = self.instance.suppliers.values_list('pk', flat=True)
+ self.initial["suppliers"] = self.instance.suppliers.values_list(
+ "pk", flat=True
+ )
def clean(self):
- category = self.cleaned_data.get('category')
- category_new = self.cleaned_data.get('category_new')
+ category = self.cleaned_data.get("category")
+ category_new = self.cleaned_data.get("category_new")
if not category and not category_new:
- raise ValidationError('Sélectionnez une catégorie ou créez en une')
+ raise ValidationError("Sélectionnez une catégorie ou créez en une")
elif not category:
category, _ = ArticleCategory.objects.get_or_create(name=category_new)
- self.cleaned_data['category'] = category
+ self.cleaned_data["category"] = category
super().clean()
class Meta:
- model = Article
- fields = ['name', 'is_sold', 'hidden', 'price', 'stock', 'category', 'box_type',
- 'box_capacity']
+ model = Article
+ fields = [
+ "name",
+ "is_sold",
+ "hidden",
+ "price",
+ "stock",
+ "category",
+ "box_type",
+ "box_capacity",
+ ]
+
class ArticleRestrictForm(ArticleForm):
class Meta(ArticleForm.Meta):
- fields = ['name', 'is_sold', 'hidden', 'price', 'category', 'box_type',
- 'box_capacity']
+ fields = [
+ "name",
+ "is_sold",
+ "hidden",
+ "price",
+ "category",
+ "box_type",
+ "box_capacity",
+ ]
+
# -----
# K-Psul forms
# -----
+
class KPsulOperationGroupForm(forms.ModelForm):
+ # FIXME(AD): Use timezone.now instead of timezone.now() to avoid using a
+ # fixed datetime (application boot here).
+ # One may even use: Checkout.objects.is_valid() if changing
+ # to now = timezone.now is ok in 'is_valid' definition.
checkout = forms.ModelChoiceField(
- queryset = Checkout.objects.filter(
- is_protected=False, valid_from__lte=timezone.now(),
- valid_to__gte=timezone.now()),
- widget = forms.HiddenInput())
+ queryset=Checkout.objects.filter(
+ is_protected=False,
+ valid_from__lte=timezone.now(),
+ valid_to__gte=timezone.now(),
+ ),
+ widget=forms.HiddenInput(),
+ )
on_acc = forms.ModelChoiceField(
- queryset = Account.objects.exclude(trigramme='GNR'),
- widget = forms.HiddenInput())
+ queryset=Account.objects.exclude(trigramme="GNR"), widget=forms.HiddenInput()
+ )
+
class Meta:
- model = OperationGroup
- fields = ['on_acc', 'checkout', 'comment']
+ model = OperationGroup
+ fields = ["on_acc", "checkout", "comment"]
+
class KPsulAccountForm(forms.ModelForm):
class Meta:
- model = Account
- fields = ['trigramme']
+ model = Account
+ fields = ["trigramme"]
widgets = {
- 'trigramme': forms.TextInput(
- attrs={
- 'autocomplete': 'off',
- 'spellcheck': 'false',
- }),
+ "trigramme": forms.TextInput(
+ attrs={"autocomplete": "off", "spellcheck": "false"}
+ )
}
class KPsulCheckoutForm(forms.Form):
checkout = forms.ModelChoiceField(
- queryset=None,
- widget=forms.Select(attrs={'id': 'id_checkout_select'}),
+ queryset=None, widget=forms.Select(attrs={"id": "id_checkout_select"})
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Create the queryset on form instanciation to use the current time.
- self.fields['checkout'].queryset = (
- Checkout.objects.is_valid().filter(is_protected=False))
+ self.fields["checkout"].queryset = Checkout.objects.is_valid().filter(
+ is_protected=False
+ )
class KPsulOperationForm(forms.ModelForm):
article = forms.ModelChoiceField(
- queryset=Article.objects.select_related('category').all(),
+ queryset=Article.objects.select_related("category").all(),
required=False,
- widget = forms.HiddenInput())
+ widget=forms.HiddenInput(),
+ )
+ article_nb = forms.IntegerField(
+ required=False,
+ initial=None,
+ validators=[validators.MinValueValidator(1)],
+ widget=forms.HiddenInput(),
+ )
+
class Meta:
- model = Operation
- fields = ['type', 'amount', 'article', 'article_nb']
- widgets = {
- 'type': forms.HiddenInput(),
- 'amount': forms.HiddenInput(),
- 'article_nb': forms.HiddenInput(),
- }
+ model = Operation
+ fields = ["type", "amount", "article", "article_nb"]
+ widgets = {"type": forms.HiddenInput(), "amount": forms.HiddenInput()}
def clean(self):
super().clean()
- type_ope = self.cleaned_data.get('type')
- amount = self.cleaned_data.get('amount')
- article = self.cleaned_data.get('article')
- article_nb = self.cleaned_data.get('article_nb')
+ type_ope = self.cleaned_data.get("type")
+ amount = self.cleaned_data.get("amount")
+ article = self.cleaned_data.get("article")
+ article_nb = self.cleaned_data.get("article_nb")
+ errors = []
if type_ope and type_ope == Operation.PURCHASE:
- if not article or not article_nb:
- raise ValidationError(
- "Un achat nécessite un article et une quantité")
- if article_nb < 1:
- raise ValidationError("Impossible d'acheter moins de 1 article")
+ if not article or article_nb is None or article_nb < 1:
+ errors.append(
+ ValidationError("Un achat nécessite un article et une quantité")
+ )
elif type_ope and type_ope in [Operation.DEPOSIT, Operation.WITHDRAW]:
if not amount or article or article_nb:
- raise ValidationError("Bad request")
- if type_ope == Operation.DEPOSIT and amount <= 0:
- raise ValidationError("Charge non positive")
- if type_ope == Operation.WITHDRAW and amount >= 0:
- raise ValidationError("Retrait non négatif")
- self.cleaned_data['article'] = None
- self.cleaned_data['article_nb'] = None
+ errors.append(ValidationError("Bad request"))
+ else:
+ if type_ope == Operation.DEPOSIT and amount <= 0:
+ errors.append(ValidationError("Charge non positive"))
+ elif type_ope == Operation.WITHDRAW and amount >= 0:
+ errors.append(ValidationError("Retrait non négatif"))
+ self.cleaned_data["article"] = None
+ self.cleaned_data["article_nb"] = None
+
+ if errors:
+ raise ValidationError(errors)
+
KPsulOperationFormSet = modelformset_factory(
Operation,
- form = KPsulOperationForm,
- can_delete = True,
- extra = 0,
- min_num = 1, validate_min = True)
+ form=KPsulOperationForm,
+ can_delete=True,
+ extra=0,
+ min_num=1,
+ validate_min=True,
+)
+
class AddcostForm(forms.Form):
- trigramme = forms.CharField(required = False)
+ trigramme = forms.CharField(required=False)
amount = forms.DecimalField(
- required = False,
- max_digits=6,decimal_places=2,min_value=Decimal(0))
+ required=False, max_digits=6, decimal_places=2, min_value=Decimal(0)
+ )
def clean(self):
- trigramme = self.cleaned_data.get('trigramme')
+ trigramme = self.cleaned_data.get("trigramme")
if trigramme:
try:
Account.objects.get(trigramme=trigramme)
except Account.DoesNotExist:
- raise ValidationError('Compte invalide')
+ raise ValidationError("Compte invalide")
else:
- self.cleaned_data['amount'] = 0
+ self.cleaned_data["amount"] = 0
super().clean()
@@ -381,34 +440,40 @@ class AddcostForm(forms.Form):
class KFetConfigForm(ConfigForm):
kfet_reduction_cof = forms.DecimalField(
- label='Réduction COF', initial=Decimal('20'),
- max_digits=6, decimal_places=2,
+ label="Réduction COF",
+ initial=Decimal("20"),
+ max_digits=6,
+ decimal_places=2,
help_text="Réduction, à donner en pourcentage, appliquée lors d'un "
- "achat par un-e membre du COF sur le montant en euros.",
+ "achat par un-e membre du COF sur le montant en euros.",
)
kfet_addcost_amount = forms.DecimalField(
- label='Montant de la majoration (en €)', initial=Decimal('0'),
+ label="Montant de la majoration (en €)",
+ initial=Decimal("0"),
required=False,
- max_digits=6, decimal_places=2,
+ max_digits=6,
+ decimal_places=2,
)
kfet_addcost_for = forms.ModelChoiceField(
- label='Destinataire de la majoration', initial=None, required=False,
- help_text='Laissez vide pour désactiver la majoration.',
- queryset=(Account.objects
- .select_related('cofprofile', 'cofprofile__user')
- .all()),
+ label="Destinataire de la majoration",
+ initial=None,
+ required=False,
+ help_text="Laissez vide pour désactiver la majoration.",
+ queryset=(
+ Account.objects.select_related("cofprofile", "cofprofile__user").all()
+ ),
)
kfet_overdraft_duration = forms.DurationField(
- label='Durée du découvert autorisé par défaut',
- initial=timedelta(days=1),
+ label="Durée du découvert autorisé par défaut", initial=timedelta(days=1)
)
kfet_overdraft_amount = forms.DecimalField(
- label='Montant du découvert autorisé par défaut (en €)',
- initial=Decimal('20'),
- max_digits=6, decimal_places=2,
+ label="Montant du découvert autorisé par défaut (en €)",
+ initial=Decimal("20"),
+ max_digits=6,
+ decimal_places=2,
)
kfet_cancel_duration = forms.DurationField(
- label='Durée pour annuler une commande sans mot de passe',
+ label="Durée pour annuler une commande sans mot de passe",
initial=timedelta(minutes=5),
)
@@ -424,105 +489,98 @@ class FilterHistoryForm(forms.Form):
# Transfer forms
# -----
+
class TransferGroupForm(forms.ModelForm):
class Meta:
- model = TransferGroup
- fields = ['comment']
+ model = TransferGroup
+ fields = ["comment"]
+
class TransferForm(forms.ModelForm):
from_acc = forms.ModelChoiceField(
- queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13', 'GNR']),
- widget = forms.HiddenInput()
+ queryset=Account.objects.exclude(trigramme__in=["LIQ", "#13", "GNR"]),
+ widget=forms.HiddenInput(),
)
to_acc = forms.ModelChoiceField(
- queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13', 'GNR']),
- widget = forms.HiddenInput()
+ queryset=Account.objects.exclude(trigramme__in=["LIQ", "#13", "GNR"]),
+ widget=forms.HiddenInput(),
)
def clean_amount(self):
- amount = self.cleaned_data['amount']
+ amount = self.cleaned_data["amount"]
if amount <= 0:
raise forms.ValidationError("Montant invalide")
return amount
class Meta:
- model = Transfer
- fields = ['from_acc', 'to_acc', 'amount']
+ model = Transfer
+ fields = ["from_acc", "to_acc", "amount"]
+
TransferFormSet = modelformset_factory(
- Transfer,
- form = TransferForm,
- min_num = 1, validate_min = True,
- extra = 9,
+ Transfer, form=TransferForm, min_num=1, validate_min=True, extra=9
)
# -----
# Inventory forms
# -----
+
class InventoryArticleForm(forms.Form):
article = forms.ModelChoiceField(
- queryset = Article.objects.all(),
- widget = forms.HiddenInput(),
- )
+ queryset=Article.objects.all(), widget=forms.HiddenInput()
+ )
stock_new = forms.IntegerField(required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if 'initial' in kwargs:
- self.name = kwargs['initial']['name']
- self.stock_old = kwargs['initial']['stock_old']
- self.category = kwargs['initial']['category']
- self.category_name = kwargs['initial']['category__name']
- self.box_capacity = kwargs['initial']['box_capacity']
+ if "initial" in kwargs:
+ self.name = kwargs["initial"]["name"]
+ self.stock_old = kwargs["initial"]["stock_old"]
+ self.category = kwargs["initial"]["category"]
+ self.category_name = kwargs["initial"]["category__name"]
+ self.box_capacity = kwargs["initial"]["box_capacity"]
+
# -----
# Order forms
# -----
-
class OrderArticleForm(forms.Form):
article = forms.ModelChoiceField(
- queryset=Article.objects.all(),
- widget=forms.HiddenInput(),
- )
+ queryset=Article.objects.all(), widget=forms.HiddenInput()
+ )
quantity_ordered = forms.IntegerField(required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if 'initial' in kwargs:
- self.name = kwargs['initial']['name']
- self.stock = kwargs['initial']['stock']
- self.category = kwargs['initial']['category']
- self.category_name = kwargs['initial']['category__name']
- self.box_capacity = kwargs['initial']['box_capacity']
- self.v_all = kwargs['initial']['v_all']
- self.v_moy = kwargs['initial']['v_moy']
- self.v_et = kwargs['initial']['v_et']
- self.v_prev = kwargs['initial']['v_prev']
- self.c_rec = kwargs['initial']['c_rec']
+ if "initial" in kwargs:
+ self.name = kwargs["initial"]["name"]
+ self.stock = kwargs["initial"]["stock"]
+ self.category = kwargs["initial"]["category"]
+ self.category_name = kwargs["initial"]["category__name"]
+ self.box_capacity = kwargs["initial"]["box_capacity"]
+ self.v_all = kwargs["initial"]["v_all"]
+ self.v_moy = kwargs["initial"]["v_moy"]
+ self.v_et = kwargs["initial"]["v_et"]
+ self.v_prev = kwargs["initial"]["v_prev"]
+ self.c_rec = kwargs["initial"]["c_rec"]
+
class OrderArticleToInventoryForm(forms.Form):
article = forms.ModelChoiceField(
- queryset = Article.objects.all(),
- widget = forms.HiddenInput(),
- )
- price_HT = forms.DecimalField(
- max_digits = 7, decimal_places = 4,
- required = False)
- TVA = forms.DecimalField(
- max_digits = 7, decimal_places = 2,
- required = False)
- rights = forms.DecimalField(
- max_digits = 7, decimal_places = 4,
- required = False)
+ queryset=Article.objects.all(), widget=forms.HiddenInput()
+ )
+ price_HT = forms.DecimalField(max_digits=7, decimal_places=4, required=False)
+ TVA = forms.DecimalField(max_digits=7, decimal_places=2, required=False)
+ rights = forms.DecimalField(max_digits=7, decimal_places=4, required=False)
quantity_received = forms.IntegerField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if 'initial' in kwargs:
- self.name = kwargs['initial']['name']
- self.category = kwargs['initial']['category']
- self.category_name = kwargs['initial']['category__name']
- self.quantity_ordered = kwargs['initial']['quantity_ordered']
+ if "initial" in kwargs:
+ self.name = kwargs["initial"]["name"]
+ self.category = kwargs["initial"]["category"]
+ self.category_name = kwargs["initial"]["category__name"]
+ self.quantity_ordered = kwargs["initial"]["quantity_ordered"]
diff --git a/kfet/management/commands/createopes.py b/kfet/management/commands/createopes.py
index 5a7699ae..03458ea0 100644
--- a/kfet/management/commands/createopes.py
+++ b/kfet/management/commands/createopes.py
@@ -1,4 +1,3 @@
-
"""
Crée des opérations aléatoires réparties sur une période de temps spécifiée
"""
@@ -6,29 +5,40 @@ Crée des opérations aléatoires réparties sur une période de temps spécifi
import random
from datetime import timedelta
from decimal import Decimal
-from django.utils import timezone
-from django.core.management.base import BaseCommand
-from kfet.models import (Account, Article, OperationGroup, Operation,
- Checkout, Transfer, TransferGroup)
+from django.core.management.base import BaseCommand
+from django.utils import timezone
+
+from kfet.models import (
+ Account,
+ Article,
+ Checkout,
+ Operation,
+ OperationGroup,
+ Transfer,
+ TransferGroup,
+)
class Command(BaseCommand):
- help = ("Crée des opérations réparties uniformément "
- "sur une période de temps")
+ help = "Crée des opérations réparties uniformément " "sur une période de temps"
def add_arguments(self, parser):
# Nombre d'opérations à créer
- parser.add_argument('opes', type=int,
- help='Number of opegroups to create')
+ parser.add_argument("opes", type=int, help="Number of opegroups to create")
# Période sur laquelle créer (depuis num_days avant maintenant)
- parser.add_argument('days', type=int,
- help='Period in which to create opegroups')
+ parser.add_argument(
+ "days", type=int, help="Period in which to create opegroups"
+ )
# Optionnel : nombre de transfert à créer (défaut 0)
- parser.add_argument('--transfers', type=int, default=0,
- help='Number of transfers to create (default 0)')
+ parser.add_argument(
+ "--transfers",
+ type=int,
+ default=0,
+ help="Number of transfers to create (default 0)",
+ )
def handle(self, *args, **options):
@@ -39,19 +49,19 @@ class Command(BaseCommand):
purchases = 0
transfers = 0
- num_ops = options['opes']
- num_transfers = options['transfers']
+ num_ops = options["opes"]
+ num_transfers = options["transfers"]
# Convert to seconds
- time = options['days'] * 24 * 3600
+ time = options["days"] * 24 * 3600
now = timezone.now()
checkout = Checkout.objects.first()
articles = Article.objects.all()
- accounts = Account.objects.exclude(trigramme='LIQ')
- liq_account = Account.objects.get(trigramme='LIQ')
+ accounts = Account.objects.exclude(trigramme="LIQ")
+ liq_account = Account.objects.get(trigramme="LIQ")
try:
con_account = Account.objects.get(
- cofprofile__user__first_name='Assurancetourix'
+ cofprofile__user__first_name="Assurancetourix"
)
except Account.DoesNotExist:
con_account = random.choice(accounts)
@@ -78,12 +88,12 @@ class Command(BaseCommand):
if random.random() < 0.2:
addcost = True
addcost_for = con_account
- addcost_amount = Decimal('0.5')
+ addcost_amount = Decimal("0.5")
else:
addcost = False
# Initialize opegroup amount
- amount = Decimal('0')
+ amount = Decimal("0")
# Generating operations
ope_list = []
@@ -95,19 +105,18 @@ class Command(BaseCommand):
if typevar > 0.9 and account != liq_account:
ope = Operation(
type=Operation.DEPOSIT,
- amount=Decimal(random.randint(1, 99)/10)
+ amount=Decimal(random.randint(1, 99) / 10),
)
# 0.05 probability to have a withdrawal
elif typevar > 0.85 and account != liq_account:
ope = Operation(
type=Operation.WITHDRAW,
- amount=-Decimal(random.randint(1, 99)/10)
+ amount=-Decimal(random.randint(1, 99) / 10),
)
# 0.05 probability to have an edition
elif typevar > 0.8 and account != liq_account:
ope = Operation(
- type=Operation.EDIT,
- amount=Decimal(random.randint(1, 99)/10)
+ type=Operation.EDIT, amount=Decimal(random.randint(1, 99) / 10)
)
else:
article = random.choice(articles)
@@ -115,9 +124,9 @@ class Command(BaseCommand):
ope = Operation(
type=Operation.PURCHASE,
- amount=-article.price*nb,
+ amount=-article.price * nb,
article=article,
- article_nb=nb
+ article_nb=nb,
)
purchases += 1
@@ -130,23 +139,23 @@ class Command(BaseCommand):
ope_list.append(ope)
amount += ope.amount
- opegroup_list.append(OperationGroup(
- on_acc=account,
- checkout=checkout,
- at=at,
- is_cof=account.cofprofile.is_cof,
- amount=amount,
- ))
+ opegroup_list.append(
+ OperationGroup(
+ on_acc=account,
+ checkout=checkout,
+ at=at,
+ is_cof=account.cofprofile.is_cof,
+ amount=amount,
+ )
+ )
at_list.append(at)
- ope_by_grp.append((at, ope_list, ))
+ ope_by_grp.append((at, ope_list))
OperationGroup.objects.bulk_create(opegroup_list)
# Fetch created OperationGroup objects pk by at
- opegroups = (OperationGroup.objects
- .filter(at__in=at_list)
- .values('id', 'at'))
- opegroups_by = {grp['at']: grp['id'] for grp in opegroups}
+ opegroups = OperationGroup.objects.filter(at__in=at_list).values("id", "at")
+ opegroups_by = {grp["at"]: grp["id"] for grp in opegroups}
all_ope = []
for _ in range(num_ops):
@@ -175,30 +184,28 @@ class Command(BaseCommand):
else:
comment = ""
- transfergroup_list.append(TransferGroup(
- at=at,
- comment=comment,
- valid_by=random.choice(accounts),
- ))
+ transfergroup_list.append(
+ TransferGroup(at=at, comment=comment, valid_by=random.choice(accounts))
+ )
at_list.append(at)
# Randomly generate transfer
transfer_list = []
for i in range(random.randint(1, 4)):
- transfer_list.append(Transfer(
- from_acc=random.choice(accounts),
- to_acc=random.choice(accounts),
- amount=Decimal(random.randint(1, 99)/10)
- ))
+ transfer_list.append(
+ Transfer(
+ from_acc=random.choice(accounts),
+ to_acc=random.choice(accounts),
+ amount=Decimal(random.randint(1, 99) / 10),
+ )
+ )
- transfer_by_grp.append((at, transfer_list, ))
+ transfer_by_grp.append((at, transfer_list))
TransferGroup.objects.bulk_create(transfergroup_list)
- transfergroups = (TransferGroup.objects
- .filter(at__in=at_list)
- .values('id', 'at'))
- transfergroups_by = {grp['at']: grp['id'] for grp in transfergroups}
+ transfergroups = TransferGroup.objects.filter(at__in=at_list).values("id", "at")
+ transfergroups_by = {grp["at"]: grp["id"] for grp in transfergroups}
all_transfer = []
for _ in range(num_transfers):
@@ -211,9 +218,10 @@ class Command(BaseCommand):
transfers += len(all_transfer)
self.stdout.write(
- "- {:d} opérations créées dont {:d} commandes d'articles"
- .format(opes_created, purchases))
+ "- {:d} opérations créées dont {:d} commandes d'articles".format(
+ opes_created, purchases
+ )
+ )
if transfers:
- self.stdout.write("- {:d} transferts créés"
- .format(transfers))
+ self.stdout.write("- {:d} transferts créés".format(transfers))
diff --git a/kfet/management/commands/loadkfetdevdata.py b/kfet/management/commands/loadkfetdevdata.py
index 6dd25f29..0543be80 100644
--- a/kfet/management/commands/loadkfetdevdata.py
+++ b/kfet/management/commands/loadkfetdevdata.py
@@ -6,18 +6,23 @@ import os
import random
from datetime import timedelta
-from django.utils import timezone
-from django.contrib.auth.models import User, Group, Permission, ContentType
+from django.contrib.auth.models import ContentType, Group, Permission, User
from django.core.management import call_command
+from django.utils import timezone
from gestioncof.management.base import MyBaseCommand
from gestioncof.models import CofProfile
-from kfet.models import (Account, Checkout, CheckoutStatement, Supplier,
- SupplierArticle, Article)
+from kfet.models import (
+ Account,
+ Article,
+ Checkout,
+ CheckoutStatement,
+ Supplier,
+ SupplierArticle,
+)
# Où sont stockés les fichiers json
-DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
- 'data')
+DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
class Command(MyBaseCommand):
@@ -28,7 +33,7 @@ class Command(MyBaseCommand):
# Groupes
# ---
- Group.objects.filter(name__icontains='K-Fêt').delete()
+ Group.objects.filter(name__icontains="K-Fêt").delete()
group_chef = Group(name="K-Fêt César")
group_boy = Group(name="K-Fêt Légionnaire")
@@ -37,10 +42,11 @@ class Command(MyBaseCommand):
group_boy.save()
permissions_chef = Permission.objects.filter(
- content_type__in=ContentType.objects.filter(
- app_label='kfet'))
+ content_type__in=ContentType.objects.filter(app_label="kfet")
+ )
permissions_boy = Permission.objects.filter(
- codename__in=['is_team', 'perform_deposit'])
+ codename__in=["is_team", "perform_deposit"]
+ )
group_chef.permissions.add(*permissions_chef)
group_boy.permissions.add(*permissions_boy)
@@ -51,11 +57,11 @@ class Command(MyBaseCommand):
self.stdout.write("Création des comptes K-Fêt")
- gaulois = CofProfile.objects.filter(user__last_name='Gaulois')
- gaulois_trigramme = map('{:03d}'.format, range(50))
+ gaulois = CofProfile.objects.filter(user__last_name="Gaulois")
+ gaulois_trigramme = map("{:03d}".format, range(50))
- romains = CofProfile.objects.filter(user__last_name='Romain')
- romains_trigramme = map(lambda x: str(100+x), range(99))
+ romains = CofProfile.objects.filter(user__last_name="Romain")
+ romains_trigramme = map(lambda x: str(100 + x), range(99))
created_accounts = 0
team_accounts = 0
@@ -64,18 +70,18 @@ class Command(MyBaseCommand):
account, created = Account.objects.get_or_create(
trigramme=trigramme,
cofprofile=profile,
- defaults={'balance': random.randint(1, 999)/10}
+ defaults={"balance": random.randint(1, 999) / 10},
)
created_accounts += int(created)
- if profile.user.first_name == 'Abraracourcix':
+ if profile.user.first_name == "Abraracourcix":
profile.user.groups.add(group_chef)
for (profile, trigramme) in zip(romains, romains_trigramme):
account, created = Account.objects.get_or_create(
trigramme=trigramme,
cofprofile=profile,
- defaults={'balance': random.randint(1, 999)/10}
+ defaults={"balance": random.randint(1, 999) / 10},
)
created_accounts += int(created)
@@ -83,47 +89,50 @@ class Command(MyBaseCommand):
profile.user.groups.add(group_boy)
team_accounts += 1
- self.stdout.write("- {:d} comptes créés, {:d} dans l'équipe K-Fêt"
- .format(created_accounts, team_accounts))
+ self.stdout.write(
+ "- {:d} comptes créés, {:d} dans l'équipe K-Fêt".format(
+ created_accounts, team_accounts
+ )
+ )
# Compte liquide
self.stdout.write("Création du compte liquide")
- liq_user, _ = User.objects.get_or_create(username='liquide')
+ liq_user, _ = User.objects.get_or_create(username="liquide")
liq_profile, _ = CofProfile.objects.get_or_create(user=liq_user)
- liq_account, _ = Account.objects.get_or_create(cofprofile=liq_profile,
- trigramme='LIQ')
+ liq_account, _ = Account.objects.get_or_create(
+ cofprofile=liq_profile, trigramme="LIQ"
+ )
# Root account if existing
- root_profile = CofProfile.objects.filter(user__username='root')
+ root_profile = CofProfile.objects.filter(user__username="root")
if root_profile.exists():
self.stdout.write("Création du compte K-Fêt root")
root_profile = root_profile.get()
- Account.objects.get_or_create(cofprofile=root_profile,
- trigramme='AAA')
+ Account.objects.get_or_create(cofprofile=root_profile, trigramme="AAA")
# ---
# Caisse
# ---
checkout, created = Checkout.objects.get_or_create(
- created_by=Account.objects.get(trigramme='000'),
- name='Chaudron',
+ created_by=Account.objects.get(trigramme="000"),
+ name="Chaudron",
defaults={
- 'valid_from': timezone.now(),
- 'valid_to': timezone.now() + timedelta(days=730)
+ "valid_from": timezone.now(),
+ "valid_to": timezone.now() + timedelta(days=730),
},
)
if created:
CheckoutStatement.objects.create(
- by=Account.objects.get(trigramme='000'),
+ by=Account.objects.get(trigramme="000"),
checkout=checkout,
balance_old=0,
balance_new=0,
amount_taken=0,
- amount_error=0
+ amount_error=0,
)
# ---
@@ -135,10 +144,7 @@ class Command(MyBaseCommand):
articles = random.sample(list(Article.objects.all()), 40)
to_create = []
for article in articles:
- to_create.append(SupplierArticle(
- supplier=supplier,
- article=article
- ))
+ to_create.append(SupplierArticle(supplier=supplier, article=article))
SupplierArticle.objects.bulk_create(to_create)
@@ -146,10 +152,10 @@ class Command(MyBaseCommand):
# Opérations
# ---
- call_command('createopes', '100', '7', '--transfers=20')
+ call_command("createopes", "100", "7", "--transfers=20")
# ---
# Wagtail CMS
# ---
- call_command('kfet_loadwagtail')
+ call_command("kfet_loadwagtail")
diff --git a/kfet/migrations/0001_initial.py b/kfet/migrations/0001_initial.py
index 8f9b14fa..8dbad4a8 100644
--- a/kfet/migrations/0001_initial.py
+++ b/kfet/migrations/0001_initial.py
@@ -1,257 +1,713 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
-import django.db.models.deletion
-import django.core.validators
import datetime
+import django.core.validators
+import django.db.models.deletion
+from django.db import migrations, models
+
class Migration(migrations.Migration):
- dependencies = [
- ('gestioncof', '0007_alter_club'),
- ]
+ dependencies = [("gestioncof", "0007_alter_club")]
operations = [
migrations.CreateModel(
- name='Account',
+ name="Account",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('trigramme', models.CharField(max_length=3, validators=[django.core.validators.RegexValidator(regex='^[^a-z]{3}$')], unique=True)),
- ('balance', models.DecimalField(decimal_places=2, default=0, max_digits=6)),
- ('frozen', models.BooleanField(default=False)),
- ('promo', models.IntegerField(null=True, blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016)], default=2015)),
- ('nickname', models.CharField(max_length=255, blank=True, default='')),
- ('password', models.CharField(max_length=255, blank=True, null=True, unique=True, default=None)),
- ('cofprofile', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='account_kfet', to='gestioncof.CofProfile')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "trigramme",
+ models.CharField(
+ max_length=3,
+ validators=[
+ django.core.validators.RegexValidator(regex="^[^a-z]{3}$")
+ ],
+ unique=True,
+ ),
+ ),
+ (
+ "balance",
+ models.DecimalField(decimal_places=2, default=0, max_digits=6),
+ ),
+ ("frozen", models.BooleanField(default=False)),
+ (
+ "promo",
+ models.IntegerField(
+ null=True,
+ blank=True,
+ choices=[
+ (1980, 1980),
+ (1981, 1981),
+ (1982, 1982),
+ (1983, 1983),
+ (1984, 1984),
+ (1985, 1985),
+ (1986, 1986),
+ (1987, 1987),
+ (1988, 1988),
+ (1989, 1989),
+ (1990, 1990),
+ (1991, 1991),
+ (1992, 1992),
+ (1993, 1993),
+ (1994, 1994),
+ (1995, 1995),
+ (1996, 1996),
+ (1997, 1997),
+ (1998, 1998),
+ (1999, 1999),
+ (2000, 2000),
+ (2001, 2001),
+ (2002, 2002),
+ (2003, 2003),
+ (2004, 2004),
+ (2005, 2005),
+ (2006, 2006),
+ (2007, 2007),
+ (2008, 2008),
+ (2009, 2009),
+ (2010, 2010),
+ (2011, 2011),
+ (2012, 2012),
+ (2013, 2013),
+ (2014, 2014),
+ (2015, 2015),
+ (2016, 2016),
+ ],
+ default=2015,
+ ),
+ ),
+ ("nickname", models.CharField(max_length=255, blank=True, default="")),
+ (
+ "password",
+ models.CharField(
+ max_length=255, blank=True, null=True, unique=True, default=None
+ ),
+ ),
+ (
+ "cofprofile",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="account_kfet",
+ to="gestioncof.CofProfile",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='AccountNegative',
+ name="AccountNegative",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('start', models.DateTimeField(default=datetime.datetime(2016, 8, 2, 10, 22, 1, 569492))),
- ('balance_offset', models.DecimalField(decimal_places=2, max_digits=6)),
- ('authorized_overdraft', models.DecimalField(decimal_places=2, default=0, max_digits=6)),
- ('comment', models.CharField(max_length=255, blank=True)),
- ('account', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='negative', to='kfet.Account')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "start",
+ models.DateTimeField(
+ default=datetime.datetime(2016, 8, 2, 10, 22, 1, 569492)
+ ),
+ ),
+ ("balance_offset", models.DecimalField(decimal_places=2, max_digits=6)),
+ (
+ "authorized_overdraft",
+ models.DecimalField(decimal_places=2, default=0, max_digits=6),
+ ),
+ ("comment", models.CharField(max_length=255, blank=True)),
+ (
+ "account",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="negative",
+ to="kfet.Account",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Article',
+ name="Article",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=45)),
- ('is_sold', models.BooleanField(default=True)),
- ('price', models.DecimalField(decimal_places=2, max_digits=6)),
- ('stock', models.IntegerField(default=0)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=45)),
+ ("is_sold", models.BooleanField(default=True)),
+ ("price", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("stock", models.IntegerField(default=0)),
],
),
migrations.CreateModel(
- name='ArticleCategory',
+ name="ArticleCategory",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=45)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=45)),
],
),
migrations.CreateModel(
- name='ArticleRule',
+ name="ArticleRule",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('ratio', models.PositiveSmallIntegerField()),
- ('article_on', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='rule_on', to='kfet.Article')),
- ('article_to', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='rule_to', to='kfet.Article')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("ratio", models.PositiveSmallIntegerField()),
+ (
+ "article_on",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="rule_on",
+ to="kfet.Article",
+ ),
+ ),
+ (
+ "article_to",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="rule_to",
+ to="kfet.Article",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Checkout',
+ name="Checkout",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=45)),
- ('valid_from', models.DateTimeField()),
- ('valid_to', models.DateTimeField()),
- ('balance', models.DecimalField(decimal_places=2, max_digits=6)),
- ('is_protected', models.BooleanField(default=False)),
- ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.Account')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=45)),
+ ("valid_from", models.DateTimeField()),
+ ("valid_to", models.DateTimeField()),
+ ("balance", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("is_protected", models.BooleanField(default=False)),
+ (
+ "created_by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="+",
+ to="kfet.Account",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='CheckoutTransfer',
+ name="CheckoutTransfer",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('amount', models.DecimalField(decimal_places=2, max_digits=6)),
- ('from_checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_from', to='kfet.Checkout')),
- ('to_checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_to', to='kfet.Checkout')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("amount", models.DecimalField(decimal_places=2, max_digits=6)),
+ (
+ "from_checkout",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="transfers_from",
+ to="kfet.Checkout",
+ ),
+ ),
+ (
+ "to_checkout",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="transfers_to",
+ to="kfet.Checkout",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Inventory',
+ name="Inventory",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('at', models.DateTimeField(auto_now_add=True)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("at", models.DateTimeField(auto_now_add=True)),
],
),
migrations.CreateModel(
- name='InventoryArticle',
+ name="InventoryArticle",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('stock_old', models.IntegerField()),
- ('stock_new', models.IntegerField()),
- ('stock_error', models.IntegerField(default=0)),
- ('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Article')),
- ('inventory', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Inventory')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("stock_old", models.IntegerField()),
+ ("stock_new", models.IntegerField()),
+ ("stock_error", models.IntegerField(default=0)),
+ (
+ "article",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT, to="kfet.Article"
+ ),
+ ),
+ (
+ "inventory",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT, to="kfet.Inventory"
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Operation',
+ name="Operation",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('type', models.CharField(max_length=8, choices=[('purchase', 'Achat'), ('deposit', 'Charge'), ('withdraw', 'Retrait')])),
- ('amount', models.DecimalField(decimal_places=2, max_digits=6)),
- ('on_checkout', models.BooleanField(default=True)),
- ('canceled_at', models.DateTimeField(blank=True, null=True, default=None)),
- ('addcost_amount', models.DecimalField(decimal_places=2, max_digits=6)),
- ('addcost_for', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='addcosts', to='kfet.Account', null=True, default=None)),
- ('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='operations', to='kfet.Article', null=True, default=None)),
- ('canceled_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=None)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "type",
+ models.CharField(
+ max_length=8,
+ choices=[
+ ("purchase", "Achat"),
+ ("deposit", "Charge"),
+ ("withdraw", "Retrait"),
+ ],
+ ),
+ ),
+ ("amount", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("on_checkout", models.BooleanField(default=True)),
+ (
+ "canceled_at",
+ models.DateTimeField(blank=True, null=True, default=None),
+ ),
+ ("addcost_amount", models.DecimalField(decimal_places=2, max_digits=6)),
+ (
+ "addcost_for",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="addcosts",
+ to="kfet.Account",
+ null=True,
+ default=None,
+ ),
+ ),
+ (
+ "article",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="operations",
+ to="kfet.Article",
+ null=True,
+ default=None,
+ ),
+ ),
+ (
+ "canceled_by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="+",
+ to="kfet.Account",
+ null=True,
+ default=None,
+ ),
+ ),
],
),
migrations.CreateModel(
- name='OperationGroup',
+ name="OperationGroup",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('at', models.DateTimeField(auto_now_add=True)),
- ('amount', models.IntegerField()),
- ('is_cof', models.BooleanField(default=False)),
- ('comment', models.CharField(max_length=255, blank=True, default='')),
- ('checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='operations', to='kfet.Checkout')),
- ('on_acc', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='operations', to='kfet.Account')),
- ('valid_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=True)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("at", models.DateTimeField(auto_now_add=True)),
+ ("amount", models.IntegerField()),
+ ("is_cof", models.BooleanField(default=False)),
+ ("comment", models.CharField(max_length=255, blank=True, default="")),
+ (
+ "checkout",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="operations",
+ to="kfet.Checkout",
+ ),
+ ),
+ (
+ "on_acc",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="operations",
+ to="kfet.Account",
+ ),
+ ),
+ (
+ "valid_by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="+",
+ to="kfet.Account",
+ null=True,
+ default=True,
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Order',
+ name="Order",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('at', models.DateTimeField(auto_now_add=True)),
- ('amount', models.DecimalField(decimal_places=2, max_digits=6)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("at", models.DateTimeField(auto_now_add=True)),
+ ("amount", models.DecimalField(decimal_places=2, max_digits=6)),
],
),
migrations.CreateModel(
- name='OrderArticle',
+ name="OrderArticle",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('quantity_ordered', models.IntegerField()),
- ('quantity_received', models.IntegerField()),
- ('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Article')),
- ('order', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Order')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("quantity_ordered", models.IntegerField()),
+ ("quantity_received", models.IntegerField()),
+ (
+ "article",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT, to="kfet.Article"
+ ),
+ ),
+ (
+ "order",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT, to="kfet.Order"
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Statement',
+ name="Statement",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('balance_old', models.DecimalField(decimal_places=2, max_digits=6)),
- ('balance_new', models.DecimalField(decimal_places=2, max_digits=6)),
- ('amount_taken', models.DecimalField(decimal_places=2, max_digits=6)),
- ('amount_error', models.DecimalField(decimal_places=2, max_digits=6)),
- ('at', models.DateTimeField(auto_now_add=True)),
- ('by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.Account')),
- ('checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='statements', to='kfet.Checkout')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("balance_old", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("balance_new", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("amount_taken", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("amount_error", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("at", models.DateTimeField(auto_now_add=True)),
+ (
+ "by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="+",
+ to="kfet.Account",
+ ),
+ ),
+ (
+ "checkout",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="statements",
+ to="kfet.Checkout",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Supplier',
+ name="Supplier",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=45)),
- ('address', models.TextField()),
- ('email', models.EmailField(max_length=254)),
- ('phone', models.CharField(max_length=10)),
- ('comment', models.TextField()),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=45)),
+ ("address", models.TextField()),
+ ("email", models.EmailField(max_length=254)),
+ ("phone", models.CharField(max_length=10)),
+ ("comment", models.TextField()),
],
),
migrations.CreateModel(
- name='SupplierArticle',
+ name="SupplierArticle",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('box_type', models.CharField(max_length=7, choices=[('caisse', 'Caisse'), ('carton', 'Carton'), ('palette', 'Palette'), ('fût', 'Fût')])),
- ('box_capacity', models.PositiveSmallIntegerField()),
- ('price_HT', models.DecimalField(decimal_places=4, max_digits=7)),
- ('TVA', models.DecimalField(decimal_places=2, max_digits=4)),
- ('rights', models.DecimalField(decimal_places=4, max_digits=7)),
- ('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Article')),
- ('supplier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Supplier')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "box_type",
+ models.CharField(
+ max_length=7,
+ choices=[
+ ("caisse", "Caisse"),
+ ("carton", "Carton"),
+ ("palette", "Palette"),
+ ("fût", "Fût"),
+ ],
+ ),
+ ),
+ ("box_capacity", models.PositiveSmallIntegerField()),
+ ("price_HT", models.DecimalField(decimal_places=4, max_digits=7)),
+ ("TVA", models.DecimalField(decimal_places=2, max_digits=4)),
+ ("rights", models.DecimalField(decimal_places=4, max_digits=7)),
+ (
+ "article",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT, to="kfet.Article"
+ ),
+ ),
+ (
+ "supplier",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT, to="kfet.Supplier"
+ ),
+ ),
],
),
migrations.CreateModel(
- name='Transfer',
+ name="Transfer",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('amount', models.DecimalField(decimal_places=2, max_digits=6)),
- ('canceled_at', models.DateTimeField(blank=True, null=True, default=None)),
- ('canceled_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=None)),
- ('from_acc', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_from', to='kfet.Account')),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("amount", models.DecimalField(decimal_places=2, max_digits=6)),
+ (
+ "canceled_at",
+ models.DateTimeField(blank=True, null=True, default=None),
+ ),
+ (
+ "canceled_by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="+",
+ to="kfet.Account",
+ null=True,
+ default=None,
+ ),
+ ),
+ (
+ "from_acc",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="transfers_from",
+ to="kfet.Account",
+ ),
+ ),
],
),
migrations.CreateModel(
- name='TransferGroup',
+ name="TransferGroup",
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('at', models.DateTimeField(auto_now_add=True)),
- ('comment', models.CharField(max_length=255, blank=True, default='')),
- ('valid_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=None)),
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("at", models.DateTimeField(auto_now_add=True)),
+ ("comment", models.CharField(max_length=255, blank=True, default="")),
+ (
+ "valid_by",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="+",
+ to="kfet.Account",
+ null=True,
+ default=None,
+ ),
+ ),
],
),
migrations.AddField(
- model_name='transfer',
- name='group',
- field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers', to='kfet.TransferGroup'),
+ model_name="transfer",
+ name="group",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="transfers",
+ to="kfet.TransferGroup",
+ ),
),
migrations.AddField(
- model_name='transfer',
- name='to_acc',
- field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_to', to='kfet.Account'),
+ model_name="transfer",
+ name="to_acc",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="transfers_to",
+ to="kfet.Account",
+ ),
),
migrations.AddField(
- model_name='supplier',
- name='articles',
- field=models.ManyToManyField(related_name='suppliers', through='kfet.SupplierArticle', to='kfet.Article'),
+ model_name="supplier",
+ name="articles",
+ field=models.ManyToManyField(
+ related_name="suppliers",
+ through="kfet.SupplierArticle",
+ to="kfet.Article",
+ ),
),
migrations.AddField(
- model_name='order',
- name='articles',
- field=models.ManyToManyField(related_name='orders', through='kfet.OrderArticle', to='kfet.Article'),
+ model_name="order",
+ name="articles",
+ field=models.ManyToManyField(
+ related_name="orders", through="kfet.OrderArticle", to="kfet.Article"
+ ),
),
migrations.AddField(
- model_name='order',
- name='supplier',
- field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='kfet.Supplier'),
+ model_name="order",
+ name="supplier",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="orders",
+ to="kfet.Supplier",
+ ),
),
migrations.AddField(
- model_name='operation',
- name='group',
- field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.OperationGroup'),
+ model_name="operation",
+ name="group",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="+",
+ to="kfet.OperationGroup",
+ ),
),
migrations.AddField(
- model_name='inventory',
- name='articles',
- field=models.ManyToManyField(related_name='inventories', through='kfet.InventoryArticle', to='kfet.Article'),
+ model_name="inventory",
+ name="articles",
+ field=models.ManyToManyField(
+ related_name="inventories",
+ through="kfet.InventoryArticle",
+ to="kfet.Article",
+ ),
),
migrations.AddField(
- model_name='inventory',
- name='by',
- field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.Account'),
+ model_name="inventory",
+ name="by",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="+",
+ to="kfet.Account",
+ ),
),
migrations.AddField(
- model_name='inventory',
- name='order',
- field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='inventory', to='kfet.Order', null=True, default=None),
+ model_name="inventory",
+ name="order",
+ field=models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ blank=True,
+ related_name="inventory",
+ to="kfet.Order",
+ null=True,
+ default=None,
+ ),
),
migrations.AddField(
- model_name='article',
- name='category',
- field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='articles', to='kfet.ArticleCategory'),
+ model_name="article",
+ name="category",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="articles",
+ to="kfet.ArticleCategory",
+ ),
),
]
diff --git a/kfet/migrations/0002_auto_20160802_2139.py b/kfet/migrations/0002_auto_20160802_2139.py
index 0a59de44..39ccbbe5 100644
--- a/kfet/migrations/0002_auto_20160802_2139.py
+++ b/kfet/migrations/0002_auto_20160802_2139.py
@@ -1,24 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import datetime
+from django.db import migrations, models
+
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0001_initial'),
- ]
+ dependencies = [("kfet", "0001_initial")]
operations = [
migrations.AlterModelOptions(
- name='account',
- options={'permissions': (('is_team', 'Is part of the team'),)},
+ name="account",
+ options={"permissions": (("is_team", "Is part of the team"),)},
),
migrations.AlterField(
- model_name='accountnegative',
- name='start',
- field=models.DateTimeField(default=datetime.datetime(2016, 8, 2, 21, 39, 30, 52279)),
+ model_name="accountnegative",
+ name="start",
+ field=models.DateTimeField(
+ default=datetime.datetime(2016, 8, 2, 21, 39, 30, 52279)
+ ),
),
]
diff --git a/kfet/migrations/0003_auto_20160802_2142.py b/kfet/migrations/0003_auto_20160802_2142.py
index 586146de..c3bfda52 100644
--- a/kfet/migrations/0003_auto_20160802_2142.py
+++ b/kfet/migrations/0003_auto_20160802_2142.py
@@ -1,20 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import datetime
+from django.db import migrations, models
+
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0002_auto_20160802_2139'),
- ]
+ dependencies = [("kfet", "0002_auto_20160802_2139")]
operations = [
migrations.AlterField(
- model_name='accountnegative',
- name='start',
+ model_name="accountnegative",
+ name="start",
field=models.DateTimeField(default=datetime.datetime.now),
- ),
+ )
]
diff --git a/kfet/migrations/0004_auto_20160802_2144.py b/kfet/migrations/0004_auto_20160802_2144.py
index b9e9d0d3..48646cef 100644
--- a/kfet/migrations/0004_auto_20160802_2144.py
+++ b/kfet/migrations/0004_auto_20160802_2144.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0003_auto_20160802_2142'),
- ]
+ dependencies = [("kfet", "0003_auto_20160802_2142")]
operations = [
migrations.AlterField(
- model_name='accountnegative',
- name='balance_offset',
+ model_name="accountnegative",
+ name="balance_offset",
field=models.DecimalField(decimal_places=2, max_digits=6, default=0),
- ),
+ )
]
diff --git a/kfet/migrations/0005_auto_20160802_2154.py b/kfet/migrations/0005_auto_20160802_2154.py
index a01419fc..49c96b1c 100644
--- a/kfet/migrations/0005_auto_20160802_2154.py
+++ b/kfet/migrations/0005_auto_20160802_2154.py
@@ -1,28 +1,31 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0004_auto_20160802_2144'),
- ]
+ dependencies = [("kfet", "0004_auto_20160802_2144")]
operations = [
migrations.CreateModel(
- name='GlobalPermissions',
+ name="GlobalPermissions",
fields=[
- ('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)),
+ (
+ "id",
+ models.AutoField(
+ serialize=False,
+ primary_key=True,
+ verbose_name="ID",
+ auto_created=True,
+ ),
+ )
],
options={
- 'permissions': (('is_team', 'Is part of the team'),),
- 'managed': False,
+ "permissions": (("is_team", "Is part of the team"),),
+ "managed": False,
},
),
- migrations.AlterModelOptions(
- name='account',
- options={},
- ),
+ migrations.AlterModelOptions(name="account", options={}),
]
diff --git a/kfet/migrations/0006_auto_20160804_0600.py b/kfet/migrations/0006_auto_20160804_0600.py
index 063504b9..524e1352 100644
--- a/kfet/migrations/0006_auto_20160804_0600.py
+++ b/kfet/migrations/0006_auto_20160804_0600.py
@@ -1,28 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0005_auto_20160802_2154'),
- ]
+ dependencies = [("kfet", "0005_auto_20160802_2154")]
operations = [
migrations.AlterModelOptions(
- name='checkout',
- options={'ordering': ['-valid_to']},
+ name="checkout", options={"ordering": ["-valid_to"]}
),
migrations.RenameField(
- model_name='account',
- old_name='frozen',
- new_name='is_frozen',
+ model_name="account", old_name="frozen", new_name="is_frozen"
),
migrations.AlterField(
- model_name='checkout',
- name='balance',
+ model_name="checkout",
+ name="balance",
field=models.DecimalField(max_digits=6, default=0, decimal_places=2),
),
]
diff --git a/kfet/migrations/0007_auto_20160804_0641.py b/kfet/migrations/0007_auto_20160804_0641.py
index 70bff402..fb870a71 100644
--- a/kfet/migrations/0007_auto_20160804_0641.py
+++ b/kfet/migrations/0007_auto_20160804_0641.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0006_auto_20160804_0600'),
- ]
+ dependencies = [("kfet", "0006_auto_20160804_0600")]
operations = [
migrations.AlterField(
- model_name='article',
- name='price',
+ model_name="article",
+ name="price",
field=models.DecimalField(default=0, max_digits=6, decimal_places=2),
- ),
+ )
]
diff --git a/kfet/migrations/0008_auto_20160804_1736.py b/kfet/migrations/0008_auto_20160804_1736.py
index 1abbb76a..930562b0 100644
--- a/kfet/migrations/0008_auto_20160804_1736.py
+++ b/kfet/migrations/0008_auto_20160804_1736.py
@@ -1,20 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import django.core.validators
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0007_auto_20160804_0641'),
- ]
+ dependencies = [("kfet", "0007_auto_20160804_0641")]
operations = [
migrations.AlterField(
- model_name='account',
- name='trigramme',
- field=models.CharField(unique=True, validators=[django.core.validators.RegexValidator(regex='^[^a-z]{3}$')], db_index=True, max_length=3),
- ),
+ model_name="account",
+ name="trigramme",
+ field=models.CharField(
+ unique=True,
+ validators=[django.core.validators.RegexValidator(regex="^[^a-z]{3}$")],
+ db_index=True,
+ max_length=3,
+ ),
+ )
]
diff --git a/kfet/migrations/0009_auto_20160805_0720.py b/kfet/migrations/0009_auto_20160805_0720.py
index 8e9a4db9..90a19749 100644
--- a/kfet/migrations/0009_auto_20160805_0720.py
+++ b/kfet/migrations/0009_auto_20160805_0720.py
@@ -1,24 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0008_auto_20160804_1736'),
- ]
+ dependencies = [("kfet", "0008_auto_20160804_1736")]
operations = [
migrations.RenameField(
- model_name='operation',
- old_name='on_checkout',
- new_name='is_checkout',
+ model_name="operation", old_name="on_checkout", new_name="is_checkout"
),
migrations.AddField(
- model_name='operation',
- name='article_nb',
+ model_name="operation",
+ name="article_nb",
field=models.PositiveSmallIntegerField(default=None, null=True, blank=True),
),
]
diff --git a/kfet/migrations/0010_auto_20160806_2343.py b/kfet/migrations/0010_auto_20160806_2343.py
index 60c8cc93..84267a6d 100644
--- a/kfet/migrations/0010_auto_20160806_2343.py
+++ b/kfet/migrations/0010_auto_20160806_2343.py
@@ -1,30 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0009_auto_20160805_0720'),
- ]
+ dependencies = [("kfet", "0009_auto_20160805_0720")]
operations = [
migrations.AlterField(
- model_name='operation',
- name='addcost_amount',
+ model_name="operation",
+ name="addcost_amount",
field=models.DecimalField(max_digits=6, default=0, decimal_places=2),
),
migrations.AlterField(
- model_name='operationgroup',
- name='amount',
+ model_name="operationgroup",
+ name="amount",
field=models.DecimalField(max_digits=6, default=0, decimal_places=2),
),
migrations.AlterField(
- model_name='operationgroup',
- name='valid_by',
- field=models.ForeignKey(default=None, related_name='+', to='kfet.Account', blank=True, null=True, on_delete=django.db.models.deletion.PROTECT),
+ model_name="operationgroup",
+ name="valid_by",
+ field=models.ForeignKey(
+ default=None,
+ related_name="+",
+ to="kfet.Account",
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ ),
),
]
diff --git a/kfet/migrations/0011_auto_20160807_1720.py b/kfet/migrations/0011_auto_20160807_1720.py
index 97525676..53064235 100644
--- a/kfet/migrations/0011_auto_20160807_1720.py
+++ b/kfet/migrations/0011_auto_20160807_1720.py
@@ -1,19 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0010_auto_20160806_2343'),
- ]
+ dependencies = [("kfet", "0010_auto_20160806_2343")]
operations = [
migrations.AlterField(
- model_name='operation',
- name='amount',
- field=models.DecimalField(decimal_places=2, max_digits=6, default=0, blank=True),
- ),
+ model_name="operation",
+ name="amount",
+ field=models.DecimalField(
+ decimal_places=2, max_digits=6, default=0, blank=True
+ ),
+ )
]
diff --git a/kfet/migrations/0012_settings.py b/kfet/migrations/0012_settings.py
index 8f0f6247..1bae911d 100644
--- a/kfet/migrations/0012_settings.py
+++ b/kfet/migrations/0012_settings.py
@@ -1,22 +1,37 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0011_auto_20160807_1720'),
- ]
+ dependencies = [("kfet", "0011_auto_20160807_1720")]
operations = [
migrations.CreateModel(
- name='Settings',
+ name="Settings",
fields=[
- ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
- ('name', models.CharField(max_length=45)),
- ('value_decimal', models.DecimalField(null=True, max_digits=6, decimal_places=2, blank=True, default=None)),
+ (
+ "id",
+ models.AutoField(
+ serialize=False,
+ auto_created=True,
+ primary_key=True,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=45)),
+ (
+ "value_decimal",
+ models.DecimalField(
+ null=True,
+ max_digits=6,
+ decimal_places=2,
+ blank=True,
+ default=None,
+ ),
+ ),
],
- ),
+ )
]
diff --git a/kfet/migrations/0013_auto_20160807_1840.py b/kfet/migrations/0013_auto_20160807_1840.py
index d7ce2c75..9a9ac3b1 100644
--- a/kfet/migrations/0013_auto_20160807_1840.py
+++ b/kfet/migrations/0013_auto_20160807_1840.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0012_settings'),
- ]
+ dependencies = [("kfet", "0012_settings")]
operations = [
migrations.AlterField(
- model_name='settings',
- name='name',
+ model_name="settings",
+ name="name",
field=models.CharField(unique=True, max_length=45),
- ),
+ )
]
diff --git a/kfet/migrations/0014_auto_20160807_2314.py b/kfet/migrations/0014_auto_20160807_2314.py
index 50417091..ecaee428 100644
--- a/kfet/migrations/0014_auto_20160807_2314.py
+++ b/kfet/migrations/0014_auto_20160807_2314.py
@@ -1,18 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0013_auto_20160807_1840'),
- ]
+ dependencies = [("kfet", "0013_auto_20160807_1840")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('can_perform_deposit', 'Peut effectuer une charge')), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("can_perform_deposit", "Peut effectuer une charge"),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0015_auto_20160807_2324.py b/kfet/migrations/0015_auto_20160807_2324.py
index a1789fc2..fa2af882 100644
--- a/kfet/migrations/0015_auto_20160807_2324.py
+++ b/kfet/migrations/0015_auto_20160807_2324.py
@@ -1,18 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0014_auto_20160807_2314'),
- ]
+ dependencies = [("kfet", "0014_auto_20160807_2314")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('can_perform_deposit', 'Peut effectuer une charge'), ('can_perform_negative_operations', 'Peut enregistrer des commandes en négatif')), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("can_perform_deposit", "Peut effectuer une charge"),
+ (
+ "can_perform_negative_operations",
+ "Peut enregistrer des commandes en négatif",
+ ),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0016_settings_value_account.py b/kfet/migrations/0016_settings_value_account.py
index 53793938..e10eb682 100644
--- a/kfet/migrations/0016_settings_value_account.py
+++ b/kfet/migrations/0016_settings_value_account.py
@@ -1,20 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0015_auto_20160807_2324'),
- ]
+ dependencies = [("kfet", "0015_auto_20160807_2324")]
operations = [
migrations.AddField(
- model_name='settings',
- name='value_account',
- field=models.ForeignKey(to='kfet.Account', on_delete=django.db.models.deletion.PROTECT, default=None, null=True, blank=True),
- ),
+ model_name="settings",
+ name="value_account",
+ field=models.ForeignKey(
+ to="kfet.Account",
+ on_delete=django.db.models.deletion.PROTECT,
+ default=None,
+ null=True,
+ blank=True,
+ ),
+ )
]
diff --git a/kfet/migrations/0017_auto_20160808_0234.py b/kfet/migrations/0017_auto_20160808_0234.py
index e8aa8ec0..795078a9 100644
--- a/kfet/migrations/0017_auto_20160808_0234.py
+++ b/kfet/migrations/0017_auto_20160808_0234.py
@@ -1,19 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0016_settings_value_account'),
- ]
+ dependencies = [("kfet", "0016_settings_value_account")]
operations = [
migrations.AlterField(
- model_name='operation',
- name='addcost_amount',
- field=models.DecimalField(blank=True, null=True, decimal_places=2, default=None, max_digits=6),
- ),
+ model_name="operation",
+ name="addcost_amount",
+ field=models.DecimalField(
+ blank=True, null=True, decimal_places=2, default=None, max_digits=6
+ ),
+ )
]
diff --git a/kfet/migrations/0018_auto_20160808_0341.py b/kfet/migrations/0018_auto_20160808_0341.py
index 384e82b2..3b29b716 100644
--- a/kfet/migrations/0018_auto_20160808_0341.py
+++ b/kfet/migrations/0018_auto_20160808_0341.py
@@ -1,18 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0017_auto_20160808_0234'),
- ]
+ dependencies = [("kfet", "0017_auto_20160808_0234")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('can_perform_deposit', 'Effectuer une charge'), ('can_perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte")), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("can_perform_deposit", "Effectuer une charge"),
+ (
+ "can_perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0019_auto_20160808_0343.py b/kfet/migrations/0019_auto_20160808_0343.py
index 6512b7ea..f500032a 100644
--- a/kfet/migrations/0019_auto_20160808_0343.py
+++ b/kfet/migrations/0019_auto_20160808_0343.py
@@ -1,18 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0018_auto_20160808_0341'),
- ]
+ dependencies = [("kfet", "0018_auto_20160808_0341")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"))},
- ),
+ name="globalpermissions",
+ options={
+ "managed": False,
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ),
+ },
+ )
]
diff --git a/kfet/migrations/0020_auto_20160808_0450.py b/kfet/migrations/0020_auto_20160808_0450.py
index 2ecc18ee..d3424bac 100644
--- a/kfet/migrations/0020_auto_20160808_0450.py
+++ b/kfet/migrations/0020_auto_20160808_0450.py
@@ -1,20 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import datetime
+from django.db import migrations, models
+
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0019_auto_20160808_0343'),
- ]
+ dependencies = [("kfet", "0019_auto_20160808_0343")]
operations = [
migrations.AlterField(
- model_name='accountnegative',
- name='start',
- field=models.DateTimeField(default=datetime.datetime.now, blank=True, null=True),
- ),
+ model_name="accountnegative",
+ name="start",
+ field=models.DateTimeField(
+ default=datetime.datetime.now, blank=True, null=True
+ ),
+ )
]
diff --git a/kfet/migrations/0021_auto_20160808_0506.py b/kfet/migrations/0021_auto_20160808_0506.py
index 61a7ef65..2ef48232 100644
--- a/kfet/migrations/0021_auto_20160808_0506.py
+++ b/kfet/migrations/0021_auto_20160808_0506.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0020_auto_20160808_0450'),
- ]
+ dependencies = [("kfet", "0020_auto_20160808_0450")]
operations = [
migrations.AlterField(
- model_name='accountnegative',
- name='start',
+ model_name="accountnegative",
+ name="start",
field=models.DateTimeField(default=None, blank=True, null=True),
- ),
+ )
]
diff --git a/kfet/migrations/0022_auto_20160808_0512.py b/kfet/migrations/0022_auto_20160808_0512.py
index ba5de03e..3701e856 100644
--- a/kfet/migrations/0022_auto_20160808_0512.py
+++ b/kfet/migrations/0022_auto_20160808_0512.py
@@ -1,24 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0021_auto_20160808_0506'),
- ]
+ dependencies = [("kfet", "0021_auto_20160808_0506")]
operations = [
migrations.AlterField(
- model_name='accountnegative',
- name='authorized_overdraft',
- field=models.DecimalField(blank=True, decimal_places=2, null=True, default=None, max_digits=6),
+ model_name="accountnegative",
+ name="authorized_overdraft",
+ field=models.DecimalField(
+ blank=True, decimal_places=2, null=True, default=None, max_digits=6
+ ),
),
migrations.AlterField(
- model_name='accountnegative',
- name='balance_offset',
- field=models.DecimalField(blank=True, decimal_places=2, null=True, default=None, max_digits=6),
+ model_name="accountnegative",
+ name="balance_offset",
+ field=models.DecimalField(
+ blank=True, decimal_places=2, null=True, default=None, max_digits=6
+ ),
),
]
diff --git a/kfet/migrations/0023_auto_20160808_0535.py b/kfet/migrations/0023_auto_20160808_0535.py
index 7e4d7051..03a8d1c3 100644
--- a/kfet/migrations/0023_auto_20160808_0535.py
+++ b/kfet/migrations/0023_auto_20160808_0535.py
@@ -1,24 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0022_auto_20160808_0512'),
- ]
+ dependencies = [("kfet", "0022_auto_20160808_0512")]
operations = [
migrations.RenameField(
- model_name='accountnegative',
- old_name='authorized_overdraft',
- new_name='authz_overdraft_amount',
+ model_name="accountnegative",
+ old_name="authorized_overdraft",
+ new_name="authz_overdraft_amount",
),
migrations.AddField(
- model_name='accountnegative',
- name='authz_overdraft_until',
+ model_name="accountnegative",
+ name="authz_overdraft_until",
field=models.DateTimeField(null=True, default=None, blank=True),
),
]
diff --git a/kfet/migrations/0024_settings_value_duration.py b/kfet/migrations/0024_settings_value_duration.py
index 1f90b1c9..56b22812 100644
--- a/kfet/migrations/0024_settings_value_duration.py
+++ b/kfet/migrations/0024_settings_value_duration.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0023_auto_20160808_0535'),
- ]
+ dependencies = [("kfet", "0023_auto_20160808_0535")]
operations = [
migrations.AddField(
- model_name='settings',
- name='value_duration',
+ model_name="settings",
+ name="value_duration",
field=models.DurationField(null=True, default=None, blank=True),
- ),
+ )
]
diff --git a/kfet/migrations/0025_auto_20160809_0750.py b/kfet/migrations/0025_auto_20160809_0750.py
index 8ba90e2d..51f3b5a3 100644
--- a/kfet/migrations/0025_auto_20160809_0750.py
+++ b/kfet/migrations/0025_auto_20160809_0750.py
@@ -1,18 +1,28 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0024_settings_value_duration'),
- ]
+ dependencies = [("kfet", "0024_settings_value_duration")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes')), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0026_auto_20160809_0810.py b/kfet/migrations/0026_auto_20160809_0810.py
index 7e96c937..942eaf26 100644
--- a/kfet/migrations/0026_auto_20160809_0810.py
+++ b/kfet/migrations/0026_auto_20160809_0810.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0025_auto_20160809_0750'),
- ]
+ dependencies = [("kfet", "0025_auto_20160809_0750")]
operations = [
migrations.AlterField(
- model_name='settings',
- name='name',
+ model_name="settings",
+ name="name",
field=models.CharField(db_index=True, max_length=45, unique=True),
- ),
+ )
]
diff --git a/kfet/migrations/0027_auto_20160811_0648.py b/kfet/migrations/0027_auto_20160811_0648.py
index 25bd826b..a0084e8a 100644
--- a/kfet/migrations/0027_auto_20160811_0648.py
+++ b/kfet/migrations/0027_auto_20160811_0648.py
@@ -1,39 +1,51 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0026_auto_20160809_0810'),
- ]
+ dependencies = [("kfet", "0026_auto_20160809_0810")]
operations = [
migrations.CreateModel(
- name='CheckoutStatement',
+ name="CheckoutStatement",
fields=[
- ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
- ('balance_old', models.DecimalField(decimal_places=2, max_digits=6)),
- ('balance_new', models.DecimalField(decimal_places=2, max_digits=6)),
- ('amount_taken', models.DecimalField(decimal_places=2, max_digits=6)),
- ('amount_error', models.DecimalField(decimal_places=2, max_digits=6)),
- ('at', models.DateTimeField(auto_now_add=True)),
- ('by', models.ForeignKey(to='kfet.Account', on_delete=django.db.models.deletion.PROTECT, related_name='+')),
- ('checkout', models.ForeignKey(to='kfet.Checkout', on_delete=django.db.models.deletion.PROTECT, related_name='statements')),
+ (
+ "id",
+ models.AutoField(
+ verbose_name="ID",
+ primary_key=True,
+ serialize=False,
+ auto_created=True,
+ ),
+ ),
+ ("balance_old", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("balance_new", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("amount_taken", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("amount_error", models.DecimalField(decimal_places=2, max_digits=6)),
+ ("at", models.DateTimeField(auto_now_add=True)),
+ (
+ "by",
+ models.ForeignKey(
+ to="kfet.Account",
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="+",
+ ),
+ ),
+ (
+ "checkout",
+ models.ForeignKey(
+ to="kfet.Checkout",
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="statements",
+ ),
+ ),
],
),
- migrations.RemoveField(
- model_name='statement',
- name='by',
- ),
- migrations.RemoveField(
- model_name='statement',
- name='checkout',
- ),
- migrations.DeleteModel(
- name='Statement',
- ),
+ migrations.RemoveField(model_name="statement", name="by"),
+ migrations.RemoveField(model_name="statement", name="checkout"),
+ migrations.DeleteModel(name="Statement"),
]
diff --git a/kfet/migrations/0028_auto_20160820_0146.py b/kfet/migrations/0028_auto_20160820_0146.py
index 5f8fa377..a1b046cf 100644
--- a/kfet/migrations/0028_auto_20160820_0146.py
+++ b/kfet/migrations/0028_auto_20160820_0146.py
@@ -1,30 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0027_auto_20160811_0648'),
- ]
+ dependencies = [("kfet", "0027_auto_20160811_0648")]
operations = [
migrations.AlterField(
- model_name='operation',
- name='group',
- field=models.ForeignKey(to='kfet.OperationGroup', on_delete=django.db.models.deletion.PROTECT, related_name='opes'),
+ model_name="operation",
+ name="group",
+ field=models.ForeignKey(
+ to="kfet.OperationGroup",
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="opes",
+ ),
),
migrations.AlterField(
- model_name='operationgroup',
- name='checkout',
- field=models.ForeignKey(to='kfet.Checkout', on_delete=django.db.models.deletion.PROTECT, related_name='opesgroup'),
+ model_name="operationgroup",
+ name="checkout",
+ field=models.ForeignKey(
+ to="kfet.Checkout",
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="opesgroup",
+ ),
),
migrations.AlterField(
- model_name='operationgroup',
- name='on_acc',
- field=models.ForeignKey(to='kfet.Account', on_delete=django.db.models.deletion.PROTECT, related_name='opesgroup'),
+ model_name="operationgroup",
+ name="on_acc",
+ field=models.ForeignKey(
+ to="kfet.Account",
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="opesgroup",
+ ),
),
]
diff --git a/kfet/migrations/0029_genericteamtoken.py b/kfet/migrations/0029_genericteamtoken.py
index ba13674c..c5a81f05 100644
--- a/kfet/migrations/0029_genericteamtoken.py
+++ b/kfet/migrations/0029_genericteamtoken.py
@@ -1,21 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0028_auto_20160820_0146'),
- ]
+ dependencies = [("kfet", "0028_auto_20160820_0146")]
operations = [
migrations.CreateModel(
- name='GenericTeamToken',
+ name="GenericTeamToken",
fields=[
- ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')),
- ('token', models.CharField(unique=True, max_length=50)),
+ (
+ "id",
+ models.AutoField(
+ serialize=False,
+ primary_key=True,
+ auto_created=True,
+ verbose_name="ID",
+ ),
+ ),
+ ("token", models.CharField(unique=True, max_length=50)),
],
- ),
+ )
]
diff --git a/kfet/migrations/0030_auto_20160821_0029.py b/kfet/migrations/0030_auto_20160821_0029.py
index ed54efa9..1858522d 100644
--- a/kfet/migrations/0030_auto_20160821_0029.py
+++ b/kfet/migrations/0030_auto_20160821_0029.py
@@ -1,18 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0029_genericteamtoken'),
- ]
+ dependencies = [("kfet", "0029_genericteamtoken")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt')), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0031_auto_20160822_0523.py b/kfet/migrations/0031_auto_20160822_0523.py
index e7ca4d6f..23aec1be 100644
--- a/kfet/migrations/0031_auto_20160822_0523.py
+++ b/kfet/migrations/0031_auto_20160822_0523.py
@@ -1,18 +1,30 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0030_auto_20160821_0029'),
- ]
+ dependencies = [("kfet", "0030_auto_20160821_0029")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations')), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0032_auto_20160822_2350.py b/kfet/migrations/0032_auto_20160822_2350.py
index 142fb29d..7cba0da3 100644
--- a/kfet/migrations/0032_auto_20160822_2350.py
+++ b/kfet/migrations/0032_auto_20160822_2350.py
@@ -1,94 +1,92 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0031_auto_20160822_0523'),
- ]
+ dependencies = [("kfet", "0031_auto_20160822_0523")]
operations = [
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_001',
+ model_name="checkoutstatement",
+ name="taken_001",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_002',
+ model_name="checkoutstatement",
+ name="taken_002",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_005',
+ model_name="checkoutstatement",
+ name="taken_005",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_01',
+ model_name="checkoutstatement",
+ name="taken_01",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_02',
+ model_name="checkoutstatement",
+ name="taken_02",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_05',
+ model_name="checkoutstatement",
+ name="taken_05",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_1',
+ model_name="checkoutstatement",
+ name="taken_1",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_10',
+ model_name="checkoutstatement",
+ name="taken_10",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_100',
+ model_name="checkoutstatement",
+ name="taken_100",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_2',
+ model_name="checkoutstatement",
+ name="taken_2",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_20',
+ model_name="checkoutstatement",
+ name="taken_20",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_200',
+ model_name="checkoutstatement",
+ name="taken_200",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_5',
+ model_name="checkoutstatement",
+ name="taken_5",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_50',
+ model_name="checkoutstatement",
+ name="taken_50",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_500',
+ model_name="checkoutstatement",
+ name="taken_500",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
- model_name='checkoutstatement',
- name='taken_cheque',
+ model_name="checkoutstatement",
+ name="taken_cheque",
field=models.PositiveSmallIntegerField(default=0),
),
]
diff --git a/kfet/migrations/0033_checkoutstatement_not_count.py b/kfet/migrations/0033_checkoutstatement_not_count.py
index 50c58256..dd445406 100644
--- a/kfet/migrations/0033_checkoutstatement_not_count.py
+++ b/kfet/migrations/0033_checkoutstatement_not_count.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0032_auto_20160822_2350'),
- ]
+ dependencies = [("kfet", "0032_auto_20160822_2350")]
operations = [
migrations.AddField(
- model_name='checkoutstatement',
- name='not_count',
+ model_name="checkoutstatement",
+ name="not_count",
field=models.BooleanField(default=False),
- ),
+ )
]
diff --git a/kfet/migrations/0034_auto_20160823_0206.py b/kfet/migrations/0034_auto_20160823_0206.py
index 90d0965c..1b28e289 100644
--- a/kfet/migrations/0034_auto_20160823_0206.py
+++ b/kfet/migrations/0034_auto_20160823_0206.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0033_checkoutstatement_not_count'),
- ]
+ dependencies = [("kfet", "0033_checkoutstatement_not_count")]
operations = [
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_cheque',
+ model_name="checkoutstatement",
+ name="taken_cheque",
field=models.DecimalField(max_digits=6, decimal_places=2, default=0),
- ),
+ )
]
diff --git a/kfet/migrations/0035_auto_20160823_1505.py b/kfet/migrations/0035_auto_20160823_1505.py
index 5fd73ae8..e2a98ca7 100644
--- a/kfet/migrations/0035_auto_20160823_1505.py
+++ b/kfet/migrations/0035_auto_20160823_1505.py
@@ -1,18 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0034_auto_20160823_0206'),
- ]
+ dependencies = [("kfet", "0034_auto_20160823_0206")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'))},
- ),
+ name="globalpermissions",
+ options={
+ "managed": False,
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ ),
+ },
+ )
]
diff --git a/kfet/migrations/0036_auto_20160823_1910.py b/kfet/migrations/0036_auto_20160823_1910.py
index 2d29fd7a..09726e37 100644
--- a/kfet/migrations/0036_auto_20160823_1910.py
+++ b/kfet/migrations/0036_auto_20160823_1910.py
@@ -1,18 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0035_auto_20160823_1505'),
- ]
+ dependencies = [("kfet", "0035_auto_20160823_1505")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des négatifs'))},
- ),
+ name="globalpermissions",
+ options={
+ "managed": False,
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ ("view_negs", "Voir la liste des négatifs"),
+ ),
+ },
+ )
]
diff --git a/kfet/migrations/0037_auto_20160826_2333.py b/kfet/migrations/0037_auto_20160826_2333.py
index 9f937b60..6ebc921d 100644
--- a/kfet/migrations/0037_auto_20160826_2333.py
+++ b/kfet/migrations/0037_auto_20160826_2333.py
@@ -1,39 +1,54 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0036_auto_20160823_1910'),
- ]
+ dependencies = [("kfet", "0036_auto_20160823_1910")]
operations = [
migrations.AlterField(
- model_name='supplierarticle',
- name='TVA',
- field=models.DecimalField(null=True, max_digits=4, decimal_places=2, default=None, blank=True),
+ model_name="supplierarticle",
+ name="TVA",
+ field=models.DecimalField(
+ null=True, max_digits=4, decimal_places=2, default=None, blank=True
+ ),
),
migrations.AlterField(
- model_name='supplierarticle',
- name='box_capacity',
+ model_name="supplierarticle",
+ name="box_capacity",
field=models.PositiveSmallIntegerField(null=True, default=None, blank=True),
),
migrations.AlterField(
- model_name='supplierarticle',
- name='box_type',
- field=models.CharField(null=True, max_length=7, choices=[('caisse', 'Caisse'), ('carton', 'Carton'), ('palette', 'Palette'), ('fût', 'Fût')], default=None, blank=True),
+ model_name="supplierarticle",
+ name="box_type",
+ field=models.CharField(
+ null=True,
+ max_length=7,
+ choices=[
+ ("caisse", "Caisse"),
+ ("carton", "Carton"),
+ ("palette", "Palette"),
+ ("fût", "Fût"),
+ ],
+ default=None,
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='supplierarticle',
- name='price_HT',
- field=models.DecimalField(null=True, max_digits=7, decimal_places=4, default=None, blank=True),
+ model_name="supplierarticle",
+ name="price_HT",
+ field=models.DecimalField(
+ null=True, max_digits=7, decimal_places=4, default=None, blank=True
+ ),
),
migrations.AlterField(
- model_name='supplierarticle',
- name='rights',
- field=models.DecimalField(null=True, max_digits=7, decimal_places=4, default=None, blank=True),
+ model_name="supplierarticle",
+ name="rights",
+ field=models.DecimalField(
+ null=True, max_digits=7, decimal_places=4, default=None, blank=True
+ ),
),
]
diff --git a/kfet/migrations/0038_auto_20160828_0402.py b/kfet/migrations/0038_auto_20160828_0402.py
index 215591b7..be8d847e 100644
--- a/kfet/migrations/0038_auto_20160828_0402.py
+++ b/kfet/migrations/0038_auto_20160828_0402.py
@@ -1,36 +1,36 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0037_auto_20160826_2333'),
- ]
+ dependencies = [("kfet", "0037_auto_20160826_2333")]
operations = [
- migrations.AlterModelOptions(
- name='inventory',
- options={'ordering': ['-at']},
- ),
- migrations.RemoveField(
- model_name='supplierarticle',
- name='box_capacity',
- ),
- migrations.RemoveField(
- model_name='supplierarticle',
- name='box_type',
- ),
+ migrations.AlterModelOptions(name="inventory", options={"ordering": ["-at"]}),
+ migrations.RemoveField(model_name="supplierarticle", name="box_capacity"),
+ migrations.RemoveField(model_name="supplierarticle", name="box_type"),
migrations.AddField(
- model_name='article',
- name='box_capacity',
+ model_name="article",
+ name="box_capacity",
field=models.PositiveSmallIntegerField(blank=True, null=True, default=None),
),
migrations.AddField(
- model_name='article',
- name='box_type',
- field=models.CharField(max_length=7, blank=True, null=True, default=None, choices=[('caisse', 'Caisse'), ('carton', 'Carton'), ('palette', 'Palette'), ('fût', 'Fût')]),
+ model_name="article",
+ name="box_type",
+ field=models.CharField(
+ max_length=7,
+ blank=True,
+ null=True,
+ default=None,
+ choices=[
+ ("caisse", "Caisse"),
+ ("carton", "Carton"),
+ ("palette", "Palette"),
+ ("fût", "Fût"),
+ ],
+ ),
),
]
diff --git a/kfet/migrations/0039_auto_20160828_0430.py b/kfet/migrations/0039_auto_20160828_0430.py
index 271fda68..2611d578 100644
--- a/kfet/migrations/0039_auto_20160828_0430.py
+++ b/kfet/migrations/0039_auto_20160828_0430.py
@@ -1,24 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0038_auto_20160828_0402'),
- ]
+ dependencies = [("kfet", "0038_auto_20160828_0402")]
operations = [
migrations.AlterField(
- model_name='order',
- name='amount',
+ model_name="order",
+ name="amount",
field=models.DecimalField(default=0, decimal_places=2, max_digits=6),
),
migrations.AlterField(
- model_name='orderarticle',
- name='quantity_received',
+ model_name="orderarticle",
+ name="quantity_received",
field=models.IntegerField(default=0),
),
]
diff --git a/kfet/migrations/0040_auto_20160829_2035.py b/kfet/migrations/0040_auto_20160829_2035.py
index 78b577a8..16bd2b36 100644
--- a/kfet/migrations/0040_auto_20160829_2035.py
+++ b/kfet/migrations/0040_auto_20160829_2035.py
@@ -1,31 +1,41 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
import datetime
+
+from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0039_auto_20160828_0430'),
- ]
+ dependencies = [("kfet", "0039_auto_20160828_0430")]
operations = [
- migrations.AlterModelOptions(
- name='order',
- options={'ordering': ['-at']},
- ),
+ migrations.AlterModelOptions(name="order", options={"ordering": ["-at"]}),
migrations.AddField(
- model_name='supplierarticle',
- name='at',
- field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2016, 8, 29, 18, 35, 3, 419033, tzinfo=utc)),
+ model_name="supplierarticle",
+ name="at",
+ field=models.DateTimeField(
+ auto_now_add=True,
+ default=datetime.datetime(2016, 8, 29, 18, 35, 3, 419033, tzinfo=utc),
+ ),
preserve_default=False,
),
migrations.AlterField(
- model_name='article',
- name='box_type',
- field=models.CharField(choices=[('caisse', 'caisse'), ('carton', 'carton'), ('palette', 'palette'), ('fût', 'fût')], null=True, max_length=7, blank=True, default=None),
+ model_name="article",
+ name="box_type",
+ field=models.CharField(
+ choices=[
+ ("caisse", "caisse"),
+ ("carton", "carton"),
+ ("palette", "palette"),
+ ("fût", "fût"),
+ ],
+ null=True,
+ max_length=7,
+ blank=True,
+ default=None,
+ ),
),
]
diff --git a/kfet/migrations/0041_auto_20160830_1502.py b/kfet/migrations/0041_auto_20160830_1502.py
index 40c83907..488d33ff 100644
--- a/kfet/migrations/0041_auto_20160830_1502.py
+++ b/kfet/migrations/0041_auto_20160830_1502.py
@@ -1,18 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0040_auto_20160829_2035'),
- ]
+ dependencies = [("kfet", "0040_auto_20160829_2035")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des négatifs'), ('order_to_inventory', "Générer un inventaire à partir d'une commande")), 'managed': False},
- ),
+ name="globalpermissions",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ ("view_negs", "Voir la liste des négatifs"),
+ (
+ "order_to_inventory",
+ "Générer un inventaire à partir d'une commande",
+ ),
+ ),
+ "managed": False,
+ },
+ )
]
diff --git a/kfet/migrations/0042_auto_20160831_0126.py b/kfet/migrations/0042_auto_20160831_0126.py
index 3306c401..70adbad5 100644
--- a/kfet/migrations/0042_auto_20160831_0126.py
+++ b/kfet/migrations/0042_auto_20160831_0126.py
@@ -1,18 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0041_auto_20160830_1502'),
- ]
+ dependencies = [("kfet", "0041_auto_20160830_1502")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des négatifs'), ('order_to_inventory', "Générer un inventaire à partir d'une commande"), ('edit_balance_account', "Modifier la balance d'un compte"))},
- ),
+ name="globalpermissions",
+ options={
+ "managed": False,
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ ("view_negs", "Voir la liste des négatifs"),
+ (
+ "order_to_inventory",
+ "Générer un inventaire à partir d'une commande",
+ ),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ ),
+ },
+ )
]
diff --git a/kfet/migrations/0043_auto_20160901_0046.py b/kfet/migrations/0043_auto_20160901_0046.py
index 2d9bf12a..b5132335 100644
--- a/kfet/migrations/0043_auto_20160901_0046.py
+++ b/kfet/migrations/0043_auto_20160901_0046.py
@@ -1,19 +1,60 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0042_auto_20160831_0126'),
- ]
+ dependencies = [("kfet", "0042_auto_20160831_0126")]
operations = [
migrations.AlterField(
- model_name='account',
- name='promo',
- field=models.IntegerField(blank=True, default=2016, null=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016)]),
- ),
+ model_name="account",
+ name="promo",
+ field=models.IntegerField(
+ blank=True,
+ default=2016,
+ null=True,
+ choices=[
+ (1980, 1980),
+ (1981, 1981),
+ (1982, 1982),
+ (1983, 1983),
+ (1984, 1984),
+ (1985, 1985),
+ (1986, 1986),
+ (1987, 1987),
+ (1988, 1988),
+ (1989, 1989),
+ (1990, 1990),
+ (1991, 1991),
+ (1992, 1992),
+ (1993, 1993),
+ (1994, 1994),
+ (1995, 1995),
+ (1996, 1996),
+ (1997, 1997),
+ (1998, 1998),
+ (1999, 1999),
+ (2000, 2000),
+ (2001, 2001),
+ (2002, 2002),
+ (2003, 2003),
+ (2004, 2004),
+ (2005, 2005),
+ (2006, 2006),
+ (2007, 2007),
+ (2008, 2008),
+ (2009, 2009),
+ (2010, 2010),
+ (2011, 2011),
+ (2012, 2012),
+ (2013, 2013),
+ (2014, 2014),
+ (2015, 2015),
+ (2016, 2016),
+ ],
+ ),
+ )
]
diff --git a/kfet/migrations/0044_auto_20160901_1614.py b/kfet/migrations/0044_auto_20160901_1614.py
index 2a91206a..f81ae828 100644
--- a/kfet/migrations/0044_auto_20160901_1614.py
+++ b/kfet/migrations/0044_auto_20160901_1614.py
@@ -1,18 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0043_auto_20160901_0046'),
- ]
+ dependencies = [("kfet", "0043_auto_20160901_0046")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en n\xe9gatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non r\xe9centes'), ('manage_perms', 'G\xe9rer les permissions K-F\xeat'), ('manage_addcosts', 'G\xe9rer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des n\xe9gatifs'), ('order_to_inventory', "G\xe9n\xe9rer un inventaire \xe0 partir d'une commande"), ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'\xe9quipe"))},
- ),
+ name="globalpermissions",
+ options={
+ "managed": False,
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en n\xe9gatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non r\xe9centes"),
+ ("manage_perms", "G\xe9rer les permissions K-F\xeat"),
+ ("manage_addcosts", "G\xe9rer les majorations"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ ("view_negs", "Voir la liste des n\xe9gatifs"),
+ (
+ "order_to_inventory",
+ "G\xe9n\xe9rer un inventaire \xe0 partir d'une commande",
+ ),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ (
+ "change_account_password",
+ "Modifier le mot de passe d'une personne de l'\xe9quipe",
+ ),
+ ),
+ },
+ )
]
diff --git a/kfet/migrations/0045_auto_20160905_0705.py b/kfet/migrations/0045_auto_20160905_0705.py
index 0673fdca..0f98c56a 100644
--- a/kfet/migrations/0045_auto_20160905_0705.py
+++ b/kfet/migrations/0045_auto_20160905_0705.py
@@ -1,23 +1,61 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0044_auto_20160901_1614'),
- ]
+ dependencies = [("kfet", "0044_auto_20160901_1614")]
operations = [
migrations.AlterModelOptions(
- name='globalpermissions',
- options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en n\xe9gatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non r\xe9centes'), ('manage_perms', 'G\xe9rer les permissions K-F\xeat'), ('manage_addcosts', 'G\xe9rer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des n\xe9gatifs'), ('order_to_inventory', "G\xe9n\xe9rer un inventaire \xe0 partir d'une commande"), ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'\xe9quipe"), ('special_add_account', 'Cr\xe9er un compte avec une balance initiale'))},
+ name="globalpermissions",
+ options={
+ "managed": False,
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en n\xe9gatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non r\xe9centes"),
+ ("manage_perms", "G\xe9rer les permissions K-F\xeat"),
+ ("manage_addcosts", "G\xe9rer les majorations"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ ("view_negs", "Voir la liste des n\xe9gatifs"),
+ (
+ "order_to_inventory",
+ "G\xe9n\xe9rer un inventaire \xe0 partir d'une commande",
+ ),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ (
+ "change_account_password",
+ "Modifier le mot de passe d'une personne de l'\xe9quipe",
+ ),
+ (
+ "special_add_account",
+ "Cr\xe9er un compte avec une balance initiale",
+ ),
+ ),
+ },
),
migrations.AlterField(
- model_name='operation',
- name='type',
- field=models.CharField(max_length=8, choices=[('purchase', 'Achat'), ('deposit', 'Charge'), ('withdraw', 'Retrait'), ('initial', 'Initial')]),
+ model_name="operation",
+ name="type",
+ field=models.CharField(
+ max_length=8,
+ choices=[
+ ("purchase", "Achat"),
+ ("deposit", "Charge"),
+ ("withdraw", "Retrait"),
+ ("initial", "Initial"),
+ ],
+ ),
),
]
diff --git a/kfet/migrations/0046_account_created_at.py b/kfet/migrations/0046_account_created_at.py
index a624c0fb..a0274432 100644
--- a/kfet/migrations/0046_account_created_at.py
+++ b/kfet/migrations/0046_account_created_at.py
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0045_auto_20160905_0705'),
- ]
+ dependencies = [("kfet", "0045_auto_20160905_0705")]
operations = [
migrations.AddField(
- model_name='account',
- name='created_at',
+ model_name="account",
+ name="created_at",
field=models.DateTimeField(auto_now_add=True, null=True),
- ),
+ )
]
diff --git a/kfet/migrations/0047_auto_20170104_1528.py b/kfet/migrations/0047_auto_20170104_1528.py
index d59447af..d391e1f4 100644
--- a/kfet/migrations/0047_auto_20170104_1528.py
+++ b/kfet/migrations/0047_auto_20170104_1528.py
@@ -6,14 +6,56 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0046_account_created_at'),
- ]
+ dependencies = [("kfet", "0046_account_created_at")]
operations = [
migrations.AlterField(
- model_name='account',
- name='promo',
- field=models.IntegerField(blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017)], default=2016, null=True),
- ),
+ model_name="account",
+ name="promo",
+ field=models.IntegerField(
+ blank=True,
+ choices=[
+ (1980, 1980),
+ (1981, 1981),
+ (1982, 1982),
+ (1983, 1983),
+ (1984, 1984),
+ (1985, 1985),
+ (1986, 1986),
+ (1987, 1987),
+ (1988, 1988),
+ (1989, 1989),
+ (1990, 1990),
+ (1991, 1991),
+ (1992, 1992),
+ (1993, 1993),
+ (1994, 1994),
+ (1995, 1995),
+ (1996, 1996),
+ (1997, 1997),
+ (1998, 1998),
+ (1999, 1999),
+ (2000, 2000),
+ (2001, 2001),
+ (2002, 2002),
+ (2003, 2003),
+ (2004, 2004),
+ (2005, 2005),
+ (2006, 2006),
+ (2007, 2007),
+ (2008, 2008),
+ (2009, 2009),
+ (2010, 2010),
+ (2011, 2011),
+ (2012, 2012),
+ (2013, 2013),
+ (2014, 2014),
+ (2015, 2015),
+ (2016, 2016),
+ (2017, 2017),
+ ],
+ default=2016,
+ null=True,
+ ),
+ )
]
diff --git a/kfet/migrations/0048_article_hidden.py b/kfet/migrations/0048_article_hidden.py
index 63869f77..d4d89022 100644
--- a/kfet/migrations/0048_article_hidden.py
+++ b/kfet/migrations/0048_article_hidden.py
@@ -6,14 +6,15 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0047_auto_20170104_1528'),
- ]
+ dependencies = [("kfet", "0047_auto_20170104_1528")]
operations = [
migrations.AddField(
- model_name='article',
- name='hidden',
- field=models.BooleanField(help_text='Si oui, ne sera pas affiché au public ; par exemple sur la carte.', default=False),
- ),
+ model_name="article",
+ name="hidden",
+ field=models.BooleanField(
+ help_text="Si oui, ne sera pas affiché au public ; par exemple sur la carte.",
+ default=False,
+ ),
+ )
]
diff --git a/kfet/migrations/0048_default_datetime.py b/kfet/migrations/0048_default_datetime.py
index c9bacf1e..d5408c59 100644
--- a/kfet/migrations/0048_default_datetime.py
+++ b/kfet/migrations/0048_default_datetime.py
@@ -1,25 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
import django.utils.timezone
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0047_auto_20170104_1528'),
- ]
+ dependencies = [("kfet", "0047_auto_20170104_1528")]
operations = [
migrations.AlterField(
- model_name='operationgroup',
- name='at',
+ model_name="operationgroup",
+ name="at",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
- model_name='transfergroup',
- name='at',
+ model_name="transfergroup",
+ name="at",
field=models.DateTimeField(default=django.utils.timezone.now),
),
]
diff --git a/kfet/migrations/0049_merge.py b/kfet/migrations/0049_merge.py
index 0ce9a525..e9bcb47a 100644
--- a/kfet/migrations/0049_merge.py
+++ b/kfet/migrations/0049_merge.py
@@ -6,10 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0048_article_hidden'),
- ('kfet', '0048_default_datetime'),
- ]
+ dependencies = [("kfet", "0048_article_hidden"), ("kfet", "0048_default_datetime")]
- operations = [
- ]
+ operations = []
diff --git a/kfet/migrations/0050_remove_checkout.py b/kfet/migrations/0050_remove_checkout.py
index b712c2d8..8cfd370a 100644
--- a/kfet/migrations/0050_remove_checkout.py
+++ b/kfet/migrations/0050_remove_checkout.py
@@ -7,32 +7,36 @@ from django.db import migrations, models
def adapt_operation_types(apps, schema_editor):
Operation = apps.get_model("kfet", "Operation")
Operation.objects.filter(
- is_checkout=False,
- type__in=['withdraw', 'deposit']).update(type='edit')
+ is_checkout=False, type__in=["withdraw", "deposit"]
+ ).update(type="edit")
def revert_operation_types(apps, schema_editor):
Operation = apps.get_model("kfet", "Operation")
- edits = Operation.objects.filter(type='edit')
- edits.filter(amount__gt=0).update(type='deposit')
- edits.filter(amount__lte=0).update(type='withdraw')
+ edits = Operation.objects.filter(type="edit")
+ edits.filter(amount__gt=0).update(type="deposit")
+ edits.filter(amount__lte=0).update(type="withdraw")
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0049_merge'),
- ]
+ dependencies = [("kfet", "0049_merge")]
operations = [
migrations.AlterField(
- model_name='operation',
- name='type',
- field=models.CharField(choices=[('purchase', 'Achat'), ('deposit', 'Charge'), ('withdraw', 'Retrait'), ('initial', 'Initial'), ('edit', 'Édition')], max_length=8),
+ model_name="operation",
+ name="type",
+ field=models.CharField(
+ choices=[
+ ("purchase", "Achat"),
+ ("deposit", "Charge"),
+ ("withdraw", "Retrait"),
+ ("initial", "Initial"),
+ ("edit", "Édition"),
+ ],
+ max_length=8,
+ ),
),
migrations.RunPython(adapt_operation_types, revert_operation_types),
- migrations.RemoveField(
- model_name='operation',
- name='is_checkout',
- ),
+ migrations.RemoveField(model_name="operation", name="is_checkout"),
]
diff --git a/kfet/migrations/0051_verbose_names.py b/kfet/migrations/0051_verbose_names.py
index ae407fac..9892af71 100644
--- a/kfet/migrations/0051_verbose_names.py
+++ b/kfet/migrations/0051_verbose_names.py
@@ -1,210 +1,303 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0050_remove_checkout'),
- ]
+ dependencies = [("kfet", "0050_remove_checkout")]
operations = [
migrations.AlterField(
- model_name='account',
- name='is_frozen',
- field=models.BooleanField(default=False, verbose_name='est gelé'),
+ model_name="account",
+ name="is_frozen",
+ field=models.BooleanField(default=False, verbose_name="est gelé"),
),
migrations.AlterField(
- model_name='account',
- name='nickname',
- field=models.CharField(default='', max_length=255, verbose_name='surnom(s)', blank=True),
+ model_name="account",
+ name="nickname",
+ field=models.CharField(
+ default="", max_length=255, verbose_name="surnom(s)", blank=True
+ ),
),
migrations.AlterField(
- model_name='accountnegative',
- name='authz_overdraft_amount',
- field=models.DecimalField(max_digits=6, blank=True, default=None, null=True, verbose_name='négatif autorisé', decimal_places=2),
+ model_name="accountnegative",
+ name="authz_overdraft_amount",
+ field=models.DecimalField(
+ max_digits=6,
+ blank=True,
+ default=None,
+ null=True,
+ verbose_name="négatif autorisé",
+ decimal_places=2,
+ ),
),
migrations.AlterField(
- model_name='accountnegative',
- name='authz_overdraft_until',
- field=models.DateTimeField(default=None, null=True, verbose_name='expiration du négatif', blank=True),
+ model_name="accountnegative",
+ name="authz_overdraft_until",
+ field=models.DateTimeField(
+ default=None,
+ null=True,
+ verbose_name="expiration du négatif",
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='accountnegative',
- name='balance_offset',
- field=models.DecimalField(blank=True, max_digits=6, help_text="Montant non compris dans l'autorisation de négatif", default=None, null=True, verbose_name='décalage de balance', decimal_places=2),
+ model_name="accountnegative",
+ name="balance_offset",
+ field=models.DecimalField(
+ blank=True,
+ max_digits=6,
+ help_text="Montant non compris dans l'autorisation de négatif",
+ default=None,
+ null=True,
+ verbose_name="décalage de balance",
+ decimal_places=2,
+ ),
),
migrations.AlterField(
- model_name='accountnegative',
- name='comment',
- field=models.CharField(blank=True, max_length=255, verbose_name='commentaire'),
+ model_name="accountnegative",
+ name="comment",
+ field=models.CharField(
+ blank=True, max_length=255, verbose_name="commentaire"
+ ),
),
migrations.AlterField(
- model_name='article',
- name='box_capacity',
- field=models.PositiveSmallIntegerField(default=None, null=True, verbose_name='capacité du contenant', blank=True),
+ model_name="article",
+ name="box_capacity",
+ field=models.PositiveSmallIntegerField(
+ default=None,
+ null=True,
+ verbose_name="capacité du contenant",
+ blank=True,
+ ),
),
migrations.AlterField(
- model_name='article',
- name='box_type',
- field=models.CharField(blank=True, max_length=7, choices=[('caisse', 'caisse'), ('carton', 'carton'), ('palette', 'palette'), ('fût', 'fût')], default=None, null=True, verbose_name='type de contenant'),
+ model_name="article",
+ name="box_type",
+ field=models.CharField(
+ blank=True,
+ max_length=7,
+ choices=[
+ ("caisse", "caisse"),
+ ("carton", "carton"),
+ ("palette", "palette"),
+ ("fût", "fût"),
+ ],
+ default=None,
+ null=True,
+ verbose_name="type de contenant",
+ ),
),
migrations.AlterField(
- model_name='article',
- name='category',
- field=models.ForeignKey(related_name='articles', to='kfet.ArticleCategory', on_delete=django.db.models.deletion.PROTECT, verbose_name='catégorie'),
+ model_name="article",
+ name="category",
+ field=models.ForeignKey(
+ related_name="articles",
+ to="kfet.ArticleCategory",
+ on_delete=django.db.models.deletion.PROTECT,
+ verbose_name="catégorie",
+ ),
),
migrations.AlterField(
- model_name='article',
- name='hidden',
- field=models.BooleanField(default=False, verbose_name='caché', help_text='Si oui, ne sera pas affiché au public ; par exemple sur la carte.'),
+ model_name="article",
+ name="hidden",
+ field=models.BooleanField(
+ default=False,
+ verbose_name="caché",
+ help_text="Si oui, ne sera pas affiché au public ; par exemple sur la carte.",
+ ),
),
migrations.AlterField(
- model_name='article',
- name='is_sold',
- field=models.BooleanField(default=True, verbose_name='en vente'),
+ model_name="article",
+ name="is_sold",
+ field=models.BooleanField(default=True, verbose_name="en vente"),
),
migrations.AlterField(
- model_name='article',
- name='name',
- field=models.CharField(max_length=45, verbose_name='nom'),
+ model_name="article",
+ name="name",
+ field=models.CharField(max_length=45, verbose_name="nom"),
),
migrations.AlterField(
- model_name='article',
- name='price',
- field=models.DecimalField(default=0, verbose_name='prix', decimal_places=2, max_digits=6),
+ model_name="article",
+ name="price",
+ field=models.DecimalField(
+ default=0, verbose_name="prix", decimal_places=2, max_digits=6
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='amount_error',
- field=models.DecimalField(max_digits=6, verbose_name="montant de l'erreur", decimal_places=2),
+ model_name="checkoutstatement",
+ name="amount_error",
+ field=models.DecimalField(
+ max_digits=6, verbose_name="montant de l'erreur", decimal_places=2
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='amount_taken',
- field=models.DecimalField(max_digits=6, verbose_name='montant pris', decimal_places=2),
+ model_name="checkoutstatement",
+ name="amount_taken",
+ field=models.DecimalField(
+ max_digits=6, verbose_name="montant pris", decimal_places=2
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='balance_new',
- field=models.DecimalField(max_digits=6, verbose_name='nouvelle balance', decimal_places=2),
+ model_name="checkoutstatement",
+ name="balance_new",
+ field=models.DecimalField(
+ max_digits=6, verbose_name="nouvelle balance", decimal_places=2
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='balance_old',
- field=models.DecimalField(max_digits=6, verbose_name='ancienne balance', decimal_places=2),
+ model_name="checkoutstatement",
+ name="balance_old",
+ field=models.DecimalField(
+ max_digits=6, verbose_name="ancienne balance", decimal_places=2
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='not_count',
- field=models.BooleanField(default=False, verbose_name='caisse non comptée'),
+ model_name="checkoutstatement",
+ name="not_count",
+ field=models.BooleanField(default=False, verbose_name="caisse non comptée"),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_001',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 1¢'),
+ model_name="checkoutstatement",
+ name="taken_001",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 1¢"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_002',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 2¢'),
+ model_name="checkoutstatement",
+ name="taken_002",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 2¢"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_005',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 5¢'),
+ model_name="checkoutstatement",
+ name="taken_005",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 5¢"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_01',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 10¢'),
+ model_name="checkoutstatement",
+ name="taken_01",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 10¢"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_02',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 20¢'),
+ model_name="checkoutstatement",
+ name="taken_02",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 20¢"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_05',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 50¢'),
+ model_name="checkoutstatement",
+ name="taken_05",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 50¢"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_1',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 1€'),
+ model_name="checkoutstatement",
+ name="taken_1",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 1€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_10',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 10€'),
+ model_name="checkoutstatement",
+ name="taken_10",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 10€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_100',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 100€'),
+ model_name="checkoutstatement",
+ name="taken_100",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 100€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_2',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='pièces de 2€'),
+ model_name="checkoutstatement",
+ name="taken_2",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="pièces de 2€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_20',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 20€'),
+ model_name="checkoutstatement",
+ name="taken_20",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 20€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_200',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 200€'),
+ model_name="checkoutstatement",
+ name="taken_200",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 200€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_5',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 5€'),
+ model_name="checkoutstatement",
+ name="taken_5",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 5€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_50',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 50€'),
+ model_name="checkoutstatement",
+ name="taken_50",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 50€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_500',
- field=models.PositiveSmallIntegerField(default=0, verbose_name='billets de 500€'),
+ model_name="checkoutstatement",
+ name="taken_500",
+ field=models.PositiveSmallIntegerField(
+ default=0, verbose_name="billets de 500€"
+ ),
),
migrations.AlterField(
- model_name='checkoutstatement',
- name='taken_cheque',
- field=models.DecimalField(default=0, verbose_name='montant des chèques', decimal_places=2, max_digits=6),
+ model_name="checkoutstatement",
+ name="taken_cheque",
+ field=models.DecimalField(
+ default=0,
+ verbose_name="montant des chèques",
+ decimal_places=2,
+ max_digits=6,
+ ),
),
migrations.AlterField(
- model_name='supplier',
- name='address',
- field=models.TextField(verbose_name='adresse'),
+ model_name="supplier",
+ name="address",
+ field=models.TextField(verbose_name="adresse"),
),
migrations.AlterField(
- model_name='supplier',
- name='comment',
- field=models.TextField(verbose_name='commentaire'),
+ model_name="supplier",
+ name="comment",
+ field=models.TextField(verbose_name="commentaire"),
),
migrations.AlterField(
- model_name='supplier',
- name='email',
- field=models.EmailField(max_length=254, verbose_name='adresse mail'),
+ model_name="supplier",
+ name="email",
+ field=models.EmailField(max_length=254, verbose_name="adresse mail"),
),
migrations.AlterField(
- model_name='supplier',
- name='name',
- field=models.CharField(max_length=45, verbose_name='nom'),
+ model_name="supplier",
+ name="name",
+ field=models.CharField(max_length=45, verbose_name="nom"),
),
migrations.AlterField(
- model_name='supplier',
- name='phone',
- field=models.CharField(max_length=10, verbose_name='téléphone'),
+ model_name="supplier",
+ name="phone",
+ field=models.CharField(max_length=10, verbose_name="téléphone"),
),
]
diff --git a/kfet/migrations/0052_category_addcost.py b/kfet/migrations/0052_category_addcost.py
index 83346a1a..8a8da85f 100644
--- a/kfet/migrations/0052_category_addcost.py
+++ b/kfet/migrations/0052_category_addcost.py
@@ -6,19 +6,21 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0051_verbose_names'),
- ]
+ dependencies = [("kfet", "0051_verbose_names")]
operations = [
migrations.AddField(
- model_name='articlecategory',
- name='has_addcost',
- field=models.BooleanField(default=True, help_text="Si oui et qu'une majoration est active, celle-ci sera appliquée aux articles de cette catégorie.", verbose_name='majorée'),
+ model_name="articlecategory",
+ name="has_addcost",
+ field=models.BooleanField(
+ default=True,
+ help_text="Si oui et qu'une majoration est active, celle-ci sera appliquée aux articles de cette catégorie.",
+ verbose_name="majorée",
+ ),
),
migrations.AlterField(
- model_name='articlecategory',
- name='name',
- field=models.CharField(max_length=45, verbose_name='nom'),
+ model_name="articlecategory",
+ name="name",
+ field=models.CharField(max_length=45, verbose_name="nom"),
),
]
diff --git a/kfet/migrations/0053_created_at.py b/kfet/migrations/0053_created_at.py
index a868de33..6da14568 100644
--- a/kfet/migrations/0053_created_at.py
+++ b/kfet/migrations/0053_created_at.py
@@ -1,20 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
import django.utils.timezone
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0052_category_addcost'),
- ]
+ dependencies = [("kfet", "0052_category_addcost")]
operations = [
migrations.AlterField(
- model_name='account',
- name='created_at',
+ model_name="account",
+ name="created_at",
field=models.DateTimeField(default=django.utils.timezone.now),
- ),
+ )
]
diff --git a/kfet/migrations/0054_delete_settings.py b/kfet/migrations/0054_delete_settings.py
index 80ee1d24..7294c8bf 100644
--- a/kfet/migrations/0054_delete_settings.py
+++ b/kfet/migrations/0054_delete_settings.py
@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
from kfet.forms import KFetConfigForm
def adapt_settings(apps, schema_editor):
- Settings = apps.get_model('kfet', 'Settings')
+ Settings = apps.get_model("kfet", "Settings")
db_alias = schema_editor.connection.alias
obj = Settings.objects.using(db_alias)
@@ -22,17 +22,17 @@ def adapt_settings(apps, schema_editor):
pass
try:
- subvention = obj.get(name='SUBVENTION_COF').value_decimal
- subvention_mult = 1 + subvention/100
- reduction = (1 - 1/subvention_mult) * 100
- cfg['kfet_reduction_cof'] = reduction
+ subvention = obj.get(name="SUBVENTION_COF").value_decimal
+ subvention_mult = 1 + subvention / 100
+ reduction = (1 - 1 / subvention_mult) * 100
+ cfg["kfet_reduction_cof"] = reduction
except Settings.DoesNotExist:
pass
- try_get('kfet_addcost_amount', 'ADDCOST_AMOUNT', 'value_decimal')
- try_get('kfet_addcost_for', 'ADDCOST_FOR', 'value_account')
- try_get('kfet_overdraft_duration', 'OVERDRAFT_DURATION', 'value_duration')
- try_get('kfet_overdraft_amount', 'OVERDRAFT_AMOUNT', 'value_decimal')
- try_get('kfet_cancel_duration', 'CANCEL_DURATION', 'value_duration')
+ try_get("kfet_addcost_amount", "ADDCOST_AMOUNT", "value_decimal")
+ try_get("kfet_addcost_for", "ADDCOST_FOR", "value_account")
+ try_get("kfet_overdraft_duration", "OVERDRAFT_DURATION", "value_duration")
+ try_get("kfet_overdraft_amount", "OVERDRAFT_AMOUNT", "value_decimal")
+ try_get("kfet_cancel_duration", "CANCEL_DURATION", "value_duration")
cfg_form = KFetConfigForm(initial=cfg)
if cfg_form.is_valid():
@@ -41,18 +41,10 @@ def adapt_settings(apps, schema_editor):
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0053_created_at'),
- ('djconfig', '0001_initial'),
- ]
+ dependencies = [("kfet", "0053_created_at"), ("djconfig", "0001_initial")]
operations = [
migrations.RunPython(adapt_settings),
- migrations.RemoveField(
- model_name='settings',
- name='value_account',
- ),
- migrations.DeleteModel(
- name='Settings',
- ),
+ migrations.RemoveField(model_name="settings", name="value_account"),
+ migrations.DeleteModel(name="Settings"),
]
diff --git a/kfet/migrations/0054_update_promos.py b/kfet/migrations/0054_update_promos.py
index 2691e903..0f86779b 100644
--- a/kfet/migrations/0054_update_promos.py
+++ b/kfet/migrations/0054_update_promos.py
@@ -6,14 +6,56 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0053_created_at'),
- ]
+ dependencies = [("kfet", "0053_created_at")]
operations = [
migrations.AlterField(
- model_name='account',
- name='promo',
- field=models.IntegerField(blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017)], default=2017, null=True),
- ),
+ model_name="account",
+ name="promo",
+ field=models.IntegerField(
+ blank=True,
+ choices=[
+ (1980, 1980),
+ (1981, 1981),
+ (1982, 1982),
+ (1983, 1983),
+ (1984, 1984),
+ (1985, 1985),
+ (1986, 1986),
+ (1987, 1987),
+ (1988, 1988),
+ (1989, 1989),
+ (1990, 1990),
+ (1991, 1991),
+ (1992, 1992),
+ (1993, 1993),
+ (1994, 1994),
+ (1995, 1995),
+ (1996, 1996),
+ (1997, 1997),
+ (1998, 1998),
+ (1999, 1999),
+ (2000, 2000),
+ (2001, 2001),
+ (2002, 2002),
+ (2003, 2003),
+ (2004, 2004),
+ (2005, 2005),
+ (2006, 2006),
+ (2007, 2007),
+ (2008, 2008),
+ (2009, 2009),
+ (2010, 2010),
+ (2011, 2011),
+ (2012, 2012),
+ (2013, 2013),
+ (2014, 2014),
+ (2015, 2015),
+ (2016, 2016),
+ (2017, 2017),
+ ],
+ default=2017,
+ null=True,
+ ),
+ )
]
diff --git a/kfet/migrations/0055_move_permissions.py b/kfet/migrations/0055_move_permissions.py
index a418124c..9db3f793 100644
--- a/kfet/migrations/0055_move_permissions.py
+++ b/kfet/migrations/0055_move_permissions.py
@@ -13,41 +13,42 @@ def forwards_perms(apps, schema_editor):
permissions which are assumed unused.
"""
- ContentType = apps.get_model('contenttypes', 'contenttype')
+ ContentType = apps.get_model("contenttypes", "contenttype")
try:
ctype_global = ContentType.objects.get(
- app_label="kfet", model="globalpermissions",
+ app_label="kfet", model="globalpermissions"
)
except ContentType.DoesNotExist:
# We are not migrating from existing data, nothing to do.
return
perms = {
- 'account': (
- 'is_team', 'manage_perms', 'manage_addcosts',
- 'edit_balance_account', 'change_account_password',
- 'special_add_account',
+ "account": (
+ "is_team",
+ "manage_perms",
+ "manage_addcosts",
+ "edit_balance_account",
+ "change_account_password",
+ "special_add_account",
),
- 'accountnegative': ('view_negs',),
- 'inventory': ('order_to_inventory',),
- 'operation': (
- 'perform_deposit', 'perform_negative_operations',
- 'override_frozen_protection', 'cancel_old_operations',
- 'perform_commented_operations',
+ "accountnegative": ("view_negs",),
+ "inventory": ("order_to_inventory",),
+ "operation": (
+ "perform_deposit",
+ "perform_negative_operations",
+ "override_frozen_protection",
+ "cancel_old_operations",
+ "perform_commented_operations",
),
}
- Permission = apps.get_model('auth', 'permission')
+ Permission = apps.get_model("auth", "permission")
global_perms = Permission.objects.filter(content_type=ctype_global)
for modelname, codenames in perms.items():
- model = apps.get_model('kfet', modelname)
+ model = apps.get_model("kfet", modelname)
ctype = ContentType.objects.get_for_model(model)
- (
- global_perms
- .filter(codename__in=codenames)
- .update(content_type=ctype)
- )
+ (global_perms.filter(codename__in=codenames).update(content_type=ctype))
ctype_global.delete()
@@ -55,27 +56,64 @@ def forwards_perms(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
- ('kfet', '0054_delete_settings'),
- ('contenttypes', '__latest__'),
- ('auth', '__latest__'),
+ ("kfet", "0054_delete_settings"),
+ ("contenttypes", "__latest__"),
+ ("auth", "__latest__"),
]
operations = [
migrations.AlterModelOptions(
- name='account',
- options={'permissions': (('is_team', 'Is part of the team'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'équipe"), ('special_add_account', 'Créer un compte avec une balance initiale'))},
+ name="account",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ (
+ "change_account_password",
+ "Modifier le mot de passe d'une personne de l'équipe",
+ ),
+ (
+ "special_add_account",
+ "Créer un compte avec une balance initiale",
+ ),
+ )
+ },
),
migrations.AlterModelOptions(
- name='accountnegative',
- options={'permissions': (('view_negs', 'Voir la liste des négatifs'),)},
+ name="accountnegative",
+ options={"permissions": (("view_negs", "Voir la liste des négatifs"),)},
),
migrations.AlterModelOptions(
- name='inventory',
- options={'ordering': ['-at'], 'permissions': (('order_to_inventory', "Générer un inventaire à partir d'une commande"),)},
+ name="inventory",
+ options={
+ "ordering": ["-at"],
+ "permissions": (
+ (
+ "order_to_inventory",
+ "Générer un inventaire à partir d'une commande",
+ ),
+ ),
+ },
),
migrations.AlterModelOptions(
- name='operation',
- options={'permissions': (('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'))},
+ name="operation",
+ options={
+ "permissions": (
+ ("perform_deposit", "Effectuer une charge"),
+ (
+ "perform_negative_operations",
+ "Enregistrer des commandes en négatif",
+ ),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
+ )
+ },
),
migrations.RunPython(forwards_perms),
]
diff --git a/kfet/migrations/0056_change_account_meta.py b/kfet/migrations/0056_change_account_meta.py
index 3992bf3c..27e51417 100644
--- a/kfet/migrations/0056_change_account_meta.py
+++ b/kfet/migrations/0056_change_account_meta.py
@@ -6,13 +6,27 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0055_move_permissions'),
- ]
+ dependencies = [("kfet", "0055_move_permissions")]
operations = [
migrations.AlterModelOptions(
- name='account',
- options={'permissions': (('is_team', 'Is part of the team'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'équipe"), ('special_add_account', 'Créer un compte avec une balance initiale'), ('can_force_close', 'Fermer manuellement la K-Fêt'))},
- ),
+ name="account",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ (
+ "change_account_password",
+ "Modifier le mot de passe d'une personne de l'équipe",
+ ),
+ (
+ "special_add_account",
+ "Créer un compte avec une balance initiale",
+ ),
+ ("can_force_close", "Fermer manuellement la K-Fêt"),
+ )
+ },
+ )
]
diff --git a/kfet/migrations/0057_merge.py b/kfet/migrations/0057_merge.py
index 48f63399..456bbeb0 100644
--- a/kfet/migrations/0057_merge.py
+++ b/kfet/migrations/0057_merge.py
@@ -7,9 +7,8 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('kfet', '0056_change_account_meta'),
- ('kfet', '0054_update_promos'),
+ ("kfet", "0056_change_account_meta"),
+ ("kfet", "0054_update_promos"),
]
- operations = [
- ]
+ operations = []
diff --git a/kfet/migrations/0058_delete_genericteamtoken.py b/kfet/migrations/0058_delete_genericteamtoken.py
index ea8b55cd..3b3216e9 100644
--- a/kfet/migrations/0058_delete_genericteamtoken.py
+++ b/kfet/migrations/0058_delete_genericteamtoken.py
@@ -6,12 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0057_merge'),
- ]
+ dependencies = [("kfet", "0057_merge")]
- operations = [
- migrations.DeleteModel(
- name='GenericTeamToken',
- ),
- ]
+ operations = [migrations.DeleteModel(name="GenericTeamToken")]
diff --git a/kfet/migrations/0059_create_generic.py b/kfet/migrations/0059_create_generic.py
index 4f04770c..7408a300 100644
--- a/kfet/migrations/0059_create_generic.py
+++ b/kfet/migrations/0059_create_generic.py
@@ -15,31 +15,22 @@ def setup_kfet_generic_user(apps, schema_editor):
See also setup_kfet_generic_user from kfet.auth.utils module.
"""
- User = apps.get_model('auth', 'User')
- CofProfile = apps.get_model('gestioncof', 'CofProfile')
- Account = apps.get_model('kfet', 'Account')
+ User = apps.get_model("auth", "User")
+ CofProfile = apps.get_model("gestioncof", "CofProfile")
+ Account = apps.get_model("kfet", "Account")
user, _ = User.objects.update_or_create(
username=KFET_GENERIC_USERNAME,
- defaults={
- 'first_name': 'Compte générique K-Fêt',
- },
+ defaults={"first_name": "Compte générique K-Fêt"},
)
profile, _ = CofProfile.objects.update_or_create(user=user)
account, _ = Account.objects.update_or_create(
- cofprofile=profile,
- defaults={
- 'trigramme': KFET_GENERIC_TRIGRAMME,
- },
+ cofprofile=profile, defaults={"trigramme": KFET_GENERIC_TRIGRAMME}
)
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0058_delete_genericteamtoken'),
- ]
+ dependencies = [("kfet", "0058_delete_genericteamtoken")]
- operations = [
- migrations.RunPython(setup_kfet_generic_user),
- ]
+ operations = [migrations.RunPython(setup_kfet_generic_user)]
diff --git a/kfet/migrations/0060_amend_supplier.py b/kfet/migrations/0060_amend_supplier.py
index 4eb569f8..0a56640d 100644
--- a/kfet/migrations/0060_amend_supplier.py
+++ b/kfet/migrations/0060_amend_supplier.py
@@ -6,34 +6,39 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0059_create_generic'),
- ]
+ dependencies = [("kfet", "0059_create_generic")]
operations = [
migrations.AlterField(
- model_name='supplier',
- name='address',
- field=models.TextField(verbose_name='adresse', blank=True),
+ model_name="supplier",
+ name="address",
+ field=models.TextField(verbose_name="adresse", blank=True),
),
migrations.AlterField(
- model_name='supplier',
- name='articles',
- field=models.ManyToManyField(verbose_name='articles vendus', through='kfet.SupplierArticle', related_name='suppliers', to='kfet.Article'),
+ model_name="supplier",
+ name="articles",
+ field=models.ManyToManyField(
+ verbose_name="articles vendus",
+ through="kfet.SupplierArticle",
+ related_name="suppliers",
+ to="kfet.Article",
+ ),
),
migrations.AlterField(
- model_name='supplier',
- name='comment',
- field=models.TextField(verbose_name='commentaire', blank=True),
+ model_name="supplier",
+ name="comment",
+ field=models.TextField(verbose_name="commentaire", blank=True),
),
migrations.AlterField(
- model_name='supplier',
- name='email',
- field=models.EmailField(max_length=254, verbose_name='adresse mail', blank=True),
+ model_name="supplier",
+ name="email",
+ field=models.EmailField(
+ max_length=254, verbose_name="adresse mail", blank=True
+ ),
),
migrations.AlterField(
- model_name='supplier',
- name='phone',
- field=models.CharField(max_length=20, verbose_name='téléphone', blank=True),
+ model_name="supplier",
+ name="phone",
+ field=models.CharField(max_length=20, verbose_name="téléphone", blank=True),
),
]
diff --git a/kfet/migrations/0061_add_perms_config.py b/kfet/migrations/0061_add_perms_config.py
index 01bdf51d..7d10da31 100644
--- a/kfet/migrations/0061_add_perms_config.py
+++ b/kfet/migrations/0061_add_perms_config.py
@@ -6,13 +6,29 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0060_amend_supplier'),
- ]
+ dependencies = [("kfet", "0060_amend_supplier")]
operations = [
migrations.AlterModelOptions(
- name='account',
- options={'permissions': (('is_team', 'Is part of the team'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'équipe"), ('special_add_account', 'Créer un compte avec une balance initiale'), ('can_force_close', 'Fermer manuellement la K-Fêt'), ('see_config', 'Voir la configuration K-Fêt'), ('change_config', 'Modifier la configuration K-Fêt'))},
- ),
+ name="account",
+ options={
+ "permissions": (
+ ("is_team", "Is part of the team"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ (
+ "change_account_password",
+ "Modifier le mot de passe d'une personne de l'équipe",
+ ),
+ (
+ "special_add_account",
+ "Créer un compte avec une balance initiale",
+ ),
+ ("can_force_close", "Fermer manuellement la K-Fêt"),
+ ("see_config", "Voir la configuration K-Fêt"),
+ ("change_config", "Modifier la configuration K-Fêt"),
+ )
+ },
+ )
]
diff --git a/kfet/migrations/0062_delete_globalpermissions.py b/kfet/migrations/0062_delete_globalpermissions.py
index ee245412..9a357a2d 100644
--- a/kfet/migrations/0062_delete_globalpermissions.py
+++ b/kfet/migrations/0062_delete_globalpermissions.py
@@ -3,12 +3,6 @@ from django.db import migrations
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0061_add_perms_config'),
- ]
+ dependencies = [("kfet", "0061_add_perms_config")]
- operations = [
- migrations.DeleteModel(
- name='GlobalPermissions',
- ),
- ]
+ operations = [migrations.DeleteModel(name="GlobalPermissions")]
diff --git a/kfet/migrations/0063_promo.py b/kfet/migrations/0063_promo.py
index 3fac5a8a..de04573a 100644
--- a/kfet/migrations/0063_promo.py
+++ b/kfet/migrations/0063_promo.py
@@ -7,14 +7,57 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = [
- ('kfet', '0062_delete_globalpermissions'),
- ]
+ dependencies = [("kfet", "0062_delete_globalpermissions")]
operations = [
migrations.AlterField(
- model_name='account',
- name='promo',
- field=models.IntegerField(blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018)], default=2017, null=True),
- ),
+ model_name="account",
+ name="promo",
+ field=models.IntegerField(
+ blank=True,
+ choices=[
+ (1980, 1980),
+ (1981, 1981),
+ (1982, 1982),
+ (1983, 1983),
+ (1984, 1984),
+ (1985, 1985),
+ (1986, 1986),
+ (1987, 1987),
+ (1988, 1988),
+ (1989, 1989),
+ (1990, 1990),
+ (1991, 1991),
+ (1992, 1992),
+ (1993, 1993),
+ (1994, 1994),
+ (1995, 1995),
+ (1996, 1996),
+ (1997, 1997),
+ (1998, 1998),
+ (1999, 1999),
+ (2000, 2000),
+ (2001, 2001),
+ (2002, 2002),
+ (2003, 2003),
+ (2004, 2004),
+ (2005, 2005),
+ (2006, 2006),
+ (2007, 2007),
+ (2008, 2008),
+ (2009, 2009),
+ (2010, 2010),
+ (2011, 2011),
+ (2012, 2012),
+ (2013, 2013),
+ (2014, 2014),
+ (2015, 2015),
+ (2016, 2016),
+ (2017, 2017),
+ (2018, 2018),
+ ],
+ default=2017,
+ null=True,
+ ),
+ )
]
diff --git a/kfet/migrations/0064_promo_2018.py b/kfet/migrations/0064_promo_2018.py
new file mode 100644
index 00000000..7fe5e160
--- /dev/null
+++ b/kfet/migrations/0064_promo_2018.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.15 on 2018-09-02 21:13
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [("kfet", "0063_promo")]
+
+ operations = [
+ migrations.AlterField(
+ model_name="account",
+ name="promo",
+ field=models.IntegerField(
+ blank=True,
+ choices=[
+ (1980, 1980),
+ (1981, 1981),
+ (1982, 1982),
+ (1983, 1983),
+ (1984, 1984),
+ (1985, 1985),
+ (1986, 1986),
+ (1987, 1987),
+ (1988, 1988),
+ (1989, 1989),
+ (1990, 1990),
+ (1991, 1991),
+ (1992, 1992),
+ (1993, 1993),
+ (1994, 1994),
+ (1995, 1995),
+ (1996, 1996),
+ (1997, 1997),
+ (1998, 1998),
+ (1999, 1999),
+ (2000, 2000),
+ (2001, 2001),
+ (2002, 2002),
+ (2003, 2003),
+ (2004, 2004),
+ (2005, 2005),
+ (2006, 2006),
+ (2007, 2007),
+ (2008, 2008),
+ (2009, 2009),
+ (2010, 2010),
+ (2011, 2011),
+ (2012, 2012),
+ (2013, 2013),
+ (2014, 2014),
+ (2015, 2015),
+ (2016, 2016),
+ (2017, 2017),
+ (2018, 2018),
+ ],
+ default=2018,
+ null=True,
+ ),
+ )
+ ]
diff --git a/kfet/models.py b/kfet/models.py
index e952e85a..5a8ea858 100644
--- a/kfet/models.py
+++ b/kfet/models.py
@@ -1,30 +1,30 @@
+import re
+from datetime import date
from functools import reduce
-from django.db import models
-from django.core.validators import RegexValidator
from django.contrib.auth.models import User
-from gestioncof.models import CofProfile
+from django.core.validators import RegexValidator
+from django.db import models, transaction
+from django.db.models import F
from django.urls import reverse
-from django.utils.six.moves import reduce
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
-from django.db import transaction
-from django.db.models import F
-from datetime import date
-import re
+
+from gestioncof.models import CofProfile
from .auth import KFET_GENERIC_TRIGRAMME
from .auth.models import GenericTeamToken # noqa
-
from .config import kfet_config
from .utils import to_ukf
+
def choices_length(choices):
return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0)
+
def default_promo():
now = date.today()
- return now.month <= 8 and now.year-1 or now.year
+ return now.month <= 8 and now.year - 1 or now.year
class AccountManager(models.Manager):
@@ -32,8 +32,7 @@ class AccountManager(models.Manager):
def get_queryset(self):
"""Always append related data to this Account."""
- return super().get_queryset().select_related('cofprofile__user',
- 'negative')
+ return super().get_queryset().select_related("cofprofile__user", "negative")
def get_generic(self):
"""
@@ -48,6 +47,7 @@ class AccountManager(models.Manager):
Raises Account.DoesNotExist if no Account has this password.
"""
from .auth.utils import hash_password
+
if password is None:
raise self.model.DoesNotExist
return self.get(password=hash_password(password))
@@ -57,69 +57,71 @@ class Account(models.Model):
objects = AccountManager()
cofprofile = models.OneToOneField(
- CofProfile, on_delete = models.PROTECT,
- related_name = "account_kfet")
+ CofProfile, on_delete=models.PROTECT, related_name="account_kfet"
+ )
trigramme = models.CharField(
- unique = True,
- max_length = 3,
- validators = [RegexValidator(regex='^[^a-z]{3}$')],
- db_index = True)
- balance = models.DecimalField(
- max_digits = 6, decimal_places = 2,
- default = 0)
- is_frozen = models.BooleanField("est gelé", default = False)
+ unique=True,
+ max_length=3,
+ validators=[RegexValidator(regex="^[^a-z]{3}$")],
+ db_index=True,
+ )
+ balance = models.DecimalField(max_digits=6, decimal_places=2, default=0)
+ is_frozen = models.BooleanField("est gelé", default=False)
created_at = models.DateTimeField(default=timezone.now)
# Optional
- PROMO_CHOICES = [(r,r) for r in range(1980, date.today().year+1)]
+ PROMO_CHOICES = [(r, r) for r in range(1980, date.today().year + 1)]
promo = models.IntegerField(
- choices = PROMO_CHOICES,
- blank = True, null = True, default = default_promo())
- nickname = models.CharField(
- "surnom(s)",
- max_length = 255,
- blank = True, default = "")
+ choices=PROMO_CHOICES, blank=True, null=True, default=default_promo()
+ )
+ nickname = models.CharField("surnom(s)", max_length=255, blank=True, default="")
password = models.CharField(
- max_length = 255,
- unique = True,
- blank = True, null = True, default = None)
+ max_length=255, unique=True, blank=True, null=True, default=None
+ )
class Meta:
permissions = (
- ('is_team', 'Is part of the team'),
- ('manage_perms', 'Gérer les permissions K-Fêt'),
- ('manage_addcosts', 'Gérer les majorations'),
- ('edit_balance_account', "Modifier la balance d'un compte"),
- ('change_account_password',
- "Modifier le mot de passe d'une personne de l'équipe"),
- ('special_add_account',
- "Créer un compte avec une balance initiale"),
- ('can_force_close', "Fermer manuellement la K-Fêt"),
- ('see_config', "Voir la configuration K-Fêt"),
- ('change_config', "Modifier la configuration K-Fêt"),
+ ("is_team", "Is part of the team"),
+ ("manage_perms", "Gérer les permissions K-Fêt"),
+ ("manage_addcosts", "Gérer les majorations"),
+ ("edit_balance_account", "Modifier la balance d'un compte"),
+ (
+ "change_account_password",
+ "Modifier le mot de passe d'une personne de l'équipe",
+ ),
+ ("special_add_account", "Créer un compte avec une balance initiale"),
+ ("can_force_close", "Fermer manuellement la K-Fêt"),
+ ("see_config", "Voir la configuration K-Fêt"),
+ ("change_config", "Modifier la configuration K-Fêt"),
)
def __str__(self):
- return '%s (%s)' % (self.trigramme, self.name)
+ return "%s (%s)" % (self.trigramme, self.name)
# Propriétés pour accéder aux attributs de cofprofile et user
@property
def user(self):
return self.cofprofile.user
+
@property
def username(self):
return self.cofprofile.user.username
+
@property
def first_name(self):
return self.cofprofile.user.first_name
+
@property
def last_name(self):
return self.cofprofile.user.last_name
+
@property
def email(self):
return self.cofprofile.user.email
+
@property
def departement(self):
return self.cofprofile.departement
+
@property
def is_cof(self):
return self.cofprofile.is_cof
@@ -131,7 +133,7 @@ class Account(models.Model):
@property
def real_balance(self):
- if hasattr(self, 'negative') and self.negative.balance_offset:
+ if hasattr(self, "negative") and self.negative.balance_offset:
return self.balance - self.negative.balance_offset
return self.balance
@@ -141,29 +143,29 @@ class Account(models.Model):
@property
def is_cash(self):
- return self.trigramme == 'LIQ'
+ return self.trigramme == "LIQ"
@property
def need_comment(self):
- return self.trigramme == '#13'
+ return self.trigramme == "#13"
@property
def readable(self):
- return self.trigramme != 'GNR'
+ return self.trigramme != "GNR"
@property
def is_team(self):
- return self.has_perm('kfet.is_team')
+ return self.has_perm("kfet.is_team")
@staticmethod
def is_validandfree(trigramme):
- data = { 'is_valid' : False, 'is_free' : False }
+ data = {"is_valid": False, "is_free": False}
pattern = re.compile("^[^a-z]{3}$")
- data['is_valid'] = pattern.match(trigramme) and True or False
+ data["is_valid"] = pattern.match(trigramme) and True or False
try:
- account = Account.objects.get(trigramme=trigramme)
+ Account.objects.get(trigramme=trigramme)
except Account.DoesNotExist:
- data['is_free'] = True
+ data["is_free"] = True
return data
def perms_to_perform_operation(self, amount):
@@ -176,31 +178,34 @@ class Account(models.Model):
# Yes, so no perms and no stop
return set(), False
if self.need_comment:
- perms.add('kfet.perform_commented_operations')
+ perms.add("kfet.perform_commented_operations")
# Checking is frozen account
if self.is_frozen:
- perms.add('kfet.override_frozen_protection')
+ perms.add("kfet.override_frozen_protection")
new_balance = self.balance + amount
if new_balance < 0 and amount < 0:
# Retrieving overdraft amount limit
- if (hasattr(self, 'negative')
- and self.negative.authz_overdraft_amount is not None):
- overdraft_amount = - self.negative.authz_overdraft_amount
+ if (
+ hasattr(self, "negative")
+ and self.negative.authz_overdraft_amount is not None
+ ):
+ overdraft_amount = -self.negative.authz_overdraft_amount
else:
- overdraft_amount = - overdraft_amount_max
+ overdraft_amount = -overdraft_amount_max
# Retrieving overdraft datetime limit
- if (hasattr(self, 'negative')
- and self.negative.authz_overdraft_until is not None):
+ if (
+ hasattr(self, "negative")
+ and self.negative.authz_overdraft_until is not None
+ ):
overdraft_until = self.negative.authz_overdraft_until
- elif hasattr(self, 'negative'):
- overdraft_until = \
- self.negative.start + overdraft_duration_max
+ elif hasattr(self, "negative"):
+ overdraft_until = self.negative.start + overdraft_duration_max
else:
overdraft_until = timezone.now() + overdraft_duration_max
# Checking it doesn't break 1 rule
if new_balance < overdraft_amount or timezone.now() > overdraft_until:
stop_ope = True
- perms.add('kfet.perform_negative_operations')
+ perms.add("kfet.perform_negative_operations")
return perms, stop_ope
# Surcharge Méthode save() avec gestions de User et CofProfile
@@ -209,7 +214,7 @@ class Account(models.Model):
# Action:
# - Enregistre User, CofProfile à partir de "data"
# - Enregistre Account
- def save(self, data = {}, *args, **kwargs):
+ def save(self, data={}, *args, **kwargs):
if self.pk and data:
# Account update
@@ -217,8 +222,8 @@ class Account(models.Model):
# Updating User with data
user = self.user
user.first_name = data.get("first_name", user.first_name)
- user.last_name = data.get("last_name", user.last_name)
- user.email = data.get("email", user.email)
+ user.last_name = data.get("last_name", user.last_name)
+ user.email = data.get("email", user.email)
user.save()
# Updating CofProfile with data
cof = self.cofprofile
@@ -240,18 +245,18 @@ class Account(models.Model):
# Creating or updating User instance
(user, _) = User.objects.get_or_create(username=username)
if "first_name" in data:
- user.first_name = data['first_name']
+ user.first_name = data["first_name"]
if "last_name" in data:
- user.last_name = data['last_name']
+ user.last_name = data["last_name"]
if "email" in data:
- user.email = data['email']
+ user.email = data["email"]
user.save()
# Creating or updating CofProfile instance
(cof, _) = CofProfile.objects.get_or_create(user=user)
if "login_clipper" in data:
- cof.login_clipper = data['login_clipper']
+ cof.login_clipper = data["login_clipper"]
if "departement" in data:
- cof.departement = data['departement']
+ cof.departement = data["departement"]
cof.save()
if data:
self.cofprofile = cof
@@ -259,6 +264,7 @@ class Account(models.Model):
def change_pwd(self, clear_password):
from .auth.utils import hash_password
+
self.password = hash_password(clear_password)
# Surcharge de delete
@@ -269,23 +275,21 @@ class Account(models.Model):
def update_negative(self):
if self.real_balance < 0:
- if hasattr(self, 'negative') and not self.negative.start:
+ if hasattr(self, "negative") and not self.negative.start:
self.negative.start = timezone.now()
self.negative.save()
- elif not hasattr(self, 'negative'):
- self.negative = (
- AccountNegative.objects.create(
- account=self, start=timezone.now(),
- )
+ elif not hasattr(self, "negative"):
+ self.negative = AccountNegative.objects.create(
+ account=self, start=timezone.now()
)
- elif hasattr(self, 'negative'):
+ elif hasattr(self, "negative"):
# self.real_balance >= 0
balance_offset = self.negative.balance_offset
if balance_offset:
(
- Account.objects
- .filter(pk=self.pk)
- .update(balance=F('balance')-balance_offset)
+ Account.objects.filter(pk=self.pk).update(
+ balance=F("balance") - balance_offset
+ )
)
self.refresh_from_db()
self.negative.delete()
@@ -299,41 +303,40 @@ class AccountNegativeManager(models.Manager):
"""Manager for AccountNegative model."""
def get_queryset(self):
- return (
- super().get_queryset()
- .select_related('account__cofprofile__user')
- )
+ return super().get_queryset().select_related("account__cofprofile__user")
class AccountNegative(models.Model):
objects = AccountNegativeManager()
account = models.OneToOneField(
- Account, on_delete=models.PROTECT,
- related_name="negative",
+ Account, on_delete=models.PROTECT, related_name="negative"
)
start = models.DateTimeField(blank=True, null=True, default=None)
balance_offset = models.DecimalField(
"décalage de balance",
help_text="Montant non compris dans l'autorisation de négatif",
- max_digits=6, decimal_places=2,
- blank=True, null=True, default=None,
+ max_digits=6,
+ decimal_places=2,
+ blank=True,
+ null=True,
+ default=None,
)
authz_overdraft_amount = models.DecimalField(
"négatif autorisé",
- max_digits=6, decimal_places=2,
- blank=True, null=True, default=None,
+ max_digits=6,
+ decimal_places=2,
+ blank=True,
+ null=True,
+ default=None,
)
authz_overdraft_until = models.DateTimeField(
- "expiration du négatif",
- blank=True, null=True, default=None,
+ "expiration du négatif", blank=True, null=True, default=None
)
comment = models.CharField("commentaire", max_length=255, blank=True)
class Meta:
- permissions = (
- ('view_negs', 'Voir la liste des négatifs'),
- )
+ permissions = (("view_negs", "Voir la liste des négatifs"),)
@property
def until_default(self):
@@ -341,31 +344,26 @@ class AccountNegative(models.Model):
class CheckoutQuerySet(models.QuerySet):
-
def is_valid(self):
now = timezone.now()
return self.filter(valid_from__lte=now, valid_to__gte=now)
class Checkout(models.Model):
- created_by = models.ForeignKey(
- Account, on_delete = models.PROTECT,
- related_name = "+")
- name = models.CharField(max_length = 45)
+ created_by = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="+")
+ name = models.CharField(max_length=45)
valid_from = models.DateTimeField()
- valid_to = models.DateTimeField()
- balance = models.DecimalField(
- max_digits = 6, decimal_places = 2,
- default = 0)
- is_protected = models.BooleanField(default = False)
+ valid_to = models.DateTimeField()
+ balance = models.DecimalField(max_digits=6, decimal_places=2, default=0)
+ is_protected = models.BooleanField(default=False)
objects = CheckoutQuerySet.as_manager()
def get_absolute_url(self):
- return reverse('kfet.checkout.read', kwargs={'pk': self.pk})
+ return reverse("kfet.checkout.read", kwargs={"pk": self.pk})
class Meta:
- ordering = ['-valid_to']
+ ordering = ["-valid_to"]
def __str__(self):
return self.name
@@ -388,31 +386,30 @@ class Checkout(models.Model):
class CheckoutTransfer(models.Model):
from_checkout = models.ForeignKey(
- Checkout, on_delete = models.PROTECT,
- related_name = "transfers_from")
+ Checkout, on_delete=models.PROTECT, related_name="transfers_from"
+ )
to_checkout = models.ForeignKey(
- Checkout, on_delete = models.PROTECT,
- related_name = "transfers_to")
- amount = models.DecimalField(
- max_digits = 6, decimal_places = 2)
+ Checkout, on_delete=models.PROTECT, related_name="transfers_to"
+ )
+ amount = models.DecimalField(max_digits=6, decimal_places=2)
class CheckoutStatement(models.Model):
- by = models.ForeignKey(
- Account, on_delete = models.PROTECT,
- related_name = "+")
+ by = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="+")
checkout = models.ForeignKey(
- Checkout, on_delete = models.PROTECT,
- related_name = "statements")
- balance_old = models.DecimalField("ancienne balance",
- max_digits = 6, decimal_places = 2)
- balance_new = models.DecimalField("nouvelle balance",
- max_digits = 6, decimal_places = 2)
- amount_taken = models.DecimalField("montant pris",
- max_digits = 6, decimal_places = 2)
- amount_error = models.DecimalField("montant de l'erreur",
- max_digits = 6, decimal_places = 2)
- at = models.DateTimeField(auto_now_add = True)
+ Checkout, on_delete=models.PROTECT, related_name="statements"
+ )
+ balance_old = models.DecimalField(
+ "ancienne balance", max_digits=6, decimal_places=2
+ )
+ balance_new = models.DecimalField(
+ "nouvelle balance", max_digits=6, decimal_places=2
+ )
+ amount_taken = models.DecimalField("montant pris", max_digits=6, decimal_places=2)
+ amount_error = models.DecimalField(
+ "montant de l'erreur", max_digits=6, decimal_places=2
+ )
+ at = models.DateTimeField(auto_now_add=True)
not_count = models.BooleanField("caisse non comptée", default=False)
taken_001 = models.PositiveSmallIntegerField("pièces de 1¢", default=0)
@@ -431,68 +428,76 @@ class CheckoutStatement(models.Model):
taken_200 = models.PositiveSmallIntegerField("billets de 200€", default=0)
taken_500 = models.PositiveSmallIntegerField("billets de 500€", default=0)
taken_cheque = models.DecimalField(
- "montant des chèques",
- default=0, max_digits=6, decimal_places=2)
+ "montant des chèques", default=0, max_digits=6, decimal_places=2
+ )
def __str__(self):
- return '%s %s' % (self.checkout, self.at)
+ return "%s %s" % (self.checkout, self.at)
def save(self, *args, **kwargs):
if not self.pk:
checkout_id = self.checkout_id
- self.balance_old = (Checkout.objects
- .values_list('balance', flat=True).get(pk=checkout_id))
+ self.balance_old = Checkout.objects.values_list("balance", flat=True).get(
+ pk=checkout_id
+ )
if self.not_count:
self.balance_new = self.balance_old - self.amount_taken
- self.amount_error = (
- self.balance_new + self.amount_taken - self.balance_old)
+ self.amount_error = self.balance_new + self.amount_taken - self.balance_old
with transaction.atomic():
Checkout.objects.filter(pk=checkout_id).update(balance=self.balance_new)
super().save(*args, **kwargs)
else:
- self.amount_error = (
- self.balance_new + self.amount_taken - self.balance_old)
+ self.amount_error = self.balance_new + self.amount_taken - self.balance_old
# Si on modifie le dernier relevé d'une caisse et que la nouvelle
# balance est modifiée alors on modifie la balance actuelle de la caisse
- last_statement = (CheckoutStatement.objects
- .filter(checkout=self.checkout)
- .order_by('at')
- .last())
- if (last_statement.pk == self.pk
- and last_statement.balance_new != self.balance_new):
+ last_statement = (
+ CheckoutStatement.objects.filter(checkout=self.checkout)
+ .order_by("at")
+ .last()
+ )
+ if (
+ last_statement.pk == self.pk
+ and last_statement.balance_new != self.balance_new
+ ):
Checkout.objects.filter(pk=self.checkout_id).update(
- balance=F('balance') - last_statement.balance_new + self.balance_new)
+ balance=F("balance") - last_statement.balance_new + self.balance_new
+ )
super().save(*args, **kwargs)
class ArticleCategory(models.Model):
name = models.CharField("nom", max_length=45)
- has_addcost = models.BooleanField("majorée", default=True,
- help_text="Si oui et qu'une majoration "
- "est active, celle-ci sera "
- "appliquée aux articles de "
- "cette catégorie.")
+ has_addcost = models.BooleanField(
+ "majorée",
+ default=True,
+ help_text="Si oui et qu'une majoration "
+ "est active, celle-ci sera "
+ "appliquée aux articles de "
+ "cette catégorie.",
+ )
def __str__(self):
return self.name
class Article(models.Model):
- name = models.CharField("nom", max_length = 45)
- is_sold = models.BooleanField("en vente", default = True)
- hidden = models.BooleanField("caché",
- default=False,
- help_text="Si oui, ne sera pas affiché "
- "au public ; par exemple "
- "sur la carte.")
- price = models.DecimalField(
- "prix",
- max_digits = 6, decimal_places = 2,
- default = 0)
- stock = models.IntegerField(default = 0)
+ name = models.CharField("nom", max_length=45)
+ is_sold = models.BooleanField("en vente", default=True)
+ hidden = models.BooleanField(
+ "caché",
+ default=False,
+ help_text="Si oui, ne sera pas affiché "
+ "au public ; par exemple "
+ "sur la carte.",
+ )
+ price = models.DecimalField("prix", max_digits=6, decimal_places=2, default=0)
+ stock = models.IntegerField(default=0)
category = models.ForeignKey(
- ArticleCategory, on_delete = models.PROTECT,
- related_name = "articles", verbose_name='catégorie')
+ ArticleCategory,
+ on_delete=models.PROTECT,
+ related_name="articles",
+ verbose_name="catégorie",
+ )
BOX_TYPE_CHOICES = (
("caisse", "caisse"),
("carton", "carton"),
@@ -501,18 +506,21 @@ class Article(models.Model):
)
box_type = models.CharField(
"type de contenant",
- choices = BOX_TYPE_CHOICES,
- max_length = choices_length(BOX_TYPE_CHOICES),
- blank = True, null = True, default = None)
+ choices=BOX_TYPE_CHOICES,
+ max_length=choices_length(BOX_TYPE_CHOICES),
+ blank=True,
+ null=True,
+ default=None,
+ )
box_capacity = models.PositiveSmallIntegerField(
- "capacité du contenant",
- blank = True, null = True, default = None)
+ "capacité du contenant", blank=True, null=True, default=None
+ )
def __str__(self):
- return '%s - %s' % (self.category.name, self.name)
+ return "%s - %s" % (self.category.name, self.name)
def get_absolute_url(self):
- return reverse('kfet.article.read', kwargs={'pk': self.pk})
+ return reverse("kfet.article.read", kwargs={"pk": self.pk})
def price_ukf(self):
return to_ukf(self.price)
@@ -520,43 +528,43 @@ class Article(models.Model):
class ArticleRule(models.Model):
article_on = models.OneToOneField(
- Article, on_delete = models.PROTECT,
- related_name = "rule_on")
+ Article, on_delete=models.PROTECT, related_name="rule_on"
+ )
article_to = models.OneToOneField(
- Article, on_delete = models.PROTECT,
- related_name = "rule_to")
+ Article, on_delete=models.PROTECT, related_name="rule_to"
+ )
ratio = models.PositiveSmallIntegerField()
+
class Inventory(models.Model):
articles = models.ManyToManyField(
- Article,
- through = 'InventoryArticle',
- related_name = "inventories")
- by = models.ForeignKey(
- Account, on_delete = models.PROTECT,
- related_name = "+")
- at = models.DateTimeField(auto_now_add = True)
+ Article, through="InventoryArticle", related_name="inventories"
+ )
+ by = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="+")
+ at = models.DateTimeField(auto_now_add=True)
# Optional
order = models.OneToOneField(
- 'Order', on_delete = models.PROTECT,
- related_name = "inventory",
- blank = True, null = True, default = None)
+ "Order",
+ on_delete=models.PROTECT,
+ related_name="inventory",
+ blank=True,
+ null=True,
+ default=None,
+ )
class Meta:
- ordering = ['-at']
+ ordering = ["-at"]
permissions = (
- ('order_to_inventory', "Générer un inventaire à partir d'une commande"),
+ ("order_to_inventory", "Générer un inventaire à partir d'une commande"),
)
class InventoryArticle(models.Model):
- inventory = models.ForeignKey(
- Inventory, on_delete = models.PROTECT)
- article = models.ForeignKey(
- Article, on_delete = models.PROTECT)
- stock_old = models.IntegerField()
- stock_new = models.IntegerField()
- stock_error = models.IntegerField(default = 0)
+ inventory = models.ForeignKey(Inventory, on_delete=models.PROTECT)
+ article = models.ForeignKey(Article, on_delete=models.PROTECT)
+ stock_old = models.IntegerField()
+ stock_new = models.IntegerField()
+ stock_error = models.IntegerField(default=0)
def save(self, *args, **kwargs):
# S'il s'agit d'un inventaire provenant d'une livraison, il n'y a pas
@@ -570,8 +578,8 @@ class Supplier(models.Model):
articles = models.ManyToManyField(
Article,
verbose_name=_("articles vendus"),
- through='SupplierArticle',
- related_name='suppliers',
+ through="SupplierArticle",
+ related_name="suppliers",
)
name = models.CharField(_("nom"), max_length=45)
address = models.TextField(_("adresse"), blank=True)
@@ -584,175 +592,187 @@ class Supplier(models.Model):
class SupplierArticle(models.Model):
- supplier = models.ForeignKey(
- Supplier, on_delete = models.PROTECT)
- article = models.ForeignKey(
- Article, on_delete = models.PROTECT)
- at = models.DateTimeField(auto_now_add = True)
+ supplier = models.ForeignKey(Supplier, on_delete=models.PROTECT)
+ article = models.ForeignKey(Article, on_delete=models.PROTECT)
+ at = models.DateTimeField(auto_now_add=True)
price_HT = models.DecimalField(
- max_digits = 7, decimal_places = 4,
- blank = True, null = True, default = None)
+ max_digits=7, decimal_places=4, blank=True, null=True, default=None
+ )
TVA = models.DecimalField(
- max_digits = 4, decimal_places = 2,
- blank = True, null = True, default = None)
+ max_digits=4, decimal_places=2, blank=True, null=True, default=None
+ )
rights = models.DecimalField(
- max_digits = 7, decimal_places = 4,
- blank = True, null = True, default = None)
+ max_digits=7, decimal_places=4, blank=True, null=True, default=None
+ )
+
class Order(models.Model):
supplier = models.ForeignKey(
- Supplier, on_delete = models.PROTECT,
- related_name = "orders")
+ Supplier, on_delete=models.PROTECT, related_name="orders"
+ )
articles = models.ManyToManyField(
- Article,
- through = "OrderArticle",
- related_name = "orders")
- at = models.DateTimeField(auto_now_add = True)
- amount = models.DecimalField(
- max_digits = 6, decimal_places = 2, default = 0)
+ Article, through="OrderArticle", related_name="orders"
+ )
+ at = models.DateTimeField(auto_now_add=True)
+ amount = models.DecimalField(max_digits=6, decimal_places=2, default=0)
class Meta:
- ordering = ['-at']
+ ordering = ["-at"]
+
class OrderArticle(models.Model):
- order = models.ForeignKey(
- Order, on_delete = models.PROTECT)
- article = models.ForeignKey(
- Article, on_delete = models.PROTECT)
+ order = models.ForeignKey(Order, on_delete=models.PROTECT)
+ article = models.ForeignKey(Article, on_delete=models.PROTECT)
quantity_ordered = models.IntegerField()
- quantity_received = models.IntegerField(default = 0)
+ quantity_received = models.IntegerField(default=0)
+
class TransferGroup(models.Model):
at = models.DateTimeField(default=timezone.now)
# Optional
- comment = models.CharField(
- max_length = 255,
- blank = True, default = "")
+ comment = models.CharField(max_length=255, blank=True, default="")
valid_by = models.ForeignKey(
- Account, on_delete = models.PROTECT,
- related_name = "+",
- blank = True, null = True, default = None)
+ Account,
+ on_delete=models.PROTECT,
+ related_name="+",
+ blank=True,
+ null=True,
+ default=None,
+ )
class Transfer(models.Model):
group = models.ForeignKey(
- TransferGroup, on_delete=models.PROTECT,
- related_name="transfers")
+ TransferGroup, on_delete=models.PROTECT, related_name="transfers"
+ )
from_acc = models.ForeignKey(
- Account, on_delete=models.PROTECT,
- related_name="transfers_from")
+ Account, on_delete=models.PROTECT, related_name="transfers_from"
+ )
to_acc = models.ForeignKey(
- Account, on_delete=models.PROTECT,
- related_name="transfers_to")
+ Account, on_delete=models.PROTECT, related_name="transfers_to"
+ )
amount = models.DecimalField(max_digits=6, decimal_places=2)
# Optional
canceled_by = models.ForeignKey(
- Account, on_delete=models.PROTECT,
- null=True, blank=True, default=None,
- related_name="+")
- canceled_at = models.DateTimeField(
- null=True, blank=True, default=None)
+ Account,
+ on_delete=models.PROTECT,
+ null=True,
+ blank=True,
+ default=None,
+ related_name="+",
+ )
+ canceled_at = models.DateTimeField(null=True, blank=True, default=None)
def __str__(self):
- return '{} -> {}: {}€'.format(self.from_acc, self.to_acc, self.amount)
+ return "{} -> {}: {}€".format(self.from_acc, self.to_acc, self.amount)
class OperationGroup(models.Model):
on_acc = models.ForeignKey(
- Account, on_delete = models.PROTECT,
- related_name = "opesgroup")
+ Account, on_delete=models.PROTECT, related_name="opesgroup"
+ )
checkout = models.ForeignKey(
- Checkout, on_delete = models.PROTECT,
- related_name = "opesgroup")
+ Checkout, on_delete=models.PROTECT, related_name="opesgroup"
+ )
at = models.DateTimeField(default=timezone.now)
- amount = models.DecimalField(
- max_digits = 6, decimal_places = 2,
- default = 0)
- is_cof = models.BooleanField(default = False)
+ amount = models.DecimalField(max_digits=6, decimal_places=2, default=0)
+ is_cof = models.BooleanField(default=False)
# Optional
- comment = models.CharField(
- max_length = 255,
- blank = True, default = "")
+ comment = models.CharField(max_length=255, blank=True, default="")
valid_by = models.ForeignKey(
- Account, on_delete = models.PROTECT,
- related_name = "+",
- blank = True, null = True, default = None)
+ Account,
+ on_delete=models.PROTECT,
+ related_name="+",
+ blank=True,
+ null=True,
+ default=None,
+ )
def __str__(self):
- return ', '.join(map(str, self.opes.all()))
+ return ", ".join(map(str, self.opes.all()))
class Operation(models.Model):
- PURCHASE = 'purchase'
- DEPOSIT = 'deposit'
- WITHDRAW = 'withdraw'
- INITIAL = 'initial'
- EDIT = 'edit'
+ PURCHASE = "purchase"
+ DEPOSIT = "deposit"
+ WITHDRAW = "withdraw"
+ INITIAL = "initial"
+ EDIT = "edit"
TYPE_ORDER_CHOICES = (
- (PURCHASE, 'Achat'),
- (DEPOSIT, 'Charge'),
- (WITHDRAW, 'Retrait'),
- (INITIAL, 'Initial'),
- (EDIT, 'Édition'),
+ (PURCHASE, "Achat"),
+ (DEPOSIT, "Charge"),
+ (WITHDRAW, "Retrait"),
+ (INITIAL, "Initial"),
+ (EDIT, "Édition"),
)
group = models.ForeignKey(
- OperationGroup, on_delete=models.PROTECT,
- related_name="opes")
+ OperationGroup, on_delete=models.PROTECT, related_name="opes"
+ )
type = models.CharField(
- choices=TYPE_ORDER_CHOICES,
- max_length=choices_length(TYPE_ORDER_CHOICES))
- amount = models.DecimalField(
- max_digits=6, decimal_places=2,
- blank=True, default=0)
+ choices=TYPE_ORDER_CHOICES, max_length=choices_length(TYPE_ORDER_CHOICES)
+ )
+ amount = models.DecimalField(max_digits=6, decimal_places=2, blank=True, default=0)
# Optional
article = models.ForeignKey(
- Article, on_delete=models.PROTECT,
+ Article,
+ on_delete=models.PROTECT,
related_name="operations",
- blank=True, null=True, default=None)
- article_nb = models.PositiveSmallIntegerField(
- blank=True, null=True, default=None)
+ blank=True,
+ null=True,
+ default=None,
+ )
+ article_nb = models.PositiveSmallIntegerField(blank=True, null=True, default=None)
canceled_by = models.ForeignKey(
- Account, on_delete=models.PROTECT,
+ Account,
+ on_delete=models.PROTECT,
related_name="+",
- blank=True, null=True, default=None)
- canceled_at = models.DateTimeField(
- blank=True, null=True, default=None)
+ blank=True,
+ null=True,
+ default=None,
+ )
+ canceled_at = models.DateTimeField(blank=True, null=True, default=None)
addcost_for = models.ForeignKey(
- Account, on_delete=models.PROTECT,
+ Account,
+ on_delete=models.PROTECT,
related_name="addcosts",
- blank=True, null=True, default=None)
+ blank=True,
+ null=True,
+ default=None,
+ )
addcost_amount = models.DecimalField(
- max_digits=6, decimal_places=2,
- blank=True, null=True, default=None)
+ max_digits=6, decimal_places=2, blank=True, null=True, default=None
+ )
class Meta:
permissions = (
- ('perform_deposit', 'Effectuer une charge'),
- ('perform_negative_operations',
- 'Enregistrer des commandes en négatif'),
- ('override_frozen_protection', "Forcer le gel d'un compte"),
- ('cancel_old_operations', 'Annuler des commandes non récentes'),
- ('perform_commented_operations',
- 'Enregistrer des commandes avec commentaires'),
+ ("perform_deposit", "Effectuer une charge"),
+ ("perform_negative_operations", "Enregistrer des commandes en négatif"),
+ ("override_frozen_protection", "Forcer le gel d'un compte"),
+ ("cancel_old_operations", "Annuler des commandes non récentes"),
+ (
+ "perform_commented_operations",
+ "Enregistrer des commandes avec commentaires",
+ ),
)
@property
def is_checkout(self):
- return (self.type == Operation.DEPOSIT or
- self.type == Operation.WITHDRAW or
- (self.type == Operation.PURCHASE and self.group.on_acc.is_cash)
- )
+ return (
+ self.type == Operation.DEPOSIT
+ or self.type == Operation.WITHDRAW
+ or (self.type == Operation.PURCHASE and self.group.on_acc.is_cash)
+ )
def __str__(self):
templates = {
- self.PURCHASE: "{nb} {article.name} ({amount}€)",
- self.DEPOSIT: "charge ({amount}€)",
- self.WITHDRAW: "retrait ({amount}€)",
- self.INITIAL: "initial ({amount}€)",
- self.EDIT: "édition ({amount}€)",
- }
- return templates[self.type].format(nb=self.article_nb,
- article=self.article,
- amount=self.amount)
+ self.PURCHASE: "{nb} {article.name} ({amount}€)",
+ self.DEPOSIT: "charge ({amount}€)",
+ self.WITHDRAW: "retrait ({amount}€)",
+ self.INITIAL: "initial ({amount}€)",
+ self.EDIT: "édition ({amount}€)",
+ }
+ return templates[self.type].format(
+ nb=self.article_nb, article=self.article, amount=self.amount
+ )
diff --git a/kfet/open/consumers.py b/kfet/open/consumers.py
index b28a4664..8b800c76 100644
--- a/kfet/open/consumers.py
+++ b/kfet/open/consumers.py
@@ -1,6 +1,5 @@
from ..decorators import kfet_is_team
from ..utils import DjangoJsonWebsocketConsumer, PermConsumerMixin
-
from .open import kfet_open
@@ -16,8 +15,8 @@ class OpenKfetConsumer(PermConsumerMixin, DjangoJsonWebsocketConsumer):
def connection_groups(self, user, **kwargs):
"""Select which group the user should be connected."""
if kfet_is_team(user):
- return ['kfet.open.team']
- return ['kfet.open.base']
+ return ["kfet.open.team"]
+ return ["kfet.open.base"]
def connect(self, message, *args, **kwargs):
"""Send current status on connect."""
diff --git a/kfet/open/open.py b/kfet/open/open.py
index 82d6217a..d0e0c901 100644
--- a/kfet/open/open.py
+++ b/kfet/open/open.py
@@ -15,23 +15,20 @@ class OpenKfet(CachedMixin, object):
Current state persists through cache.
"""
+
# status is unknown after this duration
time_unknown = timedelta(minutes=15)
# status
- OPENED = 'opened'
- CLOSED = 'closed'
- UNKNOWN = 'unknown'
+ OPENED = "opened"
+ CLOSED = "closed"
+ UNKNOWN = "unknown"
# admin status
- FAKE_CLOSED = 'fake_closed'
+ FAKE_CLOSED = "fake_closed"
# cached attributes config
- cached = {
- '_raw_open': False,
- '_last_update': None,
- 'force_close': False,
- }
- cache_prefix = 'kfetopen'
+ cached = {"_raw_open": False, "_last_update": None, "force_close": False}
+ cache_prefix = "kfetopen"
@property
def raw_open(self):
@@ -54,8 +51,10 @@ class OpenKfet(CachedMixin, object):
return False if self.force_close else self.raw_open
def status(self):
- if (self.last_update is None or
- timezone.now() - self.last_update >= self.time_unknown):
+ if (
+ self.last_update is None
+ or timezone.now() - self.last_update >= self.time_unknown
+ ):
return self.UNKNOWN
return self.OPENED if self.is_open else self.CLOSED
@@ -78,12 +77,10 @@ class OpenKfet(CachedMixin, object):
"""
status = self.status()
- base = {
- 'status': status,
- }
+ base = {"status": status}
restrict = {
- 'admin_status': self.admin_status(status),
- 'force_close': self.force_close,
+ "admin_status": self.admin_status(status),
+ "force_close": self.force_close,
}
return base, dict(base, **restrict)
@@ -101,9 +98,10 @@ class OpenKfet(CachedMixin, object):
def send_ws(self):
"""Send internal state to websocket channels."""
from .consumers import OpenKfetConsumer
+
base, team = self._export()
- OpenKfetConsumer.group_send('kfet.open.base', base)
- OpenKfetConsumer.group_send('kfet.open.team', team)
+ OpenKfetConsumer.group_send("kfet.open.base", base)
+ OpenKfetConsumer.group_send("kfet.open.team", team)
kfet_open = OpenKfet()
diff --git a/kfet/open/routing.py b/kfet/open/routing.py
index 681bfab2..811ae56e 100644
--- a/kfet/open/routing.py
+++ b/kfet/open/routing.py
@@ -2,7 +2,4 @@ from channels.routing import route_class
from . import consumers
-
-routing = [
- route_class(consumers.OpenKfetConsumer)
-]
+routing = [route_class(consumers.OpenKfetConsumer)]
diff --git a/kfet/open/tests.py b/kfet/open/tests.py
index 476eb6c0..75a9bf8a 100644
--- a/kfet/open/tests.py
+++ b/kfet/open/tests.py
@@ -2,14 +2,13 @@ import json
from datetime import timedelta
from unittest import mock
+from channels.channel import Group
+from channels.test import ChannelTestCase, WSClient
from django.contrib.auth.models import AnonymousUser, Permission, User
from django.test import Client
from django.utils import timezone
-from channels.channel import Group
-from channels.test import ChannelTestCase, WSClient
-
-from . import kfet_open, OpenKfet
+from . import OpenKfet, kfet_open
from .consumers import OpenKfetConsumer
@@ -79,40 +78,28 @@ class OpenKfetTest(ChannelTestCase):
def test_export_user(self):
"""Export is limited for an anonymous user."""
export = self.kfet_open.export(AnonymousUser())
- self.assertSetEqual(
- set(['status']),
- set(export),
- )
+ self.assertSetEqual(set(["status"]), set(export))
def test_export_team(self):
"""Export all values for a team member."""
- user = User.objects.create_user('team', '', 'team')
- user.user_permissions.add(Permission.objects.get(codename='is_team'))
+ user = User.objects.create_user("team", "", "team")
+ user.user_permissions.add(Permission.objects.get(codename="is_team"))
export = self.kfet_open.export(user)
- self.assertSetEqual(
- set(['status', 'admin_status', 'force_close']),
- set(export),
- )
+ self.assertSetEqual(set(["status", "admin_status", "force_close"]), set(export))
def test_send_ws(self):
- Group('kfet.open.base').add('test.open.base')
- Group('kfet.open.team').add('test.open.team')
+ Group("kfet.open.base").add("test.open.base")
+ Group("kfet.open.team").add("test.open.team")
self.kfet_open.send_ws()
- recv_base = self.get_next_message('test.open.base', require=True)
- base = json.loads(recv_base['text'])
- self.assertSetEqual(
- set(['status']),
- set(base),
- )
+ recv_base = self.get_next_message("test.open.base", require=True)
+ base = json.loads(recv_base["text"])
+ self.assertSetEqual(set(["status"]), set(base))
- recv_admin = self.get_next_message('test.open.team', require=True)
- admin = json.loads(recv_admin['text'])
- self.assertSetEqual(
- set(['status', 'admin_status', 'force_close']),
- set(admin),
- )
+ recv_admin = self.get_next_message("test.open.team", require=True)
+ admin = json.loads(recv_admin["text"])
+ self.assertSetEqual(set(["status", "admin_status", "force_close"]), set(admin))
class OpenKfetViewsTest(ChannelTestCase):
@@ -120,34 +107,34 @@ class OpenKfetViewsTest(ChannelTestCase):
def setUp(self):
# Need this (and here) because of '.login' in setUp
- patcher_messages = mock.patch('gestioncof.signals.messages')
+ patcher_messages = mock.patch("gestioncof.signals.messages")
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
# get some permissions
perms = {
- 'kfet.is_team': Permission.objects.get(codename='is_team'),
- 'kfet.can_force_close': Permission.objects.get(codename='can_force_close'),
+ "kfet.is_team": Permission.objects.get(codename="is_team"),
+ "kfet.can_force_close": Permission.objects.get(codename="can_force_close"),
}
# authenticated user and its client
- self.u = User.objects.create_user('user', '', 'user')
+ self.u = User.objects.create_user("user", "", "user")
self.c = Client()
- self.c.login(username='user', password='user')
+ self.c.login(username="user", password="user")
# team user and its clients
- self.t = User.objects.create_user('team', '', 'team')
- self.t.user_permissions.add(perms['kfet.is_team'])
+ self.t = User.objects.create_user("team", "", "team")
+ self.t.user_permissions.add(perms["kfet.is_team"])
self.c_t = Client()
- self.c_t.login(username='team', password='team')
+ self.c_t.login(username="team", password="team")
# admin user and its client
- self.a = User.objects.create_user('admin', '', 'admin')
+ self.a = User.objects.create_user("admin", "", "admin")
self.a.user_permissions.add(
- perms['kfet.is_team'], perms['kfet.can_force_close'],
+ perms["kfet.is_team"], perms["kfet.can_force_close"]
)
self.c_a = Client()
- self.c_a.login(username='admin', password='admin')
+ self.c_a.login(username="admin", password="admin")
def tearDown(self):
kfet_open.clear_cache()
@@ -155,17 +142,16 @@ class OpenKfetViewsTest(ChannelTestCase):
def test_door(self):
"""Edit raw_status."""
for sent, expected in [(1, True), (0, False)]:
- resp = Client().post('/k-fet/open/raw_open', {
- 'raw_open': sent,
- 'token': 'plop',
- })
+ resp = Client().post(
+ "/k-fet/open/raw_open", {"raw_open": sent, "token": "plop"}
+ )
self.assertEqual(200, resp.status_code)
self.assertEqual(expected, kfet_open.raw_open)
def test_force_close(self):
"""Edit force_close."""
for sent, expected in [(1, True), (0, False)]:
- resp = self.c_a.post('/k-fet/open/force_close', {'force_close': sent})
+ resp = self.c_a.post("/k-fet/open/force_close", {"force_close": sent})
self.assertEqual(200, resp.status_code)
self.assertEqual(expected, kfet_open.force_close)
@@ -173,7 +159,7 @@ class OpenKfetViewsTest(ChannelTestCase):
"""Can't edit force_close without kfet.can_force_close permission."""
clients = [Client(), self.c, self.c_t]
for client in clients:
- resp = client.post('/k-fet/open/force_close', {'force_close': 0})
+ resp = client.post("/k-fet/open/force_close", {"force_close": 0})
self.assertEqual(403, resp.status_code)
@@ -186,44 +172,44 @@ class OpenKfetConsumerTest(ChannelTestCase):
c = WSClient()
# connect
- c.send_and_consume('websocket.connect', path='/ws/k-fet/open',
- fail_on_none=True)
+ c.send_and_consume(
+ "websocket.connect", path="/ws/k-fet/open", fail_on_none=True
+ )
# initialization data is replied on connection
self.assertIsNotNone(c.receive())
# client belongs to the 'kfet.open' group...
- OpenKfetConsumer.group_send('kfet.open.base', {'test': 'plop'})
- self.assertEqual(c.receive(), {'test': 'plop'})
+ OpenKfetConsumer.group_send("kfet.open.base", {"test": "plop"})
+ self.assertEqual(c.receive(), {"test": "plop"})
# ...but not to the 'kfet.open.admin' one
- OpenKfetConsumer.group_send('kfet.open.team', {'test': 'plop'})
+ OpenKfetConsumer.group_send("kfet.open.team", {"test": "plop"})
self.assertIsNone(c.receive())
- @mock.patch('gestioncof.signals.messages')
+ @mock.patch("gestioncof.signals.messages")
def test_team_user(self, mock_messages):
"""Team user is added to kfet.open.team group."""
# setup team user and its client
- t = User.objects.create_user('team', '', 'team')
- t.user_permissions.add(
- Permission.objects.get(codename='is_team')
- )
+ t = User.objects.create_user("team", "", "team")
+ t.user_permissions.add(Permission.objects.get(codename="is_team"))
c = WSClient()
c.force_login(t)
# connect
- c.send_and_consume('websocket.connect', path='/ws/k-fet/open',
- fail_on_none=True)
+ c.send_and_consume(
+ "websocket.connect", path="/ws/k-fet/open", fail_on_none=True
+ )
# initialization data is replied on connection
self.assertIsNotNone(c.receive())
# client belongs to the 'kfet.open.admin' group...
- OpenKfetConsumer.group_send('kfet.open.team', {'test': 'plop'})
- self.assertEqual(c.receive(), {'test': 'plop'})
+ OpenKfetConsumer.group_send("kfet.open.team", {"test": "plop"})
+ self.assertEqual(c.receive(), {"test": "plop"})
# ... but not to the 'kfet.open' one
- OpenKfetConsumer.group_send('kfet.open.base', {'test': 'plop'})
+ OpenKfetConsumer.group_send("kfet.open.base", {"test": "plop"})
self.assertIsNone(c.receive())
@@ -232,7 +218,7 @@ class OpenKfetScenarioTest(ChannelTestCase):
def setUp(self):
# Need this (and here) because of '.login' in setUp
- patcher_messages = mock.patch('gestioncof.signals.messages')
+ patcher_messages = mock.patch("gestioncof.signals.messages")
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
@@ -242,10 +228,10 @@ class OpenKfetScenarioTest(ChannelTestCase):
self.c_ws = WSClient()
# root user
- self.r = User.objects.create_superuser('root', '', 'root')
+ self.r = User.objects.create_superuser("root", "", "root")
# its client (for views)
self.r_c = Client()
- self.r_c.login(username='root', password='root')
+ self.r_c.login(username="root", password="root")
# its client (for websockets)
self.r_c_ws = WSClient()
self.r_c_ws.force_login(self.r)
@@ -255,8 +241,7 @@ class OpenKfetScenarioTest(ChannelTestCase):
def ws_connect(self, ws_client):
ws_client.send_and_consume(
- 'websocket.connect', path='/ws/k-fet/open',
- fail_on_none=True,
+ "websocket.connect", path="/ws/k-fet/open", fail_on_none=True
)
return ws_client.receive(json=True)
@@ -264,17 +249,11 @@ class OpenKfetScenarioTest(ChannelTestCase):
"""Clients connect."""
# test for anonymous user
msg = self.ws_connect(self.c_ws)
- self.assertSetEqual(
- set(['status']),
- set(msg),
- )
+ self.assertSetEqual(set(["status"]), set(msg))
# test for root user
msg = self.ws_connect(self.r_c_ws)
- self.assertSetEqual(
- set(['status', 'admin_status', 'force_close']),
- set(msg),
- )
+ self.assertSetEqual(set(["status", "admin_status", "force_close"]), set(msg))
def test_scenario_1(self):
"""Clients connect, door opens, enable force close."""
@@ -282,33 +261,30 @@ class OpenKfetScenarioTest(ChannelTestCase):
self.ws_connect(self.r_c_ws)
# door sent "I'm open!"
- self.c.post('/k-fet/open/raw_open', {
- 'raw_open': True,
- 'token': 'plop',
- })
+ self.c.post("/k-fet/open/raw_open", {"raw_open": True, "token": "plop"})
# anonymous user agree
msg = self.c_ws.receive(json=True)
- self.assertEqual(OpenKfet.OPENED, msg['status'])
+ self.assertEqual(OpenKfet.OPENED, msg["status"])
# root user too
msg = self.r_c_ws.receive(json=True)
- self.assertEqual(OpenKfet.OPENED, msg['status'])
- self.assertEqual(OpenKfet.OPENED, msg['admin_status'])
+ self.assertEqual(OpenKfet.OPENED, msg["status"])
+ self.assertEqual(OpenKfet.OPENED, msg["admin_status"])
# admin says "no it's closed"
- self.r_c.post('/k-fet/open/force_close', {'force_close': True})
+ self.r_c.post("/k-fet/open/force_close", {"force_close": True})
# so anonymous user see it's closed
msg = self.c_ws.receive(json=True)
- self.assertEqual(OpenKfet.CLOSED, msg['status'])
+ self.assertEqual(OpenKfet.CLOSED, msg["status"])
# root user too
msg = self.r_c_ws.receive(json=True)
- self.assertEqual(OpenKfet.CLOSED, msg['status'])
+ self.assertEqual(OpenKfet.CLOSED, msg["status"])
# but root knows things
- self.assertEqual(OpenKfet.FAKE_CLOSED, msg['admin_status'])
- self.assertTrue(msg['force_close'])
+ self.assertEqual(OpenKfet.FAKE_CLOSED, msg["admin_status"])
+ self.assertTrue(msg["force_close"])
def test_scenario_2(self):
"""Starting falsely closed, clients connect, disable force close."""
@@ -316,19 +292,19 @@ class OpenKfetScenarioTest(ChannelTestCase):
kfet_open.force_close = True
msg = self.ws_connect(self.c_ws)
- self.assertEqual(OpenKfet.CLOSED, msg['status'])
+ self.assertEqual(OpenKfet.CLOSED, msg["status"])
msg = self.ws_connect(self.r_c_ws)
- self.assertEqual(OpenKfet.CLOSED, msg['status'])
- self.assertEqual(OpenKfet.FAKE_CLOSED, msg['admin_status'])
- self.assertTrue(msg['force_close'])
+ self.assertEqual(OpenKfet.CLOSED, msg["status"])
+ self.assertEqual(OpenKfet.FAKE_CLOSED, msg["admin_status"])
+ self.assertTrue(msg["force_close"])
- self.r_c.post('/k-fet/open/force_close', {'force_close': False})
+ self.r_c.post("/k-fet/open/force_close", {"force_close": False})
msg = self.c_ws.receive(json=True)
- self.assertEqual(OpenKfet.OPENED, msg['status'])
+ self.assertEqual(OpenKfet.OPENED, msg["status"])
msg = self.r_c_ws.receive(json=True)
- self.assertEqual(OpenKfet.OPENED, msg['status'])
- self.assertEqual(OpenKfet.OPENED, msg['admin_status'])
- self.assertFalse(msg['force_close'])
+ self.assertEqual(OpenKfet.OPENED, msg["status"])
+ self.assertEqual(OpenKfet.OPENED, msg["admin_status"])
+ self.assertFalse(msg["force_close"])
diff --git a/kfet/open/urls.py b/kfet/open/urls.py
index bd227b96..c38b9ce4 100644
--- a/kfet/open/urls.py
+++ b/kfet/open/urls.py
@@ -2,10 +2,7 @@ from django.conf.urls import url
from . import views
-
urlpatterns = [
- url(r'^raw_open$', views.raw_open,
- name='kfet.open.edit_raw_open'),
- url(r'^force_close$', views.force_close,
- name='kfet.open.edit_force_close'),
+ url(r"^raw_open$", views.raw_open, name="kfet.open.edit_raw_open"),
+ url(r"^force_close$", views.force_close, name="kfet.open.edit_force_close"),
]
diff --git a/kfet/open/views.py b/kfet/open/views.py
index 4f1efa5f..49b91f4a 100644
--- a/kfet/open/views.py
+++ b/kfet/open/views.py
@@ -1,32 +1,31 @@
from django.conf import settings
-from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import permission_required
+from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from .open import kfet_open
-
-TRUE_STR = ['1', 'True', 'true']
+TRUE_STR = ["1", "True", "true"]
@csrf_exempt
@require_POST
def raw_open(request):
- token = request.POST.get('token')
+ token = request.POST.get("token")
if token != settings.KFETOPEN_TOKEN:
raise PermissionDenied
- raw_open = request.POST.get('raw_open') in TRUE_STR
+ raw_open = request.POST.get("raw_open") in TRUE_STR
kfet_open.raw_open = raw_open
kfet_open.send_ws()
return HttpResponse()
-@permission_required('kfet.can_force_close', raise_exception=True)
+@permission_required("kfet.can_force_close", raise_exception=True)
@require_POST
def force_close(request):
- force_close = request.POST.get('force_close') in TRUE_STR
+ force_close = request.POST.get("force_close") in TRUE_STR
kfet_open.force_close = force_close
kfet_open.send_ws()
return HttpResponse()
diff --git a/kfet/routing.py b/kfet/routing.py
index f1305d4b..ceafca06 100644
--- a/kfet/routing.py
+++ b/kfet/routing.py
@@ -2,8 +2,7 @@ from channels.routing import include, route_class
from . import consumers
-
routing = [
- route_class(consumers.KPsul, path=r'^/k-psul/$'),
- include('kfet.open.routing.routing', path=r'^/open'),
+ route_class(consumers.KPsul, path=r"^/k-psul/$"),
+ include("kfet.open.routing.routing", path=r"^/open"),
]
diff --git a/kfet/statistic.py b/kfet/statistic.py
index 0aba4dda..02171267 100644
--- a/kfet/statistic.py
+++ b/kfet/statistic.py
@@ -1,11 +1,10 @@
from datetime import date, datetime, time, timedelta
-from dateutil.relativedelta import relativedelta
-from dateutil.parser import parse as dateutil_parse
import pytz
-
-from django.utils import timezone
+from dateutil.parser import parse as dateutil_parse
+from dateutil.relativedelta import relativedelta
from django.db.models import Sum
+from django.utils import timezone
KFET_WAKES_UP_AT = time(7, 0)
@@ -13,7 +12,7 @@ KFET_WAKES_UP_AT = time(7, 0)
def kfet_day(year, month, day, start_at=KFET_WAKES_UP_AT):
"""datetime wrapper with time offset."""
naive = datetime.combine(date(year, month, day), start_at)
- return pytz.timezone('Europe/Paris').localize(naive, is_dst=None)
+ return pytz.timezone("Europe/Paris").localize(naive, is_dst=None)
def to_kfet_day(dt, start_at=KFET_WAKES_UP_AT):
@@ -27,8 +26,7 @@ class Scale(object):
name = None
step = None
- def __init__(self, n_steps=0, begin=None, end=None,
- last=False, std_chunk=True):
+ def __init__(self, n_steps=0, begin=None, end=None, last=False, std_chunk=True):
self.std_chunk = std_chunk
if last:
end = timezone.now()
@@ -48,9 +46,11 @@ class Scale(object):
self.begin = begin
self.end = end
else:
- raise Exception('Two of these args must be specified: '
- 'n_steps, begin, end; '
- 'or use last and n_steps')
+ raise Exception(
+ "Two of these args must be specified: "
+ "n_steps, begin, end; "
+ "or use last and n_steps"
+ )
self.datetimes = self.get_datetimes()
@@ -65,7 +65,7 @@ class Scale(object):
return self.std_chunk and self.get_chunk_start(dt) or dt
def __getitem__(self, i):
- return self.datetimes[i], self.datetimes[i+1]
+ return self.datetimes[i], self.datetimes[i + 1]
def __len__(self):
return len(self.datetimes) - 1
@@ -85,21 +85,18 @@ class Scale(object):
if label_fmt is None:
label_fmt = self.label_fmt
return [
- begin.strftime(label_fmt.format(i=i, rev_i=len(self)-i))
+ begin.strftime(label_fmt.format(i=i, rev_i=len(self) - i))
for i, (begin, end) in enumerate(self)
]
def chunkify_qs(self, qs, field=None):
if field is None:
- field = 'at'
- begin_f = '{}__gte'.format(field)
- end_f = '{}__lte'.format(field)
- return [
- qs.filter(**{begin_f: begin, end_f: end})
- for begin, end in self
- ]
+ field = "at"
+ begin_f = "{}__gte".format(field)
+ end_f = "{}__lte".format(field)
+ return [qs.filter(**{begin_f: begin, end_f: end}) for begin, end in self]
- def get_by_chunks(self, qs, field_callback=None, field_db='at'):
+ def get_by_chunks(self, qs, field_callback=None, field_db="at"):
"""Objects of queryset ranked according to the scale.
Returns a generator whose each item, corresponding to a scale chunk,
@@ -122,16 +119,14 @@ class Scale(object):
"""
if field_callback is None:
+
def field_callback(obj):
return getattr(obj, field_db)
- begin_f = '{}__gte'.format(field_db)
- end_f = '{}__lte'.format(field_db)
+ begin_f = "{}__gte".format(field_db)
+ end_f = "{}__lte".format(field_db)
- qs = (
- qs
- .filter(**{begin_f: self.begin, end_f: self.end})
- )
+ qs = qs.filter(**{begin_f: self.begin, end_f: self.end})
obj_iter = iter(qs)
@@ -184,9 +179,9 @@ class Scale(object):
class DayScale(Scale):
- name = 'day'
+ name = "day"
step = timedelta(days=1)
- label_fmt = '%A'
+ label_fmt = "%A"
@classmethod
def get_chunk_start(cls, dt):
@@ -194,9 +189,9 @@ class DayScale(Scale):
class WeekScale(Scale):
- name = 'week'
+ name = "week"
step = timedelta(days=7)
- label_fmt = 'Semaine %W'
+ label_fmt = "Semaine %W"
@classmethod
def get_chunk_start(cls, dt):
@@ -206,62 +201,63 @@ class WeekScale(Scale):
class MonthScale(Scale):
- name = 'month'
+ name = "month"
step = relativedelta(months=1)
- label_fmt = '%B'
+ label_fmt = "%B"
@classmethod
def get_chunk_start(cls, dt):
return to_kfet_day(dt).replace(day=1)
-def stat_manifest(scales_def=None, scale_args=None, scale_prefix=None,
- **other_url_params):
+def stat_manifest(
+ scales_def=None, scale_args=None, scale_prefix=None, **other_url_params
+):
if scale_prefix is None:
- scale_prefix = 'scale_'
+ scale_prefix = "scale_"
if scales_def is None:
scales_def = []
if scale_args is None:
scale_args = {}
manifest = []
for label, cls in scales_def:
- url_params = {scale_prefix+'name': cls.name}
- url_params.update({scale_prefix+key: value
- for key, value in scale_args.items()})
+ url_params = {scale_prefix + "name": cls.name}
+ url_params.update(
+ {scale_prefix + key: value for key, value in scale_args.items()}
+ )
url_params.update(other_url_params)
- manifest.append(dict(
- label=label,
- url_params=url_params,
- ))
+ manifest.append(dict(label=label, url_params=url_params))
return manifest
-def last_stats_manifest(scales_def=None, scale_args=None, scale_prefix=None,
- **url_params):
+def last_stats_manifest(
+ scales_def=None, scale_args=None, scale_prefix=None, **url_params
+):
scales_def = [
- ('Derniers mois', MonthScale, ),
- ('Dernières semaines', WeekScale, ),
- ('Derniers jours', DayScale, ),
+ ("Derniers mois", MonthScale),
+ ("Dernières semaines", WeekScale),
+ ("Derniers jours", DayScale),
]
if scale_args is None:
scale_args = {}
- scale_args.update(dict(
- last=True,
- n_steps=7,
- ))
- return stat_manifest(scales_def=scales_def, scale_args=scale_args,
- scale_prefix=scale_prefix, **url_params)
+ scale_args.update(dict(last=True, n_steps=7))
+ return stat_manifest(
+ scales_def=scales_def,
+ scale_args=scale_args,
+ scale_prefix=scale_prefix,
+ **url_params
+ )
# Étant donné un queryset d'operations
# rend la somme des article_nb
def tot_ventes(queryset):
- res = queryset.aggregate(Sum('article_nb'))['article_nb__sum']
+ res = queryset.aggregate(Sum("article_nb"))["article_nb__sum"]
return res and res or 0
class ScaleMixin(object):
- scale_args_prefix = 'scale_'
+ scale_args_prefix = "scale_"
def get_scale_args(self, params=None, prefix=None):
"""Retrieve scale args from params.
@@ -282,26 +278,25 @@ class ScaleMixin(object):
scale_args = {}
- name = params.get(prefix+'name', None)
+ name = params.get(prefix + "name", None)
if name is not None:
- scale_args['name'] = name
+ scale_args["name"] = name
- n_steps = params.get(prefix+'n_steps', None)
+ n_steps = params.get(prefix + "n_steps", None)
if n_steps is not None:
- scale_args['n_steps'] = int(n_steps)
+ scale_args["n_steps"] = int(n_steps)
- begin = params.get(prefix+'begin', None)
+ begin = params.get(prefix + "begin", None)
if begin is not None:
- scale_args['begin'] = dateutil_parse(begin)
+ scale_args["begin"] = dateutil_parse(begin)
- end = params.get(prefix+'send', None)
+ end = params.get(prefix + "send", None)
if end is not None:
- scale_args['end'] = dateutil_parse(end)
+ scale_args["end"] = dateutil_parse(end)
- last = params.get(prefix+'last', None)
+ last = params.get(prefix + "last", None)
if last is not None:
- scale_args['last'] = (
- last in ['true', 'True', '1'] and True or False)
+ scale_args["last"] = last in ["true", "True", "1"] and True or False
return scale_args
@@ -309,7 +304,7 @@ class ScaleMixin(object):
context = super().get_context_data(*args, **kwargs)
scale_args = self.get_scale_args()
- scale_name = scale_args.pop('name', None)
+ scale_name = scale_args.pop("name", None)
scale_cls = Scale.by_name(scale_name)
if scale_cls is None:
@@ -318,7 +313,7 @@ class ScaleMixin(object):
scale = scale_cls(**scale_args)
self.scale = scale
- context['labels'] = scale.get_labels()
+ context["labels"] = scale.get_labels()
return context
def get_default_scale(self):
diff --git a/kfet/templatetags/dictionary_extras.py b/kfet/templatetags/dictionary_extras.py
index fafaad8d..181fd012 100644
--- a/kfet/templatetags/dictionary_extras.py
+++ b/kfet/templatetags/dictionary_extras.py
@@ -1,5 +1,6 @@
from django.template.defaulttags import register
+
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)
diff --git a/kfet/templatetags/kfet_tags.py b/kfet/templatetags/kfet_tags.py
index 68b74738..4c26dd17 100644
--- a/kfet/templatetags/kfet_tags.py
+++ b/kfet/templatetags/kfet_tags.py
@@ -6,10 +6,9 @@ from django.utils.safestring import mark_safe
from ..utils import to_ukf
-
register = template.Library()
-register.filter('ukf', to_ukf)
+register.filter("ukf", to_ukf)
@register.filter()
diff --git a/kfet/tests/test_config.py b/kfet/tests/test_config.py
index 43497ca8..02ff1ff0 100644
--- a/kfet/tests/test_config.py
+++ b/kfet/tests/test_config.py
@@ -1,10 +1,9 @@
from decimal import Decimal
+import djconfig
from django.test import TestCase
from django.utils import timezone
-import djconfig
-
from gestioncof.models import User
from kfet.config import kfet_config
from kfet.models import Account
@@ -18,18 +17,18 @@ class ConfigTest(TestCase):
djconfig.reload_maybe()
def test_get(self):
- self.assertTrue(hasattr(kfet_config, 'subvention_cof'))
+ self.assertTrue(hasattr(kfet_config, "subvention_cof"))
def test_subvention_cof(self):
- reduction_cof = Decimal('20')
- subvention_cof = Decimal('25')
+ reduction_cof = Decimal("20")
+ subvention_cof = Decimal("25")
kfet_config.set(reduction_cof=reduction_cof)
self.assertEqual(kfet_config.subvention_cof, subvention_cof)
def test_set_decimal(self):
"""Test field of decimal type."""
- reduction_cof = Decimal('10')
+ reduction_cof = Decimal("10")
# IUT
kfet_config.set(reduction_cof=reduction_cof)
# check
@@ -37,9 +36,8 @@ class ConfigTest(TestCase):
def test_set_modelinstance(self):
"""Test field of model instance type."""
- user = User.objects.create(username='foo_user')
- account = Account.objects.create(trigramme='FOO',
- cofprofile=user.profile)
+ user = User.objects.create(username="foo_user")
+ account = Account.objects.create(trigramme="FOO", cofprofile=user.profile)
# IUT
kfet_config.set(addcost_for=account)
# check
diff --git a/kfet/tests/test_forms.py b/kfet/tests/test_forms.py
index e946d39d..37b05e74 100644
--- a/kfet/tests/test_forms.py
+++ b/kfet/tests/test_forms.py
@@ -11,14 +11,14 @@ from .utils import create_user
class KPsulCheckoutFormTests(TestCase):
-
def setUp(self):
self.now = timezone.now()
user = create_user()
self.c1 = Checkout.objects.create(
- name='C1', balance=10,
+ name="C1",
+ balance=10,
created_by=user.profile.account_kfet,
valid_from=self.now,
valid_to=self.now + datetime.timedelta(days=1),
@@ -27,13 +27,12 @@ class KPsulCheckoutFormTests(TestCase):
self.form = KPsulCheckoutForm()
def test_checkout(self):
- checkout_f = self.form.fields['checkout']
- self.assertListEqual(list(checkout_f.choices), [
- ('', '---------'),
- (self.c1.pk, 'C1'),
- ])
+ checkout_f = self.form.fields["checkout"]
+ self.assertListEqual(
+ list(checkout_f.choices), [("", "---------"), (self.c1.pk, "C1")]
+ )
- @mock.patch('django.utils.timezone.now')
+ @mock.patch("django.utils.timezone.now")
def test_checkout_valid(self, mock_now):
"""
Checkout are filtered using the current datetime.
@@ -44,5 +43,5 @@ class KPsulCheckoutFormTests(TestCase):
form = KPsulCheckoutForm()
- checkout_f = form.fields['checkout']
- self.assertListEqual(list(checkout_f.choices), [('', '---------')])
+ checkout_f = form.fields["checkout"]
+ self.assertListEqual(list(checkout_f.choices), [("", "---------")])
diff --git a/kfet/tests/test_models.py b/kfet/tests/test_models.py
index 727cac4e..7ce6605c 100644
--- a/kfet/tests/test_models.py
+++ b/kfet/tests/test_models.py
@@ -12,26 +12,24 @@ User = get_user_model()
class AccountTests(TestCase):
-
def setUp(self):
- self.account = Account(trigramme='000')
- self.account.save({'username': 'user'})
+ self.account = Account(trigramme="000")
+ self.account.save({"username": "user"})
def test_password(self):
- self.account.change_pwd('anna')
+ self.account.change_pwd("anna")
self.account.save()
- self.assertEqual(Account.objects.get_by_password('anna'), self.account)
+ self.assertEqual(Account.objects.get_by_password("anna"), self.account)
with self.assertRaises(Account.DoesNotExist):
Account.objects.get_by_password(None)
with self.assertRaises(Account.DoesNotExist):
- Account.objects.get_by_password('bernard')
+ Account.objects.get_by_password("bernard")
class CheckoutTests(TestCase):
-
def setUp(self):
self.now = timezone.now()
diff --git a/kfet/tests/test_statistic.py b/kfet/tests/test_statistic.py
index 93de27a0..f0ed7f74 100644
--- a/kfet/tests/test_statistic.py
+++ b/kfet/tests/test_statistic.py
@@ -1,14 +1,13 @@
from unittest.mock import patch
-from django.test import TestCase, Client
-from django.contrib.auth.models import User, Permission
+from django.contrib.auth.models import Permission, User
+from django.test import Client, TestCase
from kfet.models import Account, Article, ArticleCategory
class TestStats(TestCase):
-
- @patch('gestioncof.signals.messages')
+ @patch("gestioncof.signals.messages")
def test_user_stats(self, mock_messages):
"""
Checks that we can get the stat-related pages without any problem.
@@ -28,8 +27,7 @@ class TestStats(TestCase):
Account.objects.create(trigramme="BAR", cofprofile=user2.profile)
article = Article.objects.create(
- name="article",
- category=ArticleCategory.objects.create(name="C")
+ name="article", category=ArticleCategory.objects.create(name="C")
)
# Each user have its own client
@@ -43,12 +41,17 @@ class TestStats(TestCase):
user_urls = [
"/k-fet/accounts/FOO/stat/operations/list",
"/k-fet/accounts/FOO/stat/operations?{}".format(
- '&'.join(["scale=day",
- "types=['purchase']",
- "scale_args={'n_steps':+7,+'last':+True}",
- "format=json"])),
+ "&".join(
+ [
+ "scale=day",
+ "types=['purchase']",
+ "scale_args={'n_steps':+7,+'last':+True}",
+ "format=json",
+ ]
+ )
+ ),
"/k-fet/accounts/FOO/stat/balance/list",
- "/k-fet/accounts/FOO/stat/balance?format=json"
+ "/k-fet/accounts/FOO/stat/balance?format=json",
]
for url in user_urls:
resp = client.get(url)
@@ -60,7 +63,7 @@ class TestStats(TestCase):
# receives a Redirect response
articles_urls = [
"/k-fet/articles/{}/stat/sales/list".format(article.pk),
- "/k-fet/articles/{}/stat/sales".format(article.pk)
+ "/k-fet/articles/{}/stat/sales".format(article.pk),
]
for url in articles_urls:
resp = client.get(url)
diff --git a/kfet/tests/test_tests_utils.py b/kfet/tests/test_tests_utils.py
index 8308bd5b..45ca2348 100644
--- a/kfet/tests/test_tests_utils.py
+++ b/kfet/tests/test_tests_utils.py
@@ -7,86 +7,79 @@ from gestioncof.models import CofProfile
from ..models import Account
from .testcases import TestCaseMixin
-from .utils import (
- create_user, create_team, create_root, get_perms, user_add_perms,
-)
-
+from .utils import create_root, create_team, create_user, get_perms, user_add_perms
User = get_user_model()
class UserHelpersTests(TestCaseMixin, TestCase):
-
def test_create_user(self):
"""create_user creates a basic user and its account."""
u = create_user()
a = u.profile.account_kfet
- self.assertInstanceExpected(u, {
- 'get_full_name': 'first last',
- 'username': 'user',
- })
+ self.assertInstanceExpected(
+ u, {"get_full_name": "first last", "username": "user"}
+ )
self.assertFalse(u.user_permissions.exists())
- self.assertEqual('000', a.trigramme)
+ self.assertEqual("000", a.trigramme)
def test_create_team(self):
u = create_team()
a = u.profile.account_kfet
- self.assertInstanceExpected(u, {
- 'get_full_name': 'team member',
- 'username': 'team',
- })
- self.assertTrue(u.has_perm('kfet.is_team'))
+ self.assertInstanceExpected(
+ u, {"get_full_name": "team member", "username": "team"}
+ )
+ self.assertTrue(u.has_perm("kfet.is_team"))
- self.assertEqual('100', a.trigramme)
+ self.assertEqual("100", a.trigramme)
def test_create_root(self):
u = create_root()
a = u.profile.account_kfet
- self.assertInstanceExpected(u, {
- 'get_full_name': 'super user',
- 'username': 'root',
- 'is_superuser': True,
- 'is_staff': True,
- })
+ self.assertInstanceExpected(
+ u,
+ {
+ "get_full_name": "super user",
+ "username": "root",
+ "is_superuser": True,
+ "is_staff": True,
+ },
+ )
- self.assertEqual('200', a.trigramme)
+ self.assertEqual("200", a.trigramme)
class PermHelpersTest(TestCaseMixin, TestCase):
-
def setUp(self):
cts = ContentType.objects.get_for_models(Account, CofProfile)
self.perm1 = Permission.objects.create(
- content_type=cts[Account],
- codename='test_perm',
- name='Perm for test',
+ content_type=cts[Account], codename="test_perm", name="Perm for test"
)
self.perm2 = Permission.objects.create(
content_type=cts[CofProfile],
- codename='another_test_perm',
- name='Another one',
+ codename="another_test_perm",
+ name="Another one",
)
self.perm_team = Permission.objects.get(
- content_type__app_label='kfet',
- codename='is_team',
+ content_type__app_label="kfet", codename="is_team"
)
def test_get_perms(self):
- perms = get_perms('kfet.test_perm', 'gestioncof.another_test_perm')
- self.assertDictEqual(perms, {
- 'kfet.test_perm': self.perm1,
- 'gestioncof.another_test_perm': self.perm2,
- })
+ perms = get_perms("kfet.test_perm", "gestioncof.another_test_perm")
+ self.assertDictEqual(
+ perms,
+ {"kfet.test_perm": self.perm1, "gestioncof.another_test_perm": self.perm2},
+ )
def test_user_add_perms(self):
- user = User.objects.create_user(username='user', password='user')
+ user = User.objects.create_user(username="user", password="user")
user.user_permissions.add(self.perm1)
- user_add_perms(user, ['kfet.is_team', 'gestioncof.another_test_perm'])
+ user_add_perms(user, ["kfet.is_team", "gestioncof.another_test_perm"])
self.assertQuerysetEqual(
user.user_permissions.all(),
diff --git a/kfet/tests/test_views.py b/kfet/tests/test_views.py
index 40f895a1..bd57b6f8 100644
--- a/kfet/tests/test_views.py
+++ b/kfet/tests/test_views.py
@@ -10,20 +10,33 @@ from django.utils import timezone
from ..config import kfet_config
from ..models import (
- Account, Article, ArticleCategory, Checkout, CheckoutStatement, Inventory,
- InventoryArticle, Operation, OperationGroup, Order, OrderArticle, Supplier,
- SupplierArticle, Transfer, TransferGroup,
+ Account,
+ AccountNegative,
+ Article,
+ ArticleCategory,
+ Checkout,
+ CheckoutStatement,
+ Inventory,
+ InventoryArticle,
+ Operation,
+ OperationGroup,
+ Order,
+ OrderArticle,
+ Supplier,
+ SupplierArticle,
+ Transfer,
+ TransferGroup,
)
from .testcases import ViewTestCaseMixin
-from .utils import create_team, create_user, get_perms
+from .utils import create_team, create_user, get_perms, user_add_perms
class AccountListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account'
- url_expected = '/k-fet/accounts/'
+ url_name = "kfet.account"
+ url_expected = "/k-fet/accounts/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
r = self.client.get(self.url)
@@ -31,58 +44,53 @@ class AccountListViewTests(ViewTestCaseMixin, TestCase):
class AccountValidFreeTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.is_validandfree.ajax'
- url_expected = '/k-fet/accounts/is_validandfree'
+ url_name = "kfet.account.is_validandfree.ajax"
+ url_expected = "/k-fet/accounts/is_validandfree"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok_isvalid_isfree(self):
"""Upper case trigramme not taken is valid and free."""
- r = self.client.get(self.url, {'trigramme': 'AAA'})
- self.assertDictEqual(json.loads(r.content.decode('utf-8')), {
- 'is_valid': True,
- 'is_free': True,
- })
+ r = self.client.get(self.url, {"trigramme": "AAA"})
+ self.assertDictEqual(
+ json.loads(r.content.decode("utf-8")), {"is_valid": True, "is_free": True}
+ )
def test_ok_isvalid_notfree(self):
"""Already taken trigramme is not free, but valid."""
- r = self.client.get(self.url, {'trigramme': '000'})
- self.assertDictEqual(json.loads(r.content.decode('utf-8')), {
- 'is_valid': True,
- 'is_free': False,
- })
+ r = self.client.get(self.url, {"trigramme": "000"})
+ self.assertDictEqual(
+ json.loads(r.content.decode("utf-8")), {"is_valid": True, "is_free": False}
+ )
def test_ok_notvalid_isfree(self):
"""Lower case if forbidden but free."""
- r = self.client.get(self.url, {'trigramme': 'aaa'})
- self.assertDictEqual(json.loads(r.content.decode('utf-8')), {
- 'is_valid': False,
- 'is_free': True,
- })
+ r = self.client.get(self.url, {"trigramme": "aaa"})
+ self.assertDictEqual(
+ json.loads(r.content.decode("utf-8")), {"is_valid": False, "is_free": True}
+ )
class AccountCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.create'
- url_expected = '/k-fet/accounts/new'
+ url_name = "kfet.account.create"
+ url_expected = "/k-fet/accounts/new"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
post_data = {
- 'trigramme': 'AAA',
- 'username': 'plopplopplop',
- 'first_name': 'first',
- 'last_name': 'last',
- 'email': 'email@domain.net',
+ "trigramme": "AAA",
+ "username": "plopplopplop",
+ "first_name": "first",
+ "last_name": "last",
+ "email": "email@domain.net",
}
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.add_account']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.add_account"])}
def test_get_ok(self):
r = self.client.get(self.url)
@@ -90,18 +98,17 @@ class AccountCreateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.account.create'))
+ self.assertRedirects(r, reverse("kfet.account.create"))
- account = Account.objects.get(trigramme='AAA')
+ account = Account.objects.get(trigramme="AAA")
- self.assertInstanceExpected(account, {
- 'username': 'plopplopplop',
- 'first_name': 'first',
- 'last_name': 'last',
- })
+ self.assertInstanceExpected(
+ account,
+ {"username": "plopplopplop", "first_name": "first", "last_name": "last"},
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -109,132 +116,128 @@ class AccountCreateViewTests(ViewTestCaseMixin, TestCase):
class AccountCreateAjaxViewTests(ViewTestCaseMixin, TestCase):
- urls_conf = [{
- 'name': 'kfet.account.create.fromuser',
- 'kwargs': {'username': 'user'},
- 'expected': '/k-fet/accounts/new/user/user',
- }, {
- 'name': 'kfet.account.create.fromclipper',
- 'kwargs': {
- 'login_clipper': 'myclipper',
- 'fullname': 'first last1 last2',
+ urls_conf = [
+ {
+ "name": "kfet.account.create.fromuser",
+ "kwargs": {"username": "user"},
+ "expected": "/k-fet/accounts/new/user/user",
},
- 'expected': (
- '/k-fet/accounts/new/clipper/myclipper/first%20last1%20last2'
- ),
- }, {
- 'name': 'kfet.account.create.empty',
- 'expected': '/k-fet/accounts/new/empty',
- }]
+ {
+ "name": "kfet.account.create.fromclipper",
+ "kwargs": {"login_clipper": "myclipper", "fullname": "first last1 last2"},
+ "expected": ("/k-fet/accounts/new/clipper/myclipper/first%20last1%20last2"),
+ },
+ {"name": "kfet.account.create.empty", "expected": "/k-fet/accounts/new/empty"},
+ ]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_fromuser(self):
r = self.client.get(self.t_urls[0])
self.assertEqual(r.status_code, 200)
- user = self.users['user']
+ user = self.users["user"]
- self.assertEqual(r.context['user_form'].instance, user)
- self.assertEqual(r.context['cof_form'].instance, user.profile)
- self.assertIn('account_form', r.context)
+ self.assertEqual(r.context["user_form"].instance, user)
+ self.assertEqual(r.context["cof_form"].instance, user.profile)
+ self.assertIn("account_form", r.context)
def test_fromclipper(self):
r = self.client.get(self.t_urls[1])
self.assertEqual(r.status_code, 200)
- self.assertIn('user_form', r.context)
- self.assertIn('cof_form', r.context)
- self.assertIn('account_form', r.context)
+ self.assertIn("user_form", r.context)
+ self.assertIn("cof_form", r.context)
+ self.assertIn("account_form", r.context)
def test_empty(self):
r = self.client.get(self.t_urls[2])
self.assertEqual(r.status_code, 200)
- self.assertIn('user_form', r.context)
- self.assertIn('cof_form', r.context)
- self.assertIn('account_form', r.context)
+ self.assertIn("user_form", r.context)
+ self.assertIn("cof_form", r.context)
+ self.assertIn("account_form", r.context)
class AccountCreateAutocompleteViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.create.autocomplete'
- url_expected = '/k-fet/autocomplete/account_new'
+ url_name = "kfet.account.create.autocomplete"
+ url_expected = "/k-fet/autocomplete/account_new"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
- r = self.client.get(self.url, {'q': 'first'})
+ r = self.client.get(self.url, {"q": "first"})
self.assertEqual(r.status_code, 200)
- self.assertEqual(len(r.context['users_notcof']), 0)
- self.assertEqual(len(r.context['users_cof']), 0)
- self.assertSetEqual(set(r.context['kfet']), set([
- (self.accounts['user'], self.users['user']),
- ]))
+ self.assertEqual(len(r.context["users_notcof"]), 0)
+ self.assertEqual(len(r.context["users_cof"]), 0)
+ self.assertSetEqual(
+ set(r.context["kfet"]), set([(self.accounts["user"], self.users["user"])])
+ )
class AccountSearchViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.search.autocomplete'
- url_expected = '/k-fet/autocomplete/account_search'
+ url_name = "kfet.account.search.autocomplete"
+ url_expected = "/k-fet/autocomplete/account_search"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
- r = self.client.get(self.url, {'q': 'first'})
+ r = self.client.get(self.url, {"q": "first"})
self.assertEqual(r.status_code, 200)
- self.assertSetEqual(set(r.context['accounts']), set([
- ('000', 'first last'),
- ]))
+ self.assertSetEqual(set(r.context["accounts"]), set([("000", "first last")]))
class AccountReadViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.read'
- url_kwargs = {'trigramme': '001'}
- url_expected = '/k-fet/accounts/001'
+ url_name = "kfet.account.read"
+ url_kwargs = {"trigramme": "001"}
+ url_expected = "/k-fet/accounts/001"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def get_users_extra(self):
- return {
- 'user1': create_user('user1', '001'),
- }
+ return {"user1": create_user("user1", "001")}
def setUp(self):
super().setUp()
- user1_acc = self.accounts['user1']
- team_acc = self.accounts['team']
+ user1_acc = self.accounts["user1"]
+ team_acc = self.accounts["team"]
# Dummy operations and operation groups
checkout = Checkout.objects.create(
- created_by=team_acc, name="checkout",
+ created_by=team_acc,
+ name="checkout",
valid_from=timezone.now(),
- valid_to=timezone.now() + timezone.timedelta(days=365)
+ valid_to=timezone.now() + timezone.timedelta(days=365),
)
opeg_data = [
- (timezone.now(), Decimal('10')),
- (timezone.now() - timezone.timedelta(days=3), Decimal('3')),
+ (timezone.now(), Decimal("10")),
+ (timezone.now() - timezone.timedelta(days=3), Decimal("3")),
]
- OperationGroup.objects.bulk_create([
- OperationGroup(
- on_acc=user1_acc, checkout=checkout, at=at, is_cof=False,
- amount=amount
- )
- for (at, amount) in opeg_data
- ])
+ OperationGroup.objects.bulk_create(
+ [
+ OperationGroup(
+ on_acc=user1_acc,
+ checkout=checkout,
+ at=at,
+ is_cof=False,
+ amount=amount,
+ )
+ for (at, amount) in opeg_data
+ ]
+ )
self.operation_groups = OperationGroup.objects.order_by("-amount")
Operation.objects.create(
group=self.operation_groups[0],
type=Operation.PURCHASE,
- amount=Decimal('10')
+ amount=Decimal("10"),
)
Operation.objects.create(
- group=self.operation_groups[1],
- type=Operation.PURCHASE,
- amount=Decimal('3')
+ group=self.operation_groups[1], type=Operation.PURCHASE, amount=Decimal("3")
)
def test_ok(self):
@@ -244,44 +247,42 @@ class AccountReadViewTests(ViewTestCaseMixin, TestCase):
def test_ok_self(self):
client = Client()
- client.login(username='user1', password='user1')
+ client.login(username="user1", password="user1")
r = client.get(self.url)
self.assertEqual(r.status_code, 200)
class AccountUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.update'
- url_kwargs = {'trigramme': '001'}
- url_expected = '/k-fet/accounts/001/edit'
+ url_name = "kfet.account.update"
+ url_kwargs = {"trigramme": "001"}
+ url_expected = "/k-fet/accounts/001/edit"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
post_data = {
# User
- 'first_name': 'The first',
- 'last_name': 'The last',
- 'email': '',
+ "first_name": "The first",
+ "last_name": "The last",
+ "email": "",
# Group
- 'groups[]': [],
+ "groups[]": [],
# Account
- 'trigramme': '051',
- 'nickname': '',
- 'promo': '',
+ "trigramme": "051",
+ "nickname": "",
+ "promo": "",
# 'is_frozen': not checked
# Account password
- 'pwd1': '',
- 'pwd2': '',
+ "pwd1": "",
+ "pwd2": "",
}
def get_users_extra(self):
return {
- 'user1': create_user('user1', '001'),
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_account',
- ]),
+ "user1": create_user("user1", "001"),
+ "team1": create_team("team1", "101", perms=["kfet.change_account"]),
}
def test_get_ok(self):
@@ -290,45 +291,40 @@ class AccountUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_get_ok_self(self):
client = Client()
- client.login(username='user1', password='user1')
+ client.login(username="user1", password="user1")
r = client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.account.read', args=['051']))
+ self.assertRedirects(r, reverse("kfet.account.read", args=["051"]))
- self.accounts['user1'].refresh_from_db()
- self.users['user1'].refresh_from_db()
+ self.accounts["user1"].refresh_from_db()
+ self.users["user1"].refresh_from_db()
- self.assertInstanceExpected(self.accounts['user1'], {
- 'first_name': 'The first',
- 'last_name': 'The last',
- 'trigramme': '051',
- })
+ self.assertInstanceExpected(
+ self.accounts["user1"],
+ {"first_name": "The first", "last_name": "The last", "trigramme": "051"},
+ )
def test_post_ok_self(self):
client = Client()
- client.login(username='user1', password='user1')
+ client.login(username="user1", password="user1")
- post_data = {
- 'first_name': 'The first',
- 'last_name': 'The last',
- }
+ post_data = {"first_name": "The first", "last_name": "The last"}
r = client.post(self.url, post_data)
- self.assertRedirects(r, reverse('kfet.account.read', args=['001']))
+ self.assertRedirects(r, reverse("kfet.account.read", args=["001"]))
- self.accounts['user1'].refresh_from_db()
- self.users['user1'].refresh_from_db()
+ self.accounts["user1"].refresh_from_db()
+ self.users["user1"].refresh_from_db()
- self.assertInstanceExpected(self.accounts['user1'], {
- 'first_name': 'The first',
- 'last_name': 'The last',
- })
+ self.assertInstanceExpected(
+ self.accounts["user1"], {"first_name": "The first", "last_name": "The last"}
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -336,63 +332,54 @@ class AccountUpdateViewTests(ViewTestCaseMixin, TestCase):
class AccountGroupListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.group'
- url_expected = '/k-fet/accounts/groups'
+ url_name = "kfet.account.group"
+ url_expected = "/k-fet/accounts/groups"
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.manage_perms']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.manage_perms"])}
def setUp(self):
super().setUp()
- self.group1 = Group.objects.create(name='K-Fêt - Group1')
- self.group2 = Group.objects.create(name='K-Fêt - Group2')
+ self.group1 = Group.objects.create(name="K-Fêt - Group1")
+ self.group2 = Group.objects.create(name="K-Fêt - Group2")
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['groups'],
- map(repr, [self.group1, self.group2]),
- ordered=False,
+ r.context["groups"], map(repr, [self.group1, self.group2]), ordered=False
)
class AccountGroupCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.group.create'
- url_expected = '/k-fet/accounts/groups/new'
+ url_name = "kfet.account.group.create"
+ url_expected = "/k-fet/accounts/groups/new"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.manage_perms']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.manage_perms"])}
@property
def post_data(self):
return {
- 'name': 'The Group',
- 'permissions': [
- str(self.perms['kfet.is_team'].pk),
- str(self.perms['kfet.manage_perms'].pk),
+ "name": "The Group",
+ "permissions": [
+ str(self.perms["kfet.is_team"].pk),
+ str(self.perms["kfet.manage_perms"].pk),
],
}
def setUp(self):
super().setUp()
- self.perms = get_perms(
- 'kfet.is_team',
- 'kfet.manage_perms',
- )
+ self.perms = get_perms("kfet.is_team", "kfet.manage_perms")
def test_get_ok(self):
r = self.client.get(self.url)
@@ -400,58 +387,50 @@ class AccountGroupCreateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
r = self.client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.account.group'))
+ self.assertRedirects(r, reverse("kfet.account.group"))
- group = Group.objects.get(name='K-Fêt The Group')
+ group = Group.objects.get(name="K-Fêt The Group")
self.assertQuerysetEqual(
group.permissions.all(),
- map(repr, [
- self.perms['kfet.is_team'],
- self.perms['kfet.manage_perms'],
- ]),
+ map(repr, [self.perms["kfet.is_team"], self.perms["kfet.manage_perms"]]),
ordered=False,
)
class AccountGroupUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.group.update'
+ url_name = "kfet.account.group.update"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
@property
def url_kwargs(self):
- return {'pk': self.group.pk}
+ return {"pk": self.group.pk}
@property
def url_expected(self):
- return '/k-fet/accounts/groups/{}/edit'.format(self.group.pk)
+ return "/k-fet/accounts/groups/{}/edit".format(self.group.pk)
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.manage_perms']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.manage_perms"])}
@property
def post_data(self):
return {
- 'name': 'The Group',
- 'permissions': [
- str(self.perms['kfet.is_team'].pk),
- str(self.perms['kfet.manage_perms'].pk),
+ "name": "The Group",
+ "permissions": [
+ str(self.perms["kfet.is_team"].pk),
+ str(self.perms["kfet.manage_perms"].pk),
],
}
def setUp(self):
super().setUp()
- self.perms = get_perms(
- 'kfet.is_team',
- 'kfet.manage_perms',
- )
- self.group = Group.objects.create(name='K-Fêt - Group')
+ self.perms = get_perms("kfet.is_team", "kfet.manage_perms")
+ self.group = Group.objects.create(name="K-Fêt - Group")
self.group.permissions.set(self.perms.values())
def test_get_ok(self):
@@ -460,36 +439,31 @@ class AccountGroupUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
r = self.client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.account.group'))
+ self.assertRedirects(r, reverse("kfet.account.group"))
self.group.refresh_from_db()
- self.assertEqual(self.group.name, 'K-Fêt The Group')
+ self.assertEqual(self.group.name, "K-Fêt The Group")
self.assertQuerysetEqual(
self.group.permissions.all(),
- map(repr, [
- self.perms['kfet.is_team'],
- self.perms['kfet.manage_perms'],
- ]),
+ map(repr, [self.perms["kfet.is_team"], self.perms["kfet.manage_perms"]]),
ordered=False,
)
class AccountNegativeListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.negative'
- url_expected = '/k-fet/accounts/negatives'
+ url_name = "kfet.account.negative"
+ url_expected = "/k-fet/accounts/negatives"
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.view_negs']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.view_negs"])}
def setUp(self):
super().setUp()
- account = self.accounts['user']
+ account = self.accounts["user"]
account.balance = -5
account.save()
account.update_negative()
@@ -498,82 +472,86 @@ class AccountNegativeListViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['negatives'],
- map(repr, [self.accounts['user'].negative]),
+ r.context["negatives"],
+ map(repr, [self.accounts["user"].negative]),
ordered=False,
)
class AccountStatOperationListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.stat.operation.list'
- url_kwargs = {'trigramme': '001'}
- url_expected = '/k-fet/accounts/001/stat/operations/list'
+ url_name = "kfet.account.stat.operation.list"
+ url_kwargs = {"trigramme": "001"}
+ url_expected = "/k-fet/accounts/001/stat/operations/list"
- auth_user = 'user1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "user1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {'user1': create_user('user1', '001')}
+ return {"user1": create_user("user1", "001")}
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- content = json.loads(r.content.decode('utf-8'))
+ content = json.loads(r.content.decode("utf-8"))
- base_url = reverse('kfet.account.stat.operation', args=['001'])
+ base_url = reverse("kfet.account.stat.operation", args=["001"])
- expected_stats = [{
- 'label': 'Derniers mois',
- 'url': {
- 'path': base_url,
- 'query': {
- 'scale_n_steps': ['7'],
- 'scale_name': ['month'],
- 'types': ["['purchase']"],
- 'scale_last': ['True'],
+ expected_stats = [
+ {
+ "label": "Derniers mois",
+ "url": {
+ "path": base_url,
+ "query": {
+ "scale_n_steps": ["7"],
+ "scale_name": ["month"],
+ "types": ["['purchase']"],
+ "scale_last": ["True"],
+ },
},
},
- }, {
- 'label': 'Dernières semaines',
- 'url': {
- 'path': base_url,
- 'query': {
- 'scale_n_steps': ['7'],
- 'scale_name': ['week'],
- 'types': ["['purchase']"],
- 'scale_last': ['True'],
+ {
+ "label": "Dernières semaines",
+ "url": {
+ "path": base_url,
+ "query": {
+ "scale_n_steps": ["7"],
+ "scale_name": ["week"],
+ "types": ["['purchase']"],
+ "scale_last": ["True"],
+ },
},
},
- }, {
- 'label': 'Derniers jours',
- 'url': {
- 'path': base_url,
- 'query': {
- 'scale_n_steps': ['7'],
- 'scale_name': ['day'],
- 'types': ["['purchase']"],
- 'scale_last': ['True'],
+ {
+ "label": "Derniers jours",
+ "url": {
+ "path": base_url,
+ "query": {
+ "scale_n_steps": ["7"],
+ "scale_name": ["day"],
+ "types": ["['purchase']"],
+ "scale_last": ["True"],
+ },
},
},
- }]
+ ]
- for stat, expected in zip(content['stats'], expected_stats):
- expected_url = expected.pop('url')
- self.assertUrlsEqual(stat['url'], expected_url)
+ for stat, expected in zip(content["stats"], expected_stats):
+ expected_url = expected.pop("url")
+ self.assertUrlsEqual(stat["url"], expected_url)
self.assertDictContainsSubset(expected, stat)
class AccountStatOperationViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.stat.operation'
- url_kwargs = {'trigramme': '001'}
- url_expected = '/k-fet/accounts/001/stat/operations'
+ url_name = "kfet.account.stat.operation"
+ url_kwargs = {"trigramme": "001"}
+ url_expected = "/k-fet/accounts/001/stat/operations"
- auth_user = 'user1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "user1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {'user1': create_user('user1', '001')}
+ return {"user1": create_user("user1", "001")}
def test_ok(self):
r = self.client.get(self.url)
@@ -581,69 +559,60 @@ class AccountStatOperationViewTests(ViewTestCaseMixin, TestCase):
class AccountStatBalanceListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.stat.balance.list'
- url_kwargs = {'trigramme': '001'}
- url_expected = '/k-fet/accounts/001/stat/balance/list'
+ url_name = "kfet.account.stat.balance.list"
+ url_kwargs = {"trigramme": "001"}
+ url_expected = "/k-fet/accounts/001/stat/balance/list"
- auth_user = 'user1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "user1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {'user1': create_user('user1', '001')}
+ return {"user1": create_user("user1", "001")}
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- content = json.loads(r.content.decode('utf-8'))
+ content = json.loads(r.content.decode("utf-8"))
- base_url = reverse('kfet.account.stat.balance', args=['001'])
+ base_url = reverse("kfet.account.stat.balance", args=["001"])
- expected_stats = [{
- 'label': 'Tout le temps',
- 'url': base_url,
- }, {
- 'label': '1 an',
- 'url': {
- 'path': base_url,
- 'query': {'last_days': ['365']},
+ expected_stats = [
+ {"label": "Tout le temps", "url": base_url},
+ {
+ "label": "1 an",
+ "url": {"path": base_url, "query": {"last_days": ["365"]}},
},
- }, {
- 'label': '6 mois',
- 'url': {
- 'path': base_url,
- 'query': {'last_days': ['183']},
+ {
+ "label": "6 mois",
+ "url": {"path": base_url, "query": {"last_days": ["183"]}},
},
- }, {
- 'label': '3 mois',
- 'url': {
- 'path': base_url,
- 'query': {'last_days': ['90']},
+ {
+ "label": "3 mois",
+ "url": {"path": base_url, "query": {"last_days": ["90"]}},
},
- }, {
- 'label': '30 jours',
- 'url': {
- 'path': base_url,
- 'query': {'last_days': ['30']},
+ {
+ "label": "30 jours",
+ "url": {"path": base_url, "query": {"last_days": ["30"]}},
},
- }]
+ ]
- for stat, expected in zip(content['stats'], expected_stats):
- expected_url = expected.pop('url')
- self.assertUrlsEqual(stat['url'], expected_url)
+ for stat, expected in zip(content["stats"], expected_stats):
+ expected_url = expected.pop("url")
+ self.assertUrlsEqual(stat["url"], expected_url)
self.assertDictContainsSubset(expected, stat)
class AccountStatBalanceViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.stat.balance'
- url_kwargs = {'trigramme': '001'}
- url_expected = '/k-fet/accounts/001/stat/balance'
+ url_name = "kfet.account.stat.balance"
+ url_kwargs = {"trigramme": "001"}
+ url_expected = "/k-fet/accounts/001/stat/balance"
- auth_user = 'user1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "user1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {'user1': create_user('user1', '001')}
+ return {"user1": create_user("user1", "001")}
def test_ok(self):
r = self.client.get(self.url)
@@ -651,23 +620,23 @@ class AccountStatBalanceViewTests(ViewTestCaseMixin, TestCase):
class CheckoutListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkout'
- url_expected = '/k-fet/checkouts/'
+ url_name = "kfet.checkout"
+ url_expected = "/k-fet/checkouts/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
self.checkout1 = Checkout.objects.create(
- name='Checkout 1',
- created_by=self.accounts['team'],
+ name="Checkout 1",
+ created_by=self.accounts["team"],
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
)
self.checkout2 = Checkout.objects.create(
- name='Checkout 2',
- created_by=self.accounts['team'],
+ name="Checkout 2",
+ created_by=self.accounts["team"],
valid_from=self.now + timedelta(days=10),
valid_to=self.now + timedelta(days=15),
)
@@ -676,33 +645,31 @@ class CheckoutListViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['checkouts'],
+ r.context["checkouts"],
map(repr, [self.checkout1, self.checkout2]),
ordered=False,
)
class CheckoutCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkout.create'
- url_expected = '/k-fet/checkouts/new'
+ url_name = "kfet.checkout.create"
+ url_expected = "/k-fet/checkouts/new"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
post_data = {
- 'name': 'Checkout',
- 'valid_from': '2017-10-08 17:45:00',
- 'valid_to': '2017-11-08 16:00:00',
- 'balance': '3.14',
+ "name": "Checkout",
+ "valid_from": "2017-10-08 17:45:00",
+ "valid_to": "2017-11-08 16:00:00",
+ "balance": "3.14",
# 'is_protected': not checked
}
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.add_checkout']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.add_checkout"])}
def test_get_ok(self):
r = self.client.get(self.url)
@@ -710,20 +677,23 @@ class CheckoutCreateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- checkout = Checkout.objects.get(name='Checkout')
+ checkout = Checkout.objects.get(name="Checkout")
self.assertRedirects(r, checkout.get_absolute_url())
- self.assertInstanceExpected(checkout, {
- 'name': 'Checkout',
- 'valid_from': timezone.make_aware(datetime(2017, 10, 8, 17, 45)),
- 'valid_to': timezone.make_aware(datetime(2017, 11, 8, 16, 00)),
- 'balance': Decimal('3.14'),
- 'is_protected': False,
- })
+ self.assertInstanceExpected(
+ checkout,
+ {
+ "name": "Checkout",
+ "valid_from": timezone.make_aware(datetime(2017, 10, 8, 17, 45)),
+ "valid_to": timezone.make_aware(datetime(2017, 11, 8, 16, 00)),
+ "balance": Decimal("3.14"),
+ "is_protected": False,
+ },
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -731,28 +701,29 @@ class CheckoutCreateViewTests(ViewTestCaseMixin, TestCase):
class CheckoutReadViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkout.read'
+ url_name = "kfet.checkout.read"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.checkout.pk}
+ return {"pk": self.checkout.pk}
@property
def url_expected(self):
- return '/k-fet/checkouts/{}'.format(self.checkout.pk)
+ return "/k-fet/checkouts/{}".format(self.checkout.pk)
def setUp(self):
super().setUp()
- with mock.patch('django.utils.timezone.now') as mock_now:
+ with mock.patch("django.utils.timezone.now") as mock_now:
mock_now.return_value = self.now
self.checkout = Checkout.objects.create(
- name='Checkout', balance=Decimal('10'),
- created_by=self.accounts['team'],
+ name="Checkout",
+ balance=Decimal("10"),
+ created_by=self.accounts["team"],
valid_from=self.now,
valid_to=self.now + timedelta(days=1),
)
@@ -760,47 +731,43 @@ class CheckoutReadViewTests(ViewTestCaseMixin, TestCase):
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertEqual(r.context['checkout'], self.checkout)
+ self.assertEqual(r.context["checkout"], self.checkout)
class CheckoutUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkout.update'
+ url_name = "kfet.checkout.update"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
post_data = {
- 'name': 'Checkout updated',
- 'valid_from': '2018-01-01 08:00:00',
- 'valid_to': '2018-07-01 16:00:00',
+ "name": "Checkout updated",
+ "valid_from": "2018-01-01 08:00:00",
+ "valid_to": "2018-07-01 16:00:00",
}
@property
def url_kwargs(self):
- return {'pk': self.checkout.pk}
+ return {"pk": self.checkout.pk}
@property
def url_expected(self):
- return '/k-fet/checkouts/{}/edit'.format(self.checkout.pk)
+ return "/k-fet/checkouts/{}/edit".format(self.checkout.pk)
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_checkout',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.change_checkout"])}
def setUp(self):
super().setUp()
self.checkout = Checkout.objects.create(
- name='Checkout',
+ name="Checkout",
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
- balance=Decimal('3.14'),
+ balance=Decimal("3.14"),
is_protected=False,
- created_by=self.accounts['team'],
+ created_by=self.accounts["team"],
)
def test_get_ok(self):
@@ -809,18 +776,21 @@ class CheckoutUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
self.assertRedirects(r, self.checkout.get_absolute_url())
self.checkout.refresh_from_db()
- self.assertInstanceExpected(self.checkout, {
- 'name': 'Checkout updated',
- 'valid_from': timezone.make_aware(datetime(2018, 1, 1, 8, 0, 0)),
- 'valid_to': timezone.make_aware(datetime(2018, 7, 1, 16, 0, 0)),
- })
+ self.assertInstanceExpected(
+ self.checkout,
+ {
+ "name": "Checkout updated",
+ "valid_from": timezone.make_aware(datetime(2018, 1, 1, 8, 0, 0)),
+ "valid_to": timezone.make_aware(datetime(2018, 7, 1, 16, 0, 0)),
+ },
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -828,29 +798,29 @@ class CheckoutUpdateViewTests(ViewTestCaseMixin, TestCase):
class CheckoutStatementListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkoutstatement'
- url_expected = '/k-fet/checkouts/statements/'
+ url_name = "kfet.checkoutstatement"
+ url_expected = "/k-fet/checkouts/statements/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
self.checkout1 = Checkout.objects.create(
- created_by=self.accounts['team'],
- name='Checkout 1',
+ created_by=self.accounts["team"],
+ name="Checkout 1",
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
)
self.checkout2 = Checkout.objects.create(
- created_by=self.accounts['team'],
- name='Checkout 2',
+ created_by=self.accounts["team"],
+ name="Checkout 2",
valid_from=self.now + timedelta(days=10),
valid_to=self.now + timedelta(days=15),
)
self.statement1 = CheckoutStatement.objects.create(
checkout=self.checkout1,
- by=self.accounts['team'],
+ by=self.accounts["team"],
balance_old=5,
balance_new=0,
amount_taken=5,
@@ -860,63 +830,80 @@ class CheckoutStatementListViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- expected_statements = (
- list(self.checkout1.statements.all()) +
- list(self.checkout2.statements.all())
+ expected_statements = list(self.checkout1.statements.all()) + list(
+ self.checkout2.statements.all()
)
self.assertQuerysetEqual(
- r.context['checkoutstatements'],
+ r.context["checkoutstatements"],
map(repr, expected_statements),
ordered=False,
)
class CheckoutStatementCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkoutstatement.create'
+ url_name = "kfet.checkoutstatement.create"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
post_data = {
# Let
- 'balance_001': 0, 'balance_002': 0, 'balance_005': 0,
- 'balance_01': 0, 'balance_02': 0, 'balance_05': 0,
- 'balance_1': 1, 'balance_2': 0, 'balance_5': 0,
- 'balance_10': 1, 'balance_20': 0, 'balance_50': 0,
- 'balance_100': 1, 'balance_200': 0, 'balance_500': 0,
+ "balance_001": 0,
+ "balance_002": 0,
+ "balance_005": 0,
+ "balance_01": 0,
+ "balance_02": 0,
+ "balance_05": 0,
+ "balance_1": 1,
+ "balance_2": 0,
+ "balance_5": 0,
+ "balance_10": 1,
+ "balance_20": 0,
+ "balance_50": 0,
+ "balance_100": 1,
+ "balance_200": 0,
+ "balance_500": 0,
# Taken
- 'taken_001': 0, 'taken_002': 0, 'taken_005': 0,
- 'taken_01': 0, 'taken_02': 0, 'taken_05': 0,
- 'taken_1': 2, 'taken_2': 0, 'taken_5': 0,
- 'taken_10': 2, 'taken_20': 0, 'taken_50': 0,
- 'taken_100': 2, 'taken_200': 0, 'taken_500': 0,
- 'taken_cheque': 0,
+ "taken_001": 0,
+ "taken_002": 0,
+ "taken_005": 0,
+ "taken_01": 0,
+ "taken_02": 0,
+ "taken_05": 0,
+ "taken_1": 2,
+ "taken_2": 0,
+ "taken_5": 0,
+ "taken_10": 2,
+ "taken_20": 0,
+ "taken_50": 0,
+ "taken_100": 2,
+ "taken_200": 0,
+ "taken_500": 0,
+ "taken_cheque": 0,
# 'not_count': not checked
}
@property
def url_kwargs(self):
- return {'pk_checkout': self.checkout.pk}
+ return {"pk_checkout": self.checkout.pk}
@property
def url_expected(self):
- return '/k-fet/checkouts/{}/statements/add'.format(self.checkout.pk)
+ return "/k-fet/checkouts/{}/statements/add".format(self.checkout.pk)
def get_users_extra(self):
return {
- 'team1': create_team('team1', '001', perms=[
- 'kfet.add_checkoutstatement',
- ]),
+ "team1": create_team("team1", "001", perms=["kfet.add_checkoutstatement"])
}
def setUp(self):
super().setUp()
self.checkout = Checkout.objects.create(
- name='Checkout',
- created_by=self.accounts['team'],
+ name="Checkout",
+ created_by=self.accounts["team"],
balance=5,
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
@@ -926,29 +913,32 @@ class CheckoutStatementCreateViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- @mock.patch('django.utils.timezone.now')
+ @mock.patch("django.utils.timezone.now")
def test_post_ok(self, mock_now):
self.now += timedelta(days=2)
mock_now.return_value = self.now
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
self.assertRedirects(r, self.checkout.get_absolute_url())
statement = CheckoutStatement.objects.get(at=self.now)
- self.assertInstanceExpected(statement, {
- 'by': self.accounts['team1'],
- 'checkout': self.checkout,
- 'balance_old': Decimal('5'),
- 'balance_new': Decimal('111'),
- 'amount_taken': Decimal('222'),
- 'amount_error': Decimal('328'),
- 'at': self.now,
- 'not_count': False,
- })
+ self.assertInstanceExpected(
+ statement,
+ {
+ "by": self.accounts["team1"],
+ "checkout": self.checkout,
+ "balance_old": Decimal("5"),
+ "balance_new": Decimal("111"),
+ "amount_taken": Decimal("222"),
+ "amount_error": Decimal("328"),
+ "at": self.now,
+ "not_count": False,
+ },
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -956,59 +946,65 @@ class CheckoutStatementCreateViewTests(ViewTestCaseMixin, TestCase):
class CheckoutStatementUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.checkoutstatement.update'
+ url_name = "kfet.checkoutstatement.update"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
post_data = {
- 'amount_taken': 3,
- 'amount_error': 2,
- 'balance_old': 8,
- 'balance_new': 5,
+ "amount_taken": 3,
+ "amount_error": 2,
+ "balance_old": 8,
+ "balance_new": 5,
# Taken
- 'taken_001': 0, 'taken_002': 0, 'taken_005': 0,
- 'taken_01': 0, 'taken_02': 0, 'taken_05': 0,
- 'taken_1': 1, 'taken_2': 1, 'taken_5': 0,
- 'taken_10': 0, 'taken_20': 0, 'taken_50': 0,
- 'taken_100': 0, 'taken_200': 0, 'taken_500': 0,
- 'taken_cheque': 0,
+ "taken_001": 0,
+ "taken_002": 0,
+ "taken_005": 0,
+ "taken_01": 0,
+ "taken_02": 0,
+ "taken_05": 0,
+ "taken_1": 1,
+ "taken_2": 1,
+ "taken_5": 0,
+ "taken_10": 0,
+ "taken_20": 0,
+ "taken_50": 0,
+ "taken_100": 0,
+ "taken_200": 0,
+ "taken_500": 0,
+ "taken_cheque": 0,
}
@property
def url_kwargs(self):
- return {
- 'pk_checkout': self.checkout.pk,
- 'pk': self.statement.pk,
- }
+ return {"pk_checkout": self.checkout.pk, "pk": self.statement.pk}
@property
def url_expected(self):
- return '/k-fet/checkouts/{pk_checkout}/statements/{pk}/edit'.format(
- pk_checkout=self.checkout.pk,
- pk=self.statement.pk,
+ return "/k-fet/checkouts/{pk_checkout}/statements/{pk}/edit".format(
+ pk_checkout=self.checkout.pk, pk=self.statement.pk
)
def get_users_extra(self):
return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_checkoutstatement',
- ]),
+ "team1": create_team(
+ "team1", "101", perms=["kfet.change_checkoutstatement"]
+ )
}
def setUp(self):
super().setUp()
self.checkout = Checkout.objects.create(
- name='Checkout',
- created_by=self.accounts['team'],
+ name="Checkout",
+ created_by=self.accounts["team"],
balance=5,
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
)
self.statement = CheckoutStatement.objects.create(
- by=self.accounts['team'],
+ by=self.accounts["team"],
checkout=self.checkout,
balance_new=5,
balance_old=8,
@@ -1020,27 +1016,30 @@ class CheckoutStatementUpdateViewTests(ViewTestCaseMixin, TestCase):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- @mock.patch('django.utils.timezone.now')
+ @mock.patch("django.utils.timezone.now")
def test_post_ok(self, mock_now):
self.now += timedelta(days=2)
mock_now.return_value = self.now
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
self.assertRedirects(r, self.checkout.get_absolute_url())
self.statement.refresh_from_db()
- self.assertInstanceExpected(self.statement, {
- 'taken_1': 1,
- 'taken_2': 1,
- 'balance_new': 5,
- 'balance_old': 8,
- 'amount_error': 0,
- 'amount_taken': 3,
- })
+ self.assertInstanceExpected(
+ self.statement,
+ {
+ "taken_1": 1,
+ "taken_2": 1,
+ "balance_new": 5,
+ "balance_old": 8,
+ "amount_error": 0,
+ "amount_taken": 3,
+ },
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -1048,60 +1047,57 @@ class CheckoutStatementUpdateViewTests(ViewTestCaseMixin, TestCase):
class ArticleCategoryListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.category'
- url_expected = '/k-fet/categories/'
+ url_name = "kfet.category"
+ url_expected = "/k-fet/categories/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
- self.category1 = ArticleCategory.objects.create(name='Category 1')
- self.category2 = ArticleCategory.objects.create(name='Category 2')
+ self.category1 = ArticleCategory.objects.create(name="Category 1")
+ self.category2 = ArticleCategory.objects.create(name="Category 2")
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['categories'],
- map(repr, [self.category1, self.category2]),
+ r.context["categories"], map(repr, [self.category1, self.category2])
)
class ArticleCategoryUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.category.update'
+ url_name = "kfet.category.update"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.category.pk}
+ return {"pk": self.category.pk}
@property
def url_expected(self):
- return '/k-fet/categories/{}/edit'.format(self.category.pk)
+ return "/k-fet/categories/{}/edit".format(self.category.pk)
def get_users_extra(self):
return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_articlecategory',
- ]),
+ "team1": create_team("team1", "101", perms=["kfet.change_articlecategory"])
}
@property
def post_data(self):
return {
- 'name': 'The Category',
+ "name": "The Category",
# 'has_addcost': not checked
}
def setUp(self):
super().setUp()
- self.category = ArticleCategory.objects.create(name='Category')
+ self.category = ArticleCategory.objects.create(name="Category")
def test_get_ok(self):
r = self.client.get(self.url)
@@ -1109,17 +1105,16 @@ class ArticleCategoryUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.category'))
+ self.assertRedirects(r, reverse("kfet.category"))
self.category.refresh_from_db()
- self.assertInstanceExpected(self.category, {
- 'name': 'The Category',
- 'has_addcost': False,
- })
+ self.assertInstanceExpected(
+ self.category, {"name": "The Category", "has_addcost": False}
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -1127,59 +1122,50 @@ class ArticleCategoryUpdateViewTests(ViewTestCaseMixin, TestCase):
class ArticleListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.article'
- url_expected = '/k-fet/articles/'
+ url_name = "kfet.article"
+ url_expected = "/k-fet/articles/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Category')
- self.article1 = Article.objects.create(
- name='Article 1',
- category=category,
- )
- self.article2 = Article.objects.create(
- name='Article 2',
- category=category,
- )
+ category = ArticleCategory.objects.create(name="Category")
+ self.article1 = Article.objects.create(name="Article 1", category=category)
+ self.article2 = Article.objects.create(name="Article 2", category=category)
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
- r.context['articles'],
- map(repr, [self.article1, self.article2]),
+ r.context["articles"], map(repr, [self.article1, self.article2])
)
class ArticleCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.article.create'
- url_expected = '/k-fet/articles/new'
+ url_name = "kfet.article.create"
+ url_expected = "/k-fet/articles/new"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.add_article']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.add_article"])}
@property
def post_data(self):
return {
- 'name': 'Article',
- 'category': self.category.pk,
- 'stock': 5,
- 'price': '2.5',
+ "name": "Article",
+ "category": self.category.pk,
+ "stock": 5,
+ "price": "2.5",
}
def setUp(self):
super().setUp()
- self.category = ArticleCategory.objects.create(name='Category')
+ self.category = ArticleCategory.objects.create(name="Category")
def test_get_ok(self):
r = self.client.get(self.url)
@@ -1187,18 +1173,17 @@ class ArticleCreateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- article = Article.objects.get(name='Article')
+ article = Article.objects.get(name="Article")
self.assertRedirects(r, article.get_absolute_url())
- self.assertInstanceExpected(article, {
- 'name': 'Article',
- 'category': self.category,
- })
+ self.assertInstanceExpected(
+ article, {"name": "Article", "category": self.category}
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -1206,76 +1191,69 @@ class ArticleCreateViewTests(ViewTestCaseMixin, TestCase):
class ArticleReadViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.article.read'
+ url_name = "kfet.article.read"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.article.pk}
+ return {"pk": self.article.pk}
@property
def url_expected(self):
- return '/k-fet/articles/{}'.format(self.article.pk)
+ return "/k-fet/articles/{}".format(self.article.pk)
def setUp(self):
super().setUp()
self.article = Article.objects.create(
- name='Article',
- category=ArticleCategory.objects.create(name='Category'),
+ name="Article",
+ category=ArticleCategory.objects.create(name="Category"),
stock=5,
- price=Decimal('2.5'),
+ price=Decimal("2.5"),
)
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- self.assertEqual(r.context['article'], self.article)
+ self.assertEqual(r.context["article"], self.article)
class ArticleUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.article.update'
+ url_name = "kfet.article.update"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.article.pk}
+ return {"pk": self.article.pk}
@property
def url_expected(self):
- return '/k-fet/articles/{}/edit'.format(self.article.pk)
+ return "/k-fet/articles/{}/edit".format(self.article.pk)
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_article',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.change_article"])}
@property
def post_data(self):
return {
- 'name': 'The Article',
- 'category': self.article.category.pk,
- 'is_sold': '1',
- 'price': '3.5',
- 'box_type': 'carton',
+ "name": "The Article",
+ "category": self.article.category.pk,
+ "is_sold": "1",
+ "price": "3.5",
+ "box_type": "carton",
# 'hidden': not checked
}
def setUp(self):
super().setUp()
- self.category = ArticleCategory.objects.create(name='Category')
+ self.category = ArticleCategory.objects.create(name="Category")
self.article = Article.objects.create(
- name='Article',
- category=self.category,
- stock=5,
- price=Decimal('2.5'),
+ name="Article", category=self.category, stock=5, price=Decimal("2.5")
)
def test_get_ok(self):
@@ -1284,7 +1262,7 @@ class ArticleUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
@@ -1292,10 +1270,9 @@ class ArticleUpdateViewTests(ViewTestCaseMixin, TestCase):
self.article.refresh_from_db()
- self.assertInstanceExpected(self.article, {
- 'name': 'The Article',
- 'price': Decimal('3.5'),
- })
+ self.assertInstanceExpected(
+ self.article, {"name": "The Article", "price": Decimal("3.5")}
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -1303,95 +1280,93 @@ class ArticleUpdateViewTests(ViewTestCaseMixin, TestCase):
class ArticleStatSalesListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.article.stat.sales.list'
+ url_name = "kfet.article.stat.sales.list"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.article.pk}
+ return {"pk": self.article.pk}
@property
def url_expected(self):
- return '/k-fet/articles/{}/stat/sales/list'.format(self.article.pk)
+ return "/k-fet/articles/{}/stat/sales/list".format(self.article.pk)
def setUp(self):
super().setUp()
self.article = Article.objects.create(
- name='Article',
- category=ArticleCategory.objects.create(name='Category'),
+ name="Article", category=ArticleCategory.objects.create(name="Category")
)
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- content = json.loads(r.content.decode('utf-8'))
+ content = json.loads(r.content.decode("utf-8"))
- base_url = reverse('kfet.article.stat.sales', args=[self.article.pk])
+ base_url = reverse("kfet.article.stat.sales", args=[self.article.pk])
expected_stats = [
{
- 'label': 'Derniers mois',
- 'url': {
- 'path': base_url,
- 'query': {
- 'scale_n_steps': ['7'],
- 'scale_name': ['month'],
- 'scale_last': ['True'],
+ "label": "Derniers mois",
+ "url": {
+ "path": base_url,
+ "query": {
+ "scale_n_steps": ["7"],
+ "scale_name": ["month"],
+ "scale_last": ["True"],
},
},
},
{
- 'label': 'Dernières semaines',
- 'url': {
- 'path': base_url,
- 'query': {
- 'scale_n_steps': ['7'],
- 'scale_name': ['week'],
- 'scale_last': ['True'],
+ "label": "Dernières semaines",
+ "url": {
+ "path": base_url,
+ "query": {
+ "scale_n_steps": ["7"],
+ "scale_name": ["week"],
+ "scale_last": ["True"],
},
},
},
{
- 'label': 'Derniers jours',
- 'url': {
- 'path': base_url,
- 'query': {
- 'scale_n_steps': ['7'],
- 'scale_name': ['day'],
- 'scale_last': ['True'],
+ "label": "Derniers jours",
+ "url": {
+ "path": base_url,
+ "query": {
+ "scale_n_steps": ["7"],
+ "scale_name": ["day"],
+ "scale_last": ["True"],
},
},
},
]
- for stat, expected in zip(content['stats'], expected_stats):
- expected_url = expected.pop('url')
- self.assertUrlsEqual(stat['url'], expected_url)
+ for stat, expected in zip(content["stats"], expected_stats):
+ expected_url = expected.pop("url")
+ self.assertUrlsEqual(stat["url"], expected_url)
self.assertDictContainsSubset(expected, stat)
class ArticleStatSalesViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.article.stat.sales'
+ url_name = "kfet.article.stat.sales"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.article.pk}
+ return {"pk": self.article.pk}
@property
def url_expected(self):
- return '/k-fet/articles/{}/stat/sales'.format(self.article.pk)
+ return "/k-fet/articles/{}/stat/sales".format(self.article.pk)
def setUp(self):
super().setUp()
self.article = Article.objects.create(
- name='Article',
- category=ArticleCategory.objects.create(name='Category'),
+ name="Article", category=ArticleCategory.objects.create(name="Category")
)
def test_ok(self):
@@ -1400,11 +1375,11 @@ class ArticleStatSalesViewTests(ViewTestCaseMixin, TestCase):
class KPsulViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul'
- url_expected = '/k-fet/k-psul/'
+ url_name = "kfet.kpsul"
+ url_expected = "/k-fet/k-psul/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
r = self.client.get(self.url)
@@ -1412,150 +1387,1652 @@ class KPsulViewTests(ViewTestCaseMixin, TestCase):
class KPsulCheckoutDataViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul.checkout_data'
- url_expected = '/k-fet/k-psul/checkout_data'
+ url_name = "kfet.kpsul.checkout_data"
+ url_expected = "/k-fet/k-psul/checkout_data"
- http_methods = ['POST']
+ http_methods = ["POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
self.checkout = Checkout.objects.create(
- name='Checkout',
- balance=Decimal('10'),
- created_by=self.accounts['team'],
+ name="Checkout",
+ balance=Decimal("10"),
+ created_by=self.accounts["team"],
valid_from=self.now,
valid_to=self.now + timedelta(days=5),
)
def test_ok(self):
- r = self.client.post(self.url, {'pk': self.checkout.pk})
+ r = self.client.post(self.url, {"pk": self.checkout.pk})
self.assertEqual(r.status_code, 200)
- content = json.loads(r.content.decode('utf-8'))
+ content = json.loads(r.content.decode("utf-8"))
- expected = {
- 'name': 'Checkout',
- 'balance': '10.00',
- }
+ expected = {"name": "Checkout", "balance": "10.00"}
self.assertDictContainsSubset(expected, content)
- self.assertSetEqual(set(content.keys()), set([
- 'balance', 'id', 'name', 'valid_from', 'valid_to',
- 'last_statement_at', 'last_statement_balance',
- 'last_statement_by_first_name', 'last_statement_by_last_name',
- 'last_statement_by_trigramme',
- ]))
+ self.assertSetEqual(
+ set(content.keys()),
+ set(
+ [
+ "balance",
+ "id",
+ "name",
+ "valid_from",
+ "valid_to",
+ "last_statement_at",
+ "last_statement_balance",
+ "last_statement_by_first_name",
+ "last_statement_by_last_name",
+ "last_statement_by_trigramme",
+ ]
+ ),
+ )
class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul.perform_operations'
- url_expected = '/k-fet/k-psul/perform_operations'
+ """
+ Test cases for kpsul_perform_operations view.
- http_methods = ['POST']
+ Below is the test ordering, try to keep this organized ;-)
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ * OperationGroup:
+ - test_group...
+ - test_invalid_group...
+ * Operation:
+ - test_purchase...
+ - test_invalid_purchase...
+ - test_deposit...
+ - test_invalid_deposit...
+ - test_withdraw...
+ - test_invalid_withdraw...
+ - test_edit...
+ - test_invalid_edit...
+ * Addcost:
+ - test_addcost...
+ * Negative:
+ - test_negative...
+ - test_invalid_negative...
+ * More concrete examples:
+ - test_multi...
- def test_ok(self):
- pass
+ To test valid requests, one should use '_assertResponseOk(response)' to get
+ hints about failure reasons, if any.
+
+ At least one test per operation type should test the complete response and
+ behavior (HTTP, WebSocket, object updates, and object creations)
+ Other tests of the same operation type can only assert the specific
+ behavior differences.
+
+ For invalid requests, response errors should be tested.
+
+ """
+
+ url_name = "kfet.kpsul.perform_operations"
+ url_expected = "/k-fet/k-psul/perform_operations"
+
+ http_methods = ["POST"]
+
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
+
+ with_liq = True
+
+ def setUp(self):
+ super(KPsulPerformOperationsViewTests, self).setUp()
+
+ # A Checkout, curently usable, balance=100
+ self.checkout = Checkout.objects.create(
+ created_by=self.accounts["team"],
+ name="Checkout",
+ valid_from=timezone.now() - timedelta(days=7),
+ valid_to=timezone.now() + timedelta(days=7),
+ balance=Decimal("100.00"),
+ )
+ # An Article, price=2.5, stock=20
+ self.article = Article.objects.create(
+ category=ArticleCategory.objects.create(name="Category"),
+ name="Article",
+ price=Decimal("2.5"),
+ stock=20,
+ )
+ # An Account, trigramme=000, balance=50
+ # Do not assume user is cof, nor not cof.
+ self.account = self.accounts["user"]
+ self.account.balance = Decimal("50.00")
+ self.account.save()
+
+ # Mock consumer of K-Psul websocket to catch what we're sending
+ kpsul_consumer_patcher = mock.patch("kfet.consumers.KPsul")
+ self.kpsul_consumer_mock = kpsul_consumer_patcher.start()
+ self.addCleanup(kpsul_consumer_patcher.stop)
+
+ # Reset cache of kfet config
+ kfet_config._conf_init = False
+
+ def _assertResponseOk(self, response):
+ """
+ Asserts that status code of 'response' is 200, and returns the
+ deserialized content of the JSONResponse.
+
+ In case status code is not 200, it prints the content of "errors" of
+ the response.
+
+ """
+ json_data = json.loads(getattr(response, "content", b"{}").decode("utf-8"))
+ try:
+ self.assertEqual(response.status_code, 200)
+ except AssertionError as exc:
+ msg = "Expected response is 200, got {}. Errors: {}".format(
+ response.status_code, json_data.get("errors")
+ )
+ raise AssertionError(msg) from exc
+ return json_data
+
+ def get_base_post_data(self):
+ return {
+ # OperationGroup form
+ "on_acc": str(self.account.pk),
+ "checkout": str(self.checkout.pk),
+ # Operation formset
+ "form-TOTAL_FORMS": "0",
+ "form-INITIAL_FORMS": "0",
+ "form-MIN_NUM_FORMS": "1",
+ "form-MAX_NUM_FORMS": "1000",
+ }
+
+ base_post_data = property(get_base_post_data)
+
+ def test_invalid_group_on_acc(self):
+ data = dict(self.base_post_data, **{"on_acc": "GNR"})
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["operation_group"], ["on_acc"])
+
+ def test_group_on_acc_expects_comment(self):
+ user_add_perms(self.users["team"], ["kfet.perform_commented_operations"])
+ self.account.trigramme = "#13"
+ self.account.save()
+ self.assertTrue(self.account.need_comment)
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "comment": "A comment to explain it",
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ def test_invalid_group_on_acc_expects_comment(self):
+ user_add_perms(self.users["team"], ["kfet.perform_commented_operations"])
+ self.account.trigramme = "#13"
+ self.account.save()
+ self.assertTrue(self.account.need_comment)
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["need_comment"], True)
+
+ def test_invalid_group_on_acc_needs_comment_requires_perm(self):
+ self.account.trigramme = "#13"
+ self.account.save()
+ self.assertTrue(self.account.need_comment)
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "comment": "A comment to explain it",
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["missing_perms"],
+ ["Enregistrer des commandes avec commentaires"],
+ )
+
+ def test_group_on_acc_frozen(self):
+ user_add_perms(self.users["team"], ["kfet.override_frozen_protection"])
+ self.account.is_frozen = True
+ self.account.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "comment": "A comment to explain it",
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ def test_invalid_group_on_acc_frozen_requires_perm(self):
+ self.account.is_frozen = True
+ self.account.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "comment": "A comment to explain it",
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["missing_perms"], ["Forcer le gel d'un compte"]
+ )
+
+ def test_invalid_group_checkout(self):
+ self.checkout.valid_from -= timedelta(days=300)
+ self.checkout.valid_to -= timedelta(days=300)
+ self.checkout.save()
+
+ data = dict(self.base_post_data)
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["operation_group"], ["checkout"])
+
+ def test_invalid_group_expects_one_operation(self):
+ data = dict(self.base_post_data)
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["operations"], [])
+
+ def test_purchase_with_user_is_nof_cof(self):
+ self.account.cofprofile.is_cof = False
+ self.account.cofprofile.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ # Check response status
+ json_data = self._assertResponseOk(resp)
+
+ # Check object creations
+ operation_group = OperationGroup.objects.get()
+ self.assertDictEqual(
+ operation_group.__dict__,
+ {
+ "_state": mock.ANY,
+ "at": mock.ANY,
+ "amount": Decimal("-5.00"),
+ "checkout_id": self.checkout.pk,
+ "comment": "",
+ "id": mock.ANY,
+ "is_cof": False,
+ "on_acc_id": self.account.pk,
+ "valid_by_id": None,
+ },
+ )
+ operation = Operation.objects.get()
+ self.assertDictEqual(
+ operation.__dict__,
+ {
+ "_state": mock.ANY,
+ "addcost_amount": None,
+ "addcost_for_id": None,
+ "amount": Decimal("-5.00"),
+ "article_id": self.article.pk,
+ "article_nb": 2,
+ "canceled_at": None,
+ "canceled_by_id": None,
+ "group_id": operation_group.pk,
+ "id": mock.ANY,
+ "type": "purchase",
+ },
+ )
+
+ # Check response content
+ self.assertDictEqual(
+ json_data,
+ {
+ "operationgroup": operation_group.pk,
+ "operations": [operation.pk],
+ "warnings": {},
+ "errors": {},
+ },
+ )
+
+ # Check object updates
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("45.00"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("100.00"))
+ self.article.refresh_from_db()
+ self.assertEqual(self.article.stock, 18)
+
+ # Check websocket data
+ self.kpsul_consumer_mock.group_send.assert_called_once_with(
+ "kfet.kpsul",
+ {
+ "opegroups": [
+ {
+ "add": True,
+ "at": mock.ANY,
+ "amount": Decimal("-5.00"),
+ "checkout__name": "Checkout",
+ "comment": "",
+ "id": operation_group.pk,
+ "is_cof": False,
+ "on_acc__trigramme": "000",
+ "valid_by__trigramme": None,
+ "opes": [
+ {
+ "id": operation.pk,
+ "addcost_amount": None,
+ "addcost_for__trigramme": None,
+ "amount": Decimal("-5.00"),
+ "article__name": "Article",
+ "article_nb": 2,
+ "canceled_at": None,
+ "canceled_by__trigramme": None,
+ "group_id": operation_group.pk,
+ "type": "purchase",
+ }
+ ],
+ }
+ ],
+ "checkouts": [{"id": self.checkout.pk, "balance": Decimal("100.00")}],
+ "articles": [{"id": self.article.pk, "stock": 18}],
+ },
+ )
+
+ def test_purchase_with_user_is_cof(self):
+ kfet_config.set(kfet_reduction_cof=Decimal("20"))
+ self.account.cofprofile.is_cof = True
+ self.account.cofprofile.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.amount, Decimal("-4.00"))
+ self.assertEqual(operation_group.is_cof, True)
+ operation = Operation.objects.get()
+ self.assertEqual(operation.amount, Decimal("-4.00"))
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("46.00"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("100.00"))
+ self.article.refresh_from_db()
+ self.assertEqual(self.article.stock, 18)
+
+ def test_purchase_with_cash(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "on_acc": str(self.accounts["liq"].pk),
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.on_acc, self.accounts["liq"])
+ self.assertEqual(operation_group.is_cof, False)
+
+ self.accounts["liq"].refresh_from_db()
+ self.assertEqual(self.accounts["liq"].balance, 0)
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("105.00"))
+ self.article.refresh_from_db()
+ self.assertEqual(self.article.stock, 18)
+
+ def test_invalid_purchase_expects_article(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": "",
+ "form-0-article_nb": "1",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"],
+ [{"__all__": ["Un achat nécessite un article et une quantité"]}],
+ )
+
+ def test_invalid_purchase_expects_article_nb(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"],
+ [{"__all__": ["Un achat nécessite un article et une quantité"]}],
+ )
+
+ def test_invalid_purchase_expects_article_nb_greater_than_1(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "-1",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"],
+ [
+ {
+ "__all__": ["Un achat nécessite un article et une quantité"],
+ "article_nb": [
+ "Assurez-vous que cette valeur est supérieure ou " "égale à 1."
+ ],
+ }
+ ],
+ )
+
+ def test_invalid_operation_not_purchase_with_cash(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "on_acc": str(self.accounts["liq"].pk),
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "deposit",
+ "form-0-amount": "10.00",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["account"], "LIQ")
+
+ def test_deposit(self):
+ user_add_perms(self.users["team"], ["kfet.perform_deposit"])
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "deposit",
+ "form-0-amount": "10.75",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ json_data = self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertDictEqual(
+ operation_group.__dict__,
+ {
+ "_state": mock.ANY,
+ "at": mock.ANY,
+ "amount": Decimal("10.75"),
+ "checkout_id": self.checkout.pk,
+ "comment": "",
+ "id": mock.ANY,
+ "is_cof": False,
+ "on_acc_id": self.account.pk,
+ "valid_by_id": self.accounts["team"].pk,
+ },
+ )
+ operation = Operation.objects.get()
+ self.assertDictEqual(
+ operation.__dict__,
+ {
+ "_state": mock.ANY,
+ "addcost_amount": None,
+ "addcost_for_id": None,
+ "amount": Decimal("10.75"),
+ "article_id": None,
+ "article_nb": None,
+ "canceled_at": None,
+ "canceled_by_id": None,
+ "group_id": operation_group.pk,
+ "id": mock.ANY,
+ "type": "deposit",
+ },
+ )
+
+ self.assertDictEqual(
+ json_data,
+ {
+ "operationgroup": operation_group.pk,
+ "operations": [operation.pk],
+ "warnings": {},
+ "errors": {},
+ },
+ )
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("60.75"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("110.75"))
+
+ self.kpsul_consumer_mock.group_send.assert_called_once_with(
+ "kfet.kpsul",
+ {
+ "opegroups": [
+ {
+ "add": True,
+ "at": mock.ANY,
+ "amount": Decimal("10.75"),
+ "checkout__name": "Checkout",
+ "comment": "",
+ "id": operation_group.pk,
+ "is_cof": False,
+ "on_acc__trigramme": "000",
+ "valid_by__trigramme": "100",
+ "opes": [
+ {
+ "id": operation.pk,
+ "addcost_amount": None,
+ "addcost_for__trigramme": None,
+ "amount": Decimal("10.75"),
+ "article__name": None,
+ "article_nb": None,
+ "canceled_at": None,
+ "canceled_by__trigramme": None,
+ "group_id": operation_group.pk,
+ "type": "deposit",
+ }
+ ],
+ }
+ ],
+ "checkouts": [{"id": self.checkout.pk, "balance": Decimal("110.75")}],
+ "articles": [],
+ },
+ )
+
+ def test_invalid_deposit_expects_amount(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "deposit",
+ "form-0-amount": "",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ )
+
+ def test_invalid_deposit_too_many_params(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "deposit",
+ "form-0-amount": "10",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "3",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ )
+
+ def test_invalid_deposit_expects_positive_amount(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "deposit",
+ "form-0-amount": "-10",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"], [{"__all__": ["Charge non positive"]}]
+ )
+
+ def test_invalid_deposit_requires_perm(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "deposit",
+ "form-0-amount": "10.75",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["missing_perms"], ["Effectuer une charge"])
+
+ def test_withdraw(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "withdraw",
+ "form-0-amount": "-10.75",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ json_data = self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertDictEqual(
+ operation_group.__dict__,
+ {
+ "_state": mock.ANY,
+ "at": mock.ANY,
+ "amount": Decimal("-10.75"),
+ "checkout_id": self.checkout.pk,
+ "comment": "",
+ "id": mock.ANY,
+ "is_cof": False,
+ "on_acc_id": self.account.pk,
+ "valid_by_id": None,
+ },
+ )
+ operation = Operation.objects.get()
+ self.assertDictEqual(
+ operation.__dict__,
+ {
+ "_state": mock.ANY,
+ "addcost_amount": None,
+ "addcost_for_id": None,
+ "amount": Decimal("-10.75"),
+ "article_id": None,
+ "article_nb": None,
+ "canceled_at": None,
+ "canceled_by_id": None,
+ "group_id": operation_group.pk,
+ "id": mock.ANY,
+ "type": "withdraw",
+ },
+ )
+
+ self.assertDictEqual(
+ json_data,
+ {
+ "operationgroup": operation_group.pk,
+ "operations": [operation.pk],
+ "warnings": {},
+ "errors": {},
+ },
+ )
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("39.25"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("89.25"))
+
+ self.kpsul_consumer_mock.group_send.assert_called_once_with(
+ "kfet.kpsul",
+ {
+ "opegroups": [
+ {
+ "add": True,
+ "at": mock.ANY,
+ "amount": Decimal("-10.75"),
+ "checkout__name": "Checkout",
+ "comment": "",
+ "id": operation_group.pk,
+ "is_cof": False,
+ "on_acc__trigramme": "000",
+ "valid_by__trigramme": None,
+ "opes": [
+ {
+ "id": operation.pk,
+ "addcost_amount": None,
+ "addcost_for__trigramme": None,
+ "amount": Decimal("-10.75"),
+ "article__name": None,
+ "article_nb": None,
+ "canceled_at": None,
+ "canceled_by__trigramme": None,
+ "group_id": operation_group.pk,
+ "type": "withdraw",
+ }
+ ],
+ }
+ ],
+ "checkouts": [{"id": self.checkout.pk, "balance": Decimal("89.25")}],
+ "articles": [],
+ },
+ )
+
+ def test_invalid_withdraw_expects_amount(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "withdraw",
+ "form-0-amount": "",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ )
+
+ def test_invalid_withdraw_too_many_params(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "withdraw",
+ "form-0-amount": "-10",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "3",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ )
+
+ def test_invalid_withdraw_expects_negative_amount(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "withdraw",
+ "form-0-amount": "10",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["operations"], [{"__all__": ["Retrait non négatif"]}]
+ )
+
+ def test_edit(self):
+ user_add_perms(self.users["team"], ["kfet.edit_balance_account"])
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "comment": "A comment to explain it",
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "edit",
+ "form-0-amount": "10.75",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ json_data = self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertDictEqual(
+ operation_group.__dict__,
+ {
+ "_state": mock.ANY,
+ "at": mock.ANY,
+ "amount": Decimal("10.75"),
+ "checkout_id": self.checkout.pk,
+ "comment": "A comment to explain it",
+ "id": mock.ANY,
+ "is_cof": False,
+ "on_acc_id": self.account.pk,
+ "valid_by_id": self.accounts["team"].pk,
+ },
+ )
+ operation = Operation.objects.get()
+ self.assertDictEqual(
+ operation.__dict__,
+ {
+ "_state": mock.ANY,
+ "addcost_amount": None,
+ "addcost_for_id": None,
+ "amount": Decimal("10.75"),
+ "article_id": None,
+ "article_nb": None,
+ "canceled_at": None,
+ "canceled_by_id": None,
+ "group_id": operation_group.pk,
+ "id": mock.ANY,
+ "type": "edit",
+ },
+ )
+
+ self.assertDictEqual(
+ json_data,
+ {
+ "operationgroup": operation_group.pk,
+ "operations": [operation.pk],
+ "warnings": {},
+ "errors": {},
+ },
+ )
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("60.75"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("100.00"))
+
+ self.kpsul_consumer_mock.group_send.assert_called_once_with(
+ "kfet.kpsul",
+ {
+ "opegroups": [
+ {
+ "add": True,
+ "at": mock.ANY,
+ "amount": Decimal("10.75"),
+ "checkout__name": "Checkout",
+ "comment": "A comment to explain it",
+ "id": operation_group.pk,
+ "is_cof": False,
+ "on_acc__trigramme": "000",
+ "valid_by__trigramme": "100",
+ "opes": [
+ {
+ "id": operation.pk,
+ "addcost_amount": None,
+ "addcost_for__trigramme": None,
+ "amount": Decimal("10.75"),
+ "article__name": None,
+ "article_nb": None,
+ "canceled_at": None,
+ "canceled_by__trigramme": None,
+ "group_id": operation_group.pk,
+ "type": "edit",
+ }
+ ],
+ }
+ ],
+ "checkouts": [{"id": self.checkout.pk, "balance": Decimal("100.00")}],
+ "articles": [],
+ },
+ )
+
+ def test_invalid_edit_requires_perm(self):
+ data = dict(
+ self.base_post_data,
+ **{
+ "comment": "A comment to explain it",
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "edit",
+ "form-0-amount": "10.75",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"]["missing_perms"], ["Modifier la balance d'un compte"]
+ )
+
+ def test_invalid_edit_expects_comment(self):
+ user_add_perms(self.users["team"], ["kfet.edit_balance_account"])
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "edit",
+ "form-0-amount": "10.75",
+ "form-0-article": "",
+ "form-0-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 400)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"]["need_comment"], True)
+
+ def _setup_addcost(self):
+ self.register_user("addcost", create_user("addcost", "ADD"))
+ kfet_config.set(
+ addcost_amount=Decimal("0.50"), addcost_for=self.accounts["addcost"]
+ )
+
+ def test_addcost_user_is_not_cof(self):
+ self.account.cofprofile.is_cof = False
+ self.account.cofprofile.save()
+ self._setup_addcost()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.amount, Decimal("-6.00"))
+ operation = Operation.objects.get()
+ self.assertEqual(operation.addcost_for, self.accounts["addcost"])
+ self.assertEqual(operation.addcost_amount, Decimal("1.00"))
+ self.assertEqual(operation.amount, Decimal("-6.00"))
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("44.00"))
+ self.accounts["addcost"].refresh_from_db()
+ self.assertEqual(self.accounts["addcost"].balance, Decimal("1.00"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("100.00"))
+
+ ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
+ 0
+ ]["opes"][0]
+ self.assertEqual(ws_data_ope["addcost_amount"], Decimal("1.00"))
+ self.assertEqual(ws_data_ope["addcost_for__trigramme"], "ADD")
+
+ def test_addcost_user_is_cof(self):
+ kfet_config.set(reduction_cof=Decimal("20"))
+ self.account.cofprofile.is_cof = True
+ self.account.cofprofile.save()
+ self._setup_addcost()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.amount, Decimal("-4.80"))
+ operation = Operation.objects.get()
+ self.assertEqual(operation.addcost_for, self.accounts["addcost"])
+ self.assertEqual(operation.addcost_amount, Decimal("0.80"))
+ self.assertEqual(operation.amount, Decimal("-4.80"))
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("45.20"))
+ self.accounts["addcost"].refresh_from_db()
+ self.assertEqual(self.accounts["addcost"].balance, Decimal("0.80"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("100.00"))
+
+ ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
+ 0
+ ]["opes"][0]
+ self.assertEqual(ws_data_ope["addcost_amount"], Decimal("0.80"))
+ self.assertEqual(ws_data_ope["addcost_for__trigramme"], "ADD")
+
+ def test_addcost_user_is_cash(self):
+ self.account.cofprofile.is_cof = True
+ self.account.cofprofile.save()
+ self._setup_addcost()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "on_acc": str(self.accounts["liq"].pk),
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.amount, Decimal("-6.00"))
+ operation = Operation.objects.get()
+ self.assertEqual(operation.addcost_for, self.accounts["addcost"])
+ self.assertEqual(operation.addcost_amount, Decimal("1.00"))
+ self.assertEqual(operation.amount, Decimal("-6.00"))
+
+ self.accounts["addcost"].refresh_from_db()
+ self.assertEqual(self.accounts["addcost"].balance, Decimal("1.00"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("106.00"))
+
+ ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
+ 0
+ ]["opes"][0]
+ self.assertEqual(ws_data_ope["addcost_amount"], Decimal("1.00"))
+ self.assertEqual(ws_data_ope["addcost_for__trigramme"], "ADD")
+
+ def test_addcost_to_self(self):
+ self._setup_addcost()
+ self.accounts["addcost"].balance = Decimal("20.00")
+ self.accounts["addcost"].save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "on_acc": str(self.accounts["addcost"].pk),
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.amount, Decimal("-5.00"))
+ operation = Operation.objects.get()
+ self.assertEqual(operation.addcost_for, None)
+ self.assertEqual(operation.addcost_amount, None)
+ self.assertEqual(operation.amount, Decimal("-5.00"))
+
+ self.accounts["addcost"].refresh_from_db()
+ self.assertEqual(self.accounts["addcost"].balance, Decimal("15.00"))
+
+ ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
+ 0
+ ]["opes"][0]
+ self.assertEqual(ws_data_ope["addcost_amount"], None)
+ self.assertEqual(ws_data_ope["addcost_for__trigramme"], None)
+
+ def test_addcost_category_disabled(self):
+ self._setup_addcost()
+ self.article.category.has_addcost = False
+ self.article.category.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ operation_group = OperationGroup.objects.get()
+ self.assertEqual(operation_group.amount, Decimal("-5.00"))
+ operation = Operation.objects.get()
+ self.assertEqual(operation.addcost_for, None)
+ self.assertEqual(operation.addcost_amount, None)
+ self.assertEqual(operation.amount, Decimal("-5.00"))
+
+ self.accounts["addcost"].refresh_from_db()
+ self.assertEqual(self.accounts["addcost"].balance, Decimal("0.00"))
+
+ ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
+ 0
+ ]["opes"][0]
+ self.assertEqual(ws_data_ope["addcost_amount"], None)
+ self.assertEqual(ws_data_ope["addcost_for__trigramme"], None)
+
+ def test_negative_new(self):
+ user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
+ self.account.balance = Decimal("1.00")
+ self.account.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("-4.00"))
+
+ def test_negative_exists(self):
+ user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
+ self.account.balance = Decimal("-10.00")
+ self.account.save()
+ self.account.update_negative()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("-15.00"))
+
+ def test_negative_exists_balance_higher_than_initial(self):
+ user_add_perms(self.users["team"], ["kfet.perform_deposit"])
+ self.account.balance = Decimal("-10.00")
+ self.account.save()
+ self.account.update_negative()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "2",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "1",
+ "form-1-type": "deposit",
+ "form-1-amount": "5.00",
+ "form-1-article": "",
+ "form-1-article_nb": "",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self._assertResponseOk(resp)
+
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("-7.50"))
+
+ def test_invalid_negative_new_requires_perm(self):
+ self.account.balance = Decimal("1.00")
+ self.account.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(
+ json_data["errors"],
+ {"missing_perms": ["Enregistrer des commandes en négatif"]},
+ )
+
+ def test_invalid_negative_exceeds_allowed_duration_from_config(self):
+ user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
+ kfet_config.set(overdraft_duration=timedelta(days=5))
+ self.account.balance = Decimal("1.00")
+ self.account.save()
+ self.account.negative = AccountNegative.objects.create(
+ account=self.account, start=timezone.now() - timedelta(days=5, minutes=1)
+ )
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"], {"negative": ["000"]})
+
+ def test_invalid_negative_exceeds_allowed_duration_from_account(self):
+ user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
+ kfet_config.set(overdraft_duration=timedelta(days=5))
+ self.account.balance = Decimal("1.00")
+ self.account.save()
+ self.account.negative = AccountNegative.objects.create(
+ account=self.account,
+ start=timezone.now() - timedelta(days=3),
+ authz_overdraft_until=timezone.now() - timedelta(seconds=1),
+ )
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"], {"negative": ["000"]})
+
+ def test_invalid_negative_exceeds_amount_allowed_from_config(self):
+ user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
+ kfet_config.set(overdraft_amount=Decimal("-1.00"))
+ self.account.balance = Decimal("1.00")
+ self.account.save()
+ self.account.update_negative()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"], {"negative": ["000"]})
+
+ def test_invalid_negative_exceeds_amount_allowed_from_account(self):
+ user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
+ kfet_config.set(overdraft_amount=Decimal("10.00"))
+ self.account.balance = Decimal("1.00")
+ self.account.save()
+ self.account.update_negative()
+ self.account.negative = AccountNegative.objects.create(
+ account=self.account,
+ start=timezone.now() - timedelta(days=3),
+ authz_overdraft_amount=Decimal("1.00"),
+ )
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "1",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ self.assertEqual(resp.status_code, 403)
+ json_data = json.loads(resp.content.decode("utf-8"))
+ self.assertEqual(json_data["errors"], {"negative": ["000"]})
+
+ def test_multi_0(self):
+ article2 = Article.objects.create(
+ name="Article 2",
+ price=Decimal("4"),
+ stock=-5,
+ category=ArticleCategory.objects.first(),
+ )
+ self.account.cofprofile.is_cof = False
+ self.account.cofprofile.save()
+
+ data = dict(
+ self.base_post_data,
+ **{
+ "form-TOTAL_FORMS": "2",
+ "form-0-type": "purchase",
+ "form-0-amount": "",
+ "form-0-article": str(self.article.pk),
+ "form-0-article_nb": "2",
+ "form-1-type": "purchase",
+ "form-1-amount": "",
+ "form-1-article": str(article2.pk),
+ "form-1-article_nb": "1",
+ }
+ )
+ resp = self.client.post(self.url, data)
+
+ # Check response status
+ json_data = self._assertResponseOk(resp)
+
+ # Check object creations
+ operation_group = OperationGroup.objects.get()
+ self.assertDictEqual(
+ operation_group.__dict__,
+ {
+ "_state": mock.ANY,
+ "at": mock.ANY,
+ "amount": Decimal("-9.00"),
+ "checkout_id": self.checkout.pk,
+ "comment": "",
+ "id": mock.ANY,
+ "is_cof": False,
+ "on_acc_id": self.account.pk,
+ "valid_by_id": None,
+ },
+ )
+ operation_list = Operation.objects.all()
+ self.assertEqual(len(operation_list), 2)
+ self.assertDictEqual(
+ operation_list[0].__dict__,
+ {
+ "_state": mock.ANY,
+ "addcost_amount": None,
+ "addcost_for_id": None,
+ "amount": Decimal("-5.00"),
+ "article_id": self.article.pk,
+ "article_nb": 2,
+ "canceled_at": None,
+ "canceled_by_id": None,
+ "group_id": operation_group.pk,
+ "id": mock.ANY,
+ "type": "purchase",
+ },
+ )
+ self.assertDictEqual(
+ operation_list[1].__dict__,
+ {
+ "_state": mock.ANY,
+ "addcost_amount": None,
+ "addcost_for_id": None,
+ "amount": Decimal("-4.00"),
+ "article_id": article2.pk,
+ "article_nb": 1,
+ "canceled_at": None,
+ "canceled_by_id": None,
+ "group_id": operation_group.pk,
+ "id": mock.ANY,
+ "type": "purchase",
+ },
+ )
+
+ # Check response content
+ self.assertDictEqual(
+ json_data,
+ {
+ "operationgroup": operation_group.pk,
+ "operations": [operation_list[0].pk, operation_list[1].pk],
+ "warnings": {},
+ "errors": {},
+ },
+ )
+
+ # Check object updates
+ self.account.refresh_from_db()
+ self.assertEqual(self.account.balance, Decimal("41.00"))
+ self.checkout.refresh_from_db()
+ self.assertEqual(self.checkout.balance, Decimal("100.00"))
+ self.article.refresh_from_db()
+ self.assertEqual(self.article.stock, 18)
+ article2.refresh_from_db()
+ self.assertEqual(article2.stock, -6)
+
+ # Check websocket data
+ self.kpsul_consumer_mock.group_send.assert_called_once_with(
+ "kfet.kpsul",
+ {
+ "opegroups": [
+ {
+ "add": True,
+ "at": mock.ANY,
+ "amount": Decimal("-9.00"),
+ "checkout__name": "Checkout",
+ "comment": "",
+ "id": operation_group.pk,
+ "is_cof": False,
+ "on_acc__trigramme": "000",
+ "valid_by__trigramme": None,
+ "opes": [
+ {
+ "id": operation_list[0].pk,
+ "addcost_amount": None,
+ "addcost_for__trigramme": None,
+ "amount": Decimal("-5.00"),
+ "article__name": "Article",
+ "article_nb": 2,
+ "canceled_at": None,
+ "canceled_by__trigramme": None,
+ "group_id": operation_group.pk,
+ "type": "purchase",
+ },
+ {
+ "id": operation_list[1].pk,
+ "addcost_amount": None,
+ "addcost_for__trigramme": None,
+ "amount": Decimal("-4.00"),
+ "article__name": "Article 2",
+ "article_nb": 1,
+ "canceled_at": None,
+ "canceled_by__trigramme": None,
+ "group_id": operation_group.pk,
+ "type": "purchase",
+ },
+ ],
+ }
+ ],
+ "checkouts": [{"id": self.checkout.pk, "balance": Decimal("100.00")}],
+ "articles": [
+ {"id": self.article.pk, "stock": 18},
+ {"id": article2.pk, "stock": -6},
+ ],
+ },
+ )
class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul.cancel_operations'
- url_expected = '/k-fet/k-psul/cancel_operations'
+ url_name = "kfet.kpsul.cancel_operations"
+ url_expected = "/k-fet/k-psul/cancel_operations"
- http_methods = ['POST']
+ http_methods = ["POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
pass
class KPsulArticlesData(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul.articles_data'
- url_expected = '/k-fet/k-psul/articles_data'
+ url_name = "kfet.kpsul.articles_data"
+ url_expected = "/k-fet/k-psul/articles_data"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Catégorie')
- self.article1 = Article.objects.create(
- category=category,
- name='Article 1',
- )
+ category = ArticleCategory.objects.create(name="Catégorie")
+ self.article1 = Article.objects.create(category=category, name="Article 1")
self.article2 = Article.objects.create(
- category=category,
- name='Article 2',
- price=Decimal('2.5'),
+ category=category, name="Article 2", price=Decimal("2.5")
)
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- content = json.loads(r.content.decode('utf-8'))
+ content = json.loads(r.content.decode("utf-8"))
- articles = content['articles']
+ articles = content["articles"]
- expected_list = [{
- 'category__name': 'Catégorie',
- 'name': 'Article 1',
- 'price': '0.00',
- }, {
- 'category__name': 'Catégorie',
- 'name': 'Article 2',
- 'price': '2.50',
- }]
+ expected_list = [
+ {"category__name": "Catégorie", "name": "Article 1", "price": "0.00"},
+ {"category__name": "Catégorie", "name": "Article 2", "price": "2.50"},
+ ]
for expected, article in zip(expected_list, articles):
self.assertDictContainsSubset(expected, article)
- self.assertSetEqual(set(article.keys()), set([
- 'id', 'name', 'price', 'stock',
- 'category_id', 'category__name', 'category__has_addcost',
- ]))
+ self.assertSetEqual(
+ set(article.keys()),
+ set(
+ [
+ "id",
+ "name",
+ "price",
+ "stock",
+ "category_id",
+ "category__name",
+ "category__has_addcost",
+ ]
+ ),
+ )
class KPsulUpdateAddcost(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul.update_addcost'
- url_expected = '/k-fet/k-psul/update_addcost'
+ url_name = "kfet.kpsul.update_addcost"
+ url_expected = "/k-fet/k-psul/update_addcost"
- http_methods = ['POST']
+ http_methods = ["POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
- post_data = {
- 'trigramme': '000',
- 'amount': '0.5',
- }
+ post_data = {"trigramme": "000", "amount": "0.5"}
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.manage_addcosts',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.manage_addcosts"])}
def test_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
self.assertEqual(r.status_code, 200)
- self.assertEqual(
- kfet_config.addcost_for,
- Account.objects.get(trigramme='000'),
- )
- self.assertEqual(kfet_config.addcost_amount, Decimal('0.5'))
+ self.assertEqual(kfet_config.addcost_for, Account.objects.get(trigramme="000"))
+ self.assertEqual(kfet_config.addcost_amount, Decimal("0.5"))
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -1563,11 +3040,11 @@ class KPsulUpdateAddcost(ViewTestCaseMixin, TestCase):
class KPsulGetSettings(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.kpsul.get_settings'
- url_expected = '/k-fet/k-psul/get_settings'
+ url_name = "kfet.kpsul.get_settings"
+ url_expected = "/k-fet/k-psul/get_settings"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
r = self.client.get(self.url)
@@ -1575,10 +3052,10 @@ class KPsulGetSettings(ViewTestCaseMixin, TestCase):
class HistoryJSONViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.history.json'
- url_expected = '/k-fet/history.json'
+ url_name = "kfet.history.json"
+ url_expected = "/k-fet/history.json"
- auth_user = 'user'
+ auth_user = "user"
auth_forbidden = [None]
def test_ok(self):
@@ -1587,46 +3064,51 @@ class HistoryJSONViewTests(ViewTestCaseMixin, TestCase):
class AccountReadJSONViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.account.read.json'
- url_expected = '/k-fet/accounts/read.json'
+ url_name = "kfet.account.read.json"
+ url_expected = "/k-fet/accounts/read.json"
- http_methods = ['POST']
+ http_methods = ["POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
- r = self.client.post(self.url, {'trigramme': '000'})
+ r = self.client.post(self.url, {"trigramme": "000"})
self.assertEqual(r.status_code, 200)
- content = json.loads(r.content.decode('utf-8'))
+ content = json.loads(r.content.decode("utf-8"))
- expected = {
- 'name': 'first last',
- 'trigramme': '000',
- 'balance': '0.00',
- }
+ expected = {"name": "first last", "trigramme": "000", "balance": "0.00"}
self.assertDictContainsSubset(expected, content)
- self.assertSetEqual(set(content.keys()), set([
- 'balance', 'departement', 'email', 'id', 'is_cof', 'is_frozen',
- 'name', 'nickname', 'promo', 'trigramme',
- ]))
+ self.assertSetEqual(
+ set(content.keys()),
+ set(
+ [
+ "balance",
+ "departement",
+ "email",
+ "id",
+ "is_cof",
+ "is_frozen",
+ "name",
+ "nickname",
+ "promo",
+ "trigramme",
+ ]
+ ),
+ )
class SettingsListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.settings'
- url_expected = '/k-fet/settings/'
+ url_name = "kfet.settings"
+ url_expected = "/k-fet/settings/"
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.see_config',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.see_config"])}
def test_ok(self):
r = self.client.get(self.url)
@@ -1634,31 +3116,27 @@ class SettingsListViewTests(ViewTestCaseMixin, TestCase):
class SettingsUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.settings.update'
- url_expected = '/k-fet/settings/edit'
+ url_name = "kfet.settings.update"
+ url_expected = "/k-fet/settings/edit"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
@property
def post_data(self):
return {
- 'kfet_reduction_cof': '25',
- 'kfet_addcost_amount': '0.5',
- 'kfet_addcost_for': self.accounts['user'].pk,
- 'kfet_overdraft_duration': '2 00:00:00',
- 'kfet_overdraft_amount': '25',
- 'kfet_cancel_duration': '00:20:00',
+ "kfet_reduction_cof": "25",
+ "kfet_addcost_amount": "0.5",
+ "kfet_addcost_for": self.accounts["user"].pk,
+ "kfet_overdraft_duration": "2 00:00:00",
+ "kfet_overdraft_amount": "25",
+ "kfet_cancel_duration": "00:20:00",
}
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_config',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.change_config"])}
def test_get_ok(self):
r = self.client.get(self.url)
@@ -1667,19 +3145,15 @@ class SettingsUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
r = self.client.post(self.url, self.post_data)
# Redirect is skipped because client may lack permissions.
- self.assertRedirects(
- r,
- reverse('kfet.settings'),
- fetch_redirect_response=False,
- )
+ self.assertRedirects(r, reverse("kfet.settings"), fetch_redirect_response=False)
expected_config = {
- 'reduction_cof': Decimal('25'),
- 'addcost_amount': Decimal('0.5'),
- 'addcost_for': self.accounts['user'],
- 'overdraft_duration': timedelta(days=2),
- 'overdraft_amount': Decimal('25'),
- 'cancel_duration': timedelta(minutes=20),
+ "reduction_cof": Decimal("25"),
+ "addcost_amount": Decimal("0.5"),
+ "addcost_for": self.accounts["user"],
+ "overdraft_duration": timedelta(days=2),
+ "overdraft_amount": Decimal("25"),
+ "cancel_duration": timedelta(minutes=20),
}
for key, expected in expected_config.items():
@@ -1687,11 +3161,11 @@ class SettingsUpdateViewTests(ViewTestCaseMixin, TestCase):
class TransferListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.transfers'
- url_expected = '/k-fet/transfers/'
+ url_name = "kfet.transfers"
+ url_expected = "/k-fet/transfers/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
r = self.client.get(self.url)
@@ -1699,11 +3173,11 @@ class TransferListViewTests(ViewTestCaseMixin, TestCase):
class TransferCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.transfers.create'
- url_expected = '/k-fet/transfers/new'
+ url_name = "kfet.transfers.create"
+ url_expected = "/k-fet/transfers/new"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def test_ok(self):
r = self.client.get(self.url)
@@ -1711,195 +3185,180 @@ class TransferCreateViewTests(ViewTestCaseMixin, TestCase):
class TransferPerformViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.transfers.perform'
- url_expected = '/k-fet/transfers/perform'
+ url_name = "kfet.transfers.perform"
+ url_expected = "/k-fet/transfers/perform"
- http_methods = ['POST']
+ http_methods = ["POST"]
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
return {
- 'team1': create_team('team1', '101', perms=[
- # Required
- 'kfet.add_transfer',
- # Convenience
- 'kfet.perform_negative_operations',
- ]),
+ "team1": create_team(
+ "team1",
+ "101",
+ perms=[
+ # Required
+ "kfet.add_transfer",
+ # Convenience
+ "kfet.perform_negative_operations",
+ ],
+ )
}
@property
def post_data(self):
return {
# General
- 'comment': '',
+ "comment": "",
# Formset management
- 'form-TOTAL_FORMS': '10',
- 'form-INITIAL_FORMS': '0',
- 'form-MIN_NUM_FORMS': '1',
- 'form-MAX_NUM_FORMS': '1000',
+ "form-TOTAL_FORMS": "10",
+ "form-INITIAL_FORMS": "0",
+ "form-MIN_NUM_FORMS": "1",
+ "form-MAX_NUM_FORMS": "1000",
# Transfer 1
- 'form-0-from_acc': str(self.accounts['user'].pk),
- 'form-0-to_acc': str(self.accounts['team'].pk),
- 'form-0-amount': '3.5',
+ "form-0-from_acc": str(self.accounts["user"].pk),
+ "form-0-to_acc": str(self.accounts["team"].pk),
+ "form-0-amount": "3.5",
# Transfer 2
- 'form-1-from_acc': str(self.accounts['team'].pk),
- 'form-1-to_acc': str(self.accounts['team1'].pk),
- 'form-1-amount': '2.4',
+ "form-1-from_acc": str(self.accounts["team"].pk),
+ "form-1-to_acc": str(self.accounts["team1"].pk),
+ "form-1-amount": "2.4",
}
def test_ok(self):
r = self.client.post(self.url, self.post_data)
self.assertEqual(r.status_code, 200)
- user = self.accounts['user']
+ user = self.accounts["user"]
user.refresh_from_db()
- self.assertEqual(user.balance, Decimal('-3.5'))
+ self.assertEqual(user.balance, Decimal("-3.5"))
- team = self.accounts['team']
+ team = self.accounts["team"]
team.refresh_from_db()
- self.assertEqual(team.balance, Decimal('1.1'))
+ self.assertEqual(team.balance, Decimal("1.1"))
- team1 = self.accounts['team1']
+ team1 = self.accounts["team1"]
team1.refresh_from_db()
- self.assertEqual(team1.balance, Decimal('2.4'))
+ self.assertEqual(team1.balance, Decimal("2.4"))
class TransferCancelViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.transfers.cancel'
- url_expected = '/k-fet/transfers/cancel'
+ url_name = "kfet.transfers.cancel"
+ url_expected = "/k-fet/transfers/cancel"
- http_methods = ['POST']
+ http_methods = ["POST"]
- auth_user = 'team1'
- auth_forbidden = [None, 'user', 'team']
+ auth_user = "team1"
+ auth_forbidden = [None, "user", "team"]
def get_users_extra(self):
return {
- 'team1': create_team('team1', '101', perms=[
- # Convenience
- 'kfet.perform_negative_operations',
- ]),
+ "team1": create_team(
+ "team1",
+ "101",
+ perms=[
+ # Convenience
+ "kfet.perform_negative_operations"
+ ],
+ )
}
@property
def post_data(self):
- return {
- 'transfers[]': [self.transfer1.pk, self.transfer2.pk],
- }
+ return {"transfers[]": [self.transfer1.pk, self.transfer2.pk]}
def setUp(self):
super().setUp()
group = TransferGroup.objects.create()
self.transfer1 = Transfer.objects.create(
group=group,
- from_acc=self.accounts['user'],
- to_acc=self.accounts['team'],
- amount='3.5',
+ from_acc=self.accounts["user"],
+ to_acc=self.accounts["team"],
+ amount="3.5",
)
self.transfer2 = Transfer.objects.create(
group=group,
- from_acc=self.accounts['team'],
- to_acc=self.accounts['root'],
- amount='2.4',
+ from_acc=self.accounts["team"],
+ to_acc=self.accounts["root"],
+ amount="2.4",
)
def test_ok(self):
r = self.client.post(self.url, self.post_data)
self.assertEqual(r.status_code, 200)
- user = self.accounts['user']
+ user = self.accounts["user"]
user.refresh_from_db()
- self.assertEqual(user.balance, Decimal('3.5'))
+ self.assertEqual(user.balance, Decimal("3.5"))
- team = self.accounts['team']
+ team = self.accounts["team"]
team.refresh_from_db()
- self.assertEqual(team.balance, Decimal('-1.1'))
+ self.assertEqual(team.balance, Decimal("-1.1"))
- root = self.accounts['root']
+ root = self.accounts["root"]
root.refresh_from_db()
- self.assertEqual(root.balance, Decimal('-2.4'))
+ self.assertEqual(root.balance, Decimal("-2.4"))
class InventoryListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.inventory'
- url_expected = '/k-fet/inventaires/'
+ url_name = "kfet.inventory"
+ url_expected = "/k-fet/inventaires/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
- self.inventory = Inventory.objects.create(
- by=self.accounts['team'],
- )
- category = ArticleCategory.objects.create(name='Category')
- article = Article.objects.create(
- name='Article',
- category=category,
- )
+ self.inventory = Inventory.objects.create(by=self.accounts["team"])
+ category = ArticleCategory.objects.create(name="Category")
+ article = Article.objects.create(name="Article", category=category)
InventoryArticle.objects.create(
- inventory=self.inventory,
- article=article,
- stock_old=5,
- stock_new=0,
+ inventory=self.inventory, article=article, stock_old=5, stock_new=0
)
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- inventories = r.context['inventories']
- self.assertQuerysetEqual(
- inventories,
- map(repr, [self.inventory]),
- )
+ inventories = r.context["inventories"]
+ self.assertQuerysetEqual(inventories, map(repr, [self.inventory]))
class InventoryCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.inventory.create'
- url_expected = '/k-fet/inventaires/new'
+ url_name = "kfet.inventory.create"
+ url_expected = "/k-fet/inventaires/new"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.add_inventory',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.add_inventory"])}
@property
def post_data(self):
return {
# Formset management
- 'form-TOTAL_FORMS': '2',
- 'form-INITIAL_FORMS': '2',
- 'form-MIN_NUM_FORMS': '0',
- 'form-MAX_NUM_FORMS': '1000',
+ "form-TOTAL_FORMS": "2",
+ "form-INITIAL_FORMS": "2",
+ "form-MIN_NUM_FORMS": "0",
+ "form-MAX_NUM_FORMS": "1000",
# Article 1
- 'form-0-article': str(self.article1.pk),
- 'form-0-stock_new': '5',
+ "form-0-article": str(self.article1.pk),
+ "form-0-stock_new": "5",
# Article 2
- 'form-1-article': str(self.article2.pk),
- 'form-1-stock_new': '10',
+ "form-1-article": str(self.article2.pk),
+ "form-1-stock_new": "10",
}
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Category')
- self.article1 = Article.objects.create(
- category=category,
- name='Article 1',
- )
- self.article2 = Article.objects.create(
- category=category,
- name='Article 2',
- )
+ category = ArticleCategory.objects.create(name="Category")
+ self.article1 = Article.objects.create(category=category, name="Article 1")
+ self.article2 = Article.objects.create(category=category, name="Article 2")
def test_get_ok(self):
r = self.client.get(self.url)
@@ -1907,10 +3366,10 @@ class InventoryCreateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.inventory'))
+ self.assertRedirects(r, reverse("kfet.inventory"))
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -1918,34 +3377,26 @@ class InventoryCreateViewTests(ViewTestCaseMixin, TestCase):
class InventoryReadViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.inventory.read'
+ url_name = "kfet.inventory.read"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.inventory.pk}
+ return {"pk": self.inventory.pk}
@property
def url_expected(self):
- return '/k-fet/inventaires/{}'.format(self.inventory.pk)
+ return "/k-fet/inventaires/{}".format(self.inventory.pk)
def setUp(self):
super().setUp()
- self.inventory = Inventory.objects.create(
- by=self.accounts['team'],
- )
- category = ArticleCategory.objects.create(name='Category')
- article = Article.objects.create(
- name='Article',
- category=category,
- )
+ self.inventory = Inventory.objects.create(by=self.accounts["team"])
+ category = ArticleCategory.objects.create(name="Category")
+ article = Article.objects.create(name="Article", category=category)
InventoryArticle.objects.create(
- inventory=self.inventory,
- article=article,
- stock_old=5,
- stock_new=0,
+ inventory=self.inventory, article=article, stock_old=5, stock_new=0
)
def test_ok(self):
@@ -1954,65 +3405,58 @@ class InventoryReadViewTests(ViewTestCaseMixin, TestCase):
class OrderListViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.order'
- url_expected = '/k-fet/orders/'
+ url_name = "kfet.order"
+ url_expected = "/k-fet/orders/"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Category')
- article = Article.objects.create(name='Article', category=category)
+ category = ArticleCategory.objects.create(name="Category")
+ article = Article.objects.create(name="Article", category=category)
- supplier = Supplier.objects.create(name='Supplier')
+ supplier = Supplier.objects.create(name="Supplier")
SupplierArticle.objects.create(supplier=supplier, article=article)
self.order = Order.objects.create(supplier=supplier)
OrderArticle.objects.create(
- order=self.order,
- article=article,
- quantity_ordered=24,
+ order=self.order, article=article, quantity_ordered=24
)
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- orders = r.context['orders']
- self.assertQuerysetEqual(
- orders,
- map(repr, [self.order]),
- )
+ orders = r.context["orders"]
+ self.assertQuerysetEqual(orders, map(repr, [self.order]))
class OrderReadViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.order.read'
+ url_name = "kfet.order.read"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.order.pk}
+ return {"pk": self.order.pk}
@property
def url_expected(self):
- return '/k-fet/orders/{}'.format(self.order.pk)
+ return "/k-fet/orders/{}".format(self.order.pk)
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Category')
- article = Article.objects.create(name='Article', category=category)
+ category = ArticleCategory.objects.create(name="Category")
+ article = Article.objects.create(name="Article", category=category)
- supplier = Supplier.objects.create(name='Supplier')
+ supplier = Supplier.objects.create(name="Supplier")
SupplierArticle.objects.create(supplier=supplier, article=article)
self.order = Order.objects.create(supplier=supplier)
OrderArticle.objects.create(
- order=self.order,
- article=article,
- quantity_ordered=24,
+ order=self.order, article=article, quantity_ordered=24
)
def test_ok(self):
@@ -2021,41 +3465,37 @@ class OrderReadViewTests(ViewTestCaseMixin, TestCase):
class SupplierUpdateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.order.supplier.update'
+ url_name = "kfet.order.supplier.update"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.supplier.pk}
+ return {"pk": self.supplier.pk}
@property
def url_expected(self):
- return '/k-fet/orders/suppliers/{}/edit'.format(self.supplier.pk)
+ return "/k-fet/orders/suppliers/{}/edit".format(self.supplier.pk)
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.change_supplier',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.change_supplier"])}
@property
def post_data(self):
return {
- 'name': 'The Supplier',
- 'phone': '',
- 'comment': '',
- 'address': '',
- 'email': '',
+ "name": "The Supplier",
+ "phone": "",
+ "comment": "",
+ "address": "",
+ "email": "",
}
def setUp(self):
super().setUp()
- self.supplier = Supplier.objects.create(name='Supplier')
+ self.supplier = Supplier.objects.create(name="Supplier")
def test_get_ok(self):
r = self.client.get(self.url)
@@ -2063,13 +3503,13 @@ class SupplierUpdateViewTests(ViewTestCaseMixin, TestCase):
def test_post_ok(self):
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.order'))
+ self.assertRedirects(r, reverse("kfet.order"))
self.supplier.refresh_from_db()
- self.assertEqual(self.supplier.name, 'The Supplier')
+ self.assertEqual(self.supplier.name, "The Supplier")
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -2077,67 +3517,59 @@ class SupplierUpdateViewTests(ViewTestCaseMixin, TestCase):
class OrderCreateViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.order.new'
+ url_name = "kfet.order.new"
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.supplier.pk}
+ return {"pk": self.supplier.pk}
@property
def url_expected(self):
- return '/k-fet/orders/suppliers/{}/new-order'.format(self.supplier.pk)
+ return "/k-fet/orders/suppliers/{}/new-order".format(self.supplier.pk)
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=['kfet.add_order']),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.add_order"])}
@property
def post_data(self):
return {
# Formset management
- 'form-TOTAL_FORMS': '1',
- 'form-INITIAL_FORMS': '1',
- 'form-MIN_NUM_FORMS': '0',
- 'form-MAX_NUM_FORMS': '1000',
+ "form-TOTAL_FORMS": "1",
+ "form-INITIAL_FORMS": "1",
+ "form-MIN_NUM_FORMS": "0",
+ "form-MAX_NUM_FORMS": "1000",
# Article
- 'form-0-article': self.article.pk,
- 'form-0-quantity_ordered': '20',
+ "form-0-article": self.article.pk,
+ "form-0-quantity_ordered": "20",
}
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Category')
- self.article = Article.objects.create(
- name='Article',
- category=category,
- )
+ category = ArticleCategory.objects.create(name="Category")
+ self.article = Article.objects.create(name="Article", category=category)
- self.supplier = Supplier.objects.create(name='Supplier')
- SupplierArticle.objects.create(
- supplier=self.supplier,
- article=self.article,
- )
+ self.supplier = Supplier.objects.create(name="Supplier")
+ SupplierArticle.objects.create(supplier=self.supplier, article=self.article)
def test_get_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- @mock.patch('django.utils.timezone.now')
+ @mock.patch("django.utils.timezone.now")
def test_post_ok(self, mock_now):
mock_now.return_value = self.now
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
order = Order.objects.get(at=self.now)
- self.assertRedirects(r, reverse('kfet.order.read', args=[order.pk]))
+ self.assertRedirects(r, reverse("kfet.order.read", args=[order.pk]))
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
@@ -2145,95 +3577,80 @@ class OrderCreateViewTests(ViewTestCaseMixin, TestCase):
class OrderToInventoryViewTests(ViewTestCaseMixin, TestCase):
- url_name = 'kfet.order.to_inventory'
+ url_name = "kfet.order.to_inventory"
- http_methods = ['GET', 'POST']
+ http_methods = ["GET", "POST"]
- auth_user = 'team'
- auth_forbidden = [None, 'user']
+ auth_user = "team"
+ auth_forbidden = [None, "user"]
@property
def url_kwargs(self):
- return {'pk': self.order.pk}
+ return {"pk": self.order.pk}
@property
def url_expected(self):
- return '/k-fet/orders/{}/to_inventory'.format(self.order.pk)
+ return "/k-fet/orders/{}/to_inventory".format(self.order.pk)
def get_users_extra(self):
- return {
- 'team1': create_team('team1', '101', perms=[
- 'kfet.order_to_inventory',
- ]),
- }
+ return {"team1": create_team("team1", "101", perms=["kfet.order_to_inventory"])}
@property
def post_data(self):
return {
# Formset mangaement
- 'form-TOTAL_FORMS': '1',
- 'form-INITIAL_FORMS': '1',
- 'form-MIN_NUM_FORMS': '0',
- 'form-MAX_NUM_FORMS': '1000',
+ "form-TOTAL_FORMS": "1",
+ "form-INITIAL_FORMS": "1",
+ "form-MIN_NUM_FORMS": "0",
+ "form-MAX_NUM_FORMS": "1000",
# Article 1
- 'form-0-article': self.article.pk,
- 'form-0-quantity_received': '20',
- 'form-0-price_HT': '',
- 'form-0-TVA': '',
- 'form-0-rights': '',
+ "form-0-article": self.article.pk,
+ "form-0-quantity_received": "20",
+ "form-0-price_HT": "",
+ "form-0-TVA": "",
+ "form-0-rights": "",
}
def setUp(self):
super().setUp()
- category = ArticleCategory.objects.create(name='Category')
- self.article = Article.objects.create(
- name='Article',
- category=category,
- )
+ category = ArticleCategory.objects.create(name="Category")
+ self.article = Article.objects.create(name="Article", category=category)
- supplier = Supplier.objects.create(name='Supplier')
+ supplier = Supplier.objects.create(name="Supplier")
SupplierArticle.objects.create(supplier=supplier, article=self.article)
self.order = Order.objects.create(supplier=supplier)
OrderArticle.objects.create(
- order=self.order,
- article=self.article,
- quantity_ordered=24,
+ order=self.order, article=self.article, quantity_ordered=24
)
def test_get_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
- @mock.patch('django.utils.timezone.now')
+ @mock.patch("django.utils.timezone.now")
def test_post_ok(self, mock_now):
mock_now.return_value = self.now
client = Client()
- client.login(username='team1', password='team1')
+ client.login(username="team1", password="team1")
r = client.post(self.url, self.post_data)
- self.assertRedirects(r, reverse('kfet.order'))
+ self.assertRedirects(r, reverse("kfet.order"))
inventory = Inventory.objects.first()
- self.assertInstanceExpected(inventory, {
- 'by': self.accounts['team1'],
- 'at': self.now,
- 'order': self.order,
- })
- self.assertQuerysetEqual(
- inventory.articles.all(),
- map(repr, [self.article]),
+ self.assertInstanceExpected(
+ inventory,
+ {"by": self.accounts["team1"], "at": self.now, "order": self.order},
)
+ self.assertQuerysetEqual(inventory.articles.all(), map(repr, [self.article]))
compte = InventoryArticle.objects.get(article=self.article)
- self.assertInstanceExpected(compte, {
- 'stock_old': 0,
- 'stock_new': 20,
- 'stock_error': 0,
- })
+ self.assertInstanceExpected(
+ compte, {"stock_old": 0, "stock_new": 20, "stock_error": 0}
+ )
def test_post_forbidden(self):
r = self.client.post(self.url, self.post_data)
diff --git a/kfet/tests/testcases.py b/kfet/tests/testcases.py
index aa2fb1b6..36a4ab65 100644
--- a/kfet/tests/testcases.py
+++ b/kfet/tests/testcases.py
@@ -37,34 +37,32 @@ class TestCaseMixin:
full_path = request.get_full_path()
querystring = QueryDict(mutable=True)
- querystring['next'] = full_path
+ querystring["next"] = full_path
- login_url = '/login?' + querystring.urlencode(safe='/')
+ login_url = "/login?" + querystring.urlencode(safe="/")
# We don't focus on what the login view does.
# So don't fetch the redirect.
- self.assertRedirects(
- response, login_url,
- fetch_redirect_response=False,
- )
+ self.assertRedirects(response, login_url, fetch_redirect_response=False)
except AssertionError:
raise AssertionError(
"%(http_method)s request at %(path)s should be forbidden for "
"%(username)s user.\n"
"Response isn't 403, nor a redirect to login view. Instead, "
- "response code is %(code)d." % {
- 'http_method': request.method,
- 'path': request.get_full_path(),
- 'username': (
+ "response code is %(code)d."
+ % {
+ "http_method": request.method,
+ "path": request.get_full_path(),
+ "username": (
"'{}'".format(request.user)
if request.user.is_authenticated
- else 'anonymous'
+ else "anonymous"
),
- 'code': response.status_code,
+ "code": response.status_code,
}
)
- def assertForbiddenKfet(self, response, form_ctx='form'):
+ def assertForbiddenKfet(self, response, form_ctx="form"):
"""
Test that a response (retrieved with a Client) contains error due to
lack of kfet permissions.
@@ -83,7 +81,7 @@ class TestCaseMixin:
form = response.context[form_ctx]
self.assertIn("Permission refusée", form.non_field_errors())
except (AssertionError, AttributeError, KeyError):
- messages = [str(msg) for msg in response.context['messages']]
+ messages = [str(msg) for msg in response.context["messages"]]
self.assertIn("Permission refusée", messages)
except AssertionError:
request = response.wsgi_request
@@ -91,15 +89,16 @@ class TestCaseMixin:
"%(http_method)s request at %(path)s should raise an error "
"for %(username)s user.\n"
"Cannot find any errors in non-field errors of form "
- "'%(form_ctx)s', nor in messages." % {
- 'http_method': request.method,
- 'path': request.get_full_path(),
- 'username': (
+ "'%(form_ctx)s', nor in messages."
+ % {
+ "http_method": request.method,
+ "path": request.get_full_path(),
+ "username": (
"'%s'" % request.user
if request.user.is_authenticated
- else 'anonymous'
+ else "anonymous"
),
- 'form_ctx': form_ctx,
+ "form_ctx": form_ctx,
}
)
@@ -131,10 +130,9 @@ class TestCaseMixin:
if type(expected) == dict:
parsed = urlparse(actual)
for part, expected_part in expected.items():
- if part == 'query':
+ if part == "query":
self.assertDictEqual(
- parse_qs(parsed.query),
- expected.get('query', {}),
+ parse_qs(parsed.query), expected.get("query", {})
)
else:
self.assertEqual(getattr(parsed, part), expected_part)
@@ -178,7 +176,9 @@ class ViewTestCaseMixin(TestCaseMixin):
During setup, three users are created with their kfet account:
- 'user': a basic user without any permission, account trigramme: 000,
- 'team': a user with kfet.is_team permission, account trigramme: 100,
- - 'root': a superuser, account trigramme: 200.
+ - 'root': a superuser, account trigramme: 200,
+ - 'liq': if class attribute 'with_liq' is 'True', account
+ trigramme: LIQ.
Their password is their username.
One can create additionnal users with 'get_users_extra' method, or prevent
@@ -213,14 +213,17 @@ class ViewTestCaseMixin(TestCaseMixin):
can be given by defining an attribute '_data'.
"""
+
url_name = None
url_expected = None
- http_methods = ['GET']
+ http_methods = ["GET"]
auth_user = None
auth_forbidden = []
+ with_liq = False
+
def setUp(self):
"""
Warning: Do not forget to call super().setUp() in subclasses.
@@ -228,7 +231,7 @@ class ViewTestCaseMixin(TestCaseMixin):
# Signals handlers on login/logout send messages.
# Due to the way the Django' test Client performs login, this raise an
# error. As workaround, we mock the Django' messages module.
- patcher_messages = mock.patch('gestioncof.signals.messages')
+ patcher_messages = mock.patch("gestioncof.signals.messages")
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
@@ -262,14 +265,17 @@ class ViewTestCaseMixin(TestCaseMixin):
"""
# Format desc: username, password, trigramme
- return {
+ users_base = {
# user, user, 000
- 'user': create_user(),
+ "user": create_user(),
# team, team, 100
- 'team': create_team(),
+ "team": create_team(),
# root, root, 200
- 'root': create_root(),
+ "root": create_root(),
}
+ if self.with_liq:
+ users_base["liq"] = create_user("liq", "LIQ")
+ return users_base
@cached_property
def users_base(self):
@@ -293,7 +299,7 @@ class ViewTestCaseMixin(TestCaseMixin):
def register_user(self, label, user):
self.users[label] = user
- if hasattr(user.profile, 'account_kfet'):
+ if hasattr(user.profile, "account_kfet"):
self.accounts[label] = user.profile.account_kfet
def get_user(self, label):
@@ -303,22 +309,25 @@ class ViewTestCaseMixin(TestCaseMixin):
@property
def urls_conf(self):
- return [{
- 'name': self.url_name,
- 'args': getattr(self, 'url_args', []),
- 'kwargs': getattr(self, 'url_kwargs', {}),
- 'expected': self.url_expected,
- }]
+ return [
+ {
+ "name": self.url_name,
+ "args": getattr(self, "url_args", []),
+ "kwargs": getattr(self, "url_kwargs", {}),
+ "expected": self.url_expected,
+ }
+ ]
@property
def t_urls(self):
return [
reverse(
- url_conf['name'],
- args=url_conf.get('args', []),
- kwargs=url_conf.get('kwargs', {}),
+ url_conf["name"],
+ args=url_conf.get("args", []),
+ kwargs=url_conf.get("kwargs", {}),
)
- for url_conf in self.urls_conf]
+ for url_conf in self.urls_conf
+ ]
@property
def url(self):
@@ -326,7 +335,7 @@ class ViewTestCaseMixin(TestCaseMixin):
def test_urls(self):
for url, conf in zip(self.t_urls, self.urls_conf):
- self.assertEqual(url, conf['expected'])
+ self.assertEqual(url, conf["expected"])
def test_forbidden(self):
for method in self.http_methods:
@@ -341,7 +350,7 @@ class ViewTestCaseMixin(TestCaseMixin):
client.login(username=user, password=user)
send_request = getattr(client, method)
- data = getattr(self, '{}_data'.format(method), {})
+ data = getattr(self, "{}_data".format(method), {})
r = send_request(url, data)
self.assertForbidden(r)
diff --git a/kfet/tests/utils.py b/kfet/tests/utils.py
index f3222e14..f1b6933a 100644
--- a/kfet/tests/utils.py
+++ b/kfet/tests/utils.py
@@ -3,7 +3,6 @@ from django.contrib.auth.models import Permission
from ..models import Account
-
User = get_user_model()
@@ -23,27 +22,27 @@ def _create_user_and_account(user_attrs, account_attrs, perms=None):
the account password is 'kfetpwd_'.
"""
- user_pwd = user_attrs.pop('password', user_attrs['username'])
+ user_pwd = user_attrs.pop("password", user_attrs["username"])
user = User.objects.create(**user_attrs)
user.set_password(user_pwd)
user.save()
- account_attrs['cofprofile'] = user.profile
- kfet_pwd = account_attrs.pop('password', 'kfetpwd_{}'.format(user_pwd))
+ account_attrs["cofprofile"] = user.profile
+ kfet_pwd = account_attrs.pop("password", "kfetpwd_{}".format(user_pwd))
account = Account.objects.create(**account_attrs)
if perms is not None:
user = user_add_perms(user, perms)
- if 'kfet.is_team' in perms:
+ if "kfet.is_team" in perms:
account.change_pwd(kfet_pwd)
account.save()
return user
-def create_user(username='user', trigramme='000', **kwargs):
+def create_user(username="user", trigramme="000", **kwargs):
"""
Create a user without any permission and its kfet account.
@@ -65,20 +64,20 @@ def create_user(username='user', trigramme='000', **kwargs):
* trigramme: 000
"""
- user_attrs = kwargs.setdefault('user_attrs', {})
+ user_attrs = kwargs.setdefault("user_attrs", {})
- user_attrs.setdefault('username', username)
- user_attrs.setdefault('first_name', 'first')
- user_attrs.setdefault('last_name', 'last')
- user_attrs.setdefault('email', 'mail@user.net')
+ user_attrs.setdefault("username", username)
+ user_attrs.setdefault("first_name", "first")
+ user_attrs.setdefault("last_name", "last")
+ user_attrs.setdefault("email", "mail@user.net")
- account_attrs = kwargs.setdefault('account_attrs', {})
- account_attrs.setdefault('trigramme', trigramme)
+ account_attrs = kwargs.setdefault("account_attrs", {})
+ account_attrs.setdefault("trigramme", trigramme)
return _create_user_and_account(**kwargs)
-def create_team(username='team', trigramme='100', **kwargs):
+def create_team(username="team", trigramme="100", **kwargs):
"""
Create a user, member of the kfet team, and its kfet account.
@@ -101,23 +100,23 @@ def create_team(username='team', trigramme='100', **kwargs):
* kfet password: kfetpwd_team
"""
- user_attrs = kwargs.setdefault('user_attrs', {})
+ user_attrs = kwargs.setdefault("user_attrs", {})
- user_attrs.setdefault('username', username)
- user_attrs.setdefault('first_name', 'team')
- user_attrs.setdefault('last_name', 'member')
- user_attrs.setdefault('email', 'mail@team.net')
+ user_attrs.setdefault("username", username)
+ user_attrs.setdefault("first_name", "team")
+ user_attrs.setdefault("last_name", "member")
+ user_attrs.setdefault("email", "mail@team.net")
- account_attrs = kwargs.setdefault('account_attrs', {})
- account_attrs.setdefault('trigramme', trigramme)
+ account_attrs = kwargs.setdefault("account_attrs", {})
+ account_attrs.setdefault("trigramme", trigramme)
- perms = kwargs.setdefault('perms', [])
- perms.append('kfet.is_team')
+ perms = kwargs.setdefault("perms", [])
+ perms.append("kfet.is_team")
return _create_user_and_account(**kwargs)
-def create_root(username='root', trigramme='200', **kwargs):
+def create_root(username="root", trigramme="200", **kwargs):
"""
Create a superuser and its kfet account.
@@ -141,16 +140,16 @@ def create_root(username='root', trigramme='200', **kwargs):
* kfet password: kfetpwd_root
"""
- user_attrs = kwargs.setdefault('user_attrs', {})
+ user_attrs = kwargs.setdefault("user_attrs", {})
- user_attrs.setdefault('username', username)
- user_attrs.setdefault('first_name', 'super')
- user_attrs.setdefault('last_name', 'user')
- user_attrs.setdefault('email', 'mail@root.net')
- user_attrs['is_superuser'] = user_attrs['is_staff'] = True
+ user_attrs.setdefault("username", username)
+ user_attrs.setdefault("first_name", "super")
+ user_attrs.setdefault("last_name", "user")
+ user_attrs.setdefault("email", "mail@root.net")
+ user_attrs["is_superuser"] = user_attrs["is_staff"] = True
- account_attrs = kwargs.setdefault('account_attrs', {})
- account_attrs.setdefault('trigramme', trigramme)
+ account_attrs = kwargs.setdefault("account_attrs", {})
+ account_attrs.setdefault("trigramme", trigramme)
return _create_user_and_account(**kwargs)
@@ -159,10 +158,9 @@ def get_perms(*labels):
"""Return Permission instances from a list of '.'."""
perms = {}
for label in set(labels):
- app_label, codename = label.split('.', 1)
+ app_label, codename = label.split(".", 1)
perms[label] = Permission.objects.get(
- content_type__app_label=app_label,
- codename=codename,
+ content_type__app_label=app_label, codename=codename
)
return perms
diff --git a/kfet/urls.py b/kfet/urls.py
index 96fd4ddf..531e0cc9 100644
--- a/kfet/urls.py
+++ b/kfet/urls.py
@@ -4,240 +4,287 @@ from django.contrib.auth.decorators import permission_required
from kfet import autocomplete, views
from kfet.decorators import teamkfet_required
-
urlpatterns = [
- url(r'^login/generic$', views.login_generic,
- name='kfet.login.generic'),
- url(r'^history$', views.history,
- name='kfet.history'),
-
+ url(r"^login/generic$", views.login_generic, name="kfet.login.generic"),
+ url(r"^history$", views.history, name="kfet.history"),
# -----
# Account urls
# -----
-
# Account - General
- url(r'^accounts/$', views.account,
- name='kfet.account'),
- url(r'^accounts/is_validandfree$', views.account_is_validandfree_ajax,
- name='kfet.account.is_validandfree.ajax'),
-
+ url(r"^accounts/$", views.account, name="kfet.account"),
+ url(
+ r"^accounts/is_validandfree$",
+ views.account_is_validandfree_ajax,
+ name="kfet.account.is_validandfree.ajax",
+ ),
# Account - Create
- url(r'^accounts/new$', views.account_create,
- name='kfet.account.create'),
- url(r'^accounts/new_special$', views.account_create_special,
- name='kfet.account.create_special'),
- url(r'^accounts/new/user/(?P.+)$', views.account_create_ajax,
- name='kfet.account.create.fromuser'),
- url(r'^accounts/new/clipper/(?P[\w-]+)/(?P.*)$',
+ url(r"^accounts/new$", views.account_create, name="kfet.account.create"),
+ url(
+ r"^accounts/new/user/(?P.+)$",
views.account_create_ajax,
- name='kfet.account.create.fromclipper'),
- url(r'^accounts/new/empty$', views.account_create_ajax,
- name='kfet.account.create.empty'),
- url(r'^autocomplete/account_new$', autocomplete.account_create,
- name='kfet.account.create.autocomplete'),
-
+ name="kfet.account.create.fromuser",
+ ),
+ url(
+ r"^accounts/new/clipper/(?P[\w-]+)/(?P.*)$",
+ views.account_create_ajax,
+ name="kfet.account.create.fromclipper",
+ ),
+ url(
+ r"^accounts/new/empty$",
+ views.account_create_ajax,
+ name="kfet.account.create.empty",
+ ),
+ url(
+ r"^autocomplete/account_new$",
+ autocomplete.account_create,
+ name="kfet.account.create.autocomplete",
+ ),
# Account - Search
- url(r'^autocomplete/account_search$', autocomplete.account_search,
- name='kfet.account.search.autocomplete'),
-
+ url(
+ r"^autocomplete/account_search$",
+ autocomplete.account_search,
+ name="kfet.account.search.autocomplete",
+ ),
# Account - Read
- url(r'^accounts/(?P.{3})$', views.account_read,
- name='kfet.account.read'),
-
+ url(
+ r"^accounts/(?P.{3})$", views.account_read, name="kfet.account.read"
+ ),
# Account - Update
- url(r'^accounts/(?P.{3})/edit$', views.account_update,
- name='kfet.account.update'),
-
+ url(
+ r"^accounts/(?P.{3})/edit$",
+ views.account_update,
+ name="kfet.account.update",
+ ),
# Account - Groups
- url(r'^accounts/groups$', views.account_group,
- name='kfet.account.group'),
- url(r'^accounts/groups/new$',
- permission_required('kfet.manage_perms')
- (views.AccountGroupCreate.as_view()),
- name='kfet.account.group.create'),
- url(r'^accounts/groups/(?P\d+)/edit$',
- permission_required('kfet.manage_perms')
- (views.AccountGroupUpdate.as_view()),
- name='kfet.account.group.update'),
-
- url(r'^accounts/negatives$',
- permission_required('kfet.view_negs')
- (views.AccountNegativeList.as_view()),
- name='kfet.account.negative'),
-
+ url(r"^accounts/groups$", views.account_group, name="kfet.account.group"),
+ url(
+ r"^accounts/groups/new$",
+ permission_required("kfet.manage_perms")(views.AccountGroupCreate.as_view()),
+ name="kfet.account.group.create",
+ ),
+ url(
+ r"^accounts/groups/(?P\d+)/edit$",
+ permission_required("kfet.manage_perms")(views.AccountGroupUpdate.as_view()),
+ name="kfet.account.group.update",
+ ),
+ url(
+ r"^accounts/negatives$",
+ permission_required("kfet.view_negs")(views.AccountNegativeList.as_view()),
+ name="kfet.account.negative",
+ ),
# Account - Statistics
- url(r'^accounts/(?P.{3})/stat/operations/list$',
+ url(
+ r"^accounts/(?P.{3})/stat/operations/list$",
views.AccountStatOperationList.as_view(),
- name='kfet.account.stat.operation.list'),
- url(r'^accounts/(?P.{3})/stat/operations$',
+ name="kfet.account.stat.operation.list",
+ ),
+ url(
+ r"^accounts/(?P.{3})/stat/operations$",
views.AccountStatOperation.as_view(),
- name='kfet.account.stat.operation'),
-
- url(r'^accounts/(?P.{3})/stat/balance/list$',
+ name="kfet.account.stat.operation",
+ ),
+ url(
+ r"^accounts/(?P.{3})/stat/balance/list$",
views.AccountStatBalanceList.as_view(),
- name='kfet.account.stat.balance.list'),
- url(r'^accounts/(?P.{3})/stat/balance$',
+ name="kfet.account.stat.balance.list",
+ ),
+ url(
+ r"^accounts/(?P.{3})/stat/balance$",
views.AccountStatBalance.as_view(),
- name='kfet.account.stat.balance'),
-
+ name="kfet.account.stat.balance",
+ ),
# -----
# Checkout urls
# -----
-
# Checkout - General
- url('^checkouts/$',
+ url(
+ "^checkouts/$",
teamkfet_required(views.CheckoutList.as_view()),
- name='kfet.checkout'),
+ name="kfet.checkout",
+ ),
# Checkout - Create
- url('^checkouts/new$',
+ url(
+ "^checkouts/new$",
teamkfet_required(views.CheckoutCreate.as_view()),
- name='kfet.checkout.create'),
+ name="kfet.checkout.create",
+ ),
# Checkout - Read
- url('^checkouts/(?P\d+)$',
+ url(
+ "^checkouts/(?P\d+)$",
teamkfet_required(views.CheckoutRead.as_view()),
- name='kfet.checkout.read'),
+ name="kfet.checkout.read",
+ ),
# Checkout - Update
- url('^checkouts/(?P\d+)/edit$',
+ url(
+ "^checkouts/(?P\d+)/edit$",
teamkfet_required(views.CheckoutUpdate.as_view()),
- name='kfet.checkout.update'),
-
+ name="kfet.checkout.update",
+ ),
# -----
# Checkout Statement urls
# -----
-
# Checkout Statement - General
- url('^checkouts/statements/$',
+ url(
+ "^checkouts/statements/$",
teamkfet_required(views.CheckoutStatementList.as_view()),
- name='kfet.checkoutstatement'),
+ name="kfet.checkoutstatement",
+ ),
# Checkout Statement - Create
- url('^checkouts/(?P\d+)/statements/add',
+ url(
+ "^checkouts/(?P\d+)/statements/add",
teamkfet_required(views.CheckoutStatementCreate.as_view()),
- name='kfet.checkoutstatement.create'),
+ name="kfet.checkoutstatement.create",
+ ),
# Checkout Statement - Update
- url('^checkouts/(?P\d+)/statements/(?P\d+)/edit',
+ url(
+ "^checkouts/(?P\d+)/statements/(?P\d+)/edit",
teamkfet_required(views.CheckoutStatementUpdate.as_view()),
- name='kfet.checkoutstatement.update'),
-
+ name="kfet.checkoutstatement.update",
+ ),
# -----
# Article urls
# -----
-
# Category - General
- url('^categories/$',
+ url(
+ "^categories/$",
teamkfet_required(views.CategoryList.as_view()),
- name='kfet.category'),
+ name="kfet.category",
+ ),
# Category - Update
- url('^categories/(?P\d+)/edit$',
+ url(
+ "^categories/(?P\d+)/edit$",
teamkfet_required(views.CategoryUpdate.as_view()),
- name='kfet.category.update'),
+ name="kfet.category.update",
+ ),
# Article - General
- url('^articles/$',
+ url(
+ "^articles/$",
teamkfet_required(views.ArticleList.as_view()),
- name='kfet.article'),
+ name="kfet.article",
+ ),
# Article - Create
- url('^articles/new$',
+ url(
+ "^articles/new$",
teamkfet_required(views.ArticleCreate.as_view()),
- name='kfet.article.create'),
+ name="kfet.article.create",
+ ),
# Article - Read
- url('^articles/(?P\d+)$',
+ url(
+ "^articles/(?P\d+)$",
teamkfet_required(views.ArticleRead.as_view()),
- name='kfet.article.read'),
+ name="kfet.article.read",
+ ),
# Article - Update
- url('^articles/(?P\d+)/edit$',
+ url(
+ "^articles/(?P\d+)/edit$",
teamkfet_required(views.ArticleUpdate.as_view()),
- name='kfet.article.update'),
+ name="kfet.article.update",
+ ),
# Article - Statistics
- url(r'^articles/(?P\d+)/stat/sales/list$',
+ url(
+ r"^articles/(?P\d+)/stat/sales/list$",
views.ArticleStatSalesList.as_view(),
- name='kfet.article.stat.sales.list'),
- url(r'^articles/(?P\d+)/stat/sales$',
+ name="kfet.article.stat.sales.list",
+ ),
+ url(
+ r"^articles/(?P\d+)/stat/sales$",
views.ArticleStatSales.as_view(),
- name='kfet.article.stat.sales'),
-
+ name="kfet.article.stat.sales",
+ ),
# -----
# K-Psul urls
# -----
-
- url('^k-psul/$', views.kpsul, name='kfet.kpsul'),
- url('^k-psul/checkout_data$', views.kpsul_checkout_data,
- name='kfet.kpsul.checkout_data'),
- url('^k-psul/perform_operations$', views.kpsul_perform_operations,
- name='kfet.kpsul.perform_operations'),
- url('^k-psul/cancel_operations$', views.kpsul_cancel_operations,
- name='kfet.kpsul.cancel_operations'),
- url('^k-psul/articles_data', views.kpsul_articles_data,
- name='kfet.kpsul.articles_data'),
- url('^k-psul/update_addcost$', views.kpsul_update_addcost,
- name='kfet.kpsul.update_addcost'),
- url('^k-psul/get_settings$', views.kpsul_get_settings,
- name='kfet.kpsul.get_settings'),
-
+ url("^k-psul/$", views.kpsul, name="kfet.kpsul"),
+ url(
+ "^k-psul/checkout_data$",
+ views.kpsul_checkout_data,
+ name="kfet.kpsul.checkout_data",
+ ),
+ url(
+ "^k-psul/perform_operations$",
+ views.kpsul_perform_operations,
+ name="kfet.kpsul.perform_operations",
+ ),
+ url(
+ "^k-psul/cancel_operations$",
+ views.kpsul_cancel_operations,
+ name="kfet.kpsul.cancel_operations",
+ ),
+ url(
+ "^k-psul/articles_data",
+ views.kpsul_articles_data,
+ name="kfet.kpsul.articles_data",
+ ),
+ url(
+ "^k-psul/update_addcost$",
+ views.kpsul_update_addcost,
+ name="kfet.kpsul.update_addcost",
+ ),
+ url(
+ "^k-psul/get_settings$",
+ views.kpsul_get_settings,
+ name="kfet.kpsul.get_settings",
+ ),
# -----
# JSON urls
# -----
-
- url(r'^history.json$', views.history_json,
- name='kfet.history.json'),
- url(r'^accounts/read.json$', views.account_read_json,
- name='kfet.account.read.json'),
-
-
+ url(r"^history.json$", views.history_json, name="kfet.history.json"),
+ url(
+ r"^accounts/read.json$", views.account_read_json, name="kfet.account.read.json"
+ ),
# -----
# Settings urls
# -----
-
- url(r'^settings/$', views.config_list,
- name='kfet.settings'),
- url(r'^settings/edit$', views.config_update,
- name='kfet.settings.update'),
-
-
+ url(r"^settings/$", views.config_list, name="kfet.settings"),
+ url(r"^settings/edit$", views.config_update, name="kfet.settings.update"),
# -----
# Transfers urls
# -----
-
- url(r'^transfers/$', views.transfers,
- name='kfet.transfers'),
- url(r'^transfers/new$', views.transfers_create,
- name='kfet.transfers.create'),
- url(r'^transfers/perform$', views.perform_transfers,
- name='kfet.transfers.perform'),
- url(r'^transfers/cancel$', views.cancel_transfers,
- name='kfet.transfers.cancel'),
-
+ url(r"^transfers/$", views.transfers, name="kfet.transfers"),
+ url(r"^transfers/new$", views.transfers_create, name="kfet.transfers.create"),
+ url(r"^transfers/perform$", views.perform_transfers, name="kfet.transfers.perform"),
+ url(r"^transfers/cancel$", views.cancel_transfers, name="kfet.transfers.cancel"),
# -----
# Inventories urls
# -----
-
- url(r'^inventaires/$',
+ url(
+ r"^inventaires/$",
teamkfet_required(views.InventoryList.as_view()),
- name='kfet.inventory'),
- url(r'^inventaires/new$', views.inventory_create,
- name='kfet.inventory.create'),
- url(r'^inventaires/(?P\d+)$',
+ name="kfet.inventory",
+ ),
+ url(r"^inventaires/new$", views.inventory_create, name="kfet.inventory.create"),
+ url(
+ r"^inventaires/(?P\d+)$",
teamkfet_required(views.InventoryRead.as_view()),
- name='kfet.inventory.read'),
-
+ name="kfet.inventory.read",
+ ),
# -----
# Order urls
# -----
-
- url(r'^orders/$',
- teamkfet_required(views.OrderList.as_view()),
- name='kfet.order'),
- url(r'^orders/(?P\d+)$',
+ url(r"^orders/$", teamkfet_required(views.OrderList.as_view()), name="kfet.order"),
+ url(
+ r"^orders/(?P\d+)$",
teamkfet_required(views.OrderRead.as_view()),
- name='kfet.order.read'),
- url(r'^orders/suppliers/(?P\d+)/edit$',
+ name="kfet.order.read",
+ ),
+ url(
+ r"^orders/suppliers/(?P\d+)/edit$",
teamkfet_required(views.SupplierUpdate.as_view()),
- name='kfet.order.supplier.update'),
- url(r'^orders/suppliers/(?P\d+)/new-order$', views.order_create,
- name='kfet.order.new'),
- url(r'^orders/(?P\d+)/to_inventory$', views.order_to_inventory,
- name='kfet.order.to_inventory'),
+ name="kfet.order.supplier.update",
+ ),
+ url(
+ r"^orders/suppliers/(?P\d+)/new-order$",
+ views.order_create,
+ name="kfet.order.new",
+ ),
+ url(
+ r"^orders/(?P\d+)/to_inventory$",
+ views.order_to_inventory,
+ name="kfet.order.to_inventory",
+ ),
]
urlpatterns += [
# K-Fêt Open urls
- url('^open/', include('kfet.open.urls')),
+ url("^open/", include("kfet.open.urls"))
]
diff --git a/kfet/utils.py b/kfet/utils.py
index 3d06bb0b..0c4f170a 100644
--- a/kfet/utils.py
+++ b/kfet/utils.py
@@ -1,11 +1,10 @@
-import math
import json
-
-from django.core.cache import cache
-from django.core.serializers.json import DjangoJSONEncoder
+import math
from channels.channel import Group
from channels.generic.websockets import JsonWebsocketConsumer
+from django.core.cache import cache
+from django.core.serializers.json import DjangoJSONEncoder
from .config import kfet_config
@@ -16,8 +15,10 @@ def to_ukf(balance, is_cof=False):
grant = (1 + subvention / 100) if is_cof else 1
return math.floor(balance * 10 * grant)
+
# Storage
+
class CachedMixin:
"""Object with cached properties.
@@ -27,8 +28,9 @@ class CachedMixin:
cache_prefix (str): Used to prefix keys in cache.
"""
+
cached = {}
- cache_prefix = ''
+ cache_prefix = ""
def __init__(self, cache_prefix=None, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -36,12 +38,12 @@ class CachedMixin:
self.cache_prefix = cache_prefix
def cachekey(self, attr):
- return '{}__{}'.format(self.cache_prefix, attr)
+ return "{}__{}".format(self.cache_prefix, attr)
def __getattr__(self, attr):
if attr in self.cached:
return cache.get(self.cachekey(attr), self.cached.get(attr))
- elif hasattr(super(), '__getattr__'):
+ elif hasattr(super(), "__getattr__"):
return super().__getattr__(attr)
else:
raise AttributeError("can't get attribute")
@@ -49,19 +51,18 @@ class CachedMixin:
def __setattr__(self, attr, value):
if attr in self.cached:
cache.set(self.cachekey(attr), value)
- elif hasattr(super(), '__setattr__'):
+ elif hasattr(super(), "__setattr__"):
super().__setattr__(attr, value)
else:
raise AttributeError("can't set attribute")
def clear_cache(self):
- cache.delete_many([
- self.cachekey(attr) for attr in self.cached.keys()
- ])
+ cache.delete_many([self.cachekey(attr) for attr in self.cached.keys()])
# Consumers
+
class DjangoJsonWebsocketConsumer(JsonWebsocketConsumer):
"""Custom Json Websocket Consumer.
@@ -84,6 +85,7 @@ class PermConsumerMixin:
message.user is appended as argument to each connection_groups method call.
"""
+
http_user = True # Enable message.user
perms_connect = []
@@ -107,7 +109,9 @@ class PermConsumerMixin:
# We add user to connection_groups call.
groups = self.connection_groups(user=message.user, **kwargs)
for group in groups:
- Group(group, channel_layer=message.channel_layer).discard(message.reply_channel)
+ Group(group, channel_layer=message.channel_layer).discard(
+ message.reply_channel
+ )
self.disconnect(message, **kwargs)
def connection_groups(self, user, **kwargs):
diff --git a/kfet/views.py b/kfet/views.py
index 29f7411a..a2a69930 100644
--- a/kfet/views.py
+++ b/kfet/views.py
@@ -1,55 +1,88 @@
import ast
-from urllib.parse import urlencode
-
-from django.shortcuts import render, get_object_or_404, redirect
-from django.core.exceptions import PermissionDenied
-from django.core.cache import cache
-from django.views.generic import ListView, DetailView, TemplateView, FormView
-from django.views.generic.detail import BaseDetailView
-from django.views.generic.edit import CreateView, UpdateView
-from django.core.urlresolvers import reverse, reverse_lazy
-from django.contrib import messages
-from django.contrib.messages.views import SuccessMessageMixin
-from django.contrib.auth.decorators import login_required, permission_required
-from django.contrib.auth.models import User, Permission
-from django.http import JsonResponse, Http404
-from django.forms import formset_factory
-from django.db import transaction
-from django.db.models import F, Sum, Prefetch, Count
-from django.db.models.functions import Coalesce
-from django.utils import timezone
-from django.utils.decorators import method_decorator
-
-from gestioncof.models import CofProfile
-
-from kfet.config import kfet_config
-from kfet.decorators import teamkfet_required
-from kfet.models import (
- Account, Checkout, Article, AccountNegative,
- CheckoutStatement, Supplier, SupplierArticle, Inventory,
- InventoryArticle, Order, OrderArticle, Operation, OperationGroup,
- TransferGroup, Transfer, ArticleCategory)
-from kfet.forms import (
- AccountTriForm, AccountBalanceForm, AccountNoTriForm, UserForm, CofForm,
- UserRestrictTeamForm, UserGroupForm, AccountForm, CofRestrictForm,
- AccountPwdForm, AccountNegativeForm, UserRestrictForm, AccountRestrictForm,
- CheckoutForm, CheckoutRestrictForm, CheckoutStatementCreateForm,
- CheckoutStatementUpdateForm, ArticleForm, ArticleRestrictForm,
- KPsulOperationGroupForm, KPsulAccountForm, KPsulCheckoutForm,
- KPsulOperationFormSet, AddcostForm, FilterHistoryForm,
- TransferFormSet, InventoryArticleForm, OrderArticleForm,
- OrderArticleToInventoryForm, CategoryForm, KFetConfigForm
- )
-from collections import defaultdict
-from kfet import consumers
-from datetime import timedelta
-from decimal import Decimal
import heapq
import statistics
-from kfet.statistic import ScaleMixin, last_stats_manifest, tot_ventes, WeekScale
+from collections import defaultdict
+from decimal import Decimal
+from urllib.parse import urlencode
+
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required, permission_required
+from django.contrib.auth.models import Permission, User
+from django.contrib.messages.views import SuccessMessageMixin
+from django.core.exceptions import PermissionDenied
+from django.core.urlresolvers import reverse, reverse_lazy
+from django.db import transaction
+from django.db.models import Count, F, Prefetch, Sum
+from django.forms import formset_factory
+from django.http import Http404, JsonResponse
+from django.shortcuts import get_object_or_404, redirect, render
+from django.utils import timezone
+from django.utils.decorators import method_decorator
+from django.views.generic import DetailView, FormView, ListView, TemplateView
+from django.views.generic.detail import BaseDetailView
+from django.views.generic.edit import CreateView, UpdateView
+
+from gestioncof.models import CofProfile
+from kfet import consumers
+from kfet.config import kfet_config
+from kfet.decorators import teamkfet_required
+from kfet.forms import (
+ AccountForm,
+ AccountNegativeForm,
+ AccountNoTriForm,
+ AccountPwdForm,
+ AccountRestrictForm,
+ AccountTriForm,
+ AddcostForm,
+ ArticleForm,
+ ArticleRestrictForm,
+ CategoryForm,
+ CheckoutForm,
+ CheckoutRestrictForm,
+ CheckoutStatementCreateForm,
+ CheckoutStatementUpdateForm,
+ CofForm,
+ CofRestrictForm,
+ FilterHistoryForm,
+ InventoryArticleForm,
+ KFetConfigForm,
+ KPsulAccountForm,
+ KPsulCheckoutForm,
+ KPsulOperationFormSet,
+ KPsulOperationGroupForm,
+ OrderArticleForm,
+ OrderArticleToInventoryForm,
+ TransferFormSet,
+ UserForm,
+ UserGroupForm,
+ UserRestrictForm,
+ UserRestrictTeamForm,
+)
+from kfet.models import (
+ Account,
+ AccountNegative,
+ Article,
+ ArticleCategory,
+ Checkout,
+ CheckoutStatement,
+ Inventory,
+ InventoryArticle,
+ Operation,
+ OperationGroup,
+ Order,
+ OrderArticle,
+ Supplier,
+ SupplierArticle,
+ Transfer,
+ TransferGroup,
+)
+from kfet.statistic import ScaleMixin, WeekScale, last_stats_manifest
from .auth.views import ( # noqa
- account_group, login_generic, AccountGroupCreate, AccountGroupUpdate,
+ AccountGroupCreate,
+ AccountGroupUpdate,
+ account_group,
+ login_generic,
)
@@ -57,103 +90,34 @@ def put_cleaned_data_in_dict(dict, form):
for field in form.cleaned_data:
dict[field] = form.cleaned_data[field]
+
# -----
# Account views
# -----
# Account - General
+
@login_required
@teamkfet_required
def account(request):
- accounts = Account.objects.select_related('cofprofile__user').order_by('trigramme')
- return render(request, "kfet/account.html", { 'accounts' : accounts })
+ accounts = Account.objects.select_related("cofprofile__user").order_by("trigramme")
+ return render(request, "kfet/account.html", {"accounts": accounts})
+
@login_required
@teamkfet_required
def account_is_validandfree_ajax(request):
- if not request.GET.get("trigramme", ''):
+ if not request.GET.get("trigramme", ""):
raise Http404
trigramme = request.GET.get("trigramme")
data = Account.is_validandfree(trigramme)
return JsonResponse(data)
-# Account - Create
-
-@login_required
-@teamkfet_required
-def account_create_special(request):
-
- # Enregistrement
- if request.method == "POST":
- trigramme_form = AccountTriForm(request.POST, initial={'balance':0})
- balance_form = AccountBalanceForm(request.POST)
-
- # Peuplement des forms
- username = request.POST.get('username')
- login_clipper = request.POST.get('login_clipper')
-
- forms = get_account_create_forms(
- request, username=username, login_clipper=login_clipper)
-
- account_form = forms['account_form']
- cof_form = forms['cof_form']
- user_form = forms['user_form']
-
- if all((user_form.is_valid(), cof_form.is_valid(),
- trigramme_form.is_valid(), account_form.is_valid(),
- balance_form.is_valid())):
- # Checking permission
- if not request.user.has_perm('kfet.special_add_account'):
- messages.error(request, 'Permission refusée')
- else:
- data = {}
- # Fill data for Account.save()
- put_cleaned_data_in_dict(data, user_form)
- put_cleaned_data_in_dict(data, cof_form)
-
- try:
- account = trigramme_form.save(data = data)
- account_form = AccountNoTriForm(request.POST, instance=account)
- account_form.save()
- balance_form = AccountBalanceForm(request.POST, instance=account)
- balance_form.save()
- amount = balance_form.cleaned_data['balance']
- checkout = Checkout.objects.get(name='Initial')
- is_cof = account.is_cof
- opegroup = OperationGroup.objects.create(
- on_acc=account,
- checkout=checkout,
- amount = amount,
- is_cof = account.is_cof)
- ope = Operation.objects.create(
- group = opegroup,
- type = Operation.INITIAL,
- amount = amount)
- messages.success(request, 'Compte créé : %s' % account.trigramme)
- return redirect('kfet.account.create')
- except Account.UserHasAccount as e:
- messages.error(request, \
- "Cet utilisateur a déjà un compte K-Fêt : %s" % e.trigramme)
- else:
- initial = { 'trigramme': request.GET.get('trigramme', '') }
- trigramme_form = AccountTriForm(initial = initial)
- balance_form = AccountBalanceForm(initial = {'balance': 0})
- account_form = None
- cof_form = None
- user_form = None
-
- return render(request, "kfet/account_create_special.html", {
- 'trigramme_form': trigramme_form,
- 'account_form': account_form,
- 'cof_form': cof_form,
- 'user_form': user_form,
- 'balance_form': balance_form,
- })
-
# Account - Create
+
@login_required
@teamkfet_required
def account_create(request):
@@ -163,21 +127,28 @@ def account_create(request):
trigramme_form = AccountTriForm(request.POST)
# Peuplement des forms
- username = request.POST.get('username')
- login_clipper = request.POST.get('login_clipper')
+ username = request.POST.get("username")
+ login_clipper = request.POST.get("login_clipper")
forms = get_account_create_forms(
- request, username=username, login_clipper=login_clipper)
+ request, username=username, login_clipper=login_clipper
+ )
- account_form = forms['account_form']
- cof_form = forms['cof_form']
- user_form = forms['user_form']
+ account_form = forms["account_form"]
+ cof_form = forms["cof_form"]
+ user_form = forms["user_form"]
- if all((user_form.is_valid(), cof_form.is_valid(),
- trigramme_form.is_valid(), account_form.is_valid())):
+ if all(
+ (
+ user_form.is_valid(),
+ cof_form.is_valid(),
+ trigramme_form.is_valid(),
+ account_form.is_valid(),
+ )
+ ):
# Checking permission
- if not request.user.has_perm('kfet.add_account'):
- messages.error(request, 'Permission refusée')
+ if not request.user.has_perm("kfet.add_account"):
+ messages.error(request, "Permission refusée")
else:
data = {}
# Fill data for Account.save()
@@ -185,35 +156,44 @@ def account_create(request):
put_cleaned_data_in_dict(data, cof_form)
try:
- account = trigramme_form.save(data = data)
+ account = trigramme_form.save(data=data)
account_form = AccountNoTriForm(request.POST, instance=account)
account_form.save()
- messages.success(request, 'Compte créé : %s' % account.trigramme)
- return redirect('kfet.account.create')
+ messages.success(request, "Compte créé : %s" % account.trigramme)
+ return redirect("kfet.account.create")
except Account.UserHasAccount as e:
- messages.error(request, \
- "Cet utilisateur a déjà un compte K-Fêt : %s" % e.trigramme)
+ messages.error(
+ request,
+ "Cet utilisateur a déjà un compte K-Fêt : %s" % e.trigramme,
+ )
else:
- initial = { 'trigramme': request.GET.get('trigramme', '') }
- trigramme_form = AccountTriForm(initial = initial)
+ initial = {"trigramme": request.GET.get("trigramme", "")}
+ trigramme_form = AccountTriForm(initial=initial)
account_form = None
cof_form = None
user_form = None
- return render(request, "kfet/account_create.html", {
- 'trigramme_form': trigramme_form,
- 'account_form': account_form,
- 'cof_form': cof_form,
- 'user_form': user_form,
- })
+ return render(
+ request,
+ "kfet/account_create.html",
+ {
+ "trigramme_form": trigramme_form,
+ "account_form": account_form,
+ "cof_form": cof_form,
+ "user_form": user_form,
+ },
+ )
+
def account_form_set_readonly_fields(user_form, cof_form):
- user_form.fields['username'].widget.attrs['readonly'] = True
- cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
- cof_form.fields['is_cof'].widget.attrs['disabled'] = True
+ user_form.fields["username"].widget.attrs["readonly"] = True
+ cof_form.fields["login_clipper"].widget.attrs["readonly"] = True
+ cof_form.fields["is_cof"].widget.attrs["disabled"] = True
-def get_account_create_forms(request=None, username=None, login_clipper=None,
- fullname=None):
+
+def get_account_create_forms(
+ request=None, username=None, login_clipper=None, fullname=None
+):
user = None
clipper = False
if login_clipper and (login_clipper == username or not username):
@@ -231,26 +211,27 @@ def get_account_create_forms(request=None, username=None, login_clipper=None,
# UserForm - Prefill
user_initial = {
- 'username' : login_clipper,
- 'email' : "%s@clipper.ens.fr" % login_clipper}
+ "username": login_clipper,
+ "email": "%s@clipper.ens.fr" % login_clipper,
+ }
if fullname:
# Prefill du nom et prénom
names = fullname.split()
# Le premier, c'est le prénom
- user_initial['first_name'] = names[0]
+ user_initial["first_name"] = names[0]
if len(names) > 1:
# Si d'autres noms -> tous dans le nom de famille
- user_initial['last_name'] = " ".join(names[1:])
+ user_initial["last_name"] = " ".join(names[1:])
# CofForm - Prefill
- cof_initial = { 'login_clipper': login_clipper }
+ cof_initial = {"login_clipper": login_clipper}
# Form créations
if request:
user_form = UserForm(request.POST, initial=user_initial)
- cof_form = CofForm(request.POST, initial=cof_initial)
+ cof_form = CofForm(request.POST, initial=cof_initial)
else:
user_form = UserForm(initial=user_initial)
- cof_form = CofForm(initial=cof_initial)
+ cof_form = CofForm(initial=cof_initial)
# Protection (read-only) des champs username et login_clipper
account_form_set_readonly_fields(user_form, cof_form)
@@ -262,11 +243,11 @@ def get_account_create_forms(request=None, username=None, login_clipper=None,
(cof, _) = CofProfile.objects.get_or_create(user=user)
# UserForm + CofForm - Création à partir des instances existantes
if request:
- user_form = UserForm(request.POST, instance = user)
- cof_form = CofForm(request.POST, instance = cof)
+ user_form = UserForm(request.POST, instance=user)
+ cof_form = CofForm(request.POST, instance=cof)
else:
user_form = UserForm(instance=user)
- cof_form = CofForm(instance=cof)
+ cof_form = CofForm(instance=cof)
# Protection (read-only) des champs username, login_clipper et is_cof
account_form_set_readonly_fields(user_form, cof_form)
except User.DoesNotExist:
@@ -277,66 +258,64 @@ def get_account_create_forms(request=None, username=None, login_clipper=None,
# connaît pas du tout, faut tout remplir
if request:
user_form = UserForm(request.POST)
- cof_form = CofForm(request.POST)
+ cof_form = CofForm(request.POST)
else:
user_form = UserForm()
- cof_form = CofForm()
+ cof_form = CofForm()
# mais on laisse le username en écriture
- cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
- cof_form.fields['is_cof'].widget.attrs['disabled'] = True
+ cof_form.fields["login_clipper"].widget.attrs["readonly"] = True
+ cof_form.fields["is_cof"].widget.attrs["disabled"] = True
if request:
account_form = AccountNoTriForm(request.POST)
else:
account_form = AccountNoTriForm()
- return {
- 'account_form': account_form,
- 'cof_form': cof_form,
- 'user_form': user_form,
- }
+ return {"account_form": account_form, "cof_form": cof_form, "user_form": user_form}
@login_required
@teamkfet_required
-def account_create_ajax(request, username=None, login_clipper=None,
- fullname=None):
+def account_create_ajax(request, username=None, login_clipper=None, fullname=None):
forms = get_account_create_forms(
- request=None, username=username, login_clipper=login_clipper,
- fullname=fullname)
- return render(request, "kfet/account_create_form.html", {
- 'account_form' : forms['account_form'],
- 'cof_form' : forms['cof_form'],
- 'user_form' : forms['user_form'],
- })
+ request=None, username=username, login_clipper=login_clipper, fullname=fullname
+ )
+ return render(
+ request,
+ "kfet/account_create_form.html",
+ {
+ "account_form": forms["account_form"],
+ "cof_form": forms["cof_form"],
+ "user_form": forms["user_form"],
+ },
+ )
# Account - Read
+
@login_required
def account_read(request, trigramme):
account = get_object_or_404(Account, trigramme=trigramme)
# Checking permissions
if not account.readable or (
- not request.user.has_perm('kfet.is_team') and
- request.user != account.user):
+ not request.user.has_perm("kfet.is_team") and request.user != account.user
+ ):
raise PermissionDenied
addcosts = (
- OperationGroup.objects
- .filter(opes__addcost_for=account,
- opes__canceled_at=None)
- .extra({'date': "date(at)"})
- .values('date')
- .annotate(sum_addcosts=Sum('opes__addcost_amount'))
- .order_by('-date')
+ OperationGroup.objects.filter(opes__addcost_for=account, opes__canceled_at=None)
+ .extra({"date": "date(at)"})
+ .values("date")
+ .annotate(sum_addcosts=Sum("opes__addcost_amount"))
+ .order_by("-date")
+ )
+
+ return render(
+ request, "kfet/account_read.html", {"account": account, "addcosts": addcosts}
)
- return render(request, "kfet/account_read.html", {
- 'account': account,
- 'addcosts': addcosts,
- })
# Account - Update
@@ -346,21 +325,19 @@ def account_update(request, trigramme):
account = get_object_or_404(Account, trigramme=trigramme)
# Checking permissions
- if not request.user.has_perm('kfet.is_team') \
- and request.user != account.user:
+ if not request.user.has_perm("kfet.is_team") and request.user != account.user:
raise PermissionDenied
- if request.user.has_perm('kfet.is_team'):
+ if request.user.has_perm("kfet.is_team"):
user_form = UserRestrictTeamForm(instance=account.user)
group_form = UserGroupForm(instance=account.user)
account_form = AccountForm(instance=account)
cof_form = CofRestrictForm(instance=account.cofprofile)
pwd_form = AccountPwdForm()
- if account.balance < 0 and not hasattr(account, 'negative'):
- AccountNegative.objects.create(account=account,
- start=timezone.now())
+ if account.balance < 0 and not hasattr(account, "negative"):
+ AccountNegative.objects.create(account=account, start=timezone.now())
account.refresh_from_db()
- if hasattr(account, 'negative'):
+ if hasattr(account, "negative"):
negative_form = AccountNegativeForm(instance=account.negative)
else:
negative_form = None
@@ -377,21 +354,23 @@ def account_update(request, trigramme):
success = False
missing_perm = True
- if request.user.has_perm('kfet.is_team'):
+ if request.user.has_perm("kfet.is_team"):
account_form = AccountForm(request.POST, instance=account)
- cof_form = CofRestrictForm(request.POST,
- instance=account.cofprofile)
- user_form = UserRestrictTeamForm(request.POST,
- instance=account.user)
+ cof_form = CofRestrictForm(request.POST, instance=account.cofprofile)
+ user_form = UserRestrictTeamForm(request.POST, instance=account.user)
group_form = UserGroupForm(request.POST, instance=account.user)
pwd_form = AccountPwdForm(request.POST)
- if hasattr(account, 'negative'):
- negative_form = AccountNegativeForm(request.POST,
- instance=account.negative)
+ if hasattr(account, "negative"):
+ negative_form = AccountNegativeForm(
+ request.POST, instance=account.negative
+ )
- if (request.user.has_perm('kfet.change_account')
- and account_form.is_valid() and cof_form.is_valid()
- and user_form.is_valid()):
+ if (
+ request.user.has_perm("kfet.change_account")
+ and account_form.is_valid()
+ and cof_form.is_valid()
+ and user_form.is_valid()
+ ):
missing_perm = False
data = {}
# Fill data for Account.save()
@@ -402,44 +381,48 @@ def account_update(request, trigramme):
account_form.save(data=data)
# Checking perm to update password
- if (request.user.has_perm('kfet.change_account_password')
- and pwd_form.is_valid()):
- pwd = pwd_form.cleaned_data['pwd1']
+ if (
+ request.user.has_perm("kfet.change_account_password")
+ and pwd_form.is_valid()
+ ):
+ pwd = pwd_form.cleaned_data["pwd1"]
account.change_pwd(pwd)
account.save()
- messages.success(request, 'Mot de passe mis à jour')
+ messages.success(request, "Mot de passe mis à jour")
# Checking perm to manage perms
- if (request.user.has_perm('kfet.manage_perms')
- and group_form.is_valid()):
+ if request.user.has_perm("kfet.manage_perms") and group_form.is_valid():
group_form.save()
# Checking perm to manage negative
- if hasattr(account, 'negative'):
+ if hasattr(account, "negative"):
balance_offset_old = 0
if account.negative.balance_offset:
balance_offset_old = account.negative.balance_offset
- if (hasattr(account, 'negative')
- and request.user.has_perm('kfet.change_accountnegative')
- and negative_form.is_valid()):
- balance_offset_new = \
- negative_form.cleaned_data['balance_offset']
+ if (
+ hasattr(account, "negative")
+ and request.user.has_perm("kfet.change_accountnegative")
+ and negative_form.is_valid()
+ ):
+ balance_offset_new = negative_form.cleaned_data["balance_offset"]
if not balance_offset_new:
balance_offset_new = 0
- balance_offset_diff = (balance_offset_new
- - balance_offset_old)
+ balance_offset_diff = balance_offset_new - balance_offset_old
Account.objects.filter(pk=account.pk).update(
- balance=F('balance') + balance_offset_diff)
+ balance=F("balance") + balance_offset_diff
+ )
negative_form.save()
- if Account.objects.get(pk=account.pk).balance >= 0 \
- and not balance_offset_new:
+ if (
+ Account.objects.get(pk=account.pk).balance >= 0
+ and not balance_offset_new
+ ):
AccountNegative.objects.get(account=account).delete()
success = True
messages.success(
request,
- 'Informations du compte %s mises à jour'
- % account.trigramme)
+ "Informations du compte %s mises à jour" % account.trigramme,
+ )
# Modification de ses propres informations
if request.user == account.user:
@@ -453,75 +436,79 @@ def account_update(request, trigramme):
user_form.save()
account_form.save()
success = True
- messages.success(request,
- 'Vos informations ont été mises à jour')
+ messages.success(request, "Vos informations ont été mises à jour")
- if request.user.has_perm('kfet.is_team') \
- and pwd_form.is_valid():
- pwd = pwd_form.cleaned_data['pwd1']
+ if request.user.has_perm("kfet.is_team") and pwd_form.is_valid():
+ pwd = pwd_form.cleaned_data["pwd1"]
account.change_pwd(pwd)
account.save()
- messages.success(
- request, 'Votre mot de passe a été mis à jour')
+ messages.success(request, "Votre mot de passe a été mis à jour")
if missing_perm:
- messages.error(request, 'Permission refusée')
+ messages.error(request, "Permission refusée")
if success:
- return redirect('kfet.account.read', account.trigramme)
+ return redirect("kfet.account.read", account.trigramme)
else:
messages.error(
- request, 'Informations non mises à jour. Corrigez les erreurs')
+ request, "Informations non mises à jour. Corrigez les erreurs"
+ )
- return render(request, "kfet/account_update.html", {
- 'account': account,
- 'account_form': account_form,
- 'cof_form': cof_form,
- 'user_form': user_form,
- 'group_form': group_form,
- 'negative_form': negative_form,
- 'pwd_form': pwd_form,
- })
+ return render(
+ request,
+ "kfet/account_update.html",
+ {
+ "account": account,
+ "account_form": account_form,
+ "cof_form": cof_form,
+ "user_form": user_form,
+ "group_form": group_form,
+ "negative_form": negative_form,
+ "pwd_form": pwd_form,
+ },
+ )
class AccountNegativeList(ListView):
- queryset = (
- AccountNegative.objects
- .select_related('account', 'account__cofprofile__user')
- .exclude(account__trigramme='#13')
- )
- template_name = 'kfet/account_negative.html'
- context_object_name = 'negatives'
+ queryset = AccountNegative.objects.select_related(
+ "account", "account__cofprofile__user"
+ ).exclude(account__trigramme="#13")
+ template_name = "kfet/account_negative.html"
+ context_object_name = "negatives"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
real_balances = (neg.account.real_balance for neg in self.object_list)
- context['negatives_sum'] = sum(real_balances)
+ context["negatives_sum"] = sum(real_balances)
return context
+
# -----
# Checkout views
# -----
# Checkout - General
+
class CheckoutList(ListView):
- model = Checkout
- template_name = 'kfet/checkout.html'
- context_object_name = 'checkouts'
+ model = Checkout
+ template_name = "kfet/checkout.html"
+ context_object_name = "checkouts"
+
# Checkout - Create
+
class CheckoutCreate(SuccessMessageMixin, CreateView):
- model = Checkout
- template_name = 'kfet/checkout_create.html'
- form_class = CheckoutForm
- success_message = 'Nouvelle caisse : %(name)s'
+ model = Checkout
+ template_name = "kfet/checkout_create.html"
+ form_class = CheckoutForm
+ success_message = "Nouvelle caisse : %(name)s"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.add_checkout'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.add_checkout"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Creating
@@ -530,127 +517,161 @@ class CheckoutCreate(SuccessMessageMixin, CreateView):
return super().form_valid(form)
+
# Checkout - Read
+
class CheckoutRead(DetailView):
model = Checkout
- template_name = 'kfet/checkout_read.html'
- context_object_name = 'checkout'
+ template_name = "kfet/checkout_read.html"
+ context_object_name = "checkout"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['statements'] = context['checkout'].statements.order_by('-at')
+ context["statements"] = context["checkout"].statements.order_by("-at")
return context
+
# Checkout - Update
+
class CheckoutUpdate(SuccessMessageMixin, UpdateView):
- model = Checkout
- template_name = 'kfet/checkout_update.html'
- form_class = CheckoutRestrictForm
- success_message = 'Informations mises à jour pour la caisse : %(name)s'
+ model = Checkout
+ template_name = "kfet/checkout_update.html"
+ form_class = CheckoutRestrictForm
+ success_message = "Informations mises à jour pour la caisse : %(name)s"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.change_checkout'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.change_checkout"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Updating
return super().form_valid(form)
+
# -----
# Checkout Statement views
# -----
# Checkout Statement - General
+
class CheckoutStatementList(ListView):
- model = CheckoutStatement
- queryset = CheckoutStatement.objects.order_by('-at')
- template_name = 'kfet/checkoutstatement.html'
- context_object_name= 'checkoutstatements'
+ model = CheckoutStatement
+ queryset = CheckoutStatement.objects.order_by("-at")
+ template_name = "kfet/checkoutstatement.html"
+ context_object_name = "checkoutstatements"
+
# Checkout Statement - Create
+
def getAmountTaken(data):
- return Decimal(data.taken_001 * 0.01 + data.taken_002 * 0.02
- + data.taken_005 * 0.05 + data.taken_01 * 0.1
- + data.taken_02 * 0.2 + data.taken_05 * 0.5
- + data.taken_1 * 1 + data.taken_2 * 2
- + data.taken_5 * 5 + data.taken_10 * 10
- + data.taken_20 * 20 + data.taken_50 * 50
- + data.taken_100 * 100 + data.taken_200 * 200
- + data.taken_500 * 500 + float(data.taken_cheque))
+ return Decimal(
+ data.taken_001 * 0.01
+ + data.taken_002 * 0.02
+ + data.taken_005 * 0.05
+ + data.taken_01 * 0.1
+ + data.taken_02 * 0.2
+ + data.taken_05 * 0.5
+ + data.taken_1 * 1
+ + data.taken_2 * 2
+ + data.taken_5 * 5
+ + data.taken_10 * 10
+ + data.taken_20 * 20
+ + data.taken_50 * 50
+ + data.taken_100 * 100
+ + data.taken_200 * 200
+ + data.taken_500 * 500
+ + float(data.taken_cheque)
+ )
+
def getAmountBalance(data):
- return Decimal(data['balance_001'] * 0.01 + data['balance_002'] * 0.02
- + data['balance_005'] * 0.05 + data['balance_01'] * 0.1
- + data['balance_02'] * 0.2 + data['balance_05'] * 0.5
- + data['balance_1'] * 1 + data['balance_2'] * 2
- + data['balance_5'] * 5 + data['balance_10'] * 10
- + data['balance_20'] * 20 + data['balance_50'] * 50
- + data['balance_100'] * 100 + data['balance_200'] * 200
- + data['balance_500'] * 500)
+ return Decimal(
+ data["balance_001"] * 0.01
+ + data["balance_002"] * 0.02
+ + data["balance_005"] * 0.05
+ + data["balance_01"] * 0.1
+ + data["balance_02"] * 0.2
+ + data["balance_05"] * 0.5
+ + data["balance_1"] * 1
+ + data["balance_2"] * 2
+ + data["balance_5"] * 5
+ + data["balance_10"] * 10
+ + data["balance_20"] * 20
+ + data["balance_50"] * 50
+ + data["balance_100"] * 100
+ + data["balance_200"] * 200
+ + data["balance_500"] * 500
+ )
+
class CheckoutStatementCreate(SuccessMessageMixin, CreateView):
- model = CheckoutStatement
- template_name = 'kfet/checkoutstatement_create.html'
- form_class = CheckoutStatementCreateForm
- success_message = 'Nouveau relevé : %(checkout)s - %(at)s'
+ model = CheckoutStatement
+ template_name = "kfet/checkoutstatement_create.html"
+ form_class = CheckoutStatementCreateForm
+ success_message = "Nouveau relevé : %(checkout)s - %(at)s"
def get_success_url(self):
- return reverse_lazy('kfet.checkout.read', kwargs={'pk':self.kwargs['pk_checkout']})
+ return reverse_lazy(
+ "kfet.checkout.read", kwargs={"pk": self.kwargs["pk_checkout"]}
+ )
def get_success_message(self, cleaned_data):
return self.success_message % dict(
- cleaned_data,
- checkout = self.object.checkout.name,
- at = self.object.at)
+ cleaned_data, checkout=self.object.checkout.name, at=self.object.at
+ )
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- checkout = Checkout.objects.get(pk=self.kwargs['pk_checkout'])
- context['checkout'] = checkout
+ checkout = Checkout.objects.get(pk=self.kwargs["pk_checkout"])
+ context["checkout"] = checkout
return context
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.add_checkoutstatement'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.add_checkoutstatement"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Creating
form.instance.amount_taken = getAmountTaken(form.instance)
if not form.instance.not_count:
form.instance.balance_new = getAmountBalance(form.cleaned_data)
- form.instance.checkout_id = self.kwargs['pk_checkout']
+ form.instance.checkout_id = self.kwargs["pk_checkout"]
form.instance.by = self.request.user.profile.account_kfet
return super().form_valid(form)
+
class CheckoutStatementUpdate(SuccessMessageMixin, UpdateView):
model = CheckoutStatement
- template_name = 'kfet/checkoutstatement_update.html'
+ template_name = "kfet/checkoutstatement_update.html"
form_class = CheckoutStatementUpdateForm
- success_message = 'Relevé modifié'
+ success_message = "Relevé modifié"
def get_success_url(self):
- return reverse_lazy('kfet.checkout.read', kwargs={'pk':self.kwargs['pk_checkout']})
+ return reverse_lazy(
+ "kfet.checkout.read", kwargs={"pk": self.kwargs["pk_checkout"]}
+ )
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- checkout = Checkout.objects.get(pk=self.kwargs['pk_checkout'])
- context['checkout'] = checkout
+ checkout = Checkout.objects.get(pk=self.kwargs["pk_checkout"])
+ context["checkout"] = checkout
return context
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.change_checkoutstatement'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.change_checkoutstatement"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Updating
form.instance.amount_taken = getAmountTaken(form.instance)
return super().form_valid(form)
+
# -----
# Category views
# -----
@@ -658,31 +679,30 @@ class CheckoutStatementUpdate(SuccessMessageMixin, UpdateView):
# Category - General
class CategoryList(ListView):
- queryset = (ArticleCategory.objects
- .prefetch_related('articles')
- .order_by('name'))
- template_name = 'kfet/category.html'
- context_object_name = 'categories'
+ queryset = ArticleCategory.objects.prefetch_related("articles").order_by("name")
+ template_name = "kfet/category.html"
+ context_object_name = "categories"
# Category - Update
class CategoryUpdate(SuccessMessageMixin, UpdateView):
model = ArticleCategory
- template_name = 'kfet/category_update.html'
+ template_name = "kfet/category_update.html"
form_class = CategoryForm
- success_url = reverse_lazy('kfet.category')
+ success_url = reverse_lazy("kfet.category")
success_message = "Informations mises à jour pour la catégorie : %(name)s"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.change_articlecategory'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.change_articlecategory"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Updating
return super().form_valid(form)
+
# -----
# Article views
# -----
@@ -691,69 +711,65 @@ class CategoryUpdate(SuccessMessageMixin, UpdateView):
# Article - General
class ArticleList(ListView):
queryset = (
- Article.objects
- .select_related('category')
+ Article.objects.select_related("category")
.prefetch_related(
Prefetch(
- 'inventories',
- queryset=Inventory.objects.order_by('-at'),
- to_attr='inventory',
+ "inventories",
+ queryset=Inventory.objects.order_by("-at"),
+ to_attr="inventory",
)
)
- .order_by('category__name', '-is_sold', 'name')
+ .order_by("category__name", "-is_sold", "name")
)
- template_name = 'kfet/article.html'
- context_object_name = 'articles'
-
+ template_name = "kfet/article.html"
+ context_object_name = "articles"
+
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
articles = context[self.context_object_name]
- context['nb_articles'] = len(articles)
+ context["nb_articles"] = len(articles)
context[self.context_object_name] = articles.filter(is_sold=True)
- context['not_sold_articles'] = articles.filter(is_sold=False)
+ context["not_sold_articles"] = articles.filter(is_sold=False)
return context
# Article - Create
class ArticleCreate(SuccessMessageMixin, CreateView):
model = Article
- template_name = 'kfet/article_create.html'
+ template_name = "kfet/article_create.html"
form_class = ArticleForm
- success_message = 'Nouvel item : %(category)s - %(name)s'
+ success_message = "Nouvel item : %(category)s - %(name)s"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.add_article'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.add_article"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Save ici pour save le manytomany suppliers
article = form.save()
# Save des suppliers déjà existant
- for supplier in form.cleaned_data['suppliers']:
- SupplierArticle.objects.create(
- article=article, supplier=supplier)
+ for supplier in form.cleaned_data["suppliers"]:
+ SupplierArticle.objects.create(article=article, supplier=supplier)
# Nouveau supplier
- supplier_new = form.cleaned_data['supplier_new'].strip()
+ supplier_new = form.cleaned_data["supplier_new"].strip()
if supplier_new:
- supplier, created = Supplier.objects.get_or_create(
- name=supplier_new)
+ supplier, created = Supplier.objects.get_or_create(name=supplier_new)
if created:
- SupplierArticle.objects.create(
- article=article, supplier=supplier)
+ SupplierArticle.objects.create(article=article, supplier=supplier)
# Inventaire avec stock initial
inventory = Inventory()
inventory.by = self.request.user.profile.account_kfet
inventory.save()
InventoryArticle.objects.create(
- inventory=inventory,
- article=article,
- stock_old=article.stock,
- stock_new=article.stock,
- )
+ inventory=inventory,
+ article=article,
+ stock_old=article.stock,
+ stock_new=article.stock,
+ )
# Creating
return super().form_valid(form)
@@ -762,60 +778,60 @@ class ArticleCreate(SuccessMessageMixin, CreateView):
# Article - Read
class ArticleRead(DetailView):
model = Article
- template_name = 'kfet/article_read.html'
- context_object_name = 'article'
+ template_name = "kfet/article_read.html"
+ context_object_name = "article"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- inventoryarts = (InventoryArticle.objects
- .filter(article=self.object)
- .select_related('inventory')
- .order_by('-inventory__at'))
- context['inventoryarts'] = inventoryarts
- supplierarts = (SupplierArticle.objects
- .filter(article=self.object)
- .select_related('supplier')
- .order_by('-at'))
- context['supplierarts'] = supplierarts
+ inventoryarts = (
+ InventoryArticle.objects.filter(article=self.object)
+ .select_related("inventory")
+ .order_by("-inventory__at")
+ )
+ context["inventoryarts"] = inventoryarts
+ supplierarts = (
+ SupplierArticle.objects.filter(article=self.object)
+ .select_related("supplier")
+ .order_by("-at")
+ )
+ context["supplierarts"] = supplierarts
return context
# Article - Update
class ArticleUpdate(SuccessMessageMixin, UpdateView):
model = Article
- template_name = 'kfet/article_update.html'
+ template_name = "kfet/article_update.html"
form_class = ArticleRestrictForm
success_message = "Informations mises à jour pour l'article : %(name)s"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.change_article'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.change_article"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Save ici pour save le manytomany suppliers
article = form.save()
# Save des suppliers déjà existant
- for supplier in form.cleaned_data['suppliers']:
+ for supplier in form.cleaned_data["suppliers"]:
if supplier not in article.suppliers.all():
- SupplierArticle.objects.create(
- article=article, supplier=supplier)
+ SupplierArticle.objects.create(article=article, supplier=supplier)
# On vire les suppliers désélectionnés
for supplier in article.suppliers.all():
- if supplier not in form.cleaned_data['suppliers']:
+ if supplier not in form.cleaned_data["suppliers"]:
SupplierArticle.objects.filter(
- article=article, supplier=supplier).delete()
+ article=article, supplier=supplier
+ ).delete()
# Nouveau supplier
- supplier_new = form.cleaned_data['supplier_new'].strip()
+ supplier_new = form.cleaned_data["supplier_new"].strip()
if supplier_new:
- supplier, created = Supplier.objects.get_or_create(
- name=supplier_new)
+ supplier, created = Supplier.objects.get_or_create(name=supplier_new)
if created:
- SupplierArticle.objects.create(
- article=article, supplier=supplier)
+ SupplierArticle.objects.create(article=article, supplier=supplier)
# Updating
return super().form_valid(form)
@@ -825,66 +841,82 @@ class ArticleUpdate(SuccessMessageMixin, UpdateView):
# K-Psul
# -----
+
@teamkfet_required
def kpsul(request):
data = {}
- data['operationgroup_form'] = KPsulOperationGroupForm()
- data['trigramme_form'] = KPsulAccountForm()
- data['checkout_form'] = KPsulCheckoutForm()
- data['operation_formset'] = KPsulOperationFormSet(
- queryset=Operation.objects.none(),
- )
- return render(request, 'kfet/kpsul.html', data)
+ data["operationgroup_form"] = KPsulOperationGroupForm()
+ data["trigramme_form"] = KPsulAccountForm()
+ data["checkout_form"] = KPsulCheckoutForm()
+ data["operation_formset"] = KPsulOperationFormSet(queryset=Operation.objects.none())
+ return render(request, "kfet/kpsul.html", data)
@teamkfet_required
def kpsul_get_settings(request):
addcost_for = kfet_config.addcost_for
data = {
- 'subvention_cof': kfet_config.subvention_cof,
- 'addcost_for': addcost_for and addcost_for.trigramme or '',
- 'addcost_amount': kfet_config.addcost_amount,
+ "subvention_cof": kfet_config.subvention_cof,
+ "addcost_for": addcost_for and addcost_for.trigramme or "",
+ "addcost_amount": kfet_config.addcost_amount,
}
return JsonResponse(data)
@teamkfet_required
def account_read_json(request):
- trigramme = request.POST.get('trigramme', '')
- account = get_object_or_404(Account, trigramme=trigramme)
- data = { 'id': account.pk, 'name': account.name, 'email': account.email,
- 'is_cof': account.is_cof, 'promo': account.promo,
- 'balance': account.balance, 'is_frozen': account.is_frozen,
- 'departement': account.departement, 'nickname': account.nickname,
- 'trigramme': account.trigramme }
+ trigramme = request.POST.get("trigramme", "")
+ account = get_object_or_404(Account, trigramme=trigramme)
+ data = {
+ "id": account.pk,
+ "name": account.name,
+ "email": account.email,
+ "is_cof": account.is_cof,
+ "promo": account.promo,
+ "balance": account.balance,
+ "is_frozen": account.is_frozen,
+ "departement": account.departement,
+ "nickname": account.nickname,
+ "trigramme": account.trigramme,
+ }
return JsonResponse(data)
@teamkfet_required
def kpsul_checkout_data(request):
- pk = request.POST.get('pk', 0)
+ pk = request.POST.get("pk", 0)
if not pk:
pk = 0
data = (
- Checkout.objects
- .annotate(
- last_statement_by_first_name=F('statements__by__cofprofile__user__first_name'),
- last_statement_by_last_name=F('statements__by__cofprofile__user__last_name'),
- last_statement_by_trigramme=F('statements__by__trigramme'),
- last_statement_balance=F('statements__balance_new'),
- last_statement_at=F('statements__at'))
+ Checkout.objects.annotate(
+ last_statement_by_first_name=F(
+ "statements__by__cofprofile__user__first_name"
+ ),
+ last_statement_by_last_name=F(
+ "statements__by__cofprofile__user__last_name"
+ ),
+ last_statement_by_trigramme=F("statements__by__trigramme"),
+ last_statement_balance=F("statements__balance_new"),
+ last_statement_at=F("statements__at"),
+ )
.select_related(
- 'statements'
- 'statements__by',
- 'statements__by__cofprofile__user')
+ "statements" "statements__by", "statements__by__cofprofile__user"
+ )
.filter(pk=pk)
- .order_by('statements__at')
+ .order_by("statements__at")
.values(
- 'id', 'name', 'balance', 'valid_from', 'valid_to',
- 'last_statement_balance', 'last_statement_at',
- 'last_statement_by_trigramme', 'last_statement_by_last_name',
- 'last_statement_by_first_name')
+ "id",
+ "name",
+ "balance",
+ "valid_from",
+ "valid_to",
+ "last_statement_balance",
+ "last_statement_at",
+ "last_statement_by_trigramme",
+ "last_statement_by_last_name",
+ "last_statement_by_first_name",
+ )
.last()
)
if data is None:
@@ -897,43 +929,34 @@ def kpsul_update_addcost(request):
addcost_form = AddcostForm(request.POST)
if not addcost_form.is_valid():
- data = {'errors': {'addcost': list(addcost_form.errors)}}
+ data = {"errors": {"addcost": list(addcost_form.errors)}}
return JsonResponse(data, status=400)
- required_perms = ['kfet.manage_addcosts']
+ required_perms = ["kfet.manage_addcosts"]
if not request.user.has_perms(required_perms):
data = {
- 'errors': {
- 'missing_perms': get_missing_perms(required_perms,
- request.user)
- }
+ "errors": {"missing_perms": get_missing_perms(required_perms, request.user)}
}
return JsonResponse(data, status=403)
- trigramme = addcost_form.cleaned_data['trigramme']
+ trigramme = addcost_form.cleaned_data["trigramme"]
account = trigramme and Account.objects.get(trigramme=trigramme) or None
- amount = addcost_form.cleaned_data['amount']
+ amount = addcost_form.cleaned_data["amount"]
- kfet_config.set(addcost_for=account,
- addcost_amount=amount)
+ kfet_config.set(addcost_for=account, addcost_amount=amount)
- data = {
- 'addcost': {
- 'for': account and account.trigramme or None,
- 'amount': amount,
- }
- }
- consumers.KPsul.group_send('kfet.kpsul', data)
+ data = {"addcost": {"for": account and account.trigramme or None, "amount": amount}}
+ consumers.KPsul.group_send("kfet.kpsul", data)
return JsonResponse(data)
def get_missing_perms(required_perms, user):
- missing_perms_codenames = [(perm.split('.'))[1]
- for perm in required_perms
- if not user.has_perm(perm)]
+ missing_perms_codenames = [
+ (perm.split("."))[1] for perm in required_perms if not user.has_perm(perm)
+ ]
missing_perms = list(
- Permission.objects
- .filter(codename__in=missing_perms_codenames)
- .values_list('name', flat=True)
+ Permission.objects.filter(codename__in=missing_perms_codenames).values_list(
+ "name", flat=True
+ )
)
return missing_perms
@@ -941,21 +964,20 @@ def get_missing_perms(required_perms, user):
@teamkfet_required
def kpsul_perform_operations(request):
# Initializing response data
- data = {'operationgroup': 0, 'operations': [],
- 'warnings': {}, 'errors': {}}
+ data = {"operationgroup": 0, "operations": [], "warnings": {}, "errors": {}}
# Checking operationgroup
operationgroup_form = KPsulOperationGroupForm(request.POST)
if not operationgroup_form.is_valid():
- data['errors']['operation_group'] = list(operationgroup_form.errors)
+ data["errors"]["operation_group"] = list(operationgroup_form.errors)
# Checking operation_formset
operation_formset = KPsulOperationFormSet(request.POST)
if not operation_formset.is_valid():
- data['errors']['operations'] = list(operation_formset.errors)
+ data["errors"]["operations"] = list(operation_formset.errors)
# Returning BAD REQUEST if errors
- if data['errors']:
+ if data["errors"]:
return JsonResponse(data, status=400)
# Pre-saving (no commit)
@@ -974,19 +996,19 @@ def kpsul_perform_operations(request):
to_addcost_for_balance = 0 # For balance of addcost_for
to_checkout_balance = 0 # For balance of selected checkout
to_articles_stocks = defaultdict(lambda: 0) # For stocks articles
- is_addcost = all((addcost_for, addcost_amount,
- addcost_for != operationgroup.on_acc))
+ is_addcost = all(
+ (addcost_for, addcost_amount, addcost_for != operationgroup.on_acc)
+ )
need_comment = operationgroup.on_acc.need_comment
# Filling data of each operations
# + operationgroup + calculating other stuffs
for operation in operations:
if operation.type == Operation.PURCHASE:
- operation.amount = - operation.article.price * operation.article_nb
+ operation.amount = -operation.article.price * operation.article_nb
if is_addcost & operation.article.category.has_addcost:
operation.addcost_for = addcost_for
- operation.addcost_amount = addcost_amount \
- * operation.article_nb
+ operation.addcost_amount = addcost_amount * operation.article_nb
operation.amount -= operation.addcost_amount
to_addcost_for_balance += operation.addcost_amount
if operationgroup.on_acc.is_cash:
@@ -998,38 +1020,37 @@ def kpsul_perform_operations(request):
to_articles_stocks[operation.article] -= operation.article_nb
else:
if operationgroup.on_acc.is_cash:
- data['errors']['account'] = 'LIQ'
+ data["errors"]["account"] = "LIQ"
if operation.type != Operation.EDIT:
to_checkout_balance += operation.amount
operationgroup.amount += operation.amount
if operation.type == Operation.DEPOSIT:
- required_perms.add('kfet.perform_deposit')
+ required_perms.add("kfet.perform_deposit")
if operation.type == Operation.EDIT:
- required_perms.add('kfet.edit_balance_account')
+ required_perms.add("kfet.edit_balance_account")
need_comment = True
if operationgroup.on_acc.is_cof:
to_addcost_for_balance = to_addcost_for_balance / cof_grant_divisor
- (perms, stop) = (operationgroup.on_acc
- .perms_to_perform_operation(
- amount=operationgroup.amount)
- )
+ (perms, stop) = operationgroup.on_acc.perms_to_perform_operation(
+ amount=operationgroup.amount
+ )
required_perms |= perms
if need_comment:
operationgroup.comment = operationgroup.comment.strip()
if not operationgroup.comment:
- data['errors']['need_comment'] = True
+ data["errors"]["need_comment"] = True
- if data['errors']:
+ if data["errors"]:
return JsonResponse(data, status=400)
if stop or not request.user.has_perms(required_perms):
missing_perms = get_missing_perms(required_perms, request.user)
if missing_perms:
- data['errors']['missing_perms'] = missing_perms
+ data["errors"]["missing_perms"] = missing_perms
if stop:
- data['errors']['negative'] = [operationgroup.on_acc.trigramme]
+ data["errors"]["negative"] = [operationgroup.on_acc.trigramme]
return JsonResponse(data, status=403)
# If 1 perm is required, filling who perform the operations
@@ -1045,9 +1066,9 @@ def kpsul_perform_operations(request):
on_acc = operationgroup.on_acc
if not on_acc.is_cash:
(
- Account.objects
- .filter(pk=on_acc.pk)
- .update(balance=F('balance') + operationgroup.amount)
+ Account.objects.filter(pk=on_acc.pk).update(
+ balance=F("balance") + operationgroup.amount
+ )
)
on_acc.refresh_from_db()
on_acc.update_negative()
@@ -1055,106 +1076,117 @@ def kpsul_perform_operations(request):
# Updating checkout's balance
if to_checkout_balance:
Checkout.objects.filter(pk=operationgroup.checkout.pk).update(
- balance=F('balance') + to_checkout_balance)
+ balance=F("balance") + to_checkout_balance
+ )
# Saving addcost_for with new balance if there is one
if is_addcost and to_addcost_for_balance:
Account.objects.filter(pk=addcost_for.pk).update(
- balance=F('balance') + to_addcost_for_balance)
+ balance=F("balance") + to_addcost_for_balance
+ )
# Saving operation group
operationgroup.save()
- data['operationgroup'] = operationgroup.pk
+ data["operationgroup"] = operationgroup.pk
# Filling operationgroup id for each operations and saving
for operation in operations:
operation.group = operationgroup
operation.save()
- data['operations'].append(operation.pk)
+ data["operations"].append(operation.pk)
# Updating articles stock
for article in to_articles_stocks:
Article.objects.filter(pk=article.pk).update(
- stock=F('stock') + to_articles_stocks[article])
+ stock=F("stock") + to_articles_stocks[article]
+ )
# Websocket data
websocket_data = {}
- websocket_data['opegroups'] = [{
- 'add': True,
- 'id': operationgroup.pk,
- 'amount': operationgroup.amount,
- 'checkout__name': operationgroup.checkout.name,
- 'at': operationgroup.at,
- 'is_cof': operationgroup.is_cof,
- 'comment': operationgroup.comment,
- 'valid_by__trigramme': (operationgroup.valid_by and
- operationgroup.valid_by.trigramme or None),
- 'on_acc__trigramme': operationgroup.on_acc.trigramme,
- 'opes': [],
- }]
+ websocket_data["opegroups"] = [
+ {
+ "add": True,
+ "id": operationgroup.pk,
+ "amount": operationgroup.amount,
+ "checkout__name": operationgroup.checkout.name,
+ "at": operationgroup.at,
+ "is_cof": operationgroup.is_cof,
+ "comment": operationgroup.comment,
+ "valid_by__trigramme": (
+ operationgroup.valid_by and operationgroup.valid_by.trigramme or None
+ ),
+ "on_acc__trigramme": operationgroup.on_acc.trigramme,
+ "opes": [],
+ }
+ ]
for operation in operations:
ope_data = {
- 'id': operation.pk, 'type': operation.type,
- 'amount': operation.amount,
- 'addcost_amount': operation.addcost_amount,
- 'addcost_for__trigramme': (
- operation.addcost_for and addcost_for.trigramme or None),
- 'article__name': (
- operation.article and operation.article.name or None),
- 'article_nb': operation.article_nb,
- 'group_id': operationgroup.pk,
- 'canceled_by__trigramme': None, 'canceled_at': None,
+ "id": operation.pk,
+ "type": operation.type,
+ "amount": operation.amount,
+ "addcost_amount": operation.addcost_amount,
+ "addcost_for__trigramme": (
+ operation.addcost_for and addcost_for.trigramme or None
+ ),
+ "article__name": (operation.article and operation.article.name or None),
+ "article_nb": operation.article_nb,
+ "group_id": operationgroup.pk,
+ "canceled_by__trigramme": None,
+ "canceled_at": None,
}
- websocket_data['opegroups'][0]['opes'].append(ope_data)
+ websocket_data["opegroups"][0]["opes"].append(ope_data)
# Need refresh from db cause we used update on queryset
operationgroup.checkout.refresh_from_db()
- websocket_data['checkouts'] = [{
- 'id': operationgroup.checkout.pk,
- 'balance': operationgroup.checkout.balance,
- }]
- websocket_data['articles'] = []
+ websocket_data["checkouts"] = [
+ {"id": operationgroup.checkout.pk, "balance": operationgroup.checkout.balance}
+ ]
+ websocket_data["articles"] = []
# Need refresh from db cause we used update on querysets
articles_pk = [article.pk for article in to_articles_stocks]
- articles = Article.objects.values('id', 'stock').filter(pk__in=articles_pk)
+ articles = Article.objects.values("id", "stock").filter(pk__in=articles_pk)
for article in articles:
- websocket_data['articles'].append({
- 'id': article['id'],
- 'stock': article['stock']
- })
- consumers.KPsul.group_send('kfet.kpsul', websocket_data)
+ websocket_data["articles"].append(
+ {"id": article["id"], "stock": article["stock"]}
+ )
+ consumers.KPsul.group_send("kfet.kpsul", websocket_data)
return JsonResponse(data)
@teamkfet_required
def kpsul_cancel_operations(request):
# Pour la réponse
- data = { 'canceled': [], 'warnings': {}, 'errors': {}}
+ data = {"canceled": [], "warnings": {}, "errors": {}}
# Checking if BAD REQUEST (opes_pk not int or not existing)
try:
# Set pour virer les doublons
- opes_post = set(map(int, filter(None, request.POST.getlist('operations[]', []))))
+ opes_post = set(
+ map(int, filter(None, request.POST.getlist("operations[]", [])))
+ )
except ValueError:
return JsonResponse(data, status=400)
- opes_all = (
- Operation.objects
- .select_related('group', 'group__on_acc', 'group__on_acc__negative')
- .filter(pk__in=opes_post))
- opes_pk = [ ope.pk for ope in opes_all ]
- opes_notexisting = [ ope for ope in opes_post if ope not in opes_pk ]
+ opes_all = Operation.objects.select_related(
+ "group", "group__on_acc", "group__on_acc__negative"
+ ).filter(pk__in=opes_post)
+ opes_pk = [ope.pk for ope in opes_all]
+ opes_notexisting = [ope for ope in opes_post if ope not in opes_pk]
if opes_notexisting:
- data['errors']['opes_notexisting'] = opes_notexisting
+ data["errors"]["opes_notexisting"] = opes_notexisting
return JsonResponse(data, status=400)
- opes_already_canceled = [] # Déjà annulée
- opes = [] # Pas déjà annulée
+ opes_already_canceled = [] # Déjà annulée
+ opes = [] # Pas déjà annulée
required_perms = set()
- stop_all = False
+ stop_all = False
cancel_duration = kfet_config.cancel_duration
- to_accounts_balances = defaultdict(lambda:0) # Modifs à faire sur les balances des comptes
- to_groups_amounts = defaultdict(lambda:0) # ------ sur les montants des groupes d'opé
- to_checkouts_balances = defaultdict(lambda:0) # ------ sur les balances de caisses
- to_articles_stocks = defaultdict(lambda:0) # ------ sur les stocks d'articles
+ to_accounts_balances = defaultdict(
+ lambda: 0
+ ) # Modifs à faire sur les balances des comptes
+ to_groups_amounts = defaultdict(
+ lambda: 0
+ ) # ------ sur les montants des groupes d'opé
+ to_checkouts_balances = defaultdict(lambda: 0) # ------ sur les balances de caisses
+ to_articles_stocks = defaultdict(lambda: 0) # ------ sur les stocks d'articles
for ope in opes_all:
if ope.canceled_at:
# Opération déjà annulée, va pour un warning en Response
@@ -1163,7 +1195,7 @@ def kpsul_cancel_operations(request):
opes.append(ope.pk)
# Si opé il y a plus de CANCEL_DURATION, permission requise
if ope.group.at + cancel_duration < timezone.now():
- required_perms.add('kfet.cancel_old_operations')
+ required_perms.add("kfet.cancel_old_operations")
# Calcul de toutes modifs à faire en cas de validation
@@ -1185,14 +1217,15 @@ def kpsul_cancel_operations(request):
# par `.save()`, amount_error est recalculé automatiquement,
# ce qui n'est pas le cas en faisant un update sur queryset
# TODO ? : Maj les balance_old de relevés pour modifier l'erreur
- last_statement = (CheckoutStatement.objects
- .filter(checkout=ope.group.checkout)
- .order_by('at')
- .last())
+ last_statement = (
+ CheckoutStatement.objects.filter(checkout=ope.group.checkout)
+ .order_by("at")
+ .last()
+ )
if not last_statement or last_statement.at < ope.group.at:
if ope.is_checkout:
if ope.group.on_acc.is_cash:
- to_checkouts_balances[ope.group.checkout] -= - ope.amount
+ to_checkouts_balances[ope.group.checkout] -= -ope.amount
else:
to_checkouts_balances[ope.group.checkout] -= ope.amount
@@ -1204,23 +1237,25 @@ def kpsul_cancel_operations(request):
# Note : si InventoryArticle est maj par .save(), stock_error
# est recalculé automatiquement
if ope.article and ope.article_nb:
- last_stock = (InventoryArticle.objects
- .select_related('inventory')
+ last_stock = (
+ InventoryArticle.objects.select_related("inventory")
.filter(article=ope.article)
- .order_by('inventory__at')
- .last())
+ .order_by("inventory__at")
+ .last()
+ )
if not last_stock or last_stock.inventory.at < ope.group.at:
to_articles_stocks[ope.article] += ope.article_nb
if not opes:
- data['warnings']['already_canceled'] = opes_already_canceled
+ data["warnings"]["already_canceled"] = opes_already_canceled
return JsonResponse(data)
negative_accounts = []
# Checking permissions or stop
for account in to_accounts_balances:
(perms, stop) = account.perms_to_perform_operation(
- amount = to_accounts_balances[account])
+ amount=to_accounts_balances[account]
+ )
required_perms |= perms
stop_all = stop_all or stop
if stop:
@@ -1229,22 +1264,25 @@ def kpsul_cancel_operations(request):
if stop_all or not request.user.has_perms(required_perms):
missing_perms = get_missing_perms(required_perms, request.user)
if missing_perms:
- data['errors']['missing_perms'] = missing_perms
+ data["errors"]["missing_perms"] = missing_perms
if stop_all:
- data['errors']['negative'] = negative_accounts
+ data["errors"]["negative"] = negative_accounts
return JsonResponse(data, status=403)
canceled_by = required_perms and request.user.profile.account_kfet or None
canceled_at = timezone.now()
with transaction.atomic():
- (Operation.objects.filter(pk__in=opes)
- .update(canceled_by=canceled_by, canceled_at=canceled_at))
+ (
+ Operation.objects.filter(pk__in=opes).update(
+ canceled_by=canceled_by, canceled_at=canceled_at
+ )
+ )
for account in to_accounts_balances:
(
- Account.objects
- .filter(pk=account.pk)
- .update(balance=F('balance') + to_accounts_balances[account])
+ Account.objects.filter(pk=account.pk).update(
+ balance=F("balance") + to_accounts_balances[account]
+ )
)
if not account.is_cash:
# Should always be true, but we want to be sure
@@ -1252,76 +1290,86 @@ def kpsul_cancel_operations(request):
account.update_negative()
for checkout in to_checkouts_balances:
Checkout.objects.filter(pk=checkout.pk).update(
- balance = F('balance') + to_checkouts_balances[checkout])
+ balance=F("balance") + to_checkouts_balances[checkout]
+ )
for group in to_groups_amounts:
OperationGroup.objects.filter(pk=group.pk).update(
- amount = F('amount') + to_groups_amounts[group])
+ amount=F("amount") + to_groups_amounts[group]
+ )
for article in to_articles_stocks:
Article.objects.filter(pk=article.pk).update(
- stock = F('stock') + to_articles_stocks[article])
+ stock=F("stock") + to_articles_stocks[article]
+ )
# Websocket data
- websocket_data = { 'opegroups': [], 'opes': [], 'checkouts': [], 'articles': [] }
+ websocket_data = {"opegroups": [], "opes": [], "checkouts": [], "articles": []}
# Need refresh from db cause we used update on querysets
- opegroups_pk = [ opegroup.pk for opegroup in to_groups_amounts ]
- opegroups = (OperationGroup.objects
- .values('id','amount','is_cof').filter(pk__in=opegroups_pk))
+ opegroups_pk = [opegroup.pk for opegroup in to_groups_amounts]
+ opegroups = OperationGroup.objects.values("id", "amount", "is_cof").filter(
+ pk__in=opegroups_pk
+ )
for opegroup in opegroups:
- websocket_data['opegroups'].append({
- 'cancellation': True,
- 'id': opegroup['id'],
- 'amount': opegroup['amount'],
- 'is_cof': opegroup['is_cof'],
- })
+ websocket_data["opegroups"].append(
+ {
+ "cancellation": True,
+ "id": opegroup["id"],
+ "amount": opegroup["amount"],
+ "is_cof": opegroup["is_cof"],
+ }
+ )
canceled_by__trigramme = canceled_by and canceled_by.trigramme or None
for ope in opes:
- websocket_data['opes'].append({
- 'cancellation': True,
- 'id': ope,
- 'canceled_by__trigramme': canceled_by__trigramme,
- 'canceled_at': canceled_at,
- })
+ websocket_data["opes"].append(
+ {
+ "cancellation": True,
+ "id": ope,
+ "canceled_by__trigramme": canceled_by__trigramme,
+ "canceled_at": canceled_at,
+ }
+ )
# Need refresh from db cause we used update on querysets
- checkouts_pk = [ checkout.pk for checkout in to_checkouts_balances]
- checkouts = (Checkout.objects
- .values('id', 'balance').filter(pk__in=checkouts_pk))
+ checkouts_pk = [checkout.pk for checkout in to_checkouts_balances]
+ checkouts = Checkout.objects.values("id", "balance").filter(pk__in=checkouts_pk)
for checkout in checkouts:
- websocket_data['checkouts'].append({
- 'id': checkout['id'],
- 'balance': checkout['balance']})
+ websocket_data["checkouts"].append(
+ {"id": checkout["id"], "balance": checkout["balance"]}
+ )
# Need refresh from db cause we used update on querysets
- articles_pk = [ article.pk for articles in to_articles_stocks]
- articles = Article.objects.values('id', 'stock').filter(pk__in=articles_pk)
+ articles_pk = [article.pk for articles in to_articles_stocks]
+ articles = Article.objects.values("id", "stock").filter(pk__in=articles_pk)
for article in articles:
- websocket_data['articles'].append({
- 'id': article['id'],
- 'stock': article['stock']})
- consumers.KPsul.group_send('kfet.kpsul', websocket_data)
+ websocket_data["articles"].append(
+ {"id": article["id"], "stock": article["stock"]}
+ )
+ consumers.KPsul.group_send("kfet.kpsul", websocket_data)
- data['canceled'] = opes
+ data["canceled"] = opes
if opes_already_canceled:
- data['warnings']['already_canceled'] = opes_already_canceled
+ data["warnings"]["already_canceled"] = opes_already_canceled
return JsonResponse(data)
+
@login_required
def history_json(request):
# Récupération des paramètres
- from_date = request.POST.get('from', None)
- to_date = request.POST.get('to', None)
- limit = request.POST.get('limit', None);
- checkouts = request.POST.getlist('checkouts[]', None)
- accounts = request.POST.getlist('accounts[]', None)
+ from_date = request.POST.get("from", None)
+ to_date = request.POST.get("to", None)
+ limit = request.POST.get("limit", None)
+ checkouts = request.POST.getlist("checkouts[]", None)
+ accounts = request.POST.getlist("accounts[]", None)
# Construction de la requête (sur les opérations) pour le prefetch
queryset_prefetch = Operation.objects.select_related(
- 'article', 'canceled_by', 'addcost_for')
+ "article", "canceled_by", "addcost_for"
+ )
# Construction de la requête principale
opegroups = (
- OperationGroup.objects
- .prefetch_related(Prefetch('opes', queryset=queryset_prefetch))
- .select_related('on_acc', 'valid_by')
- .order_by('at')
+ OperationGroup.objects.prefetch_related(
+ Prefetch("opes", queryset=queryset_prefetch)
+ )
+ .select_related("on_acc", "valid_by")
+ .order_by("at")
)
# Application des filtres
if from_date:
@@ -1333,65 +1381,68 @@ def history_json(request):
if accounts:
opegroups = opegroups.filter(on_acc_id__in=accounts)
# Un non-membre de l'équipe n'a que accès à son historique
- if not request.user.has_perm('kfet.is_team'):
+ if not request.user.has_perm("kfet.is_team"):
opegroups = opegroups.filter(on_acc=request.user.profile.account_kfet)
if limit:
opegroups = opegroups[:limit]
-
# Construction de la réponse
opegroups_list = []
for opegroup in opegroups:
opegroup_dict = {
- 'id' : opegroup.id,
- 'amount' : opegroup.amount,
- 'at' : opegroup.at,
- 'checkout_id': opegroup.checkout_id,
- 'is_cof' : opegroup.is_cof,
- 'comment' : opegroup.comment,
- 'opes' : [],
- 'on_acc__trigramme':
- opegroup.on_acc and opegroup.on_acc.trigramme or None,
+ "id": opegroup.id,
+ "amount": opegroup.amount,
+ "at": opegroup.at,
+ "checkout_id": opegroup.checkout_id,
+ "is_cof": opegroup.is_cof,
+ "comment": opegroup.comment,
+ "opes": [],
+ "on_acc__trigramme": opegroup.on_acc and opegroup.on_acc.trigramme or None,
}
- if request.user.has_perm('kfet.is_team'):
- opegroup_dict['valid_by__trigramme'] = (
- opegroup.valid_by and opegroup.valid_by.trigramme or None)
+ if request.user.has_perm("kfet.is_team"):
+ opegroup_dict["valid_by__trigramme"] = (
+ opegroup.valid_by and opegroup.valid_by.trigramme or None
+ )
for ope in opegroup.opes.all():
ope_dict = {
- 'id' : ope.id,
- 'type' : ope.type,
- 'amount' : ope.amount,
- 'article_nb' : ope.article_nb,
- 'addcost_amount': ope.addcost_amount,
- 'canceled_at' : ope.canceled_at,
- 'article__name':
- ope.article and ope.article.name or None,
- 'addcost_for__trigramme':
- ope.addcost_for and ope.addcost_for.trigramme or None,
+ "id": ope.id,
+ "type": ope.type,
+ "amount": ope.amount,
+ "article_nb": ope.article_nb,
+ "addcost_amount": ope.addcost_amount,
+ "canceled_at": ope.canceled_at,
+ "article__name": ope.article and ope.article.name or None,
+ "addcost_for__trigramme": ope.addcost_for
+ and ope.addcost_for.trigramme
+ or None,
}
- if request.user.has_perm('kfet.is_team'):
- ope_dict['canceled_by__trigramme'] = (
- ope.canceled_by and ope.canceled_by.trigramme or None)
- opegroup_dict['opes'].append(ope_dict)
+ if request.user.has_perm("kfet.is_team"):
+ ope_dict["canceled_by__trigramme"] = (
+ ope.canceled_by and ope.canceled_by.trigramme or None
+ )
+ opegroup_dict["opes"].append(ope_dict)
opegroups_list.append(opegroup_dict)
- return JsonResponse({ 'opegroups': opegroups_list })
+ return JsonResponse({"opegroups": opegroups_list})
+
@teamkfet_required
def kpsul_articles_data(request):
- articles = (
- Article.objects
- .values('id', 'name', 'price', 'stock', 'category_id',
- 'category__name', 'category__has_addcost')
- .filter(is_sold=True))
- return JsonResponse({ 'articles': list(articles) })
+ articles = Article.objects.values(
+ "id",
+ "name",
+ "price",
+ "stock",
+ "category_id",
+ "category__name",
+ "category__has_addcost",
+ ).filter(is_sold=True)
+ return JsonResponse({"articles": list(articles)})
@teamkfet_required
def history(request):
- data = {
- 'filter_form': FilterHistoryForm(),
- }
- return render(request, 'kfet/history.html', data)
+ data = {"filter_form": FilterHistoryForm()}
+ return render(request, "kfet/history.html", data)
# -----
@@ -1400,77 +1451,73 @@ def history(request):
class SettingsList(TemplateView):
- template_name = 'kfet/settings.html'
+ template_name = "kfet/settings.html"
-config_list = permission_required('kfet.see_config')(SettingsList.as_view())
+config_list = permission_required("kfet.see_config")(SettingsList.as_view())
class SettingsUpdate(SuccessMessageMixin, FormView):
form_class = KFetConfigForm
- template_name = 'kfet/settings_update.html'
- success_message = 'Paramètres mis à jour'
- success_url = reverse_lazy('kfet.settings')
+ template_name = "kfet/settings_update.html"
+ success_message = "Paramètres mis à jour"
+ success_url = reverse_lazy("kfet.settings")
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.change_config'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.change_config"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
form.save()
return super().form_valid(form)
-config_update = (
- permission_required('kfet.change_config')(SettingsUpdate.as_view())
-)
+config_update = permission_required("kfet.change_config")(SettingsUpdate.as_view())
# -----
# Transfer views
# -----
+
@teamkfet_required
def transfers(request):
transfers_pre = Prefetch(
- 'transfers',
- queryset=(
- Transfer.objects
- .select_related('from_acc', 'to_acc')
- ),
+ "transfers", queryset=(Transfer.objects.select_related("from_acc", "to_acc"))
)
transfergroups = (
- TransferGroup.objects
- .select_related('valid_by')
+ TransferGroup.objects.select_related("valid_by")
.prefetch_related(transfers_pre)
- .order_by('-at')
+ .order_by("-at")
)
- return render(request, 'kfet/transfers.html', {
- 'transfergroups': transfergroups,
- })
+ return render(request, "kfet/transfers.html", {"transfergroups": transfergroups})
@teamkfet_required
def transfers_create(request):
transfer_formset = TransferFormSet(queryset=Transfer.objects.none())
- return render(request, 'kfet/transfers_create.html',
- { 'transfer_formset': transfer_formset })
+ return render(
+ request, "kfet/transfers_create.html", {"transfer_formset": transfer_formset}
+ )
+
@teamkfet_required
def perform_transfers(request):
- data = { 'errors': {}, 'transfers': [], 'transfergroup': 0 }
+ data = {"errors": {}, "transfers": [], "transfergroup": 0}
# Checking transfer_formset
transfer_formset = TransferFormSet(request.POST)
if not transfer_formset.is_valid():
- return JsonResponse({ 'errors': list(transfer_formset.errors)}, status=400)
+ return JsonResponse({"errors": list(transfer_formset.errors)}, status=400)
- transfers = transfer_formset.save(commit = False)
+ transfers = transfer_formset.save(commit=False)
# Initializing vars
- required_perms = set(['kfet.add_transfer']) # Required perms to perform all transfers
- to_accounts_balances = defaultdict(lambda:0) # For balances of accounts
+ required_perms = set(
+ ["kfet.add_transfer"]
+ ) # Required perms to perform all transfers
+ to_accounts_balances = defaultdict(lambda: 0) # For balances of accounts
for transfer in transfers:
to_accounts_balances[transfer.from_acc] -= transfer.amount
@@ -1482,7 +1529,8 @@ def perform_transfers(request):
# Checking if ok on all accounts
for account in to_accounts_balances:
(perms, stop) = account.perms_to_perform_operation(
- amount = to_accounts_balances[account])
+ amount=to_accounts_balances[account]
+ )
required_perms |= perms
stop_all = stop_all or stop
if stop:
@@ -1491,9 +1539,9 @@ def perform_transfers(request):
if stop_all or not request.user.has_perms(required_perms):
missing_perms = get_missing_perms(required_perms, request.user)
if missing_perms:
- data['errors']['missing_perms'] = missing_perms
+ data["errors"]["missing_perms"] = missing_perms
if stop_all:
- data['errors']['negative'] = negative_accounts
+ data["errors"]["negative"] = negative_accounts
return JsonResponse(data, status=403)
# Creating transfer group
@@ -1501,69 +1549,72 @@ def perform_transfers(request):
if required_perms:
transfergroup.valid_by = request.user.profile.account_kfet
- comment = request.POST.get('comment', '')
+ comment = request.POST.get("comment", "")
transfergroup.comment = comment.strip()
with transaction.atomic():
# Updating balances accounts
for account in to_accounts_balances:
Account.objects.filter(pk=account.pk).update(
- balance = F('balance') + to_accounts_balances[account])
+ balance=F("balance") + to_accounts_balances[account]
+ )
account.refresh_from_db()
if account.balance < 0:
- if hasattr(account, 'negative'):
+ if hasattr(account, "negative"):
if not account.negative.start:
account.negative.start = timezone.now()
account.negative.save()
else:
- negative = AccountNegative(
- account = account, start = timezone.now())
+ negative = AccountNegative(account=account, start=timezone.now())
negative.save()
- elif (hasattr(account, 'negative')
- and not account.negative.balance_offset):
+ elif hasattr(account, "negative") and not account.negative.balance_offset:
account.negative.delete()
# Saving transfer group
transfergroup.save()
- data['transfergroup'] = transfergroup.pk
+ data["transfergroup"] = transfergroup.pk
# Saving all transfers with group
for transfer in transfers:
transfer.group = transfergroup
transfer.save()
- data['transfers'].append(transfer.pk)
+ data["transfers"].append(transfer.pk)
return JsonResponse(data)
+
@teamkfet_required
def cancel_transfers(request):
# Pour la réponse
- data = { 'canceled': [], 'warnings': {}, 'errors': {}}
+ data = {"canceled": [], "warnings": {}, "errors": {}}
# Checking if BAD REQUEST (transfers_pk not int or not existing)
try:
# Set pour virer les doublons
- transfers_post = set(map(int, filter(None, request.POST.getlist('transfers[]', []))))
+ transfers_post = set(
+ map(int, filter(None, request.POST.getlist("transfers[]", [])))
+ )
except ValueError:
return JsonResponse(data, status=400)
- transfers_all = (
- Transfer.objects
- .select_related('group', 'from_acc', 'from_acc__negative',
- 'to_acc', 'to_acc__negative')
- .filter(pk__in=transfers_post))
- transfers_pk = [ transfer.pk for transfer in transfers_all ]
- transfers_notexisting = [ transfer for transfer in transfers_post
- if transfer not in transfers_pk ]
+ transfers_all = Transfer.objects.select_related(
+ "group", "from_acc", "from_acc__negative", "to_acc", "to_acc__negative"
+ ).filter(pk__in=transfers_post)
+ transfers_pk = [transfer.pk for transfer in transfers_all]
+ transfers_notexisting = [
+ transfer for transfer in transfers_post if transfer not in transfers_pk
+ ]
if transfers_notexisting:
- data['errors']['transfers_notexisting'] = transfers_notexisting
+ data["errors"]["transfers_notexisting"] = transfers_notexisting
return JsonResponse(data, status=400)
- transfers_already_canceled = [] # Déjà annulée
- transfers = [] # Pas déjà annulée
+ transfers_already_canceled = [] # Déjà annulée
+ transfers = [] # Pas déjà annulée
required_perms = set()
- stop_all = False
+ stop_all = False
cancel_duration = kfet_config.cancel_duration
- to_accounts_balances = defaultdict(lambda:0) # Modifs à faire sur les balances des comptes
+ to_accounts_balances = defaultdict(
+ lambda: 0
+ ) # Modifs à faire sur les balances des comptes
for transfer in transfers_all:
if transfer.canceled_at:
# Transfert déjà annulé, va pour un warning en Response
@@ -1572,7 +1623,7 @@ def cancel_transfers(request):
transfers.append(transfer.pk)
# Si transfer il y a plus de CANCEL_DURATION, permission requise
if transfer.group.at + cancel_duration < timezone.now():
- required_perms.add('kfet.cancel_old_operations')
+ required_perms.add("kfet.cancel_old_operations")
# Calcul de toutes modifs à faire en cas de validation
@@ -1581,14 +1632,15 @@ def cancel_transfers(request):
to_accounts_balances[transfer.to_acc] += -transfer.amount
if not transfers:
- data['warnings']['already_canceled'] = transfers_already_canceled
+ data["warnings"]["already_canceled"] = transfers_already_canceled
return JsonResponse(data)
negative_accounts = []
# Checking permissions or stop
for account in to_accounts_balances:
(perms, stop) = account.perms_to_perform_operation(
- amount = to_accounts_balances[account])
+ amount=to_accounts_balances[account]
+ )
required_perms |= perms
stop_all = stop_all or stop
if stop:
@@ -1597,76 +1649,79 @@ def cancel_transfers(request):
if stop_all or not request.user.has_perms(required_perms):
missing_perms = get_missing_perms(required_perms, request.user)
if missing_perms:
- data['errors']['missing_perms'] = missing_perms
+ data["errors"]["missing_perms"] = missing_perms
if stop_all:
- data['errors']['negative'] = negative_accounts
+ data["errors"]["negative"] = negative_accounts
return JsonResponse(data, status=403)
canceled_by = required_perms and request.user.profile.account_kfet or None
canceled_at = timezone.now()
with transaction.atomic():
- (Transfer.objects.filter(pk__in=transfers)
- .update(canceled_by=canceled_by, canceled_at=canceled_at))
+ (
+ Transfer.objects.filter(pk__in=transfers).update(
+ canceled_by=canceled_by, canceled_at=canceled_at
+ )
+ )
for account in to_accounts_balances:
Account.objects.filter(pk=account.pk).update(
- balance = F('balance') + to_accounts_balances[account])
+ balance=F("balance") + to_accounts_balances[account]
+ )
account.refresh_from_db()
if account.balance < 0:
- if hasattr(account, 'negative'):
+ if hasattr(account, "negative"):
if not account.negative.start:
account.negative.start = timezone.now()
account.negative.save()
else:
- negative = AccountNegative(
- account = account, start = timezone.now())
+ negative = AccountNegative(account=account, start=timezone.now())
negative.save()
- elif (hasattr(account, 'negative')
- and not account.negative.balance_offset):
+ elif hasattr(account, "negative") and not account.negative.balance_offset:
account.negative.delete()
- data['canceled'] = transfers
+ data["canceled"] = transfers
if transfers_already_canceled:
- data['warnings']['already_canceled'] = transfers_already_canceled
+ data["warnings"]["already_canceled"] = transfers_already_canceled
return JsonResponse(data)
+
class InventoryList(ListView):
- queryset = (Inventory.objects
- .select_related('by', 'order')
- .annotate(nb_articles=Count('articles'))
- .order_by('-at'))
- template_name = 'kfet/inventory.html'
- context_object_name = 'inventories'
+ queryset = (
+ Inventory.objects.select_related("by", "order")
+ .annotate(nb_articles=Count("articles"))
+ .order_by("-at")
+ )
+ template_name = "kfet/inventory.html"
+ context_object_name = "inventories"
+
@teamkfet_required
def inventory_create(request):
- articles = (Article.objects
- .select_related('category')
- .order_by('category__name', 'name')
- )
+ articles = Article.objects.select_related("category").order_by(
+ "category__name", "name"
+ )
initial = []
for article in articles:
- initial.append({
- 'article' : article.pk,
- 'stock_old': article.stock,
- 'name' : article.name,
- 'category' : article.category_id,
- 'category__name': article.category.name,
- 'box_capacity': article.box_capacity or 0,
- })
-
- cls_formset = formset_factory(
- form = InventoryArticleForm,
- extra = 0,
+ initial.append(
+ {
+ "article": article.pk,
+ "stock_old": article.stock,
+ "name": article.name,
+ "category": article.category_id,
+ "category__name": article.category.name,
+ "box_capacity": article.box_capacity or 0,
+ }
)
+ cls_formset = formset_factory(form=InventoryArticleForm, extra=0)
+
if request.POST:
formset = cls_formset(request.POST, initial=initial)
- if not request.user.has_perm('kfet.add_inventory'):
- messages.error(request, 'Permission refusée')
+ if not request.user.has_perm("kfet.add_inventory"):
+ messages.error(request, "Permission refusée")
elif formset.is_valid():
with transaction.atomic():
@@ -1675,60 +1730,63 @@ def inventory_create(request):
inventory.by = request.user.profile.account_kfet
saved = False
for form in formset:
- if form.cleaned_data['stock_new'] is not None:
+ if form.cleaned_data["stock_new"] is not None:
if not saved:
inventory.save()
saved = True
- article = articles.get(pk=form.cleaned_data['article'].pk)
+ article = articles.get(pk=form.cleaned_data["article"].pk)
stock_old = article.stock
- stock_new = form.cleaned_data['stock_new']
+ stock_new = form.cleaned_data["stock_new"]
InventoryArticle.objects.create(
- inventory = inventory,
- article = article,
- stock_old = stock_old,
- stock_new = stock_new)
+ inventory=inventory,
+ article=article,
+ stock_old=stock_old,
+ stock_new=stock_new,
+ )
article.stock = stock_new
article.save()
if saved:
- messages.success(request, 'Inventaire créé')
- return redirect('kfet.inventory')
- messages.warning(request, 'Bah alors ? On a rien compté ?')
+ messages.success(request, "Inventaire créé")
+ return redirect("kfet.inventory")
+ messages.warning(request, "Bah alors ? On a rien compté ?")
else:
- messages.error(request, 'Pas marché')
+ messages.error(request, "Pas marché")
else:
- formset = cls_formset(initial = initial)
+ formset = cls_formset(initial=initial)
+
+ return render(request, "kfet/inventory_create.html", {"formset": formset})
- return render(request, 'kfet/inventory_create.html', {
- 'formset': formset,
- })
class InventoryRead(DetailView):
model = Inventory
- template_name = 'kfet/inventory_read.html'
- context_object_name = 'inventory'
+ template_name = "kfet/inventory_read.html"
+ context_object_name = "inventory"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- inventoryarticles = (InventoryArticle.objects
- .select_related('article', 'article__category')
- .filter(inventory = self.object)
- .order_by('article__category__name', 'article__name'))
- context['inventoryarts'] = inventoryarticles
+ inventoryarticles = (
+ InventoryArticle.objects.select_related("article", "article__category")
+ .filter(inventory=self.object)
+ .order_by("article__category__name", "article__name")
+ )
+ context["inventoryarts"] = inventoryarticles
return context
+
# -----
# Order views
# -----
+
class OrderList(ListView):
- queryset = Order.objects.select_related('supplier', 'inventory')
- template_name = 'kfet/order.html'
- context_object_name = 'orders'
+ queryset = Order.objects.select_related("supplier", "inventory")
+ template_name = "kfet/order.html"
+ context_object_name = "orders"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['suppliers'] = Supplier.objects.order_by('name')
+ context["suppliers"] = Supplier.objects.order_by("name")
return context
@@ -1737,30 +1795,25 @@ def order_create(request, pk):
supplier = get_object_or_404(Supplier, pk=pk)
articles = (
- Article.objects
- .filter(suppliers=supplier.pk)
+ Article.objects.filter(suppliers=supplier.pk)
.distinct()
- .select_related('category')
- .order_by('category__name', 'name')
+ .select_related("category")
+ .order_by("category__name", "name")
)
# Force hit to cache
articles = list(articles)
sales_q = (
- Operation.objects
- .select_related('group')
+ Operation.objects.select_related("group")
.filter(article__in=articles, canceled_at=None)
- .values('article')
- .annotate(nb=Sum('article_nb'))
+ .values("article")
+ .annotate(nb=Sum("article_nb"))
)
scale = WeekScale(last=True, n_steps=5, std_chunk=False)
- chunks = scale.chunkify_qs(sales_q, field='group__at')
+ chunks = scale.chunkify_qs(sales_q, field="group__at")
- sales = [
- {d['article']: d['nb'] for d in chunk}
- for chunk in chunks
- ]
+ sales = [{d["article"]: d["nb"] for d in chunk} for chunk in chunks]
initial = []
@@ -1789,103 +1842,103 @@ def order_create(request, pk):
c_rec = 5
else:
c_rec = round(c_rec_temp)
- initial.append({
- 'article': article.pk,
- 'name': article.name,
- 'category': article.category_id,
- 'category__name': article.category.name,
- 'stock': article.stock,
- 'box_capacity': article.box_capacity,
- 'v_all': v_all,
- 'v_moy': round(v_moy),
- 'v_et': round(v_et),
- 'v_prev': round(v_prev),
- 'c_rec': article.box_capacity and c_rec or round(c_rec_tot),
- })
+ initial.append(
+ {
+ "article": article.pk,
+ "name": article.name,
+ "category": article.category_id,
+ "category__name": article.category.name,
+ "stock": article.stock,
+ "box_capacity": article.box_capacity,
+ "v_all": v_all,
+ "v_moy": round(v_moy),
+ "v_et": round(v_et),
+ "v_prev": round(v_prev),
+ "c_rec": article.box_capacity and c_rec or round(c_rec_tot),
+ }
+ )
- cls_formset = formset_factory(
- form=OrderArticleForm,
- extra=0,
- )
+ cls_formset = formset_factory(form=OrderArticleForm, extra=0)
if request.POST:
formset = cls_formset(request.POST, initial=initial)
- if not request.user.has_perm('kfet.add_order'):
- messages.error(request, 'Permission refusée')
+ if not request.user.has_perm("kfet.add_order"):
+ messages.error(request, "Permission refusée")
elif formset.is_valid():
order = Order()
order.supplier = supplier
saved = False
for form in formset:
- if form.cleaned_data['quantity_ordered'] is not None:
+ if form.cleaned_data["quantity_ordered"] is not None:
if not saved:
order.save()
saved = True
- article = form.cleaned_data['article']
- q_ordered = form.cleaned_data['quantity_ordered']
+ article = form.cleaned_data["article"]
+ q_ordered = form.cleaned_data["quantity_ordered"]
if article.box_capacity:
q_ordered *= article.box_capacity
OrderArticle.objects.create(
- order=order,
- article=article,
- quantity_ordered=q_ordered,
+ order=order, article=article, quantity_ordered=q_ordered
)
if saved:
- messages.success(request, 'Commande créée')
- return redirect('kfet.order.read', order.pk)
- messages.warning(request, 'Rien commandé => Pas de commande')
+ messages.success(request, "Commande créée")
+ return redirect("kfet.order.read", order.pk)
+ messages.warning(request, "Rien commandé => Pas de commande")
else:
- messages.error(request, 'Corrigez les erreurs')
+ messages.error(request, "Corrigez les erreurs")
else:
formset = cls_formset(initial=initial)
scale.label_fmt = "S-{rev_i}"
- return render(request, 'kfet/order_create.html', {
- 'supplier': supplier,
- 'formset': formset,
- 'scale': scale,
- })
+ return render(
+ request,
+ "kfet/order_create.html",
+ {"supplier": supplier, "formset": formset, "scale": scale},
+ )
class OrderRead(DetailView):
model = Order
- template_name = 'kfet/order_read.html'
- context_object_name = 'order'
+ template_name = "kfet/order_read.html"
+ context_object_name = "order"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- orderarticles = (OrderArticle.objects
- .select_related('article', 'article__category')
- .filter(order=self.object)
- .order_by('article__category__name', 'article__name')
- )
- context['orderarts'] = orderarticles
- mail = ("Bonjour,\n\nNous voudrions pour le ##DATE## à la K-Fêt de "
- "l'ENS Ulm :")
+ orderarticles = (
+ OrderArticle.objects.select_related("article", "article__category")
+ .filter(order=self.object)
+ .order_by("article__category__name", "article__name")
+ )
+ context["orderarts"] = orderarticles
+ mail = (
+ "Bonjour,\n\nNous voudrions pour le ##DATE## à la K-Fêt de " "l'ENS Ulm :"
+ )
category = 0
for orderarticle in orderarticles:
if category != orderarticle.article.category:
category = orderarticle.article.category
- mail += '\n'
+ mail += "\n"
nb = orderarticle.quantity_ordered
- box = ''
+ box = ""
if orderarticle.article.box_capacity:
nb /= orderarticle.article.box_capacity
if nb >= 2:
- box = ' %ss de' % orderarticle.article.box_type
+ box = " %ss de" % orderarticle.article.box_type
else:
- box = ' %s de' % orderarticle.article.box_type
+ box = " %s de" % orderarticle.article.box_type
name = orderarticle.article.name.capitalize()
mail += "\n- %s%s %s" % (round(nb), box, name)
- mail += ("\n\nMerci d'appeler le numéro suivant lorsque les livreurs "
- "sont là : ##TELEPHONE##\nCordialement,\n##PRENOM## ##NOM## "
- ", pour la K-Fêt de l'ENS Ulm")
+ mail += (
+ "\n\nMerci d'appeler le numéro suivant lorsque les livreurs "
+ "sont là : ##TELEPHONE##\nCordialement,\n##PRENOM## ##NOM## "
+ ", pour la K-Fêt de l'ENS Ulm"
+ )
- context['mail'] = mail
+ context["mail"] = mail
return context
@@ -1893,69 +1946,70 @@ class OrderRead(DetailView):
def order_to_inventory(request, pk):
order = get_object_or_404(Order, pk=pk)
- if hasattr(order, 'inventory'):
+ if hasattr(order, "inventory"):
raise Http404
supplier_prefetch = Prefetch(
- 'article__supplierarticle_set',
+ "article__supplierarticle_set",
queryset=(
- SupplierArticle.objects
- .filter(supplier=order.supplier)
- .order_by('-at')
+ SupplierArticle.objects.filter(supplier=order.supplier).order_by("-at")
),
- to_attr='supplier',
+ to_attr="supplier",
)
order_articles = (
- OrderArticle.objects
- .filter(order=order.pk)
- .select_related('article', 'article__category')
- .prefetch_related(
- supplier_prefetch,
- )
- .order_by('article__category__name', 'article__name')
+ OrderArticle.objects.filter(order=order.pk)
+ .select_related("article", "article__category")
+ .prefetch_related(supplier_prefetch)
+ .order_by("article__category__name", "article__name")
)
initial = []
for order_article in order_articles:
article = order_article.article
- initial.append({
- 'article': article.pk,
- 'name': article.name,
- 'category': article.category_id,
- 'category__name': article.category.name,
- 'quantity_ordered': order_article.quantity_ordered,
- 'quantity_received': order_article.quantity_ordered,
- 'price_HT': article.supplier[0].price_HT,
- 'TVA': article.supplier[0].TVA,
- 'rights': article.supplier[0].rights,
- })
+ initial.append(
+ {
+ "article": article.pk,
+ "name": article.name,
+ "category": article.category_id,
+ "category__name": article.category.name,
+ "quantity_ordered": order_article.quantity_ordered,
+ "quantity_received": order_article.quantity_ordered,
+ "price_HT": article.supplier[0].price_HT,
+ "TVA": article.supplier[0].TVA,
+ "rights": article.supplier[0].rights,
+ }
+ )
cls_formset = formset_factory(OrderArticleToInventoryForm, extra=0)
- if request.method == 'POST':
+ if request.method == "POST":
formset = cls_formset(request.POST, initial=initial)
- if not request.user.has_perm('kfet.order_to_inventory'):
- messages.error(request, 'Permission refusée')
+ if not request.user.has_perm("kfet.order_to_inventory"):
+ messages.error(request, "Permission refusée")
elif formset.is_valid():
with transaction.atomic():
inventory = Inventory.objects.create(
- order=order, by=request.user.profile.account_kfet,
+ order=order, by=request.user.profile.account_kfet
)
new_supplierarticle = []
new_inventoryarticle = []
for form in formset:
- q_received = form.cleaned_data['quantity_received']
- article = form.cleaned_data['article']
+ q_received = form.cleaned_data["quantity_received"]
+ article = form.cleaned_data["article"]
- price_HT = form.cleaned_data['price_HT']
- TVA = form.cleaned_data['TVA']
- rights = form.cleaned_data['rights']
+ price_HT = form.cleaned_data["price_HT"]
+ TVA = form.cleaned_data["TVA"]
+ rights = form.cleaned_data["rights"]
- if any((form.initial['price_HT'] != price_HT,
- form.initial['TVA'] != TVA,
- form.initial['rights'] != rights)):
+ if any(
+ (
+ form.initial["price_HT"] != price_HT,
+ form.initial["TVA"] != TVA,
+ form.initial["rights"] != rights,
+ )
+ ):
new_supplierarticle.append(
SupplierArticle(
supplier=order.supplier,
@@ -1966,9 +2020,9 @@ def order_to_inventory(request, pk):
)
)
(
- OrderArticle.objects
- .filter(order=order, article=article)
- .update(quantity_received=q_received)
+ OrderArticle.objects.filter(
+ order=order, article=article
+ ).update(quantity_received=q_received)
)
new_inventoryarticle.append(
InventoryArticle(
@@ -1985,29 +2039,29 @@ def order_to_inventory(request, pk):
SupplierArticle.objects.bulk_create(new_supplierarticle)
InventoryArticle.objects.bulk_create(new_inventoryarticle)
messages.success(request, "C'est tout bon !")
- return redirect('kfet.order')
+ return redirect("kfet.order")
else:
messages.error(request, "Corrigez les erreurs")
else:
formset = cls_formset(initial=initial)
- return render(request, 'kfet/order_to_inventory.html', {
- 'formset': formset,
- 'order': order,
- })
+ return render(
+ request, "kfet/order_to_inventory.html", {"formset": formset, "order": order}
+ )
+
class SupplierUpdate(SuccessMessageMixin, UpdateView):
- model = Supplier
- template_name = 'kfet/supplier_form.html'
- fields = ['name', 'address', 'email', 'phone', 'comment']
- success_url = reverse_lazy('kfet.order')
- sucess_message = 'Données fournisseur mis à jour'
+ model = Supplier
+ template_name = "kfet/supplier_form.html"
+ fields = ["name", "address", "email", "phone", "comment"]
+ success_url = reverse_lazy("kfet.order")
+ sucess_message = "Données fournisseur mis à jour"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
- if not self.request.user.has_perm('kfet.change_supplier'):
- form.add_error(None, 'Permission refusée')
+ if not self.request.user.has_perm("kfet.change_supplier"):
+ form.add_error(None, "Permission refusée")
return self.form_invalid(form)
# Updating
return super().form_valid(form)
@@ -2025,14 +2079,12 @@ class JSONResponseMixin(object):
"""
A mixin that can be used to render a JSON response.
"""
+
def render_to_json_response(self, context, **response_kwargs):
"""
Returns a JSON response, transforming 'context' to make the payload.
"""
- return JsonResponse(
- self.get_data(context),
- **response_kwargs
- )
+ return JsonResponse(self.get_data(context), **response_kwargs)
def get_data(self, context):
"""
@@ -2053,7 +2105,6 @@ class JSONDetailView(JSONResponseMixin, BaseDetailView):
class PkUrlMixin(object):
-
def get_object(self, *args, **kwargs):
get_by = self.kwargs.get(self.pk_url_kwarg)
return get_object_or_404(self.model, **{self.pk_url_kwarg: get_by})
@@ -2066,7 +2117,8 @@ class SingleResumeStat(JSONDetailView):
url to retrieve data, label, ...
"""
- id_prefix = ''
+
+ id_prefix = ""
nb_default = 0
stats = []
@@ -2077,27 +2129,28 @@ class SingleResumeStat(JSONDetailView):
object_id = self.object.id
context = {}
stats = []
- prefix = '{}_{}'.format(self.id_prefix, object_id)
+ prefix = "{}_{}".format(self.id_prefix, object_id)
for i, stat_def in enumerate(self.stats):
url_pk = getattr(self.object, self.pk_url_kwarg)
- url_params_d = stat_def.get('url_params', {})
+ url_params_d = stat_def.get("url_params", {})
if len(url_params_d) > 0:
- url_params = '?{}'.format(urlencode(url_params_d))
+ url_params = "?{}".format(urlencode(url_params_d))
else:
- url_params = ''
- stats.append({
- 'label': stat_def['label'],
- 'btn': 'btn_{}_{}'.format(prefix, i),
- 'url': '{url}{params}'.format(
- url=reverse(self.url_stat, args=[url_pk]),
- params=url_params,
- ),
- })
- context['id_prefix'] = prefix
- context['content_id'] = "content_%s" % prefix
- context['stats'] = stats
- context['default_stat'] = self.nb_default
- context['object_id'] = object_id
+ url_params = ""
+ stats.append(
+ {
+ "label": stat_def["label"],
+ "btn": "btn_{}_{}".format(prefix, i),
+ "url": "{url}{params}".format(
+ url=reverse(self.url_stat, args=[url_pk]), params=url_params
+ ),
+ }
+ )
+ context["id_prefix"] = prefix
+ context["content_id"] = "content_%s" % prefix
+ context["stats"] = stats
+ context["default_stat"] = self.nb_default
+ context["object_id"] = object_id
return context
@@ -2109,31 +2162,18 @@ ID_PREFIX_ACC_BALANCE = "balance_acc"
class AccountStatBalanceList(PkUrlMixin, SingleResumeStat):
"""Manifest for balance stats of an account."""
+
model = Account
- context_object_name = 'account'
- pk_url_kwarg = 'trigramme'
- url_stat = 'kfet.account.stat.balance'
+ context_object_name = "account"
+ pk_url_kwarg = "trigramme"
+ url_stat = "kfet.account.stat.balance"
id_prefix = ID_PREFIX_ACC_BALANCE
stats = [
- {
- 'label': 'Tout le temps',
- },
- {
- 'label': '1 an',
- 'url_params': {'last_days': 365},
- },
- {
- 'label': '6 mois',
- 'url_params': {'last_days': 183},
- },
- {
- 'label': '3 mois',
- 'url_params': {'last_days': 90},
- },
- {
- 'label': '30 jours',
- 'url_params': {'last_days': 30},
- },
+ {"label": "Tout le temps"},
+ {"label": "1 an", "url_params": {"last_days": 365}},
+ {"label": "6 mois", "url_params": {"last_days": 183}},
+ {"label": "3 mois", "url_params": {"last_days": 90}},
+ {"label": "30 jours", "url_params": {"last_days": 30}},
]
nb_default = 0
@@ -2154,9 +2194,10 @@ class AccountStatBalance(PkUrlMixin, JSONDetailView):
Operations and Transfers are taken into account.
"""
+
model = Account
- pk_url_kwarg = 'trigramme'
- context_object_name = 'account'
+ pk_url_kwarg = "trigramme"
+ context_object_name = "account"
def get_changes_list(self, last_days=None, begin_date=None, end_date=None):
account = self.object
@@ -2169,11 +2210,7 @@ class AccountStatBalance(PkUrlMixin, JSONDetailView):
# prepare querysets
# TODO: retirer les opgroup dont tous les op sont annulées
opegroups = OperationGroup.objects.filter(on_acc=account)
- transfers = (
- Transfer.objects
- .filter(canceled_at=None)
- .select_related('group')
- )
+ transfers = Transfer.objects.filter(canceled_at=None).select_related("group")
recv_transfers = transfers.filter(to_acc=account)
sent_transfers = transfers.filter(from_acc=account)
@@ -2200,69 +2237,62 @@ class AccountStatBalance(PkUrlMixin, JSONDetailView):
actions = []
- actions.append({
- 'at': (begin_date or account.created_at).isoformat(),
- 'amount': 0,
- 'balance': 0,
- })
- actions.append({
- 'at': (end_date or timezone.now()).isoformat(),
- 'amount': 0,
- 'balance': 0,
- })
+ actions.append(
+ {
+ "at": (begin_date or account.created_at).isoformat(),
+ "amount": 0,
+ "balance": 0,
+ }
+ )
+ actions.append(
+ {"at": (end_date or timezone.now()).isoformat(), "amount": 0, "balance": 0}
+ )
- actions += [
- {
- 'at': ope_grp.at.isoformat(),
- 'amount': ope_grp.amount,
- 'balance': 0,
- } for ope_grp in opegroups
- ] + [
- {
- 'at': tr.group.at.isoformat(),
- 'amount': tr.amount,
- 'balance': 0,
- } for tr in recv_transfers
- ] + [
- {
- 'at': tr.group.at.isoformat(),
- 'amount': -tr.amount,
- 'balance': 0,
- } for tr in sent_transfers
- ]
+ actions += (
+ [
+ {"at": ope_grp.at.isoformat(), "amount": ope_grp.amount, "balance": 0}
+ for ope_grp in opegroups
+ ]
+ + [
+ {"at": tr.group.at.isoformat(), "amount": tr.amount, "balance": 0}
+ for tr in recv_transfers
+ ]
+ + [
+ {"at": tr.group.at.isoformat(), "amount": -tr.amount, "balance": 0}
+ for tr in sent_transfers
+ ]
+ )
# Maintenant on trie la liste des actions par ordre du plus récent
# an plus ancien et on met à jour la balance
if len(actions) > 1:
- actions = sorted(actions, key=lambda k: k['at'], reverse=True)
- actions[0]['balance'] = account.balance
- for i in range(len(actions)-1):
- actions[i+1]['balance'] = \
- actions[i]['balance'] - actions[i+1]['amount']
+ actions = sorted(actions, key=lambda k: k["at"], reverse=True)
+ actions[0]["balance"] = account.balance
+ for i in range(len(actions) - 1):
+ actions[i + 1]["balance"] = (
+ actions[i]["balance"] - actions[i + 1]["amount"]
+ )
return actions
def get_context_data(self, *args, **kwargs):
context = {}
- last_days = self.request.GET.get('last_days', None)
+ last_days = self.request.GET.get("last_days", None)
if last_days is not None:
last_days = int(last_days)
- begin_date = self.request.GET.get('begin_date', None)
- end_date = self.request.GET.get('end_date', None)
+ begin_date = self.request.GET.get("begin_date", None)
+ end_date = self.request.GET.get("end_date", None)
changes = self.get_changes_list(
- last_days=last_days,
- begin_date=begin_date, end_date=end_date,
+ last_days=last_days, begin_date=begin_date, end_date=end_date
)
- context['charts'] = [{
- "color": "rgb(200, 20, 60)",
- "label": "Balance",
- "values": changes,
- }]
- context['is_time_chart'] = True
+ context["charts"] = [
+ {"color": "rgb(200, 20, 60)", "label": "Balance", "values": changes}
+ ]
+ context["is_time_chart"] = True
if len(changes) > 0:
- context['min_date'] = changes[-1]['at']
- context['max_date'] = changes[0]['at']
+ context["min_date"] = changes[-1]["at"]
+ context["max_date"] = changes[0]["at"]
# TODO: offset
return context
@@ -2288,13 +2318,14 @@ ID_PREFIX_ACC_LAST_MONTHS = "last_months_acc"
class AccountStatOperationList(PkUrlMixin, SingleResumeStat):
"""Manifest for operations stats of an account."""
+
model = Account
- context_object_name = 'account'
- pk_url_kwarg = 'trigramme'
+ context_object_name = "account"
+ pk_url_kwarg = "trigramme"
id_prefix = ID_PREFIX_ACC_LAST
nb_default = 2
stats = last_stats_manifest(types=[Operation.PURCHASE])
- url_stat = 'kfet.account.stat.operation'
+ url_stat = "kfet.account.stat.operation"
def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs)
@@ -2309,9 +2340,10 @@ class AccountStatOperationList(PkUrlMixin, SingleResumeStat):
class AccountStatOperation(ScaleMixin, PkUrlMixin, JSONDetailView):
"""Datasets of operations of an account."""
+
model = Account
- pk_url_kwarg = 'trigramme'
- context_object_name = 'account'
+ pk_url_kwarg = "trigramme"
+ context_object_name = "account"
id_prefix = ""
def get_operations(self, scale, types=None):
@@ -2320,26 +2352,25 @@ class AccountStatOperation(ScaleMixin, PkUrlMixin, JSONDetailView):
# puis on choisi pour chaques intervalle les opérations
# effectuées dans ces intervalles de temps
all_operations = (
- Operation.objects
- .filter(group__on_acc=self.object,
- canceled_at=None)
- .values('article_nb', 'group__at')
- .order_by('group__at')
+ Operation.objects.filter(group__on_acc=self.object, canceled_at=None)
+ .values("article_nb", "group__at")
+ .order_by("group__at")
)
if types is not None:
all_operations = all_operations.filter(type__in=types)
chunks = scale.get_by_chunks(
- all_operations, field_db='group__at',
- field_callback=(lambda d: d['group__at']),
+ all_operations,
+ field_db="group__at",
+ field_callback=(lambda d: d["group__at"]),
)
return chunks
def get_context_data(self, *args, **kwargs):
old_ctx = super().get_context_data(*args, **kwargs)
- context = {'labels': old_ctx['labels']}
+ context = {"labels": old_ctx["labels"]}
scale = self.scale
- types = self.request.GET.get('types', None)
+ types = self.request.GET.get("types", None)
if types is not None:
types = ast.literal_eval(types)
@@ -2347,12 +2378,16 @@ class AccountStatOperation(ScaleMixin, PkUrlMixin, JSONDetailView):
# On compte les opérations
nb_ventes = []
for chunk in operations:
- ventes = sum(ope['article_nb'] for ope in chunk)
+ ventes = sum(ope["article_nb"] for ope in chunk)
nb_ventes.append(ventes)
- context['charts'] = [{"color": "rgb(200, 20, 60)",
- "label": "NB items achetés",
- "values": nb_ventes}]
+ context["charts"] = [
+ {
+ "color": "rgb(200, 20, 60)",
+ "label": "NB items achetés",
+ "values": nb_ventes,
+ }
+ ]
return context
def get_object(self, *args, **kwargs):
@@ -2377,11 +2412,12 @@ ID_PREFIX_ART_LAST_MONTHS = "last_months_art"
class ArticleStatSalesList(SingleResumeStat):
"""Manifest for sales stats of an article."""
+
model = Article
- context_object_name = 'article'
+ context_object_name = "article"
id_prefix = ID_PREFIX_ART_LAST
nb_default = 2
- url_stat = 'kfet.article.stat.sales'
+ url_stat = "kfet.article.stat.sales"
stats = last_stats_manifest()
@method_decorator(teamkfet_required)
@@ -2391,34 +2427,30 @@ class ArticleStatSalesList(SingleResumeStat):
class ArticleStatSales(ScaleMixin, JSONDetailView):
"""Datasets of sales of an article."""
+
model = Article
- context_object_name = 'article'
+ context_object_name = "article"
def get_context_data(self, *args, **kwargs):
old_ctx = super().get_context_data(*args, **kwargs)
- context = {'labels': old_ctx['labels']}
+ context = {"labels": old_ctx["labels"]}
scale = self.scale
all_purchases = (
- Operation.objects
- .filter(
- type=Operation.PURCHASE,
- article=self.object,
- canceled_at=None,
+ Operation.objects.filter(
+ type=Operation.PURCHASE, article=self.object, canceled_at=None
)
- .values('group__at', 'article_nb')
- .order_by('group__at')
+ .values("group__at", "article_nb")
+ .order_by("group__at")
)
- liq_only = all_purchases.filter(group__on_acc__trigramme='LIQ')
- liq_exclude = all_purchases.exclude(group__on_acc__trigramme='LIQ')
+ liq_only = all_purchases.filter(group__on_acc__trigramme="LIQ")
+ liq_exclude = all_purchases.exclude(group__on_acc__trigramme="LIQ")
chunks_liq = scale.get_by_chunks(
- liq_only, field_db='group__at',
- field_callback=lambda d: d['group__at'],
+ liq_only, field_db="group__at", field_callback=lambda d: d["group__at"]
)
chunks_no_liq = scale.get_by_chunks(
- liq_exclude, field_db='group__at',
- field_callback=lambda d: d['group__at'],
+ liq_exclude, field_db="group__at", field_callback=lambda d: d["group__at"]
)
# On compte les opérations
@@ -2426,21 +2458,25 @@ class ArticleStatSales(ScaleMixin, JSONDetailView):
nb_accounts = []
nb_liq = []
for chunk_liq, chunk_no_liq in zip(chunks_liq, chunks_no_liq):
- sum_accounts = sum(ope['article_nb'] for ope in chunk_no_liq)
- sum_liq = sum(ope['article_nb'] for ope in chunk_liq)
+ sum_accounts = sum(ope["article_nb"] for ope in chunk_no_liq)
+ sum_liq = sum(ope["article_nb"] for ope in chunk_liq)
nb_ventes.append(sum_accounts + sum_liq)
nb_accounts.append(sum_accounts)
nb_liq.append(sum_liq)
- context['charts'] = [{"color": "rgb(200, 20, 60)",
- "label": "Toutes consommations",
- "values": nb_ventes},
- {"color": "rgb(54, 162, 235)",
- "label": "LIQ",
- "values": nb_liq},
- {"color": "rgb(255, 205, 86)",
- "label": "Comptes K-Fêt",
- "values": nb_accounts}]
+ context["charts"] = [
+ {
+ "color": "rgb(200, 20, 60)",
+ "label": "Toutes consommations",
+ "values": nb_ventes,
+ },
+ {"color": "rgb(54, 162, 235)", "label": "LIQ", "values": nb_liq},
+ {
+ "color": "rgb(255, 205, 86)",
+ "label": "Comptes K-Fêt",
+ "values": nb_accounts,
+ },
+ ]
return context
@method_decorator(teamkfet_required)
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..93b26440
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,9 @@
+[tool.black]
+# Automatically ignore files in .gitignore (opened at this time):
+# https://github.com/ambv/black/issues/475
+exclude = '''
+/(
+ \.pyc
+ | venv
+)/
+'''
diff --git a/requirements-devel.txt b/requirements-devel.txt
index 83053f76..6a5acdd7 100644
--- a/requirements-devel.txt
+++ b/requirements-devel.txt
@@ -2,3 +2,8 @@
django-debug-toolbar
django-debug-panel
ipython
+
+# Tools
+# black # Uncomment when GC & most distros run with Python>=3.6
+flake8
+isort
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..ec29c73c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,40 @@
+[coverage:run]
+source =
+ bda
+ cof
+ gestioncof
+ kfet
+ shared
+ utils
+omit =
+ *migrations*
+ *test*.py
+branch = true
+
+[coverage:report]
+precision = 2
+show_missing = true
+
+[flake8]
+exclude = migrations
+max-line-length = 88
+ignore =
+ # whitespace before ':' (not PEP8-compliant for slicing)
+ E203,
+ # lambda expression
+ E731,
+ # line break before binary operator (not PEP8-compliant)
+ W503
+
+[isort]
+# For black compat: https://github.com/ambv/black#how-black-wraps-lines
+combine_as_imports = true
+default_section = THIRDPARTY
+force_grid_wrap = 0
+include_trailing_comma = true
+known_django = django
+known_first_party = bda,cof,gestioncof,kfet,shared,utils
+line_length = 88
+multi_line_output = 3
+not_skip = __init__.py
+sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
diff --git a/shared/tests/testcases.py b/shared/tests/testcases.py
index 6967d9b7..19122322 100644
--- a/shared/tests/testcases.py
+++ b/shared/tests/testcases.py
@@ -2,6 +2,7 @@ import csv
from unittest import mock
from urllib.parse import parse_qs, urlparse
+import icalendar
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.http import QueryDict
@@ -9,13 +10,10 @@ from django.test import Client
from django.utils import timezone
from django.utils.functional import cached_property
-import icalendar
-
User = get_user_model()
class TestCaseMixin:
-
def assertForbidden(self, response):
"""
Test that the response (retrieved with a Client) is a denial of access.
@@ -40,31 +38,30 @@ class TestCaseMixin:
full_path = request.get_full_path()
querystring = QueryDict(mutable=True)
- querystring['next'] = full_path
+ querystring["next"] = full_path
- login_url = '{}?{}'.format(
- reverse('cof-login'), querystring.urlencode(safe='/'))
+ login_url = "{}?{}".format(
+ reverse("cof-login"), querystring.urlencode(safe="/")
+ )
# We don't focus on what the login view does.
# So don't fetch the redirect.
- self.assertRedirects(
- response, login_url,
- fetch_redirect_response=False,
- )
+ self.assertRedirects(response, login_url, fetch_redirect_response=False)
except AssertionError:
raise AssertionError(
"%(http_method)s request at %(path)s should be forbidden for "
"%(username)s user.\n"
"Response isn't 403, nor a redirect to login view. Instead, "
- "response code is %(code)d." % {
- 'http_method': request.method,
- 'path': request.get_full_path(),
- 'username': (
+ "response code is %(code)d."
+ % {
+ "http_method": request.method,
+ "path": request.get_full_path(),
+ "username": (
"'{}'".format(request.user)
if request.user.is_authenticated()
- else 'anonymous'
+ else "anonymous"
),
- 'code': response.status_code,
+ "code": response.status_code,
}
)
@@ -85,19 +82,45 @@ class TestCaseMixin:
if type(expected) == dict:
parsed = urlparse(actual)
for part, expected_part in expected.items():
- if part == 'query':
+ if part == "query":
self.assertDictEqual(
- parse_qs(parsed.query),
- expected.get('query', {}),
+ parse_qs(parsed.query), expected.get("query", {})
)
else:
self.assertEqual(getattr(parsed, part), expected_part)
else:
self.assertEqual(actual, expected)
+ def mockLDAP(self, results):
+ class Elt:
+ def __init__(self, value):
+ self.value = value
+
+ class Entry:
+ def __init__(self, **kwargs):
+ for k, v in kwargs.items():
+ setattr(self, k, Elt(v))
+
+ results_as_ldap = [Entry(uid=uid, cn=name) for uid, name in results]
+
+ mock_connection = mock.MagicMock()
+ mock_connection.entries = results_as_ldap
+
+ # Connection is used as a context manager.
+ mock_context_manager = mock.MagicMock()
+ mock_context_manager.return_value.__enter__.return_value = mock_connection
+
+ patcher = mock.patch(
+ "gestioncof.autocomplete.Connection", new=mock_context_manager
+ )
+ patcher.start()
+ self.addCleanup(patcher.stop)
+
+ return mock_connection
+
def load_from_csv_response(self, r):
- decoded = r.content.decode('utf-8')
- return list(csv.reader(decoded.split('\n')[:-1]))
+ decoded = r.content.decode("utf-8")
+ return list(csv.reader(decoded.split("\n")[:-1]))
def _test_event_equal(self, event, exp):
for k, v_desc in exp.items():
@@ -123,7 +146,7 @@ class TestCaseMixin:
cal = icalendar.Calendar.from_ical(ical_content)
- for ev in cal.walk('vevent'):
+ for ev in cal.walk("vevent"):
found, i_found = self._find_event(ev, remaining)
if found:
remaining.pop(i_found)
@@ -203,10 +226,11 @@ class ViewTestCaseMixin(TestCaseMixin):
can be given by defining an attribute '_data'.
"""
+
url_name = None
url_expected = None
- http_methods = ['GET']
+ http_methods = ["GET"]
auth_user = None
auth_forbidden = []
@@ -218,7 +242,7 @@ class ViewTestCaseMixin(TestCaseMixin):
# Signals handlers on login/logout send messages.
# Due to the way the Django' test Client performs login, this raise an
# error. As workaround, we mock the Django' messages module.
- patcher_messages = mock.patch('gestioncof.signals.messages')
+ patcher_messages = mock.patch("gestioncof.signals.messages")
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
@@ -236,10 +260,7 @@ class ViewTestCaseMixin(TestCaseMixin):
if self.auth_user:
# The wrapper is a sanity check.
self.assertTrue(
- self.client.login(
- username=self.auth_user,
- password=self.auth_user,
- )
+ self.client.login(username=self.auth_user, password=self.auth_user)
)
def tearDown(self):
@@ -257,8 +278,8 @@ class ViewTestCaseMixin(TestCaseMixin):
"""
return {
- 'user': User.objects.create_user('user', '', 'user'),
- 'root': User.objects.create_superuser('root', '', 'root'),
+ "user": User.objects.create_user("user", "", "user"),
+ "root": User.objects.create_superuser("root", "", "root"),
}
@cached_property
@@ -291,22 +312,25 @@ class ViewTestCaseMixin(TestCaseMixin):
@property
def urls_conf(self):
- return [{
- 'name': self.url_name,
- 'args': getattr(self, 'url_args', []),
- 'kwargs': getattr(self, 'url_kwargs', {}),
- 'expected': self.url_expected,
- }]
+ return [
+ {
+ "name": self.url_name,
+ "args": getattr(self, "url_args", []),
+ "kwargs": getattr(self, "url_kwargs", {}),
+ "expected": self.url_expected,
+ }
+ ]
@property
def t_urls(self):
return [
reverse(
- url_conf['name'],
- args=url_conf.get('args', []),
- kwargs=url_conf.get('kwargs', {}),
+ url_conf["name"],
+ args=url_conf.get("args", []),
+ kwargs=url_conf.get("kwargs", {}),
)
- for url_conf in self.urls_conf]
+ for url_conf in self.urls_conf
+ ]
@property
def url(self):
@@ -314,7 +338,7 @@ class ViewTestCaseMixin(TestCaseMixin):
def test_urls(self):
for url, conf in zip(self.t_urls, self.urls_conf):
- self.assertEqual(url, conf['expected'])
+ self.assertEqual(url, conf["expected"])
def test_forbidden(self):
for method in self.http_methods:
@@ -329,7 +353,7 @@ class ViewTestCaseMixin(TestCaseMixin):
client.login(username=user, password=user)
send_request = getattr(client, method)
- data = getattr(self, '{}_data'.format(method), {})
+ data = getattr(self, "{}_data".format(method), {})
r = send_request(url, data)
self.assertForbidden(r)
diff --git a/utils/views/autocomplete.py b/utils/views/autocomplete.py
index ca50c63b..c5d51343 100644
--- a/utils/views/autocomplete.py
+++ b/utils/views/autocomplete.py
@@ -1,6 +1,5 @@
-from django.db.models import Q
-
from dal import autocomplete
+from django.db.models import Q
class Select2QuerySetView(autocomplete.Select2QuerySetView):
@@ -18,7 +17,7 @@ class Select2QuerySetView(autocomplete.Select2QuerySetView):
for word in words:
for field in self.search_fields:
- filter_q |= Q(**{'{}__icontains'.format(field): word})
+ filter_q |= Q(**{"{}__icontains".format(field): word})
return filter_q