Add a view to import HyperPlanning csv files

This commit is contained in:
Claude Paroz 2017-07-14 11:05:35 +02:00
parent 7b62c9cba1
commit 1a84c26f94
8 changed files with 144 additions and 16 deletions

View file

@ -30,4 +30,7 @@ class PeriodForm(forms.Form):
def __init__(self, data, *args, **kwargs):
pass
class UploadHPFileForm(forms.Form):
upload = forms.FileField(label='Fichier HyperPlanning')

View file

@ -0,0 +1,31 @@
NOMPERSO_ENS;UID_ENS;LIBELLE_MAT;NOMPERSO_DIP;TOTAL
Bernasconi Laurie;;#ASE Colloque;#Mandat_ASE;24.00
Bernasconi Laurie;;#ASE MP Expérientiel;#Mandat_ASE;40.00
Bernasconi Laurie;;#ASE TA;#Mandat_ASE;18.00
Bernasconi Laurie;;#IFFP;;
Bernasconi Laurie;;#IFFP;;
Bernasconi Laurie;;#IFFP;#Mandat_ASE;172.00
Bernasconi Laurie;;Animer I (B);1ASEFEa, 1ASEFEd, 1ASEFEe;8.00
Bernasconi Laurie;;Animer I (B);1ASEFEa, 1ASEFEd, 1ASEFEe;8.00
Bernasconi Laurie;;Animer I (B);1ASEFEb, 1ASEFEc, 1ASEFEd, 1ASEFEf;8.00
Bernasconi Laurie;;Animer I (B);1ASEFEb, 1ASEFEc, 1ASEFEd, 1ASEFEf;8.00
Bernasconi Laurie;;Animer II (Bgén);2MPTS ASE1;8.00
Bernasconi Laurie;;Animer II (Bgén);2MPTS ASE1;8.00
Bernasconi Laurie;;Animer II (Bgén);2MPTS ASE1;8.00
Bernasconi Laurie;;Animer II (Bgén);2MPTS ASE1;8.00
Bernasconi Laurie;;Animer II (Bgén);2MPTS ASE1;8.00
Bernasconi Laurie;;Colloque ASE;;
Bernasconi Laurie;;Conseil de classe;;
Bernasconi Laurie;;Conseil de classe;;
Bernasconi Laurie;;Formation AMOK EPC;;
Bernasconi Laurie;;Relations prof. (I);1ASEFEf, 3MPS ASE1;2.00
Bernasconi Laurie;;Relations prof. (I);1MPTS ASE3, 3MPS ASE3;2.00
Bernasconi Laurie;;Relations prof. (I);3MPS ASE1;8.00
Bernasconi Laurie;;Relations prof. (I);3MPS ASE1;8.00
Bernasconi Laurie;;Relations prof. (I);3MPS ASE3;8.00
Bernasconi Laurie;;Remise des titres;;
Bernasconi Laurie;;Sém. enfance 2;[2ASEFE c-d E S2];8.00
Bernasconi Laurie;;Sém. enfance 2;[2ASEFE c-d E S2];8.00
Bernasconi Laurie;;Sém. enfance 2;[2ASEFE c-d E S2];8.00
Bernasconi Laurie;;Sém. enfance 2;[2ASEFE c-d E S2];8.00
Bernasconi Laurie;;Travail personnel;[2ASEFE c-d E S2];8.00
1 NOMPERSO_ENS UID_ENS LIBELLE_MAT NOMPERSO_DIP TOTAL
2 Bernasconi Laurie #ASE Colloque #Mandat_ASE 24.00
3 Bernasconi Laurie #ASE MP Expérientiel #Mandat_ASE 40.00
4 Bernasconi Laurie #ASE TA #Mandat_ASE 18.00
5 Bernasconi Laurie #IFFP
6 Bernasconi Laurie #IFFP
7 Bernasconi Laurie #IFFP #Mandat_ASE 172.00
8 Bernasconi Laurie Animer I (B) 1ASEFEa, 1ASEFEd, 1ASEFEe 8.00
9 Bernasconi Laurie Animer I (B) 1ASEFEa, 1ASEFEd, 1ASEFEe 8.00
10 Bernasconi Laurie Animer I (B) 1ASEFEb, 1ASEFEc, 1ASEFEd, 1ASEFEf 8.00
11 Bernasconi Laurie Animer I (B) 1ASEFEb, 1ASEFEc, 1ASEFEd, 1ASEFEf 8.00
12 Bernasconi Laurie Animer II (Bgén) 2MPTS ASE1 8.00
13 Bernasconi Laurie Animer II (Bgén) 2MPTS ASE1 8.00
14 Bernasconi Laurie Animer II (Bgén) 2MPTS ASE1 8.00
15 Bernasconi Laurie Animer II (Bgén) 2MPTS ASE1 8.00
16 Bernasconi Laurie Animer II (Bgén) 2MPTS ASE1 8.00
17 Bernasconi Laurie Colloque ASE
18 Bernasconi Laurie Conseil de classe
19 Bernasconi Laurie Conseil de classe
20 Bernasconi Laurie Formation AMOK EPC
21 Bernasconi Laurie Relations prof. (I) 1ASEFEf, 3MPS ASE1 2.00
22 Bernasconi Laurie Relations prof. (I) 1MPTS ASE3, 3MPS ASE3 2.00
23 Bernasconi Laurie Relations prof. (I) 3MPS ASE1 8.00
24 Bernasconi Laurie Relations prof. (I) 3MPS ASE1 8.00
25 Bernasconi Laurie Relations prof. (I) 3MPS ASE3 8.00
26 Bernasconi Laurie Remise des titres
27 Bernasconi Laurie Sém. enfance 2 [2ASEFE c-d E S2] 8.00
28 Bernasconi Laurie Sém. enfance 2 [2ASEFE c-d E S2] 8.00
29 Bernasconi Laurie Sém. enfance 2 [2ASEFE c-d E S2] 8.00
30 Bernasconi Laurie Sém. enfance 2 [2ASEFE c-d E S2] 8.00
31 Bernasconi Laurie Travail personnel [2ASEFE c-d E S2] 8.00

