Revision f69ae8a2
Added by Benjamin Dauvergne almost 12 years ago
calebasse/personnes/forms.py | ||
---|---|---|
1 | 1 |
# -*- coding: utf-8 -*- |
2 | 2 |
from django import forms |
3 |
from django.forms.models import inlineformset_factory, BaseInlineFormSet |
|
3 |
from django.forms.models import (inlineformset_factory, modelformset_factory, |
|
4 |
BaseInlineFormSet) |
|
4 | 5 |
from django.utils.translation import gettext_lazy as _ |
5 | 6 |
from django.contrib.auth.models import User |
6 | 7 |
|
... | ... | |
114 | 115 |
'services': forms.CheckboxSelectMultiple, |
115 | 116 |
} |
116 | 117 |
|
118 |
|
|
117 | 119 |
class BaseTimetableFormSet(BaseInlineFormSet): |
118 | 120 |
def __init__(self, weekday=None, *args, **kwargs): |
119 | 121 |
kwargs['queryset'] = kwargs.get('queryset', TimeTable.objects).filter(weekday=weekday) |
120 | 122 |
super(BaseTimetableFormSet, self).__init__(*args, **kwargs) |
121 | 123 |
|
124 |
|
|
122 | 125 |
TimetableFormSet = inlineformset_factory(Worker, TimeTable, |
123 | 126 |
formset=BaseTimetableFormSet, |
124 | 127 |
fields=('start_time', 'end_time', 'start_date', 'end_date')) |
... | ... | |
126 | 129 |
HolidayFormSet = inlineformset_factory( |
127 | 130 |
Worker, Holiday, |
128 | 131 |
fields=('start_date', 'end_date', 'start_time', 'end_time')) |
132 |
|
|
133 |
class HolidaySearchForm(forms.Form): |
|
134 |
start_date = forms.DateField(required=False) |
|
135 |
end_date = forms.DateField(required=False) |
|
136 |
|
|
137 |
def clean(self): |
|
138 |
cleaned_data = super(HolidaySearchForm, self).clean() |
|
139 |
if cleaned_data.get('start_date') or cleaned_data.get('end_date'): |
|
140 |
if not cleaned_data.get('start_date') \ |
|
141 |
or not cleaned_data.get('end_date'): |
|
142 |
raise forms.ValidationError(u'Vous devez fournir une date de début et de fin') |
|
143 |
if cleaned_data['start_date'] > cleaned_data['end_date']: |
|
144 |
raise forms.ValidationError(u'La date de début doit être supérieure à la date de fin') |
|
145 |
return cleaned_data |
|
146 |
|
|
147 |
class YearlyHolidayForm(forms.ModelForm): |
|
148 |
for_all_services = forms.BooleanField(required=False) |
|
149 |
|
|
150 |
def save(self, commit=True): |
|
151 |
instance = super(YearlyHolidayForm, self).save(commit=commit) |
|
152 |
instance.for_all_services = self.cleaned_data.get('for_all_services', False) |
|
153 |
return instance |
|
154 |
|
|
155 |
class Meta: |
|
156 |
form = Holiday |
|
157 |
|
|
158 |
YearlyHolidayFormSet = modelformset_factory(Holiday, |
|
159 |
can_delete=True, |
|
160 |
form=YearlyHolidayForm, |
|
161 |
fields=('start_date', 'end_date')) |
calebasse/personnes/templates/personnes/holidays.html | ||
---|---|---|
1 |
{% extends "calebasse/base.html" %} |
|
2 |
|
|
3 |
{% load url from future %} |
|
4 |
|
|
5 |
{% block appbar %} |
|
6 |
<h2>Gestion des personnes — Congés</h2> |
|
7 |
<a href="..">Retourner à la gestion des personnes</a> |
|
8 |
{% endblock %} |
|
9 |
|
|
10 |
{% block content %} |
|
11 |
<h3>Congés du personnel</h3> |
|
12 |
|
|
13 |
{% if current_holidays %} |
|
14 |
<h4>En cours</h4> |
|
15 |
|
|
16 |
<ul> |
|
17 |
{% for holiday in current_holidays %} |
|
18 |
<li><a href="{% url 'worker_update' service=service pk=holiday.worker.pk %}"> |
|
19 |
{{ holiday.worker.last_name }} {{holiday.worker.first_name }} |
|
20 |
</a>, {{ holiday }}</li> |
|
21 |
{% endfor %} |
|
22 |
</ul> |
|
23 |
{% endif %} |
|
24 |
|
|
25 |
{% if future_holidays %} |
|
26 |
<h4>À venir</h4> |
|
27 |
|
|
28 |
<table id="conges-a-venir"> |
|
29 |
<thead> |
|
30 |
<tr> |
|
31 |
{% for month in future_holidays %} |
|
32 |
<th>{{ month.date|date:"F"|capfirst }}</th> |
|
33 |
{% endfor %} |
|
34 |
</tr> |
|
35 |
</thead> |
|
36 |
<tbody> |
|
37 |
<tr> |
|
38 |
{% for month in future_holidays %} |
|
39 |
<td> |
|
40 |
<ul> |
|
41 |
{% for holiday in month.holidays %} |
|
42 |
<li><a href="{% url 'worker_update' service=service pk=holiday.worker.pk %}"> |
|
43 |
{{ holiday.worker.last_name }} {{holiday.worker.first_name }} |
|
44 |
</a>, {{ holiday }}</li> |
|
45 |
{% endfor %} |
|
46 |
</ul> |
|
47 |
</td> |
|
48 |
{% endfor %} |
|
49 |
</tr> |
|
50 |
</tbody> |
|
51 |
</table> |
|
52 |
{% endif %} |
|
53 |
|
|
54 |
{% if annual_holidays %} |
|
55 |
<h3>Congés annuels</h3> |
|
56 |
<ul> |
|
57 |
{% for holiday in annual_holidays %} |
|
58 |
<li>{{ holiday|capfirst }}</li> |
|
59 |
{% endfor %} |
|
60 |
</ul> |
|
61 |
{% endif %} |
|
62 |
<!-- <button>Gestion des congés annuels</button> --> |
|
63 |
<p> |
|
64 |
<a href="annuel/">Gestion des congés annuels</a> |
|
65 |
</p> |
|
66 |
|
|
67 |
<h3>Affichage interactif</h3> |
|
68 |
|
|
69 |
<form> |
|
70 |
{{ search_form.non_field_errors }} |
|
71 |
{{ search_form.start_date.errors }} |
|
72 |
<p>Afficher la liste des congés pris entre |
|
73 |
<span id="start-date-datepicker" data-number-of-months="3" data-before-selector="#end-date-datepicker" class="datepicker">{{ search_form.start_date }}</span> |
|
74 |
et |
|
75 |
<span id="end-date-datepicker" class="datepicker" data-number-of-months="3" data-after-selector="#start-date-datepicker">{{ search_form.end_date }}</span> |
|
76 |
<button class="enable-on-change">Valider</button> |
|
77 |
<button class="reset">Effacer</button> |
|
78 |
</p> |
|
79 |
</form> |
|
80 |
{% endblock %} |
calebasse/personnes/templates/personnes/yearly_holiday_update.html | ||
---|---|---|
1 |
{% extends "calebasse/simple-form.html" %} |
|
2 |
|
|
3 |
{% block appbar %} |
|
4 |
<h2>Congés de {{object.last_name}} {{object.first_name}}</h2> |
|
5 |
<a href="..">Retour</a> |
|
6 |
{% endblock %} |
|
7 |
|
|
8 |
|
|
9 |
{% block content %} |
|
10 |
<form method="post"> |
|
11 |
<div id="form-content"> |
|
12 |
{% csrf_token %} |
|
13 |
{% with formset=form %} |
|
14 |
{{ formset.management_form }} |
|
15 |
<table class="inline"> |
|
16 |
<thead> |
|
17 |
<tr> |
|
18 |
<td><label class="required">Date de début</label></td> |
|
19 |
<td><label class="required">Date de fin</label></td> |
|
20 |
<td><label>Pour tous les services</label></td> |
|
21 |
<td><label>Supprimer</label></td> |
|
22 |
</tr> |
|
23 |
</thead> |
|
24 |
<tbody id="timetables"> |
|
25 |
{% for form in formset %} |
|
26 |
{% if form.non_field_errors %} |
|
27 |
<tr><td colspan="4">{{ form.non_field_errors }}</td></tr> |
|
28 |
{% endif %} |
|
29 |
<tr class="timetable"> |
|
30 |
<td id="start-{{ forloop.counter0 }}" class="datepicker" data-before-selector="#end-{{ forloop.counter0 }}" data-number-of-months="3">{{ form.start_date }}</td> |
|
31 |
<td id="end-{{ forloop.counter0 }}" class="datepicker" data-after-selector="#start-{{ forloop.counter0 }}" data-number-of-months="3">{{ form.end_date }}</td> |
|
32 |
<td>{{ form.for_all_services }}</td> |
|
33 |
<td class="delete">{% if form.id.value != None %}{{ form.DELETE }}{% endif %} |
|
34 |
{% for field in form %} |
|
35 |
{% if field.is_hidden %} |
|
36 |
{{field}} |
|
37 |
{% endif %} |
|
38 |
{% endfor %} |
|
39 |
</td> |
|
40 |
</tr> |
|
41 |
{% endfor %} |
|
42 |
</tbody> |
|
43 |
</table> |
|
44 |
{% endwith %} |
|
45 |
</div> |
|
46 |
{% block buttons %} |
|
47 |
<button class="enable-on-change">Modifier</button> |
|
48 |
<button id="add-form">Ajouter une ligne</button> |
|
49 |
{% endblock %} |
|
50 |
<a href="..">{% block back-link %}Retour{% endblock %}</a> |
|
51 |
</form> |
|
52 |
{% endblock %} |
|
53 |
|
|
54 |
{% block page-end %} |
|
55 |
{{ block.super }} |
|
56 |
<script> |
|
57 |
$(function () { |
|
58 |
var completions = []; |
|
59 |
for (var i = 8*60; i < 21*60; i += 15) { |
|
60 |
var completion = '' |
|
61 |
var hour = Math.floor(i/60); |
|
62 |
var minute = i % 60; |
|
63 |
var c = function (v) { |
|
64 |
if (v < 10) { |
|
65 |
return '0'+v; |
|
66 |
} |
|
67 |
return v; |
|
68 |
} |
|
69 |
completions.push(''+c(hour)+':'+c(minute)); |
|
70 |
} |
|
71 |
$('.timepicker input').autocomplete({delay:0, source: completions, minLength: 0}); |
|
72 |
function addForm() { |
|
73 |
var count = $('.timetable').length |
|
74 |
var new_row = $('.timetable:first').clone(false).get(0); |
|
75 |
$('input', new_row).val(''); |
|
76 |
$('input, select', new_row).each(function (i, v) { |
|
77 |
v.name = v.name.replace('-0-', '-' + count + '-'); |
|
78 |
}); |
|
79 |
$('.delete input[type="checkbox"]', new_row).remove(); |
|
80 |
$('.hasDatepicker', new_row).removeClass('hasDatepicker'); |
|
81 |
$('*', new_row).each(function (i, v) { |
|
82 |
if (v.id) { |
|
83 |
v.id = v.id.replace('-0', '-' + count); |
|
84 |
if ($(v).data('before-selector')) { |
|
85 |
var old_value = $(v).data('before-selector'); |
|
86 |
$(v).data('before-selector', old_value.replace('-0', '-' + count)); |
|
87 |
} |
|
88 |
if ($(v).data('after-selector')) { |
|
89 |
var old_value = $(v).data('after-selector'); |
|
90 |
$(v).data('after-selector', old_value.replace('-0', '-' + count)); |
|
91 |
} |
|
92 |
} |
|
93 |
}); |
|
94 |
|
|
95 |
$(new_row).appendTo($('#timetables')); |
|
96 |
$('#id_timetable_set-TOTAL_FORMS').val(count+1); |
|
97 |
window.calebasse_dialogs(); |
|
98 |
return false; |
|
99 |
} |
|
100 |
$('#add-form').click(addForm); |
|
101 |
}); |
|
102 |
</script> |
|
103 |
{% endblock %} |
|
104 |
|
|
105 |
|
calebasse/personnes/urls.py | ||
---|---|---|
12 | 12 |
worker_patterns = patterns('calebasse.personnes.views', |
13 | 13 |
url(r'^$', 'worker_listing'), |
14 | 14 |
url(r'^new/$', 'worker_new'), |
15 |
url(r'^(?P<pk>\d+)/$', 'worker_update'), |
|
15 |
url(r'^(?P<pk>\d+)/$', 'worker_update', name='worker_update'),
|
|
16 | 16 |
url(r'^(?P<pk>\d+)/delete/$', 'worker_delete'), |
17 | 17 |
url(r'^(?P<pk>\d+)/holidays/$', 'worker_holidays_update'), |
18 | 18 |
url(r'^(?P<pk>\d+)/(?P<weekday>\w+)/$', 'worker_schedule_update'), |
19 | 19 |
) |
20 | 20 |
|
21 |
holidays_patterns = patterns('calebasse.personnes.views', |
|
22 |
url(r'^$', 'holiday_listing'), |
|
23 |
url(r'^annuel/$', 'yearly_holiday_update')) |
|
21 | 24 |
|
22 | 25 |
urlpatterns = patterns('calebasse.personnes.views', |
23 | 26 |
url(r'^$', 'homepage'), |
24 | 27 |
url(r'^acces/', include(user_patterns)), |
25 | 28 |
url(r'^gestion/', include(worker_patterns)), |
29 |
url(r'^conges/', include(holidays_patterns)), |
|
26 | 30 |
) |
calebasse/personnes/views.py | ||
---|---|---|
1 | 1 |
from collections import defaultdict |
2 | 2 |
from datetime import date |
3 | 3 |
|
4 |
from dateutil.relativedelta import relativedelta |
|
5 |
|
|
4 | 6 |
from django.http import HttpResponseRedirect, Http404 |
5 | 7 |
from django.db.models import Q |
6 | 8 |
from django.contrib.auth.models import User |
... | ... | |
181 | 183 |
success_url = '../' |
182 | 184 |
template_name = 'personnes/worker_holidays_update.html' |
183 | 185 |
|
186 |
def get_success_url(self): |
|
187 |
return self.success_url |
|
188 |
|
|
189 |
|
|
184 | 190 |
worker_listing = WorkerView.as_view() |
185 | 191 |
worker_new = cbv.CreateView.as_view(model=models.Worker, |
186 | 192 |
template_name='calebasse/simple-form.html', |
... | ... | |
191 | 197 |
worker_delete = cbv.DeleteView.as_view(model=models.Worker, |
192 | 198 |
template_name='calebasse/simple-form.html', |
193 | 199 |
success_url='../') |
200 |
|
|
201 |
|
|
202 |
class HolidayView(cbv.TemplateView): |
|
203 |
months = 3 |
|
204 |
template_name='personnes/holidays.html' |
|
205 |
|
|
206 |
def get_form(self): |
|
207 |
return forms.HolidaySearchForm(data=self.request.GET) |
|
208 |
|
|
209 |
def get_context_data(self, **kwargs): |
|
210 |
ctx = super(HolidayView, self).get_context_data(**kwargs) |
|
211 |
end_date = date.today() + relativedelta(months=self.months) |
|
212 |
qs = models.Holiday.objects.for_service_workers(self.service) |
|
213 |
today = date.today() |
|
214 |
future_qs = qs.filter(start_date__gt=today, |
|
215 |
start_date__lte=end_date) |
|
216 |
annual_qs = models.Holiday.objects.for_service(self.service) |
|
217 |
current_qs = qs.filter(start_date__lte=today) |
|
218 |
form = self.get_form() |
|
219 |
if form.is_valid() and form.cleaned_data.get('start_date'): |
|
220 |
cleaned_data = form.cleaned_data |
|
221 |
start_date = cleaned_data['start_date'] |
|
222 |
end_date = cleaned_data['end_date'] |
|
223 |
q = Q(start_date__gte=start_date, start_date__lte=end_date) |
|
224 |
q |= Q(end_date__gte=start_date, end_date__lte=end_date) |
|
225 |
future_qs = models.Holiday.objects.filter(q) \ |
|
226 |
.filter(worker__services=self.service) |
|
227 |
annual_qs = annual_qs.filter(q) |
|
228 |
current_qs = [] |
|
229 |
ctx['current_holidays'] = current_qs |
|
230 |
future_holidays = defaultdict(lambda:[]) |
|
231 |
for holiday in future_qs: |
|
232 |
key = (holiday.start_date.year, holiday.start_date.month, holiday.start_date.strftime('%B')) |
|
233 |
future_holidays[key].append(holiday) |
|
234 |
ctx['future_holidays'] = [ { |
|
235 |
'date': date(day=1, month=key[1], year=key[0]), |
|
236 |
'holidays': future_holidays[key] |
|
237 |
} for key in sorted(future_holidays.keys()) ] |
|
238 |
ctx['annual_holidays'] = annual_qs |
|
239 |
ctx['search_form'] = form |
|
240 |
return ctx |
|
241 |
|
|
242 |
|
|
243 |
holiday_listing = HolidayView.as_view() |
|
244 |
|
|
245 |
|
|
246 |
class YearlyHolidayUpdateView(cbv.FormView): |
|
247 |
form_class = forms.YearlyHolidayFormSet |
|
248 |
template_name = 'personnes/yearly_holiday_update.html' |
|
249 |
|
|
250 |
def get_success_url(self): |
|
251 |
return '../' |
|
252 |
|
|
253 |
def get_form_kwargs(self): |
|
254 |
kwargs = super(YearlyHolidayUpdateView, self).get_form_kwargs() |
|
255 |
qs = models.Holiday.objects.for_service(self.service) |
|
256 |
kwargs['queryset'] = qs |
|
257 |
initial = [ { 'for_all_services': o.service is None } for o in qs ] |
|
258 |
kwargs['initial'] = initial |
|
259 |
return kwargs |
|
260 |
|
|
261 |
def form_valid(self, form): |
|
262 |
instances = form.save(commit=False) |
|
263 |
for instance in instances: |
|
264 |
if instance.for_all_services: |
|
265 |
instance.service = None |
|
266 |
else: |
|
267 |
instance.service = self.service |
|
268 |
instance.save() |
|
269 |
return HttpResponseRedirect('') |
|
270 |
|
|
271 |
|
|
272 |
yearly_holiday_update = YearlyHolidayUpdateView.as_view() |
Also available in: Unified diff
personnes: add views to manage service holidays