cleaned up code
This commit is contained in:
@@ -1,10 +1,5 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
|
|
||||||
from .models import *
|
from .models import *
|
||||||
from .notes import Observation
|
from .notes import Observation
|
||||||
|
|
||||||
@@ -12,6 +7,7 @@ from .notes import Observation
|
|||||||
# Basic registration
|
# Basic registration
|
||||||
admin.site.register(Lieu)
|
admin.site.register(Lieu)
|
||||||
|
|
||||||
|
|
||||||
# Inlines
|
# Inlines
|
||||||
class ObservationInline(admin.StackedInline):
|
class ObservationInline(admin.StackedInline):
|
||||||
model = Observation
|
model = Observation
|
||||||
@@ -32,7 +28,6 @@ class RencontreAdmin(admin.ModelAdmin):
|
|||||||
list_filter = ['lieu']
|
list_filter = ['lieu']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Maraude)
|
@admin.register(Maraude)
|
||||||
class MaraudeAdmin(admin.ModelAdmin):
|
class MaraudeAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,3 @@ from django.apps import AppConfig
|
|||||||
|
|
||||||
class Config(AppConfig):
|
class Config(AppConfig):
|
||||||
name = 'maraudes'
|
name = 'maraudes'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
from django.utils.translation import gettext
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from django_select2.forms import Select2Widget
|
from django_select2.forms import Select2Widget
|
||||||
|
|
||||||
# Models
|
|
||||||
from .models import *
|
|
||||||
from .notes import *
|
|
||||||
from notes.forms import UserNoteForm, SimpleNoteForm
|
from notes.forms import UserNoteForm, SimpleNoteForm
|
||||||
from notes.models import Sujet, GENRE_CHOICES
|
from notes.models import Sujet, GENRE_CHOICES
|
||||||
|
from .models import *
|
||||||
|
from .notes import *
|
||||||
|
|
||||||
|
|
||||||
|
MONTHS = [
|
||||||
|
(num, gettext(calendar.month_name[num])) for num in range(1, 13)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def current_year_range():
|
def current_year_range():
|
||||||
""" Returns a range from year -1 to year + 2 """
|
""" Returns a range from year -1 to year + 2 """
|
||||||
year = timezone.now().date().year
|
year = timezone.now().date().year
|
||||||
return (year - 1, year, year + 1, year + 2)
|
return year - 1, year, year + 1, year + 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MaraudeHiddenDateForm(forms.ModelForm):
|
class MaraudeHiddenDateForm(forms.ModelForm):
|
||||||
@@ -24,8 +26,6 @@ class MaraudeHiddenDateForm(forms.ModelForm):
|
|||||||
widgets = {'date': forms.HiddenInput()}
|
widgets = {'date': forms.HiddenInput()}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RencontreForm(forms.ModelForm):
|
class RencontreForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rencontre
|
model = Rencontre
|
||||||
@@ -35,36 +35,32 @@ class RencontreForm(forms.ModelForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ObservationInlineFormSet = forms.inlineformset_factory( Rencontre, Observation,
|
ObservationInlineFormSet = forms.inlineformset_factory(
|
||||||
|
Rencontre, Observation,
|
||||||
form=SimpleNoteForm,
|
form=SimpleNoteForm,
|
||||||
extra = 1,
|
extra=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
RencontreInlineFormSet = forms.inlineformset_factory(
|
RencontreInlineFormSet = forms.inlineformset_factory(
|
||||||
Maraude, Rencontre,
|
Maraude, Rencontre,
|
||||||
form = RencontreForm,
|
form=RencontreForm,
|
||||||
extra = 0,
|
extra=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
ObservationInlineFormSetNoExtra = forms.inlineformset_factory(
|
ObservationInlineFormSetNoExtra = forms.inlineformset_factory(
|
||||||
Rencontre, Observation,
|
Rencontre, Observation,
|
||||||
form = SimpleNoteForm,
|
form=SimpleNoteForm,
|
||||||
extra = 0
|
extra=0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MonthSelectForm(forms.Form):
|
class MonthSelectForm(forms.Form):
|
||||||
|
|
||||||
month = forms.ChoiceField(label="Mois",
|
month = forms.ChoiceField(label="Mois",
|
||||||
choices=[
|
choices=MONTHS,
|
||||||
(1, 'Janvier'), (2, 'Février'), (3, 'Mars'), (4, 'Avril'),
|
|
||||||
(5, 'Mai'), (6, 'Juin'), (7, 'Juillet'), (8, 'Août'),
|
|
||||||
(9, 'Septembre'),(10, 'Octobre'),(11, 'Novembre'),(12, 'Décembre')
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
year = forms.ChoiceField(label="Année",
|
year = forms.ChoiceField(label="Année",
|
||||||
choices = [(y, y) for y in current_year_range()]
|
choices=[(y, y) for y in current_year_range()],
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, month=None, year=None, **kwargs):
|
def __init__(self, *args, month=None, year=None, **kwargs):
|
||||||
@@ -73,16 +69,13 @@ class MonthSelectForm(forms.Form):
|
|||||||
self.fields['year'].initial = year
|
self.fields['year'].initial = year
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AppelForm(UserNoteForm):
|
class AppelForm(UserNoteForm):
|
||||||
class Meta(UserNoteForm.Meta):
|
class Meta(UserNoteForm.Meta):
|
||||||
model = Appel
|
model = Appel
|
||||||
fields = ['sujet', 'text', 'entrant', 'created_date', 'created_time']
|
fields = ['sujet', 'text', 'entrant', 'created_date', 'created_time']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SignalementForm(UserNoteForm):
|
class SignalementForm(UserNoteForm):
|
||||||
|
|
||||||
nom = forms.CharField(64, required=False)
|
nom = forms.CharField(64, required=False)
|
||||||
prenom = forms.CharField(64, required=False)
|
prenom = forms.CharField(64, required=False)
|
||||||
age = forms.IntegerField(required=False)
|
age = forms.IntegerField(required=False)
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
from django.db.models import Manager
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
from django.db.models import Manager
|
||||||
|
|
||||||
|
|
||||||
# TODO: What is really useful in there ??
|
|
||||||
class MaraudeManager(Manager):
|
class MaraudeManager(Manager):
|
||||||
""" Manager for Maraude objects """
|
""" Manager for Maraude objects """
|
||||||
|
|
||||||
@@ -33,7 +31,8 @@ class MaraudeManager(Manager):
|
|||||||
|
|
||||||
def get_future(self, date=None):
|
def get_future(self, date=None):
|
||||||
""" Retourne la liste des prochaines maraudes """
|
""" Retourne la liste des prochaines maraudes """
|
||||||
if not date: date = self.today
|
if not date:
|
||||||
|
date = self.today
|
||||||
return self.get_queryset().filter(
|
return self.get_queryset().filter(
|
||||||
date__gte=date
|
date__gte=date
|
||||||
).order_by(
|
).order_by(
|
||||||
@@ -42,7 +41,8 @@ class MaraudeManager(Manager):
|
|||||||
|
|
||||||
def get_past(self, date=None):
|
def get_past(self, date=None):
|
||||||
""" Retourne la liste des maraudes passées """
|
""" Retourne la liste des maraudes passées """
|
||||||
if not date: date = self.today
|
if not date:
|
||||||
|
date = self.today
|
||||||
return self.get_queryset().filter(
|
return self.get_queryset().filter(
|
||||||
date__lt=date
|
date__lt=date
|
||||||
).order_by(
|
).order_by(
|
||||||
@@ -81,15 +81,3 @@ class MaraudeManager(Manager):
|
|||||||
return None
|
return None
|
||||||
except self.model.DoesNotExist:
|
except self.model.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ObservationManager(Manager):
|
|
||||||
|
|
||||||
def get_for_sujet(self, sujet):
|
|
||||||
return self.filter(sujet=sujet)
|
|
||||||
|
|
||||||
def get_first_for_sujet(self, sujet):
|
|
||||||
return self.filter(sujet=sujet).order_by('date').first()
|
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
import calendar
|
import calendar
|
||||||
import datetime
|
import datetime
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from utilisateurs.models import Maraudeur
|
from utilisateurs.models import Maraudeur
|
||||||
from . import managers
|
from . import managers
|
||||||
|
|
||||||
|
|
||||||
## Fonctions utiles
|
# Fonctions utiles
|
||||||
|
|
||||||
def get_referent_maraude():
|
def get_referent_maraude():
|
||||||
""" Retourne l'administrateur et référent de la Maraude """
|
""" Retourne l'administrateur et référent de la Maraude """
|
||||||
return Maraudeur.objects.get_referent()
|
return Maraudeur.objects.get_referent()
|
||||||
|
|
||||||
|
|
||||||
def split_by_12h_blocks(iterable):
|
def split_by_12h_blocks(iterable):
|
||||||
""" Move object with given 'field' time under 12:00 to the end of stream.
|
""" Move object with given 'field' time under 12:00 to the end of stream.
|
||||||
Apart from this, order is untouched.
|
Apart from this, order is untouched.
|
||||||
@@ -31,22 +30,20 @@ def split_by_12h_blocks(iterable):
|
|||||||
for note in to_end:
|
for note in to_end:
|
||||||
yield note
|
yield note
|
||||||
|
|
||||||
## Constantes
|
|
||||||
|
|
||||||
|
# Constantes
|
||||||
# Jours de la semaine
|
# Jours de la semaine
|
||||||
WEEKDAYS = [
|
WEEKDAYS = [
|
||||||
(0, "Lundi"),
|
(n, _(calendar.day_name[n])) for n in range(7)
|
||||||
(1, "Mardi"),
|
|
||||||
(2, "Mercredi"),
|
|
||||||
(3, "Jeudi"),
|
|
||||||
(4, "Vendredi"),
|
|
||||||
(5, "Samedi"),
|
|
||||||
(6, "Dimanche")
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
MONTHS = {
|
||||||
|
n: _(calendar.month_name[n]) for n in range(1, 13)
|
||||||
|
}
|
||||||
|
|
||||||
# Horaires
|
# Horaires
|
||||||
HORAIRES_APRESMIDI = datetime.time(16, 0)
|
HORAIRES_APRESMIDI = datetime.time(16, 0)
|
||||||
HORAIRES_SOIREE = datetime.time(20, 0)
|
HORAIRES_SOIREE = datetime.time(19, 0)
|
||||||
HORAIRES_CHOICES = (
|
HORAIRES_CHOICES = (
|
||||||
(HORAIRES_APRESMIDI, 'Après-midi'),
|
(HORAIRES_APRESMIDI, 'Après-midi'),
|
||||||
(HORAIRES_SOIREE, 'Soirée')
|
(HORAIRES_SOIREE, 'Soirée')
|
||||||
@@ -60,12 +57,13 @@ DUREE_CHOICES = (
|
|||||||
(20, '20 min'),
|
(20, '20 min'),
|
||||||
(30, '30 min'),
|
(30, '30 min'),
|
||||||
(45, '45 min'),
|
(45, '45 min'),
|
||||||
(60, '1 heure'),
|
(60, '1heure'),
|
||||||
|
(75, '1h15min'),
|
||||||
|
(90, '1h30min'),
|
||||||
)
|
)
|
||||||
|
|
||||||
## Modèles
|
|
||||||
|
|
||||||
|
|
||||||
|
# Modèles
|
||||||
class Lieu(models.Model):
|
class Lieu(models.Model):
|
||||||
""" Lieu de rencontre """
|
""" Lieu de rencontre """
|
||||||
nom = models.CharField(max_length=128)
|
nom = models.CharField(max_length=128)
|
||||||
@@ -77,7 +75,6 @@ class Lieu(models.Model):
|
|||||||
verbose_name = "Lieu de rencontre"
|
verbose_name = "Lieu de rencontre"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Maraude(models.Model):
|
class Maraude(models.Model):
|
||||||
""" Modèle pour une maraude
|
""" Modèle pour une maraude
|
||||||
- date : jour de la maraude
|
- date : jour de la maraude
|
||||||
@@ -135,12 +132,12 @@ class Maraude(models.Model):
|
|||||||
('view_maraudes', "Accès à l'application 'maraudes'"),
|
('view_maraudes', "Accès à l'application 'maraudes'"),
|
||||||
)
|
)
|
||||||
|
|
||||||
MOIS = ["Jan.", "Fév.", "Mars", "Avr.", "Mai", "Juin",
|
|
||||||
"Juil.", "Août", "Sept.", "Oct.", "Nov.", "Déc."]
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s %i %s' % (WEEKDAYS[self.date.weekday()][1], # Retrieve text inside tuple
|
return '%(dayname)s %(day)i %(month)s' % {
|
||||||
self.date.day,
|
'dayname': WEEKDAYS[self.date.weekday()][1], # Retrieve text inside tuple
|
||||||
self.MOIS[self.date.month - 1])
|
'day': self.date.day,
|
||||||
|
'month': MONTHS[self.date.month][:3] + ".",
|
||||||
|
}
|
||||||
|
|
||||||
def est_terminee(self):
|
def est_terminee(self):
|
||||||
""" Indique si la maraude est considérée comme terminée """
|
""" Indique si la maraude est considérée comme terminée """
|
||||||
@@ -161,7 +158,6 @@ class Maraude(models.Model):
|
|||||||
return reverse('notes:details-maraude', kwargs={'pk': self.id})
|
return reverse('notes:details-maraude', kwargs={'pk': self.id})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Rencontre(models.Model):
|
class Rencontre(models.Model):
|
||||||
""" Une Rencontre dans le cadre d'une maraude
|
""" Une Rencontre dans le cadre d'une maraude
|
||||||
"""
|
"""
|
||||||
@@ -170,7 +166,7 @@ class Rencontre(models.Model):
|
|||||||
maraude = models.ForeignKey(
|
maraude = models.ForeignKey(
|
||||||
Maraude,
|
Maraude,
|
||||||
models.CASCADE,
|
models.CASCADE,
|
||||||
related_name = 'rencontres',
|
related_name='rencontres',
|
||||||
limit_choices_to={'heure_fin__isnull': False}
|
limit_choices_to={'heure_fin__isnull': False}
|
||||||
)
|
)
|
||||||
lieu = models.ForeignKey(
|
lieu = models.ForeignKey(
|
||||||
@@ -188,18 +184,19 @@ class Rencontre(models.Model):
|
|||||||
ordering = ['maraude', 'heure_debut']
|
ordering = ['maraude', 'heure_debut']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s à %s (%imin)" % (
|
return "%(lieu)s à %(heure)s (%(duree)imin)" % {
|
||||||
self.lieu,
|
'lieu': self.lieu,
|
||||||
self.heure_debut.strftime("%Hh%M"),
|
'heure': self.heure_debut.strftime("%Hh%M"),
|
||||||
self.duree
|
'duree': self.duree
|
||||||
)
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
return self.maraude.date
|
return self.maraude.date
|
||||||
|
|
||||||
INDIVIDU = "Individu"
|
INDIVIDU = _("Individu")
|
||||||
GROUPE = "Groupe"
|
GROUPE = _("Groupe")
|
||||||
|
|
||||||
def groupe_ou_individu(self):
|
def groupe_ou_individu(self):
|
||||||
""" Retourne le type de rencontre : 'groupe'/'individu' """
|
""" Retourne le type de rencontre : 'groupe'/'individu' """
|
||||||
nb = self.observations.count()
|
nb = self.observations.count()
|
||||||
@@ -254,7 +251,6 @@ class CompteRendu(Maraude):
|
|||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FoyerAccueil(Lieu):
|
class FoyerAccueil(Lieu):
|
||||||
""" Foyer d'hébergement partenaire """
|
""" Foyer d'hébergement partenaire """
|
||||||
|
|
||||||
@@ -264,7 +260,6 @@ class FoyerAccueil(Lieu):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Planning(models.Model):
|
class Planning(models.Model):
|
||||||
""" Plannification des maraudes. Chaque instance représente un jour de la
|
""" Plannification des maraudes. Chaque instance représente un jour de la
|
||||||
semaine et un horaire par défaut.
|
semaine et un horaire par défaut.
|
||||||
@@ -293,7 +288,6 @@ class Planning(models.Model):
|
|||||||
""" Renvoie le jour et l'horaire prévu de maraude, comme un tuple,
|
""" Renvoie le jour et l'horaire prévu de maraude, comme un tuple,
|
||||||
pour l'année et le mois donnés.
|
pour l'année et le mois donnés.
|
||||||
"""
|
"""
|
||||||
planning = Planning.get_planning()
|
|
||||||
for week in calendar.monthcalendar(year, month):
|
for week in calendar.monthcalendar(year, month):
|
||||||
for planned in cls.get_planning():
|
for planned in cls.get_planning():
|
||||||
day_of_maraude = week[planned.week_day]
|
day_of_maraude = week[planned.week_day]
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from notes.models import Note
|
from notes.models import Note
|
||||||
from . import managers
|
|
||||||
|
|
||||||
# Extends 'notes' module
|
# Extends 'notes' module
|
||||||
|
|
||||||
@@ -9,7 +8,6 @@ from . import managers
|
|||||||
class Observation(Note):
|
class Observation(Note):
|
||||||
""" Note dans le cadre d'une rencontre """
|
""" Note dans le cadre d'une rencontre """
|
||||||
|
|
||||||
objects = managers.ObservationManager()
|
|
||||||
rencontre = models.ForeignKey('maraudes.Rencontre',
|
rencontre = models.ForeignKey('maraudes.Rencontre',
|
||||||
models.CASCADE,
|
models.CASCADE,
|
||||||
related_name="observations")
|
related_name="observations")
|
||||||
@@ -25,18 +23,24 @@ class Observation(Note):
|
|||||||
|
|
||||||
def note_bg_colors(self): return "info", "info"
|
def note_bg_colors(self): return "info", "info"
|
||||||
|
|
||||||
|
|
||||||
class Appel(Note):
|
class Appel(Note):
|
||||||
|
|
||||||
entrant = models.BooleanField( "Appel entrant ?")
|
entrant = models.BooleanField("Appel entrant ?")
|
||||||
|
|
||||||
def note_labels(self): return ["Reçu" if self.entrant else "Émis", self.created_by]
|
def note_labels(self):
|
||||||
def note_bg_colors(self): return "warning", "info"
|
return ["Reçu" if self.entrant else "Émis", self.created_by]
|
||||||
|
|
||||||
|
def note_bg_colors(self):
|
||||||
|
return "warning", "info"
|
||||||
|
|
||||||
|
|
||||||
class Signalement(Note):
|
class Signalement(Note):
|
||||||
|
|
||||||
source = models.ForeignKey("utilisateurs.Organisme")
|
source = models.ForeignKey("utilisateurs.Organisme")
|
||||||
|
|
||||||
def note_labels(self): return [self.source, self.created_by]
|
def note_labels(self):
|
||||||
def note_bg_colors(self): return 'danger', 'info'
|
return [self.source, self.created_by]
|
||||||
|
|
||||||
|
def note_bg_colors(self):
|
||||||
|
return 'danger', 'info'
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import random
|
|
||||||
|
|
||||||
from calendar import monthrange
|
from calendar import monthrange
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Maraude, Maraudeur, Planning,
|
Maraude, Maraudeur, Planning,
|
||||||
WEEKDAYS, HORAIRES_SOIREE,
|
HORAIRES_SOIREE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -14,6 +13,7 @@ MARAUDE_DAYS = [
|
|||||||
True, True, False, True, True, False, False
|
True, True, False, True, True, False, False
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_maraude_days(start, end):
|
def get_maraude_days(start, end):
|
||||||
""" Iterator that returns date of maraude within start-end range """
|
""" Iterator that returns date of maraude within start-end range """
|
||||||
maraude_days = []
|
maraude_days = []
|
||||||
@@ -32,6 +32,7 @@ def get_maraude_days(start, end):
|
|||||||
|
|
||||||
return maraude_days
|
return maraude_days
|
||||||
|
|
||||||
|
|
||||||
class PlanningTestCase(TestCase):
|
class PlanningTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -50,9 +51,11 @@ class PlanningTestCase(TestCase):
|
|||||||
def test_get_maraudes_days_for_month(self):
|
def test_get_maraudes_days_for_month(self):
|
||||||
test_values = [
|
test_values = [
|
||||||
{'year': 2017, 'month': 2,
|
{'year': 2017, 'month': 2,
|
||||||
'test': [(day, HORAIRES_SOIREE) for day in (2,3,6,7,9,10,13,14,16,17,20,21,23,24,27,28)] },
|
'test': [(day, HORAIRES_SOIREE) for day in (2, 3, 6, 7, 9, 10, 13, 14, 16,
|
||||||
|
17, 20, 21, 23, 24, 27, 28)]},
|
||||||
{'year': 2016, 'month': 3,
|
{'year': 2016, 'month': 3,
|
||||||
'test': [(day, HORAIRES_SOIREE) for day in (1,3,4,7,8,10,11,14,15,17,18,21,22,24,25,28,29,31)] },
|
'test': [(day, HORAIRES_SOIREE) for day in (1, 3, 4, 7, 8, 10, 11, 14, 15,
|
||||||
|
17, 18, 21, 22, 24, 25, 28, 29, 31)]},
|
||||||
]
|
]
|
||||||
|
|
||||||
for test in test_values:
|
for test in test_values:
|
||||||
@@ -61,7 +64,9 @@ class PlanningTestCase(TestCase):
|
|||||||
|
|
||||||
class MaraudeManagerTestCase(TestCase):
|
class MaraudeManagerTestCase(TestCase):
|
||||||
|
|
||||||
maraudeurs = [{"first_name": "Astérix", "last_name": "Le Gaulois"}, {"first_name": "Obélix", "last_name": "et Idéfix"}]
|
maraudeurs = [
|
||||||
|
{"first_name": "Astérix", "last_name": "Le Gaulois"},
|
||||||
|
{"first_name": "Obélix", "last_name": "et Idéfix"}]
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
first = True
|
first = True
|
||||||
@@ -78,14 +83,15 @@ class MaraudeManagerTestCase(TestCase):
|
|||||||
self.past_dates = [self.today - datetime.timedelta(d) for d in (1, 3, 5)]
|
self.past_dates = [self.today - datetime.timedelta(d) for d in (1, 3, 5)]
|
||||||
self.future_dates = [self.today + datetime.timedelta(d) for d in (2, 4, 6)]
|
self.future_dates = [self.today + datetime.timedelta(d) for d in (2, 4, 6)]
|
||||||
|
|
||||||
for date in [self.today,] + self.past_dates + self.future_dates:
|
for date in [self.today, ] + self.past_dates + self.future_dates:
|
||||||
Maraude.objects.create(
|
Maraude.objects.create(
|
||||||
date = date,
|
date=date,
|
||||||
referent = self.referent,
|
referent=self.referent,
|
||||||
binome = self.binome
|
binome=self.binome
|
||||||
)
|
)
|
||||||
|
|
||||||
def retrieve_date(self, maraude):
|
@staticmethod
|
||||||
|
def retrieve_date(maraude):
|
||||||
return maraude.date
|
return maraude.date
|
||||||
|
|
||||||
def test_all_of(self):
|
def test_all_of(self):
|
||||||
@@ -99,12 +105,12 @@ class MaraudeManagerTestCase(TestCase):
|
|||||||
|
|
||||||
def test_future_maraudes_no_args(self):
|
def test_future_maraudes_no_args(self):
|
||||||
""" La liste des futures maraudes """
|
""" La liste des futures maraudes """
|
||||||
test_set = set(self.future_dates + [self.today,])
|
test_set = set(self.future_dates + [self.today, ])
|
||||||
check_set = set(map(self.retrieve_date, Maraude.objects.get_future()))
|
check_set = set(map(self.retrieve_date, Maraude.objects.get_future()))
|
||||||
self.assertEqual(test_set, check_set)
|
self.assertEqual(test_set, check_set)
|
||||||
|
|
||||||
def test_future_maraudes_are_sorted_by_date(self):
|
def test_future_maraudes_are_sorted_by_date(self):
|
||||||
check_generator = iter(sorted(self.future_dates + [self.today,]))
|
check_generator = iter(sorted(self.future_dates + [self.today, ]))
|
||||||
for maraude in Maraude.objects.get_future():
|
for maraude in Maraude.objects.get_future():
|
||||||
self.assertEqual(maraude.date, next(check_generator))
|
self.assertEqual(maraude.date, next(check_generator))
|
||||||
|
|
||||||
@@ -128,7 +134,6 @@ class MaraudeManagerTestCase(TestCase):
|
|||||||
self.assertEqual(self.retrieve_date(Maraude.objects.get_next_of(self.binome)), self.today)
|
self.assertEqual(self.retrieve_date(Maraude.objects.get_next_of(self.binome)), self.today)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MaraudeTestCase(TestCase):
|
class MaraudeTestCase(TestCase):
|
||||||
|
|
||||||
def test_est_terminee(self):
|
def test_est_terminee(self):
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
import logging
|
import logging
|
||||||
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.shortcuts import redirect, reverse
|
from django.shortcuts import redirect, reverse
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.forms import modelformset_factory
|
from django.forms import modelformset_factory
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
from utilisateurs.mixins import MaraudeurMixin
|
from utilisateurs.mixins import MaraudeurMixin
|
||||||
|
|
||||||
from .models import (Maraude, Maraudeur,
|
from .models import (Maraude, Maraudeur,
|
||||||
CompteRendu,
|
CompteRendu,
|
||||||
Rencontre, Lieu,
|
Lieu,
|
||||||
Planning,)
|
Planning,)
|
||||||
from .notes import Signalement
|
from .notes import Signalement
|
||||||
# Forms
|
|
||||||
from .forms import (RencontreForm,
|
from .forms import (RencontreForm,
|
||||||
ObservationInlineFormSet,
|
ObservationInlineFormSet,
|
||||||
MaraudeHiddenDateForm, MonthSelectForm,
|
MaraudeHiddenDateForm, MonthSelectForm,
|
||||||
@@ -26,6 +23,9 @@ from notes.mixins import NoteFormMixin
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# How many month shall we look back
|
||||||
|
NUMBER_OF_MONTH_BACKWARDS = 1 # Must be lower than 12 !
|
||||||
|
|
||||||
|
|
||||||
def derniers_sujets_rencontres():
|
def derniers_sujets_rencontres():
|
||||||
""" Renvoie le 'set' des sujets rencontrés dans les deux dernières maraudes """
|
""" Renvoie le 'set' des sujets rencontrés dans les deux dernières maraudes """
|
||||||
@@ -38,11 +38,8 @@ def derniers_sujets_rencontres():
|
|||||||
|
|
||||||
def derniers_sujets_signales():
|
def derniers_sujets_signales():
|
||||||
def recent_filter(qs):
|
def recent_filter(qs):
|
||||||
NUMBER_OF_MONTH_BACKWARDS = 1 # Must be lower than 12 !
|
|
||||||
|
|
||||||
current_date = timezone.localtime(timezone.now()).date()
|
current_date = timezone.localtime(timezone.now()).date()
|
||||||
recent_dates = [(current_date.month, current_date.year)]
|
recent_dates = [(current_date.month, current_date.year)]
|
||||||
|
|
||||||
for i in range(1, NUMBER_OF_MONTH_BACKWARDS + 1):
|
for i in range(1, NUMBER_OF_MONTH_BACKWARDS + 1):
|
||||||
prev_month, prev_year = current_date.month - i, current_date.year
|
prev_month, prev_year = current_date.month - i, current_date.year
|
||||||
if prev_month <= 0:
|
if prev_month <= 0:
|
||||||
@@ -56,7 +53,6 @@ def derniers_sujets_signales():
|
|||||||
filtered = []
|
filtered = []
|
||||||
for month, year in recent_dates:
|
for month, year in recent_dates:
|
||||||
filtered += list(qs.filter(created_date__year=year, created_date__month=month))
|
filtered += list(qs.filter(created_date__year=year, created_date__month=month))
|
||||||
|
|
||||||
return filtered
|
return filtered
|
||||||
|
|
||||||
return recent_filter(Signalement.objects.all())
|
return recent_filter(Signalement.objects.all())
|
||||||
@@ -66,7 +62,7 @@ class IndexView(NoteFormMixin, MaraudeurMixin, generic.TemplateView):
|
|||||||
|
|
||||||
template_name = "maraudes/index.html"
|
template_name = "maraudes/index.html"
|
||||||
|
|
||||||
#NoteFormMixin
|
# NoteFormMixin
|
||||||
forms = {
|
forms = {
|
||||||
'appel': AppelForm,
|
'appel': AppelForm,
|
||||||
'signalement': SignalementForm,
|
'signalement': SignalementForm,
|
||||||
@@ -89,18 +85,19 @@ class IndexView(NoteFormMixin, MaraudeurMixin, generic.TemplateView):
|
|||||||
if self.request.user.is_superuser:
|
if self.request.user.is_superuser:
|
||||||
context['missing_cr'] = CompteRendu.objects.get_queryset().filter(
|
context['missing_cr'] = CompteRendu.objects.get_queryset().filter(
|
||||||
heure_fin__isnull=True,
|
heure_fin__isnull=True,
|
||||||
date__lt = timezone.localtime(timezone.now()).date()
|
date__lt=timezone.localtime(timezone.now()).date()
|
||||||
)
|
)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
## COMPTE-RENDU DE MARAUDE
|
# COMPTE-RENDU DE MARAUDE
|
||||||
|
|
||||||
|
|
||||||
def redirect_to_current_compterendu(request):
|
def redirect_to_current_compterendu(request):
|
||||||
maraude_en_cours = Maraude.objects.get_in_progress()
|
maraude_en_cours = Maraude.objects.get_in_progress()
|
||||||
|
|
||||||
if not maraude_en_cours:
|
if not maraude_en_cours:
|
||||||
|
messages.warning(request, "Il n'y a actuellement aucune maraude en cours !")
|
||||||
return redirect("maraudes:index")
|
return redirect("maraudes:index")
|
||||||
|
|
||||||
kwargs = {'pk': maraude_en_cours.pk}
|
kwargs = {'pk': maraude_en_cours.pk}
|
||||||
@@ -128,7 +125,7 @@ class CompteRenduCreateView(MaraudeurMixin, generic.DetailView):
|
|||||||
instance=self.form.instance
|
instance=self.form.instance
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, **kwargs):
|
||||||
self.get_forms(request.POST, request.FILES)
|
self.get_forms(request.POST, request.FILES)
|
||||||
if self.form.has_changed():
|
if self.form.has_changed():
|
||||||
if not self.form.is_valid() or not self.inline_formset.is_valid():
|
if not self.form.is_valid() or not self.inline_formset.is_valid():
|
||||||
@@ -145,8 +142,10 @@ class CompteRenduCreateView(MaraudeurMixin, generic.DetailView):
|
|||||||
def calculate_end_time(debut, duree):
|
def calculate_end_time(debut, duree):
|
||||||
end_minute = debut.minute + duree
|
end_minute = debut.minute + duree
|
||||||
hour = debut.hour + end_minute // 60
|
hour = debut.hour + end_minute // 60
|
||||||
if hour >= 24: hour -= 24
|
if hour >= 24:
|
||||||
elif hour < 0: hour += 24
|
hour -= 24
|
||||||
|
elif hour < 0:
|
||||||
|
hour += 24
|
||||||
minute = end_minute % 60
|
minute = end_minute % 60
|
||||||
return datetime.time(
|
return datetime.time(
|
||||||
hour,
|
hour,
|
||||||
@@ -179,8 +178,7 @@ class CompteRenduCreateView(MaraudeurMixin, generic.DetailView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class FinalizeView(MaraudeurMixin,
|
||||||
class FinalizeView( MaraudeurMixin,
|
|
||||||
generic.detail.SingleObjectMixin,
|
generic.detail.SingleObjectMixin,
|
||||||
generic.edit.FormView):
|
generic.edit.FormView):
|
||||||
|
|
||||||
@@ -190,8 +188,7 @@ class FinalizeView( MaraudeurMixin,
|
|||||||
success_url = "/maraudes/"
|
success_url = "/maraudes/"
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
print(self.request.GET)
|
if bool(self.request.GET.get("no_mail", False)):
|
||||||
if bool(self.request.GET.get("no_mail", False)) == True:
|
|
||||||
messages.warning(self.request, "Aucun compte-rendu n'a été envoyé !")
|
messages.warning(self.request, "Aucun compte-rendu n'a été envoyé !")
|
||||||
return self.finalize()
|
return self.finalize()
|
||||||
return super().get(*args, **kwargs)
|
return super().get(*args, **kwargs)
|
||||||
@@ -232,23 +229,25 @@ class FinalizeView( MaraudeurMixin,
|
|||||||
)
|
)
|
||||||
|
|
||||||
if result == 1:
|
if result == 1:
|
||||||
|
if settings.DEBUG:
|
||||||
|
messages.warning(self.request, "En mode DEBUG, le compte-rendu n'est pas réellement envoyé !")
|
||||||
|
else:
|
||||||
messages.success(self.request, "Le compte-rendu a été transmis à %s" % ", ".join(map(str, recipients)))
|
messages.success(self.request, "Le compte-rendu a été transmis à %s" % ", ".join(map(str, recipients)))
|
||||||
else:
|
else:
|
||||||
messages.error(self.request, "Erreur lors de l'envoi du message !")
|
messages.error(self.request, "Erreur lors de l'envoi du message !")
|
||||||
return self.finalize()
|
return self.finalize()
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
self.object = self.get_object()
|
obj = self.get_object()
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
if self.object.est_terminee is True:
|
if obj.est_terminee is True:
|
||||||
context['form'] = None#Useless form
|
context['form'] = None # Useless form
|
||||||
return context
|
return context
|
||||||
# Link there so that "Compte-rendu" menu item is not disabled
|
# Link there so that "Compte-rendu" menu item is not disabled
|
||||||
context['prochaine_maraude'] = self.object
|
context['prochaine_maraude'] = obj
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PlanningView(MaraudeurMixin, generic.TemplateView):
|
class PlanningView(MaraudeurMixin, generic.TemplateView):
|
||||||
""" Vue d'édition du planning des maraudes """
|
""" Vue d'édition du planning des maraudes """
|
||||||
|
|
||||||
@@ -256,10 +255,14 @@ class PlanningView(MaraudeurMixin, generic.TemplateView):
|
|||||||
|
|
||||||
def _parse_request(self):
|
def _parse_request(self):
|
||||||
self.current_date = datetime.date.today()
|
self.current_date = datetime.date.today()
|
||||||
try: self.month = int(self.request.GET['month'])
|
try:
|
||||||
except: self.month = self.current_date.month
|
self.month = int(self.request.GET['month'])
|
||||||
try: self.year = int(self.request.GET['year'])
|
except ValueError:
|
||||||
except: self.year = self.current_date.year
|
self.month = self.current_date.month
|
||||||
|
try:
|
||||||
|
self.year = int(self.request.GET['year'])
|
||||||
|
except ValueError:
|
||||||
|
self.year = self.current_date.year
|
||||||
|
|
||||||
def _calculate_initials(self):
|
def _calculate_initials(self):
|
||||||
self._parse_request()
|
self._parse_request()
|
||||||
@@ -267,7 +270,7 @@ class PlanningView(MaraudeurMixin, generic.TemplateView):
|
|||||||
for day, time in Planning.get_maraudes_days_for_month(self.year, self.month):
|
for day, time in Planning.get_maraudes_days_for_month(self.year, self.month):
|
||||||
date = datetime.date(self.year, self.month, day)
|
date = datetime.date(self.year, self.month, day)
|
||||||
try:
|
try:
|
||||||
maraude = Maraude.objects.get(date=date)
|
Maraude.objects.get(date=date)
|
||||||
except Maraude.DoesNotExist:
|
except Maraude.DoesNotExist:
|
||||||
self.initials.append({
|
self.initials.append({
|
||||||
'date': date,
|
'date': date,
|
||||||
@@ -284,26 +287,26 @@ class PlanningView(MaraudeurMixin, generic.TemplateView):
|
|||||||
self._calculate_initials()
|
self._calculate_initials()
|
||||||
return modelformset_factory(
|
return modelformset_factory(
|
||||||
Maraude,
|
Maraude,
|
||||||
form = MaraudeHiddenDateForm,
|
form=MaraudeHiddenDateForm,
|
||||||
extra = len(self.initials),
|
extra=len(self.initials),
|
||||||
)(
|
)(
|
||||||
*args,
|
*args,
|
||||||
queryset = self.get_queryset(),
|
queryset=self.get_queryset(),
|
||||||
initial = self.initials
|
initial=self.initials
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
self.formset = self.get_formset(request.POST, request.FILES)
|
formset = self.get_formset(request.POST, request.FILES)
|
||||||
for form in self.formset.forms:
|
for form in formset.forms:
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
else:
|
else:
|
||||||
logger.info("Form was ignored ! (%s)" % (form.errors.as_data()))
|
logger.info("Form was ignored ! (%s)" % (form.errors.as_data()))
|
||||||
return redirect('maraudes:planning')
|
return redirect('maraudes:planning')
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request, *args, **kwargs):
|
||||||
self.formset = self.get_formset()
|
self.formset = self.get_formset()
|
||||||
return super().get(request)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_weeks(self):
|
def get_weeks(self):
|
||||||
""" List of (day, form) tuples, split by weeks """
|
""" List of (day, form) tuples, split by weeks """
|
||||||
@@ -330,8 +333,8 @@ class PlanningView(MaraudeurMixin, generic.TemplateView):
|
|||||||
for week in calendar.monthcalendar(self.year, self.month)
|
for week in calendar.monthcalendar(self.year, self.month)
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(*args, **kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['weekdays'] = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"]
|
context['weekdays'] = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"]
|
||||||
context['weeks'] = self.get_weeks()
|
context['weeks'] = self.get_weeks()
|
||||||
|
|
||||||
@@ -341,7 +344,6 @@ class PlanningView(MaraudeurMixin, generic.TemplateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LieuCreateView(generic.edit.CreateView):
|
class LieuCreateView(generic.edit.CreateView):
|
||||||
""" Vue de création d'un lieu """
|
""" Vue de création d'un lieu """
|
||||||
|
|
||||||
@@ -359,6 +361,6 @@ class LieuCreateView(generic.edit.CreateView):
|
|||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
try:
|
try:
|
||||||
context['next'] = self.request.GET['next']
|
context['next'] = self.request.GET['next']
|
||||||
except:
|
except KeyError:
|
||||||
context['next'] = None
|
context['next'] = None
|
||||||
return context
|
return context
|
||||||
|
|||||||
Reference in New Issue
Block a user