View file

@ -9,7 +9,7 @@ from django.utils.html import escape
from .models import (
Level, Domain, Section, Klass, Period, Student, Corporation, Availability,
CorpContact, Referent, Training
CorpContact, Referent, Teacher, Training,
)
from .utils import school_year
@ -157,7 +157,7 @@ class ImportTests(TestCase):
path = os.path.join(os.path.dirname(__file__), 'test_files', 'EXPORT_GAN.xls')
self.client.login(username='me', password='mepassword')
with open(path, 'rb') as fh:
response = self.client.post(reverse('tabimport'), {'upload': fh}, follow=True)
response = self.client.post(reverse('import-students'), {'upload': fh}, follow=True)
self.assertContains(response, escape("La classe '1ASEFEa' n'existe pas encore"))
lev1 = Level.objects.create(name='1')
@ -172,5 +172,16 @@ class ImportTests(TestCase):
level=lev1,
)
with open(path, 'rb') as fh:
response = self.client.post(reverse('tabimport'), {'upload': fh}, follow=True)
response = self.client.post(reverse('import-students'), {'upload': fh}, follow=True)
self.assertContains(response, "Created objects: 2")
def test_import_hp(self):
teacher = Teacher.objects.create(
first_name='Laurie', last_name='Bernasconi', birth_date='1974-08-08'
)
path = os.path.join(os.path.dirname(__file__), 'test_files', 'HYPERPLANNING.csv')
self.client.login(username='me', password='mepassword')
with open(path, 'rb') as fh:
response = self.client.post(reverse('import-hp'), {'upload': fh}, follow=True)
self.assertContains(response, "Created objects: 13, modified objects: 10")
self.assertEqual(teacher.course_set.count(), 13)

View file

@ -2,10 +2,11 @@ import json
from collections import OrderedDict
from datetime import date, datetime, timedelta
from tabimport import FileFactory
from tabimport import CSVImportedFile, FileFactory
from django.conf import settings
from django.contrib import messages
from django.core.files import File
from django.db.models import Case, Count, When
from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect
from django.shortcuts import get_object_or_404
@ -13,9 +14,11 @@ from django.urls import reverse
from django.utils.translation import ugettext as _
from django.views.generic import DetailView, FormView, TemplateView, ListView
from .forms import PeriodForm, StudentImportForm
from .models import (Klass, Section, Student, Corporation, CorpContact, Period,
Training, Referent, Availability)
from .forms import PeriodForm, StudentImportForm, UploadHPFileForm
from .models import (
Klass, Section, Student, Teacher, Corporation, CorpContact, Course, Period,
Training, Referent, Availability,
)
def school_year_start():
@ -282,13 +285,18 @@ def del_training(request):
return HttpResponse(json.dumps({'ref_id': ref_id}), content_type="application/json")
class StudentImportView(FormView):
template_name = 'student_import.html'
form_class = StudentImportForm
class ImportViewBase(FormView):
template_name = 'file_import.html'
def form_valid(self, form):
upfile = form.cleaned_data['upload']
try:
imp_file = FileFactory(form.cleaned_data['upload'])
if 'csv' in upfile.content_type:
# Reopen the file in text mode
upfile = open(upfile.temporary_file_path(), mode='r', encoding='utf-8-sig')
imp_file = CSVImportedFile(File(upfile))
else:
imp_file = FileFactory(upfile)
created, modified = self.import_data(imp_file)
except Exception as e:
if settings.DEBUG:
@ -299,6 +307,11 @@ class StudentImportView(FormView):
'cr': created, 'mod': modified})
return HttpResponseRedirect(reverse('admin:index'))
class StudentImportView(ImportViewBase):
title = "Importation étudiants"
form_class = StudentImportForm
def import_data(self, up_file):
""" Import Student data from uploaded file. """
student_mapping = settings.STUDENT_IMPORT_MAPPING
@ -334,6 +347,74 @@ class StudentImportView(FormView):
return obj_created, obj_modified
class HPImportView(ImportViewBase):
"""
Importation du fichier HyperPlanning pour l'établissement des feuilles
de charges.
"""
form_class = UploadHPFileForm
mapping = {
'NOMPERSO_ENS': 'teacher',
'LIBELLE_MAT': 'subject',
'NOMPERSO_DIP': 'klass',
'TOTAL': 'period',
}
# Mapping between klass field and imputation
account_categories = {
'ASAFE': 'ASA',
'ASEFE': 'ASE',
'ASSCFE': 'ASSC',
'MP': 'LEP',
'EDEpe': 'EDEpe',
'EDEps': 'EDEps',
'EDE': 'EDE',
'EDS': 'EDS',
'CAS-FPP': 'CAS-FPP',
'Mandat_ASSC': 'ASSC',
'Mandat_ASE': 'ASE',
'Mandat_EDE': 'EDE',
'Mandat_EDS': 'EDA',
}
def import_data(self, up_file):
obj_created = obj_modified = 0
#Pour accélérer la recherche
profs = {}
for t in Teacher.objects.all():
profs[t.__str__()] = t
Course.objects.all().delete()
for line in up_file:
if (line['LIBELLE_MAT'] == '' or line['NOMPERSO_DIP'] == '' or
line['TOTAL'] == ''):
continue
defaults = {
'teacher': profs[line['NOMPERSO_ENS']],
'subject': line['LIBELLE_MAT'],
'klass': line['NOMPERSO_DIP'],
}
obj, created = Course.objects.get_or_create(
teacher = defaults['teacher'],
subject = defaults['subject'],
klass = defaults['klass'])
period = int(float(line['TOTAL']))
if created:
obj.period = period
obj_created += 1
for k, v in self.account_categories.items():
if k in obj.klass:
obj.imputation = v
break
else:
obj.period += period
obj_modified += 1
obj.save()
return obj_created, obj_modified
EXPORT_FIELDS = [
('Prénom', 'student__first_name'), ('Nom', 'student__last_name'),
('ID externe', 'student__ext_id'),