diff --git a/common/urls.py b/common/urls.py index 693382a..f94dfd6 100644 --- a/common/urls.py +++ b/common/urls.py @@ -21,10 +21,11 @@ urlpatterns = patterns('', # AJAX/JSON urls url(r'^section/(?P\d+)/periods/', 'stages.views.section_periods'), url(r'^period/(?P\d+)/students/', 'stages.views.period_students'), - url(r'^period/(?P\d+)/corporations/', 'stages.views.period_corporations'), + url(r'^period/(?P\d+)/corporations/', 'stages.views.period_availabilities'), # Training params in POST: url(r'^training/new/', 'stages.views.new_training'), + url(r'^training/by_period/(?P\d+)/', views.TrainingsByPeriodView.as_view()), url(r'^student/(?P\d+)/summary/', views.StudentSummaryView.as_view()), - url(r'^corporation/(?P\d+)/summary/', views.CorporationSummaryView.as_view()), + url(r'^availability/(?P\d+)/summary/', views.AvailabilitySummaryView.as_view()), ) diff --git a/docs/SchemaRelationnel.odg b/docs/SchemaRelationnel.odg index 464c146..08fc5a5 100644 Binary files a/docs/SchemaRelationnel.odg and b/docs/SchemaRelationnel.odg differ diff --git a/stages/admin.py b/stages/admin.py index c52e445..7c20148 100644 --- a/stages/admin.py +++ b/stages/admin.py @@ -25,14 +25,20 @@ class CorporationAdmin(admin.ModelAdmin): inlines = [ContactInline] +class AvailabilityInline(admin.TabularInline): + model = Availability + extra = 1 + class PeriodAdmin(admin.ModelAdmin): list_display = ('dates', 'section') list_filter = ('section',) + inlines = [AvailabilityInline] class AvailabilityAdmin(admin.ModelAdmin): - list_display = ('corporation', 'period', 'number') - fields = (('corporation', 'period'), ('number', 'domain')) + list_display = ('corporation', 'period', 'domain') + list_filter = ('period',) + fields = (('corporation', 'period'), 'domain', 'comment') admin.site.register(Student, StudentAdmin) diff --git a/stages/fixtures/test_fixture.json b/stages/fixtures/test_fixture.json index b2a8745..0a1d01a 100644 --- a/stages/fixtures/test_fixture.json +++ b/stages/fixtures/test_fixture.json @@ -24,48 +24,48 @@ "pk": 1, "model": "stages.student", "fields": { - "birth_date": "1994-05-12", + "city": "La Chaux-de-Fonds", "first_name": "Albin", - "last_name": "Dupond", - "section": 1, - "pcode": "2300", - "city": "La Chaux-de-Fonds" + "last_name": "Dupond", + "section": 1, + "pcode": "2300", + "birth_date": "1994-05-12" } }, { "pk": 2, "model": "stages.student", "fields": { - "birth_date": "1994-07-12", + "city": "Neuch\u00e2tel", "first_name": "Justine", - "last_name": "Varrin", - "section": 1, - "pcode": "2000", - "city": "Neuchâtel" + "last_name": "Varrin", + "section": 1, + "pcode": "2000", + "birth_date": "1994-07-12" } }, { "pk": 3, "model": "stages.student", "fields": { - "birth_date": "1994-05-20", + "city": "Cernier", "first_name": "Elvire", - "last_name": "Hickx", - "section": 1, - "pcode": "2053", - "city": "Cernier" + "last_name": "Hickx", + "section": 1, + "pcode": "2053", + "birth_date": "1994-05-20" } }, { "pk": 4, "model": "stages.student", "fields": { - "birth_date": "1994-10-11", - "first_name": "André", - "last_name": "Allemand", - "section": 1, - "pcode": "2314", - "city": "La Sagne" + "city": "La Sagne", + "first_name": "Andr\u00e9", + "last_name": "Allemand", + "section": 1, + "pcode": "2314", + "birth_date": "1994-10-11" } }, { @@ -88,6 +88,17 @@ "email": "" } }, + { + "pk": 1, + "model": "stages.corpcontact", + "fields": { + "corporation": 1, + "first_name": "Jean", + "last_name": "Horner", + "tel": "", + "email": "" + } + }, { "pk": 1, "model": "stages.domain", @@ -113,13 +124,32 @@ }, { "pk": 1, - "model": "stages.training", + "model": "stages.availability", "fields": { "corporation": 1, "domain": 1, "period": 1, + "comment": "" + } + }, + { + "pk": 2, + "model": "stages.availability", + "fields": { + "corporation": 1, + "domain": 2, + "period": 1, + "comment": "" + } + }, + { + "pk": 1, + "model": "stages.training", + "fields": { + "availability": 1, "student": 1, - "referent": 1 + "referent": 1, + "comment": "" } } ] diff --git a/stages/models.py b/stages/models.py index 578c4be..7437bf1 100644 --- a/stages/models.py +++ b/stages/models.py @@ -101,26 +101,33 @@ class Availability(models.Model): """ Disponibilités des institutions """ corporation = models.ForeignKey(Corporation, verbose_name='Institution') period = models.ForeignKey(Period, verbose_name='Période') - number = models.IntegerField(verbose_name='Nombre de places') domain = models.ForeignKey(Domain, verbose_name='Domaine') + comment = models.TextField(blank=True, verbose_name='Remarques') class Meta: verbose_name = "Disponibilité" def __unicode__(self): - return '%d place(s) chez %s (%s)' % (self.number, self.corporation, self.period) + return '%s - %s (%s)' % (self.period, self.corporation, self.domain) + + @property + def free(self): + try: + self.training + except Training.DoesNotExist: + return True + return False class Training(models.Model): """ Stages """ student = models.ForeignKey(Student, verbose_name='Étudiant') - corporation = models.ForeignKey(Corporation, verbose_name='Institution') + availability = models.OneToOneField(Availability, verbose_name='Disponibilité') referent = models.ForeignKey(Referent, verbose_name='Référent') - period = models.ForeignKey(Period, verbose_name='Période') - domain = models.ForeignKey(Domain, verbose_name='Domaine') + comment = models.TextField(blank=True, verbose_name='Remarques') class Meta: verbose_name = "Stage" def __unicode__(self): - return '%s chez %s (%s)' % (self.student, self.corporation, self.period) + return '%s chez %s (%s)' % (self.student, self.availability.corporation, self.availability.period) diff --git a/stages/views.py b/stages/views.py index 8b603fb..2193459 100644 --- a/stages/views.py +++ b/stages/views.py @@ -6,10 +6,10 @@ import json from django.http import HttpResponse, HttpResponseNotAllowed from django.shortcuts import get_object_or_404 from django.views.decorators.csrf import csrf_exempt -from django.views.generic import DetailView, TemplateView +from django.views.generic import DetailView, TemplateView, ListView from .forms import PeriodForm -from .models import Section, Student, Corporation, Period, Training +from .models import Section, Student, Corporation, Period, Training, Referent, Availability class StudentSummaryView(DetailView): @@ -17,9 +17,18 @@ class StudentSummaryView(DetailView): template_name = 'student_summary.html' -class CorporationSummaryView(DetailView): - model = Corporation - template_name = 'corporation_summary.html' +class AvailabilitySummaryView(DetailView): + model = Availability + template_name = 'availability_summary.html' + + +class TrainingsByPeriodView(ListView): + template_name = 'trainings_list.html' + context_object_name = 'trainings' + + def get_queryset(self): + return Training.objects.select_related('student', 'availability__corporation', 'availability__domain' + ).filter(availability__period__pk=self.kwargs['pk']) class AttributionView(TemplateView): @@ -30,6 +39,7 @@ class AttributionView(TemplateView): context.update({ #'period_form': PeriodForm(), 'sections': Section.objects.all(), + 'referents': Referent.objects.all(), }) return context @@ -47,14 +57,14 @@ def period_students(request, pk): """ period = get_object_or_404(Period, pk=pk) students = period.section.student_set.all().order_by('last_name') - trainings = dict((t.student_id, t.id) for t in Training.objects.filter(period=period)) + trainings = dict((t.student_id, t.id) for t in Training.objects.filter(availability__period=period)) data = [{'name': unicode(s), 'id': s.id, 'training_id': trainings.get(s.id)} for s in students] return HttpResponse(json.dumps(data), content_type="application/json") -def period_corporations(request, pk): - """ Return all corporations with availabilities in the specified period """ +def period_availabilities(request, pk): + """ Return all availabilities in the specified period """ period = get_object_or_404(Period, pk=pk) - corps = [(av.corporation.id, av.corporation.name) + corps = [{'id': av.id, 'corp_name': av.corporation.name, 'domain': av.domain.name, 'free': av.free} for av in period.availability_set.select_related('corporation').all()] return HttpResponse(json.dumps(corps), content_type="application/json") @@ -62,11 +72,14 @@ def period_corporations(request, pk): def new_training(request): if request.method != 'POST': return HttpResponseNotAllowed() - training = Training.objects.create( - period=Period.objects.get(pk=request.POST.get('period')), - student=Student.objects.get(pk=request.POST.get('student')), - corporation=Corporation.objects.get(pk=request.POST.get('corp')) - ) + try: + training = Training.objects.create( + student=Student.objects.get(pk=request.POST.get('student')), + availability=Availability.objects.get(pk=request.POST.get('avail')), + referent=Referent.objects.get(pk=request.POST.get('referent')), + ) + except Exception as exc: + return HttpResponse(str(exc)) return HttpResponse('OK') @@ -77,10 +90,10 @@ def stages_export(request): export_fields = [ ('Prénom', 'student__first_name'), ('Nom', 'student__last_name'), - ('Filière', 'period__section__name'), - ('Début', 'period__start_date'), ('Fin', 'period__end_date'), - ('Institution', 'corporation__name'), - ('Domaine', 'domain__name'), + ('Filière', 'student__section__name'), + ('Début', 'availability__period__start_date'), ('Fin', 'availability__period__end_date'), + ('Institution', 'availability__corporation__name'), + ('Domaine', 'availability__domain__name'), ('Prénom référent', 'referent__first_name'), ('Nom référent', 'referent__last_name') ] diff --git a/templates/admin/index.html b/templates/admin/index.html index 79a4eef..9ed840a 100644 --- a/templates/admin/index.html +++ b/templates/admin/index.html @@ -46,7 +46,10 @@ {% endfor %} -

Exporter les données de stages

+ {% else %}

{% trans "You don't have permission to edit anything." %}

{% endif %} diff --git a/templates/attribution.html b/templates/attribution.html index 39bff09..72cdee4 100644 --- a/templates/attribution.html +++ b/templates/attribution.html @@ -1,23 +1,28 @@ {% extends "admin/base_site.html" %} -{% load admin_static %} +{% load i18n admin_static %} +{% load url from future %} {% block extrastyle %} {% endblock %} @@ -40,32 +45,37 @@ function update_periods(section_id) { function update_students(period_id) { $('#student_select').find('option').remove(); - $('#student_detail').html(''); + $('#student_detail').html('').removeClass("filled"); current_student = null; $('input#valid_training').hide() if (period_id == '') return; $.getJSON('/period/' + period_id + '/students/', function(data) { var sel = $('#student_select'); $.each(data, function() { - sel.append($("