-package org.lilie.services.eliot.notes.brevet
-
-import org.lilie.services.eliot.brevet.BrevetNote
-import org.hibernate.FetchMode
-import org.lilie.services.eliot.scolarite.Personne
-import org.lilie.services.eliot.brevet.BrevetEpreuve
-import org.lilie.services.eliot.notes.NotesDroitService
-import org.lilie.services.eliot.annuaire.SecuriteSession
-import org.lilie.services.eliot.notes.NotesFonction
-import org.lilie.services.eliot.droits.Action
-import org.lilie.services.eliot.scolarite.Etablissement
-import org.lilie.services.eliot.scolarite.StructureEnseignement
-import org.hibernate.SessionFactory
-import org.lilie.services.eliot.scolarite.structureenseignement.LocalStructureEnseignementService
-import org.lilie.services.eliot.brevet.BrevetRelEpreuveMatiere
-import org.lilie.services.eliot.scolarite.Matiere
-import org.lilie.services.eliot.notes.scolarite.NotesServiceService
-import org.lilie.services.eliot.scolarite.Periode
-import org.lilie.services.eliot.notes.scolarite.NotesPeriodeService
-import org.lilie.services.eliot.scolarite.IntervalleEnum
-import org.lilie.services.eliot.scolarite.Service
-import org.lilie.services.eliot.notes.resultat.eleve.ResultatEleveServicePeriodeService
-import org.lilie.services.eliot.notes.ResultatEleveServicePeriode
-import org.lilie.services.eliot.notes.resultat.eleve.AppreciationEleveEnseignementPeriodeService
-
-
-
-import org.lilie.services.eliot.notes.resultat.NoteInfo
-import org.lilie.services.eliot.notes.resultat.MoyenneService
-import org.lilie.services.eliot.brevet.BrevetSerie
-import org.lilie.services.eliot.notes.scolarite.NotesStructureEnseignementService
-import org.lilie.services.eliot.notes.resultat.CalculationService
-import org.lilie.services.eliot.scolarite.anneescolaire.AnneeScolaireService
-import org.lilie.services.eliot.brevet.BrevetFiche
-import org.lilie.services.eliot.brevet.BrevetModeCalculNote
-import org.lilie.services.eliot.notes.Note
-import org.lilie.services.eliot.scolarite.NaturePeriode
-
-/**
- * Gestion des notes de brevet
- * @author msan
- * @author bper
- */
-class BrevetNoteService {
-
- NotesDroitService notesDroitService
- LocalStructureEnseignementService localStructureEnseignementService
- NotesServiceService notesServiceService
- NotesPeriodeService notesPeriodeService
- ResultatEleveServicePeriodeService resultatEleveServicePeriodeService
- AppreciationEleveEnseignementPeriodeService appreciationEleveEnseignementPeriodeService
- MoyenneService moyenneService
- BrevetRelEpreuveMatiereService brevetRelEpreuveMatiereService
- BrevetSerieService brevetSerieService
- NotesStructureEnseignementService notesStructureEnseignementService
- CalculationService calculationService
-
- AnneeScolaireService anneeScolaireService
-
- SessionFactory sessionFactory
-
- static transactional = true
-
-
- /**
- * Initialise les notes des brevets
- * @author msan
- */
- Boolean initialiseNotesBrevet(SecuriteSession securiteSession,
- List<StructureEnseignement> classes) {
-
- // verifie que l'utilisateur a le droit de voir les notes
- List<Etablissement> etabs = (classes*.etablissement).unique { it.id }
- etabs.each {
- notesDroitService.verifieAutorisationByEtablissement(
- securiteSession,
- it,
- Action.CREATION,
- NotesFonction.DIRECTION_ASSIMILE)
- }
-
- Boolean initialisationOk = true
-
- // recupere notes
- List<BrevetNoteInfo> notesInitialises =
- internalActualiseNotes(securiteSession, classes, true)
-
- // enregsitre les changements
- notesInitialises.each { BrevetNoteInfo noteInfo ->
- BrevetNote brevetNote = BrevetNote.get(noteInfo.noteId)
- if (noteInfo.appreciation != null || noteInfo.valeurNumerique != null || noteInfo.noteValeur) {
-
- if (noteInfo.appreciation != null) {
- brevetNote.appreciation = noteInfo.appreciation
- }
-
- if (noteInfo.valeurNumerique != null) {
- brevetNote.valeurNumerique = noteInfo.valeurNumerique
- }
- else if (noteInfo.noteValeur != null) {
- brevetNote.setValeurTextuelle(noteInfo.noteValeur)
- }
-
- brevetNote.save(failOnError: true)
- }
- }
- sessionFactory.currentSession.flush()
-
- return initialisationOk
- }
-
- /**
- * Recupere BrevetNotes avec les valeurs actualisees avec les resultats reels
- * d'eleves.
- * La liste ne contiendra tout les eleves car il n'est pas necessaire
- * que tout les eleves d'une classe suivent la meme serie.
- * @author msan
- */
- List<BrevetNoteInfo> actualiseNotes(SecuriteSession securiteSession,
- StructureEnseignement classe,
- List<Personne> eleves) {
-
- // verifie que l'utilisateur a le droit de voir les notes
- notesDroitService.verifieAutorisationByEtablissement(
- securiteSession,
- classe.etablissement,
- Action.CONSULTATION,
- NotesFonction.DIRECTION_ASSIMILE)
-
- Map eleveMap = [:]
- eleves.each {
- eleveMap.put(it, classe)
- }
-
- List<BrevetNoteInfo> noteInfos =
- internalActualiseNotes(securiteSession, [classe], eleveMap)
-
- majAppreciations(noteInfos)
-
- return noteInfos
- }
-
- /**
- * Met à jour les appréciations des notes de Brevet à partir des appréciations
- * annuelles récupérées lors de l'actualisation des notes.
- * @author bper
- */
- private void majAppreciations(List<BrevetNoteInfo> noteInfos) {
- noteInfos.each {
- BrevetNote note = BrevetNote.get(it.noteId)
- if (note && note.appreciation != it.appreciation) {
- note.appreciation = it.appreciation
- note.save(failOnError: true, flush: true)
- }
- }
- }
-
- /**
- * Toutes les BrevetNotes pour les eleves avec les associantions fetches.
- * @author msan
- */
- List<BrevetNote> internalFindAllNotes(List<Personne> eleves) {
- return BrevetNote.createCriteria().listDistinct {
- fiche {
- 'in'('eleve', eleves)
- eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())
- }
- fetchMode('valeurTextuelle', FetchMode.JOIN) // AB,DI,NV ..
- fetchMode('epreuve', FetchMode.JOIN)
- fetchMode('epreuve.serie', FetchMode.JOIN)
- fetchMode('epreuve.valeurTextuelleAutorisees', FetchMode.JOIN)
- fetchMode('fiche', FetchMode.JOIN)
- fetchMode('fiche.eleve', FetchMode.JOIN)
- }
- }
-
- /**
- * Recupere BrevetNotes avec les valeurs actualisees avec les resultats reels
- * d'eleves. A utiliser pour l'actualisation ou l'initialisation.
- * @param securiteSession
- * @param classes liste des classes
- * @param eleveMap une map Eleve -> Sa classe
- * @param initialisation true s'il s'agit d'initiaisation
- * @author msan
- */
- List<BrevetNoteInfo> internalActualiseNotes(SecuriteSession securiteSession,
- List<StructureEnseignement> classes,
- Map<Personne, StructureEnseignement> eleveMap,
- Boolean initialisation = false) {
-
- List<BrevetNoteInfo> notesActualisess = []
-
- List<Personne> eleves = eleveMap.keySet().toList()
- Etablissement etablissement = classes.first().etablissement
-
- // get BrevetNotes
- List<BrevetNote> notes = internalFindAllNotes(eleves)
- List<BrevetEpreuve> epreuves = notes.collect { it.epreuve }.unique { it.id }
- epreuves = epreuves.findAll {it.notee}
-
- // get relations Epreuve - Metieres fixes
- List<BrevetRelEpreuveMatiere> relFixes = brevetRelEpreuveMatiereService.
- internalFindAllRel(epreuves)
-
- Map<StructureEnseignement, Periode> periodesAnnee =
- internalFindAllPeriodeAnneeByClasses(classes)
-
- notes.groupBy{it.fiche.eleve}.each { Personne eleve, List<BrevetNote> listeNotes ->
- List<BrevetEpreuve> eleveEpreuves = listeNotes.collect { it.epreuve }
- eleveEpreuves = eleveEpreuves.findAll {it.notee == true}
-
- StructureEnseignement classe = eleveMap.get(eleve)
- Periode periodeAnnee = periodesAnnee.get(classe)
-
- List<EpreuveInfo> epreuveInfos = internalChercheMatieres(
- securiteSession,
- eleveEpreuves,
- eleve,
- etablissement,
- relFixes,
- listeNotes,
- periodeAnnee,
- initialisation
- )
-
- // on peut avoir plusieurs services pour une epreuve dans le cas de partage des matieres
- internalAjouteInfoServices(
- securiteSession,
- epreuveInfos,
- eleve,
- periodeAnnee
- )
-
- internalAjouteInfoMoyennes(
- securiteSession,
- epreuveInfos,
- eleve,
- periodeAnnee
- )
-
- internalAjouteInfoAppreciations(
- securiteSession,
- epreuveInfos,
- eleve,
- periodeAnnee
- )
-
- // actualise les notes de brevet avec les resultats reels
- listeNotes.each { BrevetNote brevetNote ->
- EpreuveInfo epreuveInfo = epreuveInfos.find {
- it.epreuve.id == brevetNote.epreuve.id }
-
- notesActualisess += internalActualiseNote(
- epreuveInfo.moyenne,
- epreuveInfo.appreciation,
- brevetNote
- )
- }
-
- }
-
- return notesActualisess
- }
-
- /**
- * Ajoute les appreciations dans epreuveInfos
- * @author msan
- */
- void internalAjouteInfoAppreciations(SecuriteSession securiteSession,
- List<EpreuveInfo> epreuveInfos,
- Personne eleve,
- Periode periode) {
- List<Service> services = (List) epreuveInfos.collect { it.services }.flatten().
- findAll { it != null }.unique { it.id }
-
- Map<Service, List<String>> apps =
- appreciationEleveEnseignementPeriodeService.internalFindAll(
- eleve,
- periode,
- services
- )
-
- epreuveInfos.each { EpreuveInfo epreuveInfo ->
- if (epreuveInfo.services?.size() > 0) {
- List<String> appsEpreuve = (List) epreuveInfo.services.collect { Service service ->
- List<String> serviceApps = apps.get(service)
- if (serviceApps?.size() > 0) {
- return serviceApps
- } else {
- return []
- }
- }.flatten().findAll { it != null }
- if (appsEpreuve?.size() > 0) {
- // scotche les appreciations
- epreuveInfo.appreciation = appsEpreuve.join(' ')
- }
- }
- }
- }
-
- /**
- * Ajoute les moyennes dans epreuveInfos.
- * Re-initialise les listes des matières et des services en fonction des moyennes utilisées.
- * On ne garde que les matières et les services pour lesquels les moyennes ont été trouvées.
- * @author msan
- * @author bper
- */
- void internalAjouteInfoMoyennes(SecuriteSession securiteSession,
- List<EpreuveInfo> epreuveInfos,
- Personne eleve,
- Periode periode) {
-
- List<Service> services = (List) epreuveInfos.collect { it.services }.flatten().
- findAll { it != null }.unique { it.id }
-
- Map<Long, Integer> mapMatiereIdOrdre = getMapMatiereIdOrdre(services, periode)
-
- List<ResultatEleveServicePeriode> resultats = resultatEleveServicePeriodeService.
- internalFindAll(
- [eleve.autorite],
- services,
- [periode],
- [NaturePeriode.NOTATION]
- )
-
- resultats = (List) resultats.findAll {it.moyenne != null}
- List<Service> serviceAvecMoyennes = resultats*.service
-
- if (resultats.size() == 0) {
- epreuveInfos*.matieres = []
- epreuveInfos*.services = []
- return
- }
-
- Map resultatsParMatiere = resultats.groupBy {it.service.matiere}
-
- Map moyenneParMatiere = [:]
-
- // Calcule les moyennes des matères. Si une matières correspond à plusieurs services,
- // on calcule la moyenne des moyennes des services pondérée par les coeffs
- // des services pour la période donnée .
- resultatsParMatiere.each {Matiere matiere, List<ResultatEleveServicePeriode> ress ->
- BigDecimal moyenne = ress.size() == 1 ?
- ress.first().moyenne : internalCalculeMoyenneResultats(ress, periode)
-
- moyenneParMatiere.put(matiere, moyenne)
- }
-
- epreuveInfos.each {EpreuveInfo epreuveInfo ->
- Map moyenneParMatierePourEpreuve =
- (Map) moyenneParMatiere.findAll {Matiere matiere, BigDecimal moyenne ->
- epreuveInfo.matieres*.id.contains(matiere.id)
- }
-
- if (moyenneParMatierePourEpreuve.size() == 0) {
- epreuveInfo.matieres = []
- epreuveInfo.services = []
- return
- }
-
- switch (epreuveInfo.epreuve.modeCalculNote) {
- case BrevetModeCalculNote.PREMIERE_TROUVEE :
- List<Matiere> matieres = moyenneParMatierePourEpreuve.keySet().toList()
- matieres.sort{m1,m2 -> mapMatiereIdOrdre.get(m1.id) <=> mapMatiereIdOrdre.get(m2.id)}
- Matiere matiere = (Matiere) matieres.first()
- epreuveInfo.moyenne = (BigDecimal) moyenneParMatierePourEpreuve.get(matiere)
- epreuveInfo.matieres = [matiere]
- break
-
- case BrevetModeCalculNote.MOYENNE :
- List<BigDecimal> moyennes = (List<BigDecimal>) moyenneParMatierePourEpreuve.values().toList()
- epreuveInfo.moyenne = calculationService.calculeMoyenne(moyennes, true)?.valeurNumerique
- epreuveInfo.matieres = moyenneParMatierePourEpreuve.keySet().toList()
- break
-
- case BrevetModeCalculNote.MOYENNE_SPORT :
- Service serviceSport = findServiceSport(periode.classe)
- epreuveInfo.moyenne = calculeMoyenneSport(serviceSport, eleve)
- epreuveInfo.matieres = serviceSport ? [serviceSport.matiere] : []
- break
-
- default:
- throw new IllegalStateException(
- "Le mode de calcul de note ${epreuveInfo.epreuve.modeCalculNote} " +
- "pour l'épreuve ${epreuveInfo.epreuve} n'est pris en compte")
- }
-
- epreuveInfo.services = (List) serviceAvecMoyennes.findAll {
- epreuveInfo.matieres.contains(it.matiere)
- }
- }
- }
-
- private Map<Long, Integer> getMapMatiereIdOrdre(List<Service> services, Periode periode) {
- services = notesServiceService.trieServices(services, periode)
-
- Map<Service, Integer> mapServiceOrdre = [:]
-
- services.eachWithIndex {Service service, Integer ordre ->
- mapServiceOrdre.put(service, ordre)
- }
-
- Map<Long, Integer> mapMatiereIdOrdre = [:]
-
- services.groupBy{it.matiere}.each{Matiere matiere, List<Service> servicesMatiere ->
- List<Integer> ordres = servicesMatiere.collect{mapServiceOrdre.get(it)}
- mapMatiereIdOrdre.put(matiere.id, ordres.min())
- }
-
- return mapMatiereIdOrdre
- }
-
- private findServiceSport(StructureEnseignement classe) {
- return Service.findByStructureEnseignementAndChoisiPourSport(classe, true)
- }
-
- private BigDecimal calculeMoyenneSport(Service serviceSport, Personne eleve) {
-
- if (!serviceSport) {
- return null
- }
-
- List<Note> notes = Note.createCriteria().listDistinct {
- eq('eleve', eleve.autorite)
- evaluation {
- enseignement {
- eq('service', serviceSport)
- }
- periodes {
- typePeriode {
- eq('nature', NaturePeriode.NOTATION)
- }
- }
- }
-
- eq('choisiePourSport', true)
- }
-
- if (notes.size() < 3) {
- return null
- }
-
- if (notes.size() > 3) {
- throw new IllegalStateException(
- "L'élève $eleve a plus de 3 notes sélectionnées sport dans le service $serviceSport")
- }
-
- return calculationService.calculeMoyenne(notes*.valeurSur20, true)?.valeurNumerique
- }
-
- /**
- * Moyenne ponderee des resultats
- * @author msan
- */
- BigDecimal internalCalculeMoyenneResultats(List<ResultatEleveServicePeriode> resultats,
- Periode periode) {
- // calcule la moyenne ponderee
- List<NoteInfo> noteInfos = resultats.collect {
- new NoteInfo(
- it.getObjetMoyenne(),
- it.service.getCoeffPourPeriode(periode),
- false)
- }
- return calculationService.calculeMoyennePonderee(noteInfos, true)?.valeurNumerique
- }
-
- /**
- * Ajoute la correspondence entre les epreuves et les services dans epreuve info
- * @author msan
- * @author bper
- */
- void internalAjouteInfoServices(SecuriteSession securiteSession,
- List<EpreuveInfo> epreuveInfos,
- Personne eleve,
- Periode periode) {
-
- List<Matiere> matieres = epreuveInfos*.matieres.flatten().toList()
-
- // get services
- List<Service> services = notesServiceService.
- internalFindAllServiceByElevePeriodeMatieres(
- securiteSession,
- eleve,
- periode,
- matieres
- )
-
- // Affecte les services en fonction des matières affectées
- services.each {Service service ->
- epreuveInfos.each {EpreuveInfo epreuveInfo ->
- if (epreuveInfo.matieres*.id.contains(service.matiere.id)) {
- epreuveInfo.services.add(service)
- }
- }
- }
- }
-
-
- /**
- * Actualise note si necessaire et met la dans la liste noteActualisees.
- * S'il existe déjà une valeur textuelle saisie pour une note de brevet
- * la valeur numérique de cette note n'est pas mise à jour.
- * @author msan
- */
- private List<BrevetNoteInfo> internalActualiseNote(BigDecimal note,
- String appreciation,
- BrevetNote brevetNote) {
-
- List<BrevetNoteInfo> notesActualises = []
-
- // si la moyenne ou l'appr existe, ajoute la note
- // dans la liste des resultats envoyes
- if (note != null || appreciation != null ||
- (brevetNote.epreuve.isSport() && brevetNote.valeurTextuelle == null)) {
-
- BrevetNoteInfo brevetNoteInfo = new BrevetNoteInfo(
- noteId: brevetNote.id,
- eleveId: brevetNote.fiche.eleve.id,
- epreuveId: brevetNote.epreuve.id,
- appreciation: brevetNote.appreciation,
- noteValeur: brevetNote.valeur,
- valeurNumerique: brevetNote.valeurNumerique
- )
-
- if (brevetNote.valeurTextuelle == null) {
- if (note != null) {
- brevetNoteInfo.valeurNumerique = note
- brevetNoteInfo.noteValeur = BrevetNote.NOTE_FORMATEUR.format(note)
- }
- else if (brevetNote.epreuve.isSport()) {
- brevetNoteInfo.valeurNumerique = null
- brevetNoteInfo.noteValeur = NoteTextuellesEnum.DI
- }
- }
-
- if (appreciation != null) {
- brevetNoteInfo.appreciation = coupeAppreciation(appreciation)
- }
-
- notesActualises.add(brevetNoteInfo)
- }
-
- return notesActualises
- }
-
- /**
- * Coupe une appreciation a la taille de 255 characteres
- * @author msan
- */
- String coupeAppreciation(String appreciation) {
- return appreciation.length()>255 ? appreciation.substring(0, 255) : appreciation
- }
-
- /**
- * Une map des periodes annees, indexee par les classes
- * @author msan
- */
- Map<StructureEnseignement, Periode> internalFindAllPeriodeAnneeByClasses(List<StructureEnseignement> classes) {
- Map classesPeriodes = [:]
- List<Periode> periodesAnnees = notesPeriodeService.
- internalFindAllPeriodeByClasses(
- classes,
- IntervalleEnum.ANNEE
- )
- periodesAnnees.each { Periode periodeAnnee ->
- classesPeriodes.put(periodeAnnee.classe, periodeAnnee)
- }
- return classesPeriodes
- }
-
- /**
- * Cherche les matieres correspondant a une epreuve pour un eleve donne
- * @author msan
- * @author bper
- */
- List<EpreuveInfo> internalChercheMatieres(SecuriteSession securiteSession,
- List<BrevetEpreuve> epreuves,
- Personne eleve,
- Etablissement etablissement,
- List<BrevetRelEpreuveMatiere> relFixes,
- List<BrevetNote> notes,
- Periode periodeAnnee,
- Boolean initialisation) {
- List<EpreuveInfo> epreuveInfos = []
- notes.each { BrevetNote note ->
- List<Matiere> matieres = internalChercheMatiere(
- securiteSession,
- note.epreuve,
- eleve,
- etablissement,
- relFixes,
- note,
- periodeAnnee,
- initialisation
- )
- epreuveInfos.add(new EpreuveInfo(
- epreuve: note.epreuve,
- matieres: matieres
- ))
- }
- return epreuveInfos
- }
-
- /**
- * Cherche le matiere correspondant a une epreuve pour un eleve donne
- * @author msan
- * @author bper
- */
- private List<Matiere> internalChercheMatiere(SecuriteSession securiteSession,
- BrevetEpreuve epreuve,
- Personne eleve,
- Etablissement etablissement,
- List<BrevetRelEpreuveMatiere> relFixes,
- BrevetNote note,
- Periode periodeAnnee,
- Boolean initialisation) {
- List<Matiere> matieres = null
-
- if (epreuve.personnalisable) {
- // epreuve personalisable - impactee par les options d'eleve
-
- if (isMatiereAinitialiser(initialisation, note.matiere)) {
- internalInitialiseMatiere(
- securiteSession,
- eleve,
- periodeAnnee,
- relFixes,
- note)
- }
- matieres = [note.matiere]
- } else {
- // epreuve avec les matieres fixes
- matieres = relFixes.findAll {
- it.epreuve.id == epreuve.id &&
- it.matiere.etablissement.id == etablissement.id
- }?.collect { it.matiere }
- }
-
- // traitement HiGeo - EduCivique.
- // si EduCivique n'est pas liee au matiere, on prend le rsultat de HiGeo
- if (epreuve.epreuveMatieresAHeriter != null &&
- (matieres == null || matieres.size()==0)) {
- matieres = relFixes.findAll {
- it.epreuve.id == epreuve.epreuveMatieresAHeriter.id &&
- it.matiere.etablissement.id == etablissement.id
- }?.collect { it.matiere }
- }
-
- return matieres
- }
-
- /**
- * Initialise la matiere de BrevetNote par la premiere matiere ou on trouve
- * une note pour l'eleve donne
- * @author msan
- */
- void internalInitialiseMatiere(SecuriteSession securiteSession,
- Personne eleve,
- Periode periodeAnnee,
- List<BrevetRelEpreuveMatiere> relFixes,
- BrevetNote note) {
- // Spec: Si une épreuve de type « LV1 ou LV2 ou Opt. facultative » (== personalisable)
- // est liée à plusieurs matières, le module Notes affecte à l'élève la
- // première matière trouvée où l'élève a une note.
- note.matiere = internalFindPremiereMatiereAvecNote(
- securiteSession,
- eleve,
- periodeAnnee,
- relFixes.findAll {
- it.epreuve.id == note.epreuve.id
- }?.collect { it.matiere }
- )
- if (log.isDebugEnabled()) {
- log.debug("BrevetNote "+note.id+" initialisee avec matiere "+note.matiere)
- }
- }
-
- /**
- * S'il faut initialiser la matiere
- * @author msan
- */
- Boolean isMatiereAinitialiser(boolean initialisation, Matiere matiere) {
- return (initialisation && matiere == null)
- }
-
- /**
- * Cherche une matiere qui est note pour l'eleve donne
- * @author msan
- */
- Matiere internalFindPremiereMatiereAvecNote(SecuriteSession securiteSession,
- Personne eleve,
- Periode periodeAnnee,
- List<Matiere> matieres) {
-
- // si note.matiere n'est pas saisie il faut chercher les resultats d'eleve
- // pour les matieres fixes de cette epreuve et prendre la matiere ou l'eleve
- // a une note + positionner la matiere de note
-
- List<Service> services = notesServiceService.
- internalFindAllServiceByElevePeriodeMatieres(
- securiteSession,
- eleve,
- periodeAnnee,
- matieres)
-
- List<ResultatEleveServicePeriode> resultats = resultatEleveServicePeriodeService.
- internalFindAll(
- [eleve.autorite],
- services,
- [periodeAnnee],
- [NaturePeriode.NOTATION]
- )
-
- resultats = (List) resultats.findAll {it.moyenne != null}
-
- if (resultats?.size()>0) {
- return resultats.first().service.matiere
- } else {
- return null
- }
- }
-
- /**
- * Recupere BrevetNotes avec les valeurs actualisees avec les resultats reels
- * d'eleves.
- * @author msan
- */
- List<BrevetNoteInfo> internalActualiseNotes(SecuriteSession securiteSession,
- List<StructureEnseignement> classes,
- Boolean initialisation = false) {
-
- if (classes == null || classes.size()==0) {
- return []
- }
-
- // prepare la liste des eleves
- Map<Personne, StructureEnseignement> eleveMap = [:]
- List elevesClasses = localStructureEnseignementService.
- findAllPersonneEleveAndClasseForAllClasses(classes)
-
- elevesClasses.each { def eleveClasse ->
- Personne eleve = eleveClasse[0].personne
- StructureEnseignement classe = eleveClasse[1]
- eleveMap.put(eleve, classe)
- }
-
- return internalActualiseNotes(securiteSession, classes, eleveMap, initialisation)
-
- }
-
- /**
- * Retourne le mapping personnalisée Epreuve -> Matiere.
- * @author bper
- */
- Map<Personne,Map<BrevetEpreuve,Matiere>> internalFindAllMapEleveEpreuveMatierePourEleves(List<Personne> eleves) {
-
- List<BrevetNote> notes = BrevetNote.withCriteria {
- fiche {
- 'in'('eleve',eleves)
- eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())
- }
- isNotNull('matiere')
- epreuve {
- eq('personnalisable', true)
- }
- }
-
- Map<Personne,Map<BrevetEpreuve,Matiere>> map = [:]
-
- eleves.each {Personne eleve ->
- Map mapEpreuveMatiere = [:]
- notes.each {
- if (it.fiche.eleve.id == eleve.id) {
- mapEpreuveMatiere.put(it.epreuve, it.matiere)
- }
- }
- map.put(eleve,mapEpreuveMatiere)
- }
-
- return map
- }
-
-
- /**
- * Met à jour la les choix de matières pour les épreuves personnalisables
- * pour un élève donné.
- * @author bper
- */
- void majChoixMateiresPourEleve(SecuriteSession securiteSession,
- Personne eleve,
- Map<BrevetEpreuve,Matiere> mapEpreuveMatiere) {
-
- StructureEnseignement classe =
- notesStructureEnseignementService.findClasseForEleve(securiteSession,eleve)
-
- notesDroitService.verifieAutorisationByEtablissement(
- securiteSession,
- classe.etablissement,
- Action.MODIFICATION,
- NotesFonction.DIRECTION_ASSIMILE)
-
- List<BrevetNote> notes = BrevetNote.withCriteria {
- fiche {
- eq('eleve',eleve)
- eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())
- }
- epreuve {
- eq('personnalisable', true)
- }
- }
-
- mapEpreuveMatiere.each {BrevetEpreuve epreuve, Matiere matiere ->
- if (!epreuve.personnalisable) {
- throw new IllegalArgumentException("L'épreuve $epreuve n'est pas pesronnalisable")
- }
-
- BrevetNote note = notes.find {it.epreuve.id == epreuve.id}
-
- if (note) {
- note.matiere = matiere
- note.save(failOnError: true)
- } else if (matiere) {
- throw new IllegalArgumentException(
- "Impossible d'assoceier la matière $matiere à l'épreuve $epreuve pour " +
- "l L'élève $eleve. Il n'est pas inscrit pour cette épreuve."
- )
- }
- }
-
- sessionFactory.currentSession.flush()
- }
-
-
- /**
- * Inscrit l'élève pour les épreuves qui ont des épreuves exclusives.
- * @author bper
- */
- void majInscriptionEpreuveExclusives(SecuriteSession securiteSession,
- Personne eleve,
- List<BrevetEpreuve> epreuves) {
-
- if (!epreuves) {
- return
- }
-
- StructureEnseignement classe =
- notesStructureEnseignementService.findClasseForEleve(securiteSession,eleve)
-
- notesDroitService.verifieAutorisationByEtablissement(
- securiteSession,
- classe.etablissement,
- Action.MODIFICATION,
- NotesFonction.DIRECTION_ASSIMILE)
-
- BrevetSerie serie = brevetSerieService.internalFindSeriePourEleve(eleve)
-
- if (!serie.id) {
- throw new IllegalArgumentException("L'élève $eleve n'est pas inscrit au Brevet")
- }
-
- BrevetFiche fiche = BrevetFiche.findByEleveAndAnneeScolaire(
- eleve,
- anneeScolaireService.anneeScolaireEnCours()
- )
-
- // Suppime les notes aux épreuves exclusives
- List<BrevetNote> noteToDeletes = BrevetNote.withCriteria {
- eq('fiche',fiche)
- 'in'('epreuve',epreuves*.epreuveExclusive)
- }
-
- noteToDeletes.each {
- fiche.removeFromNotes(it)
- it.delete()
- }
- sessionFactory.currentSession.flush()
-
- List<Long> epreuveDejaInscriteIds = (List) BrevetNote.withCriteria {
- eq('fiche',fiche)
- 'in'('epreuve',epreuves)
- epreuve {
- projections {
- property('id')
- }
- }
- }
-
- epreuves.each {BrevetEpreuve epreuve ->
- if (epreuve.serie.id != serie.id) {
- throw new IllegalArgumentException(
- "La série $serie de l'élève $eleve ne correspond pas à celle de l'épreuve $epreuve"
- )
- }
-
- if (!epreuve.epreuveExclusive) {
- throw new IllegalArgumentException("L'épreuve $eleve n'a d'épreuve exclusive")
- }
-
- if (!epreuveDejaInscriteIds.any {it == epreuve.id}) {
- BrevetNote note = new BrevetNote(fiche: fiche, epreuve: epreuve)
- fiche.addToNotes(note)
- }
- }
- fiche.save(failOnError: true, flush: true)
- }
-
-
- /**
- * Inscrit l'élève aux épreuves optionnelles passées en paramétres et
- * le desinscrit des épreuves optionnelles qui ne sont pas dans la liste.
- * @author bper
- */
- void majInscriptionEpreuveOptionnelles(SecuriteSession securiteSession,
- Personne eleve,
- List<BrevetEpreuve> epreuves) {
- StructureEnseignement classe =
- notesStructureEnseignementService.findClasseForEleve(securiteSession,eleve)
-
- notesDroitService.verifieAutorisationByEtablissement(
- securiteSession,
- classe.etablissement,
- Action.MODIFICATION,
- NotesFonction.DIRECTION_ASSIMILE)
-
- BrevetSerie serie = brevetSerieService.internalFindSeriePourEleve(eleve)
-
- if (!serie.id) {
- throw new IllegalArgumentException("L'élève $eleve n'est pas inscrit au Brevet")
- }
-
- BrevetFiche fiche = BrevetFiche.findByEleveAndAnneeScolaire(
- eleve,
- anneeScolaireService.anneeScolaireEnCours()
- )
-
- // Suppime les notes aux épreuves optionnelles qui ne sont pas dans la liste
- BrevetNote.withCriteria {
- eq('fiche',fiche)
- epreuve {
- eq('optionnelle',true)
- }
- if (epreuves) {
- not{'in'('epreuve',epreuves)}
- }
- }*.delete()
-
- List<Long> epreuveDejaInscriteIds = (List) BrevetNote.withCriteria {
- eq('fiche', fiche)
- if (epreuves) {
- 'in'('epreuve', epreuves)
- }
- epreuve {
- eq('optionnelle',true)
- projections {
- property('id')
- }
- }
- }
-
- epreuves.each {BrevetEpreuve epreuve ->
- if (serie?.id != epreuve.serie.id) {
- throw new IllegalArgumentException(
- "La série $serie de l'élève $eleve ne correspond pas à celle de l'épreuve $epreuve"
- )
- }
-
- if (!epreuve.optionnelle) {
- throw new IllegalArgumentException("L'épreuve $eleve n'est pas une épreuve optionnelle")
- }
-
- if (!epreuveDejaInscriteIds.any {it == epreuve.id}) {
- new BrevetNote(fiche: fiche, epreuve: epreuve).save(failOnError: true)
- }
- }
- sessionFactory.currentSession.flush()
- }
-
- BrevetNote findByEleveAndEpreuve(Personne eleve,
- BrevetEpreuve epreuve) {
-
- return BrevetNote.createCriteria().get {
- fiche {
- eq('eleve', eleve)
- eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())
- }
- eq('epreuve', epreuve)
- }
- }
-
-
-}
+package org.lilie.services.eliot.notes.brevet\r
+\r
+import org.lilie.services.eliot.brevet.BrevetNote\r
+import org.hibernate.FetchMode\r
+import org.lilie.services.eliot.scolarite.Personne\r
+import org.lilie.services.eliot.brevet.BrevetEpreuve\r
+import org.lilie.services.eliot.notes.NotesDroitService\r
+import org.lilie.services.eliot.annuaire.SecuriteSession\r
+import org.lilie.services.eliot.notes.NotesFonction\r
+import org.lilie.services.eliot.droits.Action\r
+import org.lilie.services.eliot.scolarite.Etablissement\r
+import org.lilie.services.eliot.scolarite.StructureEnseignement\r
+import org.hibernate.SessionFactory\r
+import org.lilie.services.eliot.scolarite.structureenseignement.LocalStructureEnseignementService\r
+import org.lilie.services.eliot.brevet.BrevetRelEpreuveMatiere\r
+import org.lilie.services.eliot.scolarite.Matiere\r
+import org.lilie.services.eliot.notes.scolarite.NotesServiceService\r
+import org.lilie.services.eliot.scolarite.Periode\r
+import org.lilie.services.eliot.notes.scolarite.NotesPeriodeService\r
+import org.lilie.services.eliot.scolarite.IntervalleEnum\r
+import org.lilie.services.eliot.scolarite.Service\r
+import org.lilie.services.eliot.notes.resultat.eleve.ResultatEleveServicePeriodeService\r
+import org.lilie.services.eliot.notes.ResultatEleveServicePeriode\r
+import org.lilie.services.eliot.notes.resultat.eleve.AppreciationEleveEnseignementPeriodeService\r
+\r
+\r
+\r
+import org.lilie.services.eliot.notes.resultat.NoteInfo\r
+import org.lilie.services.eliot.notes.resultat.MoyenneService\r
+import org.lilie.services.eliot.brevet.BrevetSerie\r
+import org.lilie.services.eliot.notes.scolarite.NotesStructureEnseignementService\r
+import org.lilie.services.eliot.notes.resultat.CalculationService\r
+import org.lilie.services.eliot.scolarite.anneescolaire.AnneeScolaireService\r
+import org.lilie.services.eliot.brevet.BrevetFiche\r
+import org.lilie.services.eliot.brevet.BrevetModeCalculNote\r
+import org.lilie.services.eliot.notes.Note\r
+import org.lilie.services.eliot.scolarite.NaturePeriode\r
+\r
+/**\r
+ * Gestion des notes de brevet\r
+ * @author msan\r
+ * @author bper\r
+ */\r
+class BrevetNoteService {\r
+\r
+ NotesDroitService notesDroitService\r
+ LocalStructureEnseignementService localStructureEnseignementService\r
+ NotesServiceService notesServiceService\r
+ NotesPeriodeService notesPeriodeService\r
+ ResultatEleveServicePeriodeService resultatEleveServicePeriodeService\r
+ AppreciationEleveEnseignementPeriodeService appreciationEleveEnseignementPeriodeService\r
+ MoyenneService moyenneService\r
+ BrevetRelEpreuveMatiereService brevetRelEpreuveMatiereService\r
+ BrevetSerieService brevetSerieService\r
+ NotesStructureEnseignementService notesStructureEnseignementService\r
+ CalculationService calculationService\r
+\r
+ AnneeScolaireService anneeScolaireService\r
+ \r
+ SessionFactory sessionFactory\r
+\r
+ static transactional = true\r
+\r
+\r
+ /**\r
+ * Initialise les notes des brevets\r
+ * @author msan\r
+ */\r
+ Boolean initialiseNotesBrevet(SecuriteSession securiteSession,\r
+ List<StructureEnseignement> classes) {\r
+\r
+ // verifie que l'utilisateur a le droit de voir les notes\r
+ List<Etablissement> etabs = (classes*.etablissement).unique { it.id }\r
+ etabs.each {\r
+ notesDroitService.verifieAutorisationByEtablissement(\r
+ securiteSession,\r
+ it,\r
+ Action.CREATION,\r
+ NotesFonction.DIRECTION_ASSIMILE)\r
+ }\r
+\r
+ Boolean initialisationOk = true\r
+\r
+ // recupere notes\r
+ List<BrevetNoteInfo> notesInitialises =\r
+ internalActualiseNotes(securiteSession, classes, true)\r
+\r
+ // enregsitre les changements\r
+ notesInitialises.each { BrevetNoteInfo noteInfo ->\r
+ BrevetNote brevetNote = BrevetNote.get(noteInfo.noteId)\r
+ if (noteInfo.appreciation != null || noteInfo.valeurNumerique != null || noteInfo.noteValeur) {\r
+\r
+ if (noteInfo.appreciation != null) {\r
+ brevetNote.appreciation = noteInfo.appreciation\r
+ }\r
+\r
+ if (noteInfo.valeurNumerique != null) {\r
+ brevetNote.valeurNumerique = noteInfo.valeurNumerique\r
+ }\r
+ else if (noteInfo.noteValeur != null) {\r
+ brevetNote.setValeurTextuelle(noteInfo.noteValeur)\r
+ }\r
+\r
+ brevetNote.save(failOnError: true)\r
+ }\r
+ }\r
+ sessionFactory.currentSession.flush()\r
+\r
+ return initialisationOk\r
+ }\r
+\r
+ /**\r
+ * Recupere BrevetNotes avec les valeurs actualisees avec les resultats reels\r
+ * d'eleves.\r
+ * La liste ne contiendra tout les eleves car il n'est pas necessaire\r
+ * que tout les eleves d'une classe suivent la meme serie.\r
+ * @author msan\r
+ */\r
+ List<BrevetNoteInfo> actualiseNotes(SecuriteSession securiteSession,\r
+ StructureEnseignement classe,\r
+ List<Personne> eleves) {\r
+\r
+ // verifie que l'utilisateur a le droit de voir les notes\r
+ notesDroitService.verifieAutorisationByEtablissement(\r
+ securiteSession,\r
+ classe.etablissement,\r
+ Action.CONSULTATION,\r
+ NotesFonction.DIRECTION_ASSIMILE)\r
+\r
+ Map eleveMap = [:]\r
+ eleves.each {\r
+ eleveMap.put(it, classe)\r
+ }\r
+\r
+ List<BrevetNoteInfo> noteInfos =\r
+ internalActualiseNotes(securiteSession, [classe], eleveMap)\r
+\r
+ majAppreciations(noteInfos)\r
+\r
+ return noteInfos\r
+ }\r
+\r
+ /**\r
+ * Met à jour les appréciations des notes de Brevet à partir des appréciations\r
+ * annuelles récupérées lors de l'actualisation des notes.\r
+ * @author bper\r
+ */\r
+ private void majAppreciations(List<BrevetNoteInfo> noteInfos) {\r
+ noteInfos.each {\r
+ BrevetNote note = BrevetNote.get(it.noteId)\r
+ if (note && note.appreciation != it.appreciation) {\r
+ note.appreciation = it.appreciation\r
+ note.save(failOnError: true, flush: true)\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Toutes les BrevetNotes pour les eleves avec les associantions fetches.\r
+ * @author msan\r
+ */\r
+ List<BrevetNote> internalFindAllNotes(List<Personne> eleves) {\r
+ return BrevetNote.createCriteria().listDistinct {\r
+ fiche {\r
+ 'in'('eleve', eleves)\r
+ eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())\r
+ }\r
+ fetchMode('valeurTextuelle', FetchMode.JOIN) // AB,DI,NV ..\r
+ fetchMode('epreuve', FetchMode.JOIN)\r
+ fetchMode('epreuve.serie', FetchMode.JOIN)\r
+ fetchMode('epreuve.valeurTextuelleAutorisees', FetchMode.JOIN)\r
+ fetchMode('fiche', FetchMode.JOIN)\r
+ fetchMode('fiche.eleve', FetchMode.JOIN)\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Recupere BrevetNotes avec les valeurs actualisees avec les resultats reels\r
+ * d'eleves. A utiliser pour l'actualisation ou l'initialisation.\r
+ * @param securiteSession\r
+ * @param classes liste des classes\r
+ * @param eleveMap une map Eleve -> Sa classe\r
+ * @param initialisation true s'il s'agit d'initiaisation\r
+ * @author msan\r
+ */\r
+ List<BrevetNoteInfo> internalActualiseNotes(SecuriteSession securiteSession,\r
+ List<StructureEnseignement> classes,\r
+ Map<Personne, StructureEnseignement> eleveMap,\r
+ Boolean initialisation = false) {\r
+\r
+ List<BrevetNoteInfo> notesActualisess = []\r
+\r
+ List<Personne> eleves = eleveMap.keySet().toList()\r
+ Etablissement etablissement = classes.first().etablissement\r
+\r
+ // get BrevetNotes\r
+ List<BrevetNote> notes = internalFindAllNotes(eleves)\r
+ List<BrevetEpreuve> epreuves = notes.collect { it.epreuve }.unique { it.id }\r
+ epreuves = epreuves.findAll {it.notee}\r
+\r
+ // get relations Epreuve - Metieres fixes\r
+ List<BrevetRelEpreuveMatiere> relFixes = brevetRelEpreuveMatiereService.\r
+ internalFindAllRel(epreuves)\r
+\r
+ Map<StructureEnseignement, Periode> periodesAnnee =\r
+ internalFindAllPeriodeAnneeByClasses(classes)\r
+\r
+ notes.groupBy{it.fiche.eleve}.each { Personne eleve, List<BrevetNote> listeNotes ->\r
+ List<BrevetEpreuve> eleveEpreuves = listeNotes.collect { it.epreuve }\r
+ eleveEpreuves = eleveEpreuves.findAll {it.notee == true}\r
+\r
+ StructureEnseignement classe = eleveMap.get(eleve)\r
+ Periode periodeAnnee = periodesAnnee.get(classe)\r
+\r
+ List<EpreuveInfo> epreuveInfos = internalChercheMatieres(\r
+ securiteSession,\r
+ eleveEpreuves,\r
+ eleve,\r
+ etablissement,\r
+ relFixes,\r
+ listeNotes,\r
+ periodeAnnee,\r
+ initialisation\r
+ )\r
+\r
+ // on peut avoir plusieurs services pour une epreuve dans le cas de partage des matieres\r
+ internalAjouteInfoServices(\r
+ securiteSession,\r
+ epreuveInfos,\r
+ eleve,\r
+ periodeAnnee\r
+ )\r
+\r
+ internalAjouteInfoMoyennes(\r
+ securiteSession,\r
+ epreuveInfos,\r
+ eleve,\r
+ periodeAnnee\r
+ )\r
+\r
+ internalAjouteInfoAppreciations(\r
+ securiteSession,\r
+ epreuveInfos,\r
+ eleve,\r
+ periodeAnnee\r
+ )\r
+\r
+ // actualise les notes de brevet avec les resultats reels\r
+ listeNotes.each { BrevetNote brevetNote ->\r
+ EpreuveInfo epreuveInfo = epreuveInfos.find {\r
+ it.epreuve.id == brevetNote.epreuve.id }\r
+\r
+ notesActualisess += internalActualiseNote(\r
+ epreuveInfo.moyenne,\r
+ epreuveInfo.appreciation,\r
+ brevetNote\r
+ )\r
+ }\r
+\r
+ }\r
+\r
+ return notesActualisess\r
+ }\r
+\r
+ /**\r
+ * Ajoute les appreciations dans epreuveInfos\r
+ * @author msan\r
+ */\r
+ void internalAjouteInfoAppreciations(SecuriteSession securiteSession,\r
+ List<EpreuveInfo> epreuveInfos,\r
+ Personne eleve,\r
+ Periode periode) {\r
+ List<Service> services = (List) epreuveInfos.collect { it.services }.flatten().\r
+ findAll { it != null }.unique { it.id }\r
+\r
+ Map<Service, List<String>> apps =\r
+ appreciationEleveEnseignementPeriodeService.internalFindAll(\r
+ eleve,\r
+ periode,\r
+ services\r
+ )\r
+\r
+ epreuveInfos.each { EpreuveInfo epreuveInfo ->\r
+ if (epreuveInfo.services?.size() > 0) {\r
+ List<String> appsEpreuve = (List) epreuveInfo.services.collect { Service service ->\r
+ List<String> serviceApps = apps.get(service)\r
+ if (serviceApps?.size() > 0) {\r
+ return serviceApps\r
+ } else {\r
+ return []\r
+ }\r
+ }.flatten().findAll { it != null }\r
+ if (appsEpreuve?.size() > 0) {\r
+ // scotche les appreciations\r
+ epreuveInfo.appreciation = appsEpreuve.join(' ')\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Ajoute les moyennes dans epreuveInfos.\r
+ * Re-initialise les listes des matières et des services en fonction des moyennes utilisées.\r
+ * On ne garde que les matières et les services pour lesquels les moyennes ont été trouvées.\r
+ * @author msan\r
+ * @author bper\r
+ */\r
+ void internalAjouteInfoMoyennes(SecuriteSession securiteSession,\r
+ List<EpreuveInfo> epreuveInfos,\r
+ Personne eleve,\r
+ Periode periode) {\r
+\r
+ List<Service> services = (List) epreuveInfos.collect { it.services }.flatten().\r
+ findAll { it != null }.unique { it.id }\r
+\r
+ Map<Long, Integer> mapMatiereIdOrdre = getMapMatiereIdOrdre(services, periode)\r
+\r
+ List<ResultatEleveServicePeriode> resultats = resultatEleveServicePeriodeService.\r
+ internalFindAll(\r
+ [eleve.autorite],\r
+ services,\r
+ [periode],\r
+ [NaturePeriode.NOTATION]\r
+ )\r
+\r
+ resultats = (List) resultats.findAll {it.moyenne != null}\r
+ List<Service> serviceAvecMoyennes = resultats*.service\r
+\r
+ if (resultats.size() == 0) {\r
+ epreuveInfos*.matieres = []\r
+ epreuveInfos*.services = []\r
+ return\r
+ }\r
+\r
+ Map resultatsParMatiere = resultats.groupBy {it.service.matiere}\r
+\r
+ Map moyenneParMatiere = [:]\r
+\r
+ // Calcule les moyennes des matères. Si une matières correspond à plusieurs services,\r
+ // on calcule la moyenne des moyennes des services pondérée par les coeffs\r
+ // des services pour la période donnée .\r
+ resultatsParMatiere.each {Matiere matiere, List<ResultatEleveServicePeriode> ress ->\r
+ BigDecimal moyenne = ress.size() == 1 ? \r
+ ress.first().moyenne : internalCalculeMoyenneResultats(ress, periode)\r
+\r
+ moyenneParMatiere.put(matiere, moyenne)\r
+ }\r
+\r
+ epreuveInfos.each {EpreuveInfo epreuveInfo ->\r
+ Map moyenneParMatierePourEpreuve =\r
+ (Map) moyenneParMatiere.findAll {Matiere matiere, BigDecimal moyenne ->\r
+ epreuveInfo.matieres*.id.contains(matiere.id)\r
+ }\r
+\r
+ if (moyenneParMatierePourEpreuve.size() == 0) {\r
+ epreuveInfo.matieres = []\r
+ epreuveInfo.services = []\r
+ return\r
+ }\r
+\r
+ switch (epreuveInfo.epreuve.modeCalculNote) {\r
+ case BrevetModeCalculNote.PREMIERE_TROUVEE :\r
+ List<Matiere> matieres = moyenneParMatierePourEpreuve.keySet().toList()\r
+ matieres.sort{m1,m2 -> mapMatiereIdOrdre.get(m1.id) <=> mapMatiereIdOrdre.get(m2.id)}\r
+ Matiere matiere = (Matiere) matieres.first()\r
+ epreuveInfo.moyenne = (BigDecimal) moyenneParMatierePourEpreuve.get(matiere)\r
+ epreuveInfo.matieres = [matiere]\r
+ break\r
+\r
+ case BrevetModeCalculNote.MOYENNE :\r
+ List<BigDecimal> moyennes = (List<BigDecimal>) moyenneParMatierePourEpreuve.values().toList()\r
+ epreuveInfo.moyenne = calculationService.calculeMoyenne(moyennes, true)?.valeurNumerique\r
+ epreuveInfo.matieres = moyenneParMatierePourEpreuve.keySet().toList()\r
+ break\r
+\r
+ case BrevetModeCalculNote.MOYENNE_SPORT :\r
+ Service serviceSport = findServiceSport(periode.classe)\r
+ epreuveInfo.moyenne = calculeMoyenneSport(serviceSport, eleve)\r
+ epreuveInfo.matieres = serviceSport ? [serviceSport.matiere] : []\r
+ break\r
+\r
+ default: \r
+ throw new IllegalStateException(\r
+ "Le mode de calcul de note ${epreuveInfo.epreuve.modeCalculNote} " +\r
+ "pour l'épreuve ${epreuveInfo.epreuve} n'est pris en compte")\r
+ }\r
+\r
+ epreuveInfo.services = (List) serviceAvecMoyennes.findAll {\r
+ epreuveInfo.matieres.contains(it.matiere)\r
+ }\r
+ }\r
+ }\r
+\r
+ private Map<Long, Integer> getMapMatiereIdOrdre(List<Service> services, Periode periode) {\r
+ services = notesServiceService.trieServices(services, periode)\r
+\r
+ Map<Service, Integer> mapServiceOrdre = [:]\r
+\r
+ services.eachWithIndex {Service service, Integer ordre ->\r
+ mapServiceOrdre.put(service, ordre)\r
+ }\r
+\r
+ Map<Long, Integer> mapMatiereIdOrdre = [:]\r
+\r
+ services.groupBy{it.matiere}.each{Matiere matiere, List<Service> servicesMatiere ->\r
+ List<Integer> ordres = servicesMatiere.collect{mapServiceOrdre.get(it)}\r
+ mapMatiereIdOrdre.put(matiere.id, ordres.min())\r
+ }\r
+\r
+ return mapMatiereIdOrdre\r
+ }\r
+\r
+ private findServiceSport(StructureEnseignement classe) {\r
+ return Service.findByStructureEnseignementAndChoisiPourSport(classe, true)\r
+ }\r
+\r
+ private BigDecimal calculeMoyenneSport(Service serviceSport, Personne eleve) {\r
+\r
+ if (!serviceSport) {\r
+ return null\r
+ }\r
+\r
+ List<Note> notes = Note.createCriteria().listDistinct {\r
+ eq('eleve', eleve.autorite)\r
+ evaluation {\r
+ enseignement {\r
+ eq('service', serviceSport)\r
+ }\r
+ periodes {\r
+ typePeriode {\r
+ eq('nature', NaturePeriode.NOTATION)\r
+ }\r
+ }\r
+ }\r
+\r
+ eq('choisiePourSport', true)\r
+ }\r
+\r
+ if (notes.size() < 3) {\r
+ return null\r
+ }\r
+\r
+ if (notes.size() > 3) {\r
+ throw new IllegalStateException(\r
+ "L'élève $eleve a plus de 3 notes sélectionnées sport dans le service $serviceSport")\r
+ }\r
+\r
+ return calculationService.calculeMoyenne(notes*.valeurSur20, true)?.valeurNumerique\r
+ }\r
+\r
+ /**\r
+ * Moyenne ponderee des resultats\r
+ * @author msan\r
+ */\r
+ BigDecimal internalCalculeMoyenneResultats(List<ResultatEleveServicePeriode> resultats,\r
+ Periode periode) {\r
+ // calcule la moyenne ponderee\r
+ List<NoteInfo> noteInfos = resultats.collect {\r
+ new NoteInfo(\r
+ it.getObjetMoyenne(),\r
+ it.service.getCoeffPourPeriode(periode),\r
+ false)\r
+ }\r
+ return calculationService.calculeMoyennePonderee(noteInfos, true)?.valeurNumerique\r
+ }\r
+\r
+ /**\r
+ * Ajoute la correspondence entre les epreuves et les services dans epreuve info\r
+ * @author msan\r
+ * @author bper\r
+ */\r
+ void internalAjouteInfoServices(SecuriteSession securiteSession,\r
+ List<EpreuveInfo> epreuveInfos,\r
+ Personne eleve,\r
+ Periode periode) {\r
+\r
+ List<Matiere> matieres = epreuveInfos*.matieres.flatten().toList()\r
+\r
+ // get services\r
+ List<Service> services = notesServiceService.\r
+ internalFindAllServiceByElevePeriodeMatieres( \r
+ securiteSession,\r
+ eleve,\r
+ periode,\r
+ matieres\r
+ )\r
+\r
+ // Affecte les services en fonction des matières affectées\r
+ services.each {Service service ->\r
+ epreuveInfos.each {EpreuveInfo epreuveInfo ->\r
+ if (epreuveInfo.matieres*.id.contains(service.matiere.id)) {\r
+ epreuveInfo.services.add(service)\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Actualise note si necessaire et met la dans la liste noteActualisees.\r
+ * S'il existe déjà une valeur textuelle saisie pour une note de brevet\r
+ * la valeur numérique de cette note n'est pas mise à jour.\r
+ * @author msan\r
+ */\r
+ private List<BrevetNoteInfo> internalActualiseNote(BigDecimal note,\r
+ String appreciation,\r
+ BrevetNote brevetNote) {\r
+\r
+ List<BrevetNoteInfo> notesActualises = []\r
+\r
+ // si la moyenne ou l'appr existe, ajoute la note\r
+ // dans la liste des resultats envoyes\r
+ if (note != null || appreciation != null ||\r
+ (brevetNote.epreuve.isSport() && brevetNote.valeur == null)) {\r
+\r
+ BrevetNoteInfo brevetNoteInfo = new BrevetNoteInfo(\r
+ noteId: brevetNote.id,\r
+ eleveId: brevetNote.fiche.eleve.id,\r
+ epreuveId: brevetNote.epreuve.id,\r
+ isSport: brevetNote.epreuve.isSport()\r
+ )\r
+\r
+ if (brevetNote.valeurTextuelle == null && note != null) {\r
+ brevetNoteInfo.valeurNumerique = note\r
+ brevetNoteInfo.noteValeur = BrevetNote.NOTE_FORMATEUR.format(note)\r
+ }\r
+\r
+ // Cas particulier de l'épreuve de Sport (EPS) :\r
+ // La note textuelle "DI" pour cette épreuve peut etre remplacée par\r
+ // la note numérique. Si la note numérique est null on lui affecte\r
+ // la note textuelle "DI" comme valeur par défaut.\r
+ if (brevetNote.epreuve.isSport()) {\r
+ if (brevetNote.valeurTextuelle == null ||\r
+ brevetNote.valeurTextuelle.valeur == NoteTextuellesEnum.DI.toString()) {\r
+\r
+ if (note == null) {\r
+ brevetNoteInfo.valeurNumerique = null\r
+ brevetNoteInfo.noteValeur = NoteTextuellesEnum.DI\r
+ }\r
+ else {\r
+ brevetNoteInfo.valeurNumerique = note\r
+ brevetNoteInfo.noteValeur = BrevetNote.NOTE_FORMATEUR.format(note)\r
+ }\r
+ }\r
+ }\r
+\r
+ if (appreciation != null) {\r
+ brevetNoteInfo.appreciation = coupeAppreciation(appreciation)\r
+ }\r
+\r
+ notesActualises.add(brevetNoteInfo)\r
+ }\r
+\r
+ return notesActualises\r
+ }\r
+\r
+ /**\r
+ * Coupe une appreciation a la taille de 255 characteres\r
+ * @author msan\r
+ */\r
+ String coupeAppreciation(String appreciation) {\r
+ return appreciation.length()>255 ? appreciation.substring(0, 255) : appreciation\r
+ }\r
+\r
+ /**\r
+ * Une map des periodes annees, indexee par les classes\r
+ * @author msan\r
+ */\r
+ Map<StructureEnseignement, Periode> internalFindAllPeriodeAnneeByClasses(List<StructureEnseignement> classes) {\r
+ Map classesPeriodes = [:]\r
+ List<Periode> periodesAnnees = notesPeriodeService.\r
+ internalFindAllPeriodeByClasses(\r
+ classes,\r
+ IntervalleEnum.ANNEE\r
+ )\r
+ periodesAnnees.each { Periode periodeAnnee ->\r
+ classesPeriodes.put(periodeAnnee.classe, periodeAnnee)\r
+ }\r
+ return classesPeriodes\r
+ }\r
+\r
+ /**\r
+ * Cherche les matieres correspondant a une epreuve pour un eleve donne\r
+ * @author msan\r
+ * @author bper\r
+ */\r
+ List<EpreuveInfo> internalChercheMatieres(SecuriteSession securiteSession,\r
+ List<BrevetEpreuve> epreuves,\r
+ Personne eleve,\r
+ Etablissement etablissement,\r
+ List<BrevetRelEpreuveMatiere> relFixes,\r
+ List<BrevetNote> notes,\r
+ Periode periodeAnnee,\r
+ Boolean initialisation) {\r
+ List<EpreuveInfo> epreuveInfos = []\r
+ notes.each { BrevetNote note ->\r
+ List<Matiere> matieres = internalChercheMatiere(\r
+ securiteSession,\r
+ note.epreuve,\r
+ eleve,\r
+ etablissement,\r
+ relFixes,\r
+ note,\r
+ periodeAnnee,\r
+ initialisation\r
+ )\r
+ epreuveInfos.add(new EpreuveInfo(\r
+ epreuve: note.epreuve,\r
+ matieres: matieres\r
+ ))\r
+ }\r
+ return epreuveInfos\r
+ }\r
+\r
+ /**\r
+ * Cherche le matiere correspondant a une epreuve pour un eleve donne\r
+ * @author msan\r
+ * @author bper\r
+ */\r
+ private List<Matiere> internalChercheMatiere(SecuriteSession securiteSession,\r
+ BrevetEpreuve epreuve,\r
+ Personne eleve,\r
+ Etablissement etablissement,\r
+ List<BrevetRelEpreuveMatiere> relFixes,\r
+ BrevetNote note,\r
+ Periode periodeAnnee,\r
+ Boolean initialisation) {\r
+ List<Matiere> matieres = null\r
+\r
+ if (epreuve.personnalisable) {\r
+ // epreuve personalisable - impactee par les options d'eleve\r
+\r
+ if (isMatiereAinitialiser(initialisation, note.matiere)) {\r
+ internalInitialiseMatiere(\r
+ securiteSession,\r
+ eleve,\r
+ periodeAnnee,\r
+ relFixes,\r
+ note)\r
+ }\r
+ matieres = [note.matiere]\r
+ } else {\r
+ // epreuve avec les matieres fixes\r
+ matieres = relFixes.findAll {\r
+ it.epreuve.id == epreuve.id &&\r
+ it.matiere.etablissement.id == etablissement.id\r
+ }?.collect { it.matiere }\r
+ }\r
+\r
+ // traitement HiGeo - EduCivique.\r
+ // si EduCivique n'est pas liee au matiere, on prend le rsultat de HiGeo\r
+ if (epreuve.epreuveMatieresAHeriter != null &&\r
+ (matieres == null || matieres.size()==0)) {\r
+ matieres = relFixes.findAll {\r
+ it.epreuve.id == epreuve.epreuveMatieresAHeriter.id &&\r
+ it.matiere.etablissement.id == etablissement.id\r
+ }?.collect { it.matiere }\r
+ }\r
+\r
+ return matieres\r
+ }\r
+\r
+ /**\r
+ * Initialise la matiere de BrevetNote par la premiere matiere ou on trouve\r
+ * une note pour l'eleve donne\r
+ * @author msan\r
+ */\r
+ void internalInitialiseMatiere(SecuriteSession securiteSession,\r
+ Personne eleve,\r
+ Periode periodeAnnee,\r
+ List<BrevetRelEpreuveMatiere> relFixes,\r
+ BrevetNote note) {\r
+ // Spec: Si une épreuve de type « LV1 ou LV2 ou Opt. facultative » (== personalisable)\r
+ // est liée à plusieurs matières, le module Notes affecte à l'élève la\r
+ // première matière trouvée où l'élève a une note.\r
+ note.matiere = internalFindPremiereMatiereAvecNote(\r
+ securiteSession,\r
+ eleve,\r
+ periodeAnnee,\r
+ relFixes.findAll {\r
+ it.epreuve.id == note.epreuve.id\r
+ }?.collect { it.matiere }\r
+ )\r
+ if (log.isDebugEnabled()) {\r
+ log.debug("BrevetNote "+note.id+" initialisee avec matiere "+note.matiere)\r
+ }\r
+ }\r
+\r
+ /**\r
+ * S'il faut initialiser la matiere\r
+ * @author msan\r
+ */\r
+ Boolean isMatiereAinitialiser(boolean initialisation, Matiere matiere) {\r
+ return (initialisation && matiere == null)\r
+ }\r
+\r
+ /**\r
+ * Cherche une matiere qui est note pour l'eleve donne\r
+ * @author msan\r
+ */\r
+ Matiere internalFindPremiereMatiereAvecNote(SecuriteSession securiteSession,\r
+ Personne eleve,\r
+ Periode periodeAnnee,\r
+ List<Matiere> matieres) {\r
+\r
+ // si note.matiere n'est pas saisie il faut chercher les resultats d'eleve\r
+ // pour les matieres fixes de cette epreuve et prendre la matiere ou l'eleve\r
+ // a une note + positionner la matiere de note\r
+\r
+ List<Service> services = notesServiceService.\r
+ internalFindAllServiceByElevePeriodeMatieres(\r
+ securiteSession,\r
+ eleve,\r
+ periodeAnnee,\r
+ matieres)\r
+\r
+ List<ResultatEleveServicePeriode> resultats = resultatEleveServicePeriodeService.\r
+ internalFindAll(\r
+ [eleve.autorite],\r
+ services,\r
+ [periodeAnnee],\r
+ [NaturePeriode.NOTATION]\r
+ )\r
+\r
+ resultats = (List) resultats.findAll {it.moyenne != null}\r
+\r
+ if (resultats?.size()>0) {\r
+ return resultats.first().service.matiere\r
+ } else {\r
+ return null\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Recupere BrevetNotes avec les valeurs actualisees avec les resultats reels\r
+ * d'eleves.\r
+ * @author msan\r
+ */\r
+ List<BrevetNoteInfo> internalActualiseNotes(SecuriteSession securiteSession,\r
+ List<StructureEnseignement> classes,\r
+ Boolean initialisation = false) {\r
+\r
+ if (classes == null || classes.size()==0) {\r
+ return []\r
+ }\r
+\r
+ // prepare la liste des eleves\r
+ Map<Personne, StructureEnseignement> eleveMap = [:]\r
+ List elevesClasses = localStructureEnseignementService.\r
+ findAllPersonneEleveAndClasseForAllClasses(classes)\r
+\r
+ elevesClasses.each { def eleveClasse ->\r
+ Personne eleve = eleveClasse[0].personne\r
+ StructureEnseignement classe = eleveClasse[1]\r
+ eleveMap.put(eleve, classe)\r
+ }\r
+\r
+ return internalActualiseNotes(securiteSession, classes, eleveMap, initialisation)\r
+\r
+ }\r
+\r
+ /**\r
+ * Retourne le mapping personnalisée Epreuve -> Matiere.\r
+ * @author bper\r
+ */\r
+ Map<Personne,Map<BrevetEpreuve,Matiere>> internalFindAllMapEleveEpreuveMatierePourEleves(List<Personne> eleves) {\r
+\r
+ List<BrevetNote> notes = BrevetNote.withCriteria {\r
+ fiche {\r
+ 'in'('eleve',eleves)\r
+ eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())\r
+ }\r
+ isNotNull('matiere')\r
+ epreuve {\r
+ eq('personnalisable', true)\r
+ }\r
+ }\r
+\r
+ Map<Personne,Map<BrevetEpreuve,Matiere>> map = [:]\r
+\r
+ eleves.each {Personne eleve ->\r
+ Map mapEpreuveMatiere = [:]\r
+ notes.each {\r
+ if (it.fiche.eleve.id == eleve.id) {\r
+ mapEpreuveMatiere.put(it.epreuve, it.matiere)\r
+ }\r
+ }\r
+ map.put(eleve,mapEpreuveMatiere)\r
+ }\r
+\r
+ return map\r
+ }\r
+\r
+\r
+ /**\r
+ * Met à jour la les choix de matières pour les épreuves personnalisables\r
+ * pour un élève donné.\r
+ * @author bper\r
+ */\r
+ void majChoixMateiresPourEleve(SecuriteSession securiteSession,\r
+ Personne eleve,\r
+ Map<BrevetEpreuve,Matiere> mapEpreuveMatiere) {\r
+\r
+ StructureEnseignement classe =\r
+ notesStructureEnseignementService.findClasseForEleve(securiteSession,eleve)\r
+\r
+ notesDroitService.verifieAutorisationByEtablissement(\r
+ securiteSession,\r
+ classe.etablissement,\r
+ Action.MODIFICATION,\r
+ NotesFonction.DIRECTION_ASSIMILE)\r
+\r
+ List<BrevetNote> notes = BrevetNote.withCriteria {\r
+ fiche {\r
+ eq('eleve',eleve)\r
+ eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())\r
+ }\r
+ epreuve {\r
+ eq('personnalisable', true)\r
+ }\r
+ }\r
+\r
+ mapEpreuveMatiere.each {BrevetEpreuve epreuve, Matiere matiere ->\r
+ if (!epreuve.personnalisable) {\r
+ throw new IllegalArgumentException("L'épreuve $epreuve n'est pas pesronnalisable")\r
+ }\r
+\r
+ BrevetNote note = notes.find {it.epreuve.id == epreuve.id}\r
+\r
+ if (note) {\r
+ note.matiere = matiere\r
+ note.save(failOnError: true)\r
+ } else if (matiere) {\r
+ throw new IllegalArgumentException(\r
+ "Impossible d'assoceier la matière $matiere à l'épreuve $epreuve pour " +\r
+ "l L'élève $eleve. Il n'est pas inscrit pour cette épreuve."\r
+ )\r
+ }\r
+ }\r
+\r
+ sessionFactory.currentSession.flush()\r
+ }\r
+\r
+\r
+ /**\r
+ * Inscrit l'élève pour les épreuves qui ont des épreuves exclusives.\r
+ * @author bper\r
+ */\r
+ void majInscriptionEpreuveExclusives(SecuriteSession securiteSession,\r
+ Personne eleve,\r
+ List<BrevetEpreuve> epreuves) {\r
+\r
+ if (!epreuves) {\r
+ return\r
+ }\r
+\r
+ StructureEnseignement classe =\r
+ notesStructureEnseignementService.findClasseForEleve(securiteSession,eleve)\r
+\r
+ notesDroitService.verifieAutorisationByEtablissement(\r
+ securiteSession,\r
+ classe.etablissement,\r
+ Action.MODIFICATION,\r
+ NotesFonction.DIRECTION_ASSIMILE)\r
+\r
+ BrevetSerie serie = brevetSerieService.internalFindSeriePourEleve(eleve)\r
+\r
+ if (!serie.id) {\r
+ throw new IllegalArgumentException("L'élève $eleve n'est pas inscrit au Brevet")\r
+ }\r
+\r
+ BrevetFiche fiche = BrevetFiche.findByEleveAndAnneeScolaire(\r
+ eleve,\r
+ anneeScolaireService.anneeScolaireEnCours()\r
+ )\r
+\r
+ // Suppime les notes aux épreuves exclusives\r
+ List<BrevetNote> noteToDeletes = BrevetNote.withCriteria {\r
+ eq('fiche',fiche)\r
+ 'in'('epreuve',epreuves*.epreuveExclusive)\r
+ }\r
+\r
+ noteToDeletes.each {\r
+ fiche.removeFromNotes(it) \r
+ it.delete()\r
+ }\r
+ sessionFactory.currentSession.flush()\r
+\r
+ List<Long> epreuveDejaInscriteIds = (List) BrevetNote.withCriteria {\r
+ eq('fiche',fiche)\r
+ 'in'('epreuve',epreuves)\r
+ epreuve {\r
+ projections {\r
+ property('id')\r
+ }\r
+ }\r
+ }\r
+\r
+ epreuves.each {BrevetEpreuve epreuve ->\r
+ if (epreuve.serie.id != serie.id) {\r
+ throw new IllegalArgumentException(\r
+ "La série $serie de l'élève $eleve ne correspond pas à celle de l'épreuve $epreuve"\r
+ )\r
+ }\r
+\r
+ if (!epreuve.epreuveExclusive) {\r
+ throw new IllegalArgumentException("L'épreuve $eleve n'a d'épreuve exclusive")\r
+ }\r
+\r
+ if (!epreuveDejaInscriteIds.any {it == epreuve.id}) {\r
+ BrevetNote note = new BrevetNote(fiche: fiche, epreuve: epreuve)\r
+ fiche.addToNotes(note)\r
+ }\r
+ }\r
+ fiche.save(failOnError: true, flush: true)\r
+ }\r
+\r
+\r
+ /**\r
+ * Inscrit l'élève aux épreuves optionnelles passées en paramétres et\r
+ * le desinscrit des épreuves optionnelles qui ne sont pas dans la liste.\r
+ * @author bper\r
+ */\r
+ void majInscriptionEpreuveOptionnelles(SecuriteSession securiteSession,\r
+ Personne eleve,\r
+ List<BrevetEpreuve> epreuves) {\r
+ StructureEnseignement classe =\r
+ notesStructureEnseignementService.findClasseForEleve(securiteSession,eleve)\r
+\r
+ notesDroitService.verifieAutorisationByEtablissement(\r
+ securiteSession,\r
+ classe.etablissement,\r
+ Action.MODIFICATION,\r
+ NotesFonction.DIRECTION_ASSIMILE)\r
+\r
+ BrevetSerie serie = brevetSerieService.internalFindSeriePourEleve(eleve)\r
+\r
+ if (!serie.id) {\r
+ throw new IllegalArgumentException("L'élève $eleve n'est pas inscrit au Brevet")\r
+ }\r
+\r
+ BrevetFiche fiche = BrevetFiche.findByEleveAndAnneeScolaire(\r
+ eleve,\r
+ anneeScolaireService.anneeScolaireEnCours()\r
+ )\r
+\r
+ // Suppime les notes aux épreuves optionnelles qui ne sont pas dans la liste\r
+ BrevetNote.withCriteria {\r
+ eq('fiche',fiche)\r
+ epreuve {\r
+ eq('optionnelle',true)\r
+ }\r
+ if (epreuves) {\r
+ not{'in'('epreuve',epreuves)}\r
+ }\r
+ }*.delete()\r
+\r
+ List<Long> epreuveDejaInscriteIds = (List) BrevetNote.withCriteria {\r
+ eq('fiche', fiche)\r
+ if (epreuves) {\r
+ 'in'('epreuve', epreuves)\r
+ }\r
+ epreuve {\r
+ eq('optionnelle',true)\r
+ projections {\r
+ property('id')\r
+ }\r
+ }\r
+ }\r
+\r
+ epreuves.each {BrevetEpreuve epreuve ->\r
+ if (serie?.id != epreuve.serie.id) {\r
+ throw new IllegalArgumentException(\r
+ "La série $serie de l'élève $eleve ne correspond pas à celle de l'épreuve $epreuve"\r
+ )\r
+ }\r
+\r
+ if (!epreuve.optionnelle) {\r
+ throw new IllegalArgumentException("L'épreuve $eleve n'est pas une épreuve optionnelle")\r
+ }\r
+\r
+ if (!epreuveDejaInscriteIds.any {it == epreuve.id}) {\r
+ new BrevetNote(fiche: fiche, epreuve: epreuve).save(failOnError: true)\r
+ }\r
+ }\r
+ sessionFactory.currentSession.flush()\r
+ }\r
+\r
+ BrevetNote findByEleveAndEpreuve(Personne eleve,\r
+ BrevetEpreuve epreuve) {\r
+\r
+ return BrevetNote.createCriteria().get {\r
+ fiche {\r
+ eq('eleve', eleve)\r
+ eq('anneeScolaire', anneeScolaireService.anneeScolaireEnCours())\r
+ }\r
+ eq('epreuve', epreuve)\r
+ }\r
+ }\r
+ \r
+\r
+}\r