Add ESTER students import
This commit is contained in:
parent
e5147187e2
commit
b84289e25c
5 changed files with 133 additions and 28 deletions
BIN
stages/test_files/CLOEE2_Export_Ester_2018.xls
Normal file
BIN
stages/test_files/CLOEE2_Export_Ester_2018.xls
Normal file
Binary file not shown.
|
|
@ -438,7 +438,7 @@ class ImportTests(TestCase):
|
|||
for f in os.listdir(bulletins_dir):
|
||||
os.remove(os.path.join(bulletins_dir, f))
|
||||
|
||||
def test_import_students(self):
|
||||
def test_import_students_EPC(self):
|
||||
"""
|
||||
Import CLOEE file for FE students (ASAFE, ASEFE, ASSCF, EDE, EDS) version 2018!!
|
||||
|
||||
|
|
@ -512,6 +512,59 @@ class ImportTests(TestCase):
|
|||
stud_arch = Student.objects.get(ext_id=44444)
|
||||
self.assertTrue(stud_arch.archived)
|
||||
|
||||
def test_import_students_ESTER(self):
|
||||
"""
|
||||
Import CLOEE file for ESTER students (MP_*) version 2018
|
||||
|
||||
Student :
|
||||
- S. Lampion, 1MPTS ASE1 - Généraliste
|
||||
- B. Castafiore, 1MPTS ASE1
|
||||
|
||||
Export CLOEE:
|
||||
- S. Lampion, 2MPTS ASE1 - Accompagnement des enfants
|
||||
- T. Tournesol, 2MPS ASSC1
|
||||
|
||||
Results in Student:
|
||||
- S. Lampion, 2MPTS ASE1 (Student data + Cloee klass)
|
||||
- T. Tournesol, 2MPS ASSC1 (Candidate data + Cloee klass)
|
||||
- B. Castafiore, archived
|
||||
"""
|
||||
lev1 = Level.objects.create(name='1')
|
||||
lev2 = Level.objects.create(name='2')
|
||||
mp_ase = Section.objects.create(name='MP_ASE')
|
||||
mp_assc = Section.objects.create(name='MP_ASSC')
|
||||
Option.objects.create(name='Accompagnement des enfants')
|
||||
Option.objects.create(name='Généraliste')
|
||||
k1 = Klass.objects.create(name='1MPTS ASE1', section=mp_ase, level=lev1)
|
||||
k2 = Klass.objects.create(name='2MPTS ASE1', section=mp_ase, level=lev2)
|
||||
|
||||
# Existing students, klass should be changed or student archived.
|
||||
Student.objects.create(ext_id=11111, first_name="Séraphin", last_name="Lampion", city='Marin', klass=k1)
|
||||
Student.objects.create(ext_id=22222, first_name="Bianca", last_name="Castafiore", city='Marin', klass=k1)
|
||||
|
||||
path = os.path.join(os.path.dirname(__file__), 'test_files', 'CLOEE2_Export_Ester_2018.xls')
|
||||
self.client.login(username='me', password='mepassword')
|
||||
with open(path, 'rb') as fh:
|
||||
response = self.client.post(reverse('import-students-ester'), {'upload': fh}, follow=True)
|
||||
msg = "\n".join(str(m) for m in response.context['messages'])
|
||||
self.assertIn("La classe '2MPS ASSC1' n'existe pas encore", msg)
|
||||
|
||||
k3 = Klass.objects.create(name='2MPS ASSC1', section=mp_assc, level=lev2)
|
||||
with open(path, 'rb') as fh:
|
||||
response = self.client.post(reverse('import-students-ester'), {'upload': fh}, follow=True)
|
||||
msg = "\n".join(str(m) for m in response.context['messages'])
|
||||
self.assertIn("Objets créés : 1", msg)
|
||||
self.assertIn("Objets modifiés : 1", msg)
|
||||
|
||||
# Student already existed, klass changed
|
||||
student1 = Student.objects.get(ext_id=11111)
|
||||
self.assertEqual(student1.klass.name, '2MPTS ASE1')
|
||||
self.assertEqual(student1.option_ase.name, 'Accompagnement des enfants')
|
||||
self.assertEqual(student1.city, 'Le Locle')
|
||||
# Castafiore was archived
|
||||
stud_arch = Student.objects.get(ext_id=22222)
|
||||
self.assertTrue(stud_arch.archived)
|
||||
|
||||
def test_import_hp(self):
|
||||
teacher = Teacher.objects.create(
|
||||
first_name='Jeanne', last_name='Dupond', birth_date='1974-08-08'
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import tempfile
|
|||
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
from fnmatch import fnmatch
|
||||
from subprocess import PIPE, Popen, call
|
||||
|
||||
from tabimport import CSVImportedFile, FileFactory
|
||||
|
|
@ -72,7 +73,7 @@ class ImportViewBase(FormView):
|
|||
|
||||
|
||||
class StudentImportView(ImportViewBase):
|
||||
title = "Importation étudiants"
|
||||
title = "Importation étudiants EPC"
|
||||
form_class = StudentImportForm
|
||||
# Mapping between column names of a tabular file and Student field names
|
||||
student_mapping = {
|
||||
|
|
@ -81,6 +82,7 @@ class StudentImportView(ImportViewBase):
|
|||
'ELE_PRENOM': 'first_name',
|
||||
'ELE_RUE': 'street',
|
||||
'ELE_NPA_LOCALITE': 'city', # pcode is separated from city in prepare_import
|
||||
'ELE_CODE_CANTON': 'district',
|
||||
'ELE_TEL_PRIVE': 'tel',
|
||||
'ELE_TEL_MOBILE': 'mobile',
|
||||
'ELE_EMAIL_RPN': 'email',
|
||||
|
|
@ -102,12 +104,14 @@ class StudentImportView(ImportViewBase):
|
|||
}
|
||||
mapping_option_ase = {
|
||||
'GEN': 'Généraliste',
|
||||
'Enfants': 'Accompagnement des enfants',
|
||||
'ENF': 'Accompagnement des enfants',
|
||||
'HAN': 'Accompagnement des personnes handicapées',
|
||||
'PAG': 'Accompagnement des personnes âgées',
|
||||
}
|
||||
# Those values are always taken from the import file
|
||||
fields_to_overwrite = ['klass', 'login_rpn']
|
||||
klasses_to_skip = []
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
|
|
@ -142,6 +146,27 @@ class StudentImportView(ImportViewBase):
|
|||
values['option_ase'] = None
|
||||
return values
|
||||
|
||||
@property
|
||||
def _existing_students(self):
|
||||
return Student.objects.filter(
|
||||
archived=False,
|
||||
ext_id__isnull=False,
|
||||
klass__section__in=[s for s in Section.objects.all() if s.is_EPC]
|
||||
)
|
||||
|
||||
def update_defaults_from_candidate(self, defaults):
|
||||
# Any DoesNotExist exception will bubble up.
|
||||
candidate = Candidate.objects.get(last_name=defaults['last_name'],
|
||||
first_name=defaults['first_name'])
|
||||
# Mix CLOEE data and Candidate data
|
||||
if candidate.option in self.mapping_option_ase:
|
||||
defaults['option_ase'] = Option.objects.get(name=self.mapping_option_ase[candidate.option])
|
||||
if candidate.corporation:
|
||||
defaults['corporation'] = candidate.corporation
|
||||
defaults['instructor'] = candidate.instructor
|
||||
defaults['dispense_ecg'] = candidate.exemption_ecg
|
||||
defaults['soutien_dys'] = candidate.handicap
|
||||
|
||||
def import_data(self, up_file):
|
||||
""" Import Student data from uploaded file. """
|
||||
|
||||
|
|
@ -151,12 +176,8 @@ class StudentImportView(ImportViewBase):
|
|||
obj_created = obj_modified = 0
|
||||
err_msg = []
|
||||
seen_students_ids = set()
|
||||
fe_students_ids = set(
|
||||
Student.objects.filter(
|
||||
archived=False,
|
||||
ext_id__isnull=False,
|
||||
klass__section__in=[s for s in Section.objects.all() if s.is_EPC]
|
||||
).values_list('ext_id', flat=True)
|
||||
existing_students_ids = set(
|
||||
self._existing_students.values_list('ext_id', flat=True)
|
||||
)
|
||||
|
||||
for line in up_file:
|
||||
|
|
@ -166,12 +187,20 @@ class StudentImportView(ImportViewBase):
|
|||
if student_defaults['ext_id'] in seen_students_ids:
|
||||
# Second line for student, ignore it
|
||||
continue
|
||||
for klass in self.klasses_to_skip:
|
||||
if fnmatch(student_defaults['klass'], klass):
|
||||
continue
|
||||
seen_students_ids.add(student_defaults['ext_id'])
|
||||
|
||||
corporation_defaults = {
|
||||
val: strip(line[key]) for key, val in self.corporation_mapping.items()
|
||||
}
|
||||
student_defaults['corporation'] = self.get_corporation(corporation_defaults)
|
||||
if self.corporation_mapping:
|
||||
corporation_defaults = {
|
||||
val: strip(line[key]) for key, val in self.corporation_mapping.items()
|
||||
}
|
||||
student_defaults['corporation'] = self.get_corporation(corporation_defaults)
|
||||
|
||||
if 'option_ase' in self.fields_to_overwrite:
|
||||
if student_defaults['option_ase'] in self.mapping_option_ase:
|
||||
student_defaults['option_ase'] = self.mapping_option_ase[student_defaults['option_ase']]
|
||||
|
||||
defaults = self.clean_values(student_defaults)
|
||||
try:
|
||||
|
|
@ -189,18 +218,7 @@ class StudentImportView(ImportViewBase):
|
|||
obj_modified += 1
|
||||
except Student.DoesNotExist:
|
||||
try:
|
||||
candidate = Candidate.objects.get(last_name=defaults['last_name'],
|
||||
first_name=defaults['first_name'])
|
||||
# Mix CLOEE data and Candidate data
|
||||
if candidate.option in self.mapping_option_ase:
|
||||
defaults['option_ase'] = Option.objects.get(name=self.mapping_option_ase[candidate.option])
|
||||
if candidate.corporation:
|
||||
defaults['corporation'] = candidate.corporation
|
||||
defaults['instructor'] = candidate.instructor
|
||||
defaults['dispense_ecg'] = candidate.exemption_ecg
|
||||
defaults['soutien_dys'] = candidate.handicap
|
||||
Student.objects.create(**defaults)
|
||||
obj_created += 1
|
||||
self.update_defaults_from_candidate(defaults)
|
||||
except Candidate.DoesNotExist:
|
||||
# New student with no matching Candidate
|
||||
err_msg.append('Étudiant non trouvé dans les candidats: {0} {1} - classe: {2}'.format(
|
||||
|
|
@ -208,12 +226,12 @@ class StudentImportView(ImportViewBase):
|
|||
defaults['first_name'],
|
||||
defaults['klass'])
|
||||
)
|
||||
Student.objects.create(**defaults)
|
||||
obj_created += 1
|
||||
|
||||
Student.objects.create(**defaults)
|
||||
obj_created += 1
|
||||
|
||||
# Archive students who have not been exported
|
||||
rest = fe_students_ids - seen_students_ids
|
||||
rest = existing_students_ids - seen_students_ids
|
||||
archived = 0
|
||||
for student_id in rest:
|
||||
st = Student.objects.get(ext_id=student_id)
|
||||
|
|
@ -237,6 +255,38 @@ class StudentImportView(ImportViewBase):
|
|||
return corp
|
||||
|
||||
|
||||
class StudentEsterImportView(StudentImportView):
|
||||
title = "Importation étudiants ESTER"
|
||||
# Mapping between column names of a tabular file and Student field names
|
||||
student_mapping = {
|
||||
'ELE_NUMERO': 'ext_id',
|
||||
'ELE_NOM': 'last_name',
|
||||
'ELE_PRENOM': 'first_name',
|
||||
'ELE_RUE': 'street',
|
||||
'ELE_NPA_LOCALITE': 'city', # pcode is separated from city in prepare_import
|
||||
'ELE_DATE_NAISSANCE': 'birth_date',
|
||||
'ELE_AVS': 'avs',
|
||||
'ELE_SEXE': 'gender',
|
||||
'INS_CLASSE': 'klass',
|
||||
'PROF_DOMAINE_SPEC': 'option_ase',
|
||||
}
|
||||
corporation_mapping = None
|
||||
# Those values are always taken from the import file
|
||||
fields_to_overwrite = ['klass', 'street', 'city', 'option_ase']
|
||||
klasses_to_skip = ['1CMS*'] # Abandon classes 1CMS ASE + 1CMS ASSC
|
||||
|
||||
@property
|
||||
def _existing_students(self):
|
||||
return Student.objects.filter(
|
||||
archived=False,
|
||||
ext_id__isnull=False,
|
||||
klass__section__in=[s for s in Section.objects.all() if s.is_ESTER]
|
||||
)
|
||||
|
||||
def update_defaults_from_candidate(self, defaults):
|
||||
pass
|
||||
|
||||
|
||||
class HPImportView(ImportViewBase):
|
||||
"""
|
||||
Importation du fichier HyperPlanning pour l'établissement des feuilles
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue