using EPAServeur.Context ;
using EPAServeur.Exceptions ;
using EPAServeur.IServices ;
using EPAServeur.Models.EP ;
using EPAServeur.Models.Formation ;
using IO.Swagger.DTO ;
using Microsoft.EntityFrameworkCore ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
namespace EPAServeur.Services
{
public class FormationService : IFormationService
{
#region Variables
/// <summary>
/// Accès et gestion de la base de données
/// </summary>
private readonly EpContext epContext ;
/// <summary>
/// Accès et service collaborateur
/// </summary>
private readonly ICollaborateurService collaborateurService ;
/// <summary>
/// Accès au service permettant de transformer un modèle en dto
/// </summary>
private readonly ITransformDTO transformDTO ;
/// <summary>
/// Nombre d'éléments min à afficher par page
/// </summary>
private readonly int minParPage = 5 ;
/// <summary>
/// Nom d'éléments max à affichar par page
/// </summary>
private readonly int maxParPage = 1 0 0 ;
/// <summary>
/// Nombre d'éléments à afficher par défaut par page
/// </summary>
private readonly int defaultParPage = 1 5 ;
/// <summary>
/// Numéro de page min à afficher par défaut
/// </summary>
private readonly int defaultNumPage = 1 ;
/// <summary>
/// Ordonnancement par défaut
/// </summary>
private readonly bool defaultAsc = true ;
# endregion
#region Contructeurs
/// <summary>
/// Constructeur de la classe FormationService
/// </summary>
/// <param name="_epContext"></param>
public FormationService ( EpContext _ epContext , ICollaborateurService _ collaborateurService , ITransformDTO _ transformDTO )
{
epContext = _ epContext ;
collaborateurService = _ collaborateurService ;
transformDTO = _ transformDTO ;
}
# endregion
#region Méthodes Service
/// <summary>
/// Récupérer une formation par son id de manière asynchrone
/// </summary>
/// <param name="idFormation"></param>
/// <returns></returns>
public async Task < FormationDTO > GetFormationByIdAsync ( long idFormation )
{
Formation formation = await epContext . Formation . Include ( formation = > formation . Statut )
. Include ( formation = > formation . ModeFormation )
. Include ( formation = > formation . Origine )
. Include ( formation = > formation . TypeFormation )
. Include ( formation = > formation . ParticipationsFormation )
. ThenInclude ( participation = > participation . DemandeFormation )
. ThenInclude ( demande = > demande . Ep )
. FirstOrDefaultAsync ( formation = > formation . IdFormation = = idFormation ) ;
if ( formation = = null )
throw new FormationNotFoundException ( string . Format ( "Aucune formation trouvée avec l'id suivant: {0}." , idFormation ) ) ;
if ( formation . ParticipationsFormation . Count > 0 )
{
IEnumerable < CollaborateurDTO > collaborateurDTOs = await collaborateurService . GetCollaborateurDTOsAsync ( formation . ParticipationsFormation ) ;
return transformDTO . GetFormationDTO ( formation , collaborateurDTOs ) ;
}
else
{
return transformDTO . GetFormationDTOWhitoutParticipationFormation ( formation ) ;
}
}
/// <summary>
/// Récupérer la liste des formations de manière asynchrone
/// </summary>
/// <param name="asc">Préciser si les données sont dans l'ordre (true) ou dans l'ordre inverse (false)</param>
/// <param name="numPage">Numéro de la page du tableau qui affiche les données</param>
/// <param name="parPage">Nombre d'éléments affiché sur chaque page du tableau</param>
/// <param name="idAgence">id de l'agence à laquelle sont rattachées les données à récupérer</param>
/// <param name="texte">Texte permettant d'identifier l'objet rechercher</param>
/// <param name="tri">Colonne du tableau sur lequel le tri s'effectue</param>
/// <returns></returns>
public async Task < IEnumerable < FormationDetailsDTO > > GetFormationsAsync ( long? idAgence , List < int? > idStatuts , bool? asc , int? numPage , int? parPage , string texte , string tri , DateTime ? dateDebut , DateTime ? dateFin )
{
IQueryable < Formation > query ;
IEnumerable < Formation > formations ;
IEnumerable < FormationDetailsDTO > formationDTOs ;
query = epContext . Formation
. Include ( formation = > formation . Statut )
. Include ( formation = > formation . ModeFormation )
. Include ( formation = > formation . Origine )
. Include ( formation = > formation . TypeFormation )
. Include ( formation = > formation . ParticipationsFormation ) ;
query = IdStatutsFilter ( query , idStatuts ) ;
query = IdAgenceFilter ( query , idAgence ) ;
query = IntituleFilter ( query , texte ) ;
query = DateFilter ( query , dateDebut , dateFin ) ;
query = OrderByColumn ( query , asc , tri ) ;
query = SkipAndTake ( query , parPage , numPage ) ;
formations = await query . ToListAsync ( ) ;
formationDTOs = formations . Select ( formation = > transformDTO . GetFormationDetailsDTO ( formation ) ) ;
return formationDTOs ;
}
/// <summary>
/// Récupérer le nombre total de formations de manière asynchrone
/// </summary>
/// <param name="numPage">Numéro de la page du tableau qui affiche les données</param>
/// <param name="parPage">Nombre d'éléments affiché sur chaque page du tableau</param>
/// <param name="idAgence">id de l'agence à laquelle sont rattachées les données à récupérer</param>
/// <param name="texte">Texte permettant d'identifier l'objet rechercher</param>
/// <returns></returns>
public async Task < long > GetFormationsCountAsync ( long? idAgence , List < int? > idStatuts , string texte , DateTime ? dateDebut , DateTime ? dateFin )
{
IQueryable < Formation > query ;
long count ;
query = epContext . Formation
. Include ( formation = > formation . Statut )
. Include ( formation = > formation . ModeFormation )
. Include ( formation = > formation . Origine )
. Include ( formation = > formation . TypeFormation )
. Include ( formation = > formation . ParticipationsFormation ) ;
query = IntituleFilter ( query , texte ) ;
query = IdStatutsFilter ( query , idStatuts ) ;
query = IdAgenceFilter ( query , idAgence ) ;
query = DateFilter ( query , dateDebut , dateFin ) ;
count = await query . CountAsync ( ) ;
return count ;
}
/// <summary>
/// Récupérer les modes de formation de manière asynchrone
/// </summary>
/// <returns></returns>
public async Task < IEnumerable < ModeFormationDTO > > GetModesFormationAsync ( )
{
IEnumerable < ModeFormation > modeFormations ;
IEnumerable < ModeFormationDTO > modeFormationDTOs ;
modeFormations = await epContext . ModeFormation . ToListAsync ( ) ;
modeFormationDTOs = modeFormations . Select ( modeFormation = > transformDTO . GetModeFormationDTO ( modeFormation ) ) ;
return modeFormationDTOs ;
}
/// <summary>
/// Récupérer les origines de formation de manière asynchrone
/// </summary>
/// <returns></returns>
public async Task < IEnumerable < OrigineFormationDTO > > GetOriginesFormationAsync ( )
{
IEnumerable < OrigineFormation > origineFormations ;
IEnumerable < OrigineFormationDTO > origineFormationDTOs ;
origineFormations = await epContext . OrigineFormation . ToListAsync ( ) ;
origineFormationDTOs = origineFormations . Select ( origineFormation = > transformDTO . GetOrigineFormationDTO ( origineFormation ) ) ;
return origineFormationDTOs ;
}
/// <summary>
/// Récupérer les statuts de formation de manière asynchrone
/// </summary>
/// <returns></returns>
public async Task < IEnumerable < StatutFormationDTO > > GetStatutsFormationAsync ( )
{
IEnumerable < StatutFormation > statutFormations ;
IEnumerable < StatutFormationDTO > statutFormationDTOs ;
statutFormations = await epContext . StatutFormation . ToListAsync ( ) ;
statutFormationDTOs = statutFormations . Select ( statutFormation = > transformDTO . GetStatutFormationDTO ( statutFormation ) ) ;
return statutFormationDTOs ;
}
/// <summary>
/// Récupérer les types de formation de manière asynchrone
/// </summary>
/// <returns></returns>
public async Task < IEnumerable < TypeFormationDTO > > GetTypesFormationAsync ( )
{
IEnumerable < TypeFormation > typeFormations ;
IEnumerable < TypeFormationDTO > typeFormationDTOs ;
typeFormations = await epContext . TypeFormation . ToListAsync ( ) ;
typeFormationDTOs = typeFormations . Select ( typeFormation = > transformDTO . GetTypeFormationDTO ( typeFormation ) ) ;
return typeFormationDTOs ;
}
/// <summary>
/// Ajouter une formation de manière asynchrone
/// </summary>
/// <param name="formationDTO"></param>
/// <returns></returns>
public async Task < FormationDTO > AddFormationAsync ( FormationDTO formationDTO )
{
IsFormationValide ( formationDTO ) ;
Formation formation = new Formation ( ) ;
formation = transformDTO . SetFormation ( formation , formationDTO ) ;
epContext . StatutFormation . Attach ( formation . Statut ) ;
epContext . OrigineFormation . Attach ( formation . Origine ) ;
epContext . ModeFormation . Attach ( formation . ModeFormation ) ;
epContext . TypeFormation . Attach ( formation . TypeFormation ) ;
epContext . Add ( formation ) ;
await epContext . SaveChangesAsync ( ) ;
return transformDTO . GetFormationDTOWhitoutParticipationFormation ( formation ) ;
}
/// <summary>
/// Modifier une formation de manière asynchrone
/// </summary>
/// <param name="idFormation"></param>
/// <param name="formationDTO"></param>
/// <returns></returns>
public async Task < FormationDTO > UpdateFormationAsync ( long idFormation , FormationDTO formationDTO )
{
IsFormationValide ( formationDTO ) ;
if ( ! formationDTO . Id . HasValue | | formationDTO . Id . Value ! = idFormation )
throw new FormationIncompatibleIdException ( "L'id de la formation a mettre à jour et la formation a mettre à jour sont incompatble." ) ;
Formation formation = await epContext . Formation . Include ( formation = > formation . Statut )
. Include ( formation = > formation . ModeFormation )
. Include ( formation = > formation . Origine )
. Include ( formation = > formation . TypeFormation )
. Include ( formation = > formation . ParticipationsFormation )
. ThenInclude ( participation = > participation . DemandeFormation )
. ThenInclude ( demande = > demande . Ep )
. FirstOrDefaultAsync ( formation = > formation . IdFormation = = idFormation ) ;
if ( formation = = null )
throw new FormationNotFoundException ( string . Format ( "Aucune formation trouvée avec l'id suivant: {0}." , idFormation ) ) ;
formation = transformDTO . SetFormation ( formation , formationDTO ) ;
await epContext . SaveChangesAsync ( ) ;
return transformDTO . GetFormationDTOWhitoutParticipationFormation ( formation ) ;
}
/// <summary>
/// Supprimer une formation de manière asynchrone
/// </summary>
/// <param name="idFormation"></param>
/// <returns></returns>
public async Task < FormationDTO > DeleteFormationByIdAsync ( long idFormation )
{
Formation formation = await epContext . Formation . Include ( formation = > formation . Statut )
. Include ( formation = > formation . ModeFormation )
. Include ( formation = > formation . Origine )
. Include ( formation = > formation . TypeFormation )
. Include ( formation = > formation . ParticipationsFormation )
. ThenInclude ( participation = > participation . DemandeFormation )
. ThenInclude ( demande = > demande . Ep )
. FirstOrDefaultAsync ( formation = > formation . IdFormation = = idFormation ) ;
if ( formation = = null )
throw new FormationNotFoundException ( string . Format ( "Aucune formation trouvée avec l'id suivant: {0}." , idFormation ) ) ;
epContext . Remove ( formation ) ;
await epContext . SaveChangesAsync ( ) ;
return transformDTO . GetFormationDTOWhitoutParticipationFormation ( formation ) ;
}
# endregion
#region Méthodes Privée
/// <summary>
/// Vérifier si un objet FormationDTO est valide pour ajout ou mise à jour
/// </summary>
/// <remarks> Un objet FormationDTO est valide si aucune de ses propriétés n'est à null,si la date de début de la formation est inférieur à la date de fin et si le statut, l'origine,le mode et le type sont présents dans la base de données</remarks>
/// <param name="formation"></param>
/// <returns>true si l'objet est valide, false sinon</returns>
private void IsFormationValide ( FormationDTO formation )
{
// Vérifier que la formation n'est pas null
if ( formation = = null )
throw new FormationInvalidException ( "Aucune formation n'a été reçue" ) ;
// Vérfier que la formation a bien un statut de formation
if ( formation . Statut = = null | | ! formation . Statut . Id . HasValue )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans statut de formation." ) ;
// Vérfier que la formation a bien un mode de formation
if ( formation . Mode = = null | | ! formation . Mode . Id . HasValue )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans mode de formation." ) ;
// Vérfier que la formation a bien une origine de formation
if ( formation . Origine = = null | | ! formation . Origine . Id . HasValue )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans origine de formation." ) ;
// Vérfier que la formation a bien un type de formation
if ( formation . Type = = null | | ! formation . Type . Id . HasValue )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans type de formation." ) ;
// Vérfier que la formation a bien une agence
if ( ! formation . IdAgence . HasValue | | formation . IdAgence = = 0 )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans mode de formation." ) ;
// Vérifier que la formation a bien un intitulé
if ( string . IsNullOrWhiteSpace ( formation . Intitule ) )
throw new FormationInvalidException ( "L'intitulé de la formation doit contenir au moins 1 caractère." ) ;
// Vérifier que la formation a bien un organisme
if ( string . IsNullOrWhiteSpace ( formation . Organisme ) )
throw new FormationInvalidException ( "L'organisme de la formation doit contenir au moins 1 caractère." ) ;
// Vérifier que la formation a bien une date de début
if ( ! formation . DateDebut . HasValue )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans date de début de formation." ) ;
// Vérifier que la formation a bien une date de fin
if ( ! formation . DateFin . HasValue )
throw new FormationInvalidException ( "Impossible d'enregistrer une formation sans date de fin de formation." ) ;
// Vérifier que la formation a bien une date de début inférieure à la date de fin
if ( formation . DateDebut . Value > formation . DateFin . Value )
throw new FormationInvalidException ( "La date de début de la formation est supérieure à la date de fin." ) ;
// Vérfier que le statut de la formation est présent dans la BDD
if ( ! epContext . StatutFormation . Any ( statut = > statut . IdStatutFormation = = formation . Statut . Id . Value & & statut . Libelle = = formation . Statut . Libelle ) )
throw new FormationInvalidException ( "Le statut de la formation n'existe pas." ) ;
// Vérfier que le mode de la formation est présent dans la BDD
if ( ! epContext . ModeFormation . Any ( mode = > mode . IdModeFormation = = formation . Mode . Id . Value & & mode . Libelle = = formation . Mode . Libelle ) )
throw new FormationInvalidException ( "Le mode de la formation n'existe pas." ) ;
// Vérfier que l'orgine de la formation est présente dans la BDD
if ( ! epContext . OrigineFormation . Any ( origine = > origine . IdOrigineFormation = = formation . Origine . Id . Value & & origine . Libelle = = formation . Origine . Libelle ) )
throw new FormationInvalidException ( "L'origine de la formation n'existe pas." ) ;
// Vérfier que le type de la formation est présent dans la BDD
if ( ! epContext . TypeFormation . Any ( type = > type . IdTypeFormation = = formation . Type . Id . Value & & type . Libelle = = formation . Type . Libelle ) )
throw new FormationInvalidException ( "Le type de la formation n'existe pas." ) ;
}
/// <summary>
/// Ajouter un ordonnancement croissant ou décroissant sur colonne
/// </summary>
/// <param name="query"></param>
/// <param name="idStatuts"></param>
/// <returns></returns>
private IQueryable < Formation > OrderByColumn ( IQueryable < Formation > query , bool? asc , string columnName )
{
if ( ! asc . HasValue )
asc = defaultAsc ;
if ( string . IsNullOrWhiteSpace ( columnName ) )
{
if ( asc . Value )
return query . OrderBy ( p = > p . Intitule ) ;
else
return query . OrderByDescending ( p = > p . Intitule ) ;
}
switch ( columnName . ToLower ( ) )
{
case "intitule" :
if ( asc . Value )
return query . OrderBy ( p = > p . Intitule ) ;
else
return query . OrderByDescending ( p = > p . Intitule ) ;
case "statut" :
if ( asc . Value )
return query . OrderBy ( p = > p . Statut . Libelle ) ;
else
return query . OrderByDescending ( p = > p . Statut . Libelle ) ;
case "origine" :
if ( asc . Value )
return query . OrderBy ( p = > p . Origine . Libelle ) ;
else
return query . OrderByDescending ( p = > p . Origine . Libelle ) ;
case "date" :
if ( asc . Value )
return query . OrderBy ( p = > p . DateDebut ) ;
else
return query . OrderByDescending ( p = > p . DateDebut ) ;
case "certification" :
if ( asc . Value )
return query . OrderBy ( p = > p . EstCertifiee ) ;
else
return query . OrderByDescending ( p = > p . EstCertifiee ) ;
case "participants" :
if ( asc . Value )
return query . OrderBy ( p = > p . ParticipationsFormation . Count ) ;
else
return query . OrderByDescending ( p = > p . ParticipationsFormation . Count ) ;
default :
if ( asc . Value )
return query . OrderBy ( p = > p . Intitule ) ;
else
return query . OrderByDescending ( p = > p . Intitule ) ;
}
}
/// <summary>
/// Ajouter un filtre pour récupérer les formations en fonction de plusieurs identifiants de statut de formation
/// </summary>
/// <param name="query"></param>
/// <param name="idStatuts"></param>
/// <returns></returns>
private IQueryable < Formation > IdStatutsFilter ( IQueryable < Formation > query , List < int? > idStatuts )
{
if ( idStatuts ! = null & & idStatuts . Count > 0 & & idStatuts . First ( ) . HasValue )
return query . Where ( formation = > idStatuts . Contains ( formation . Statut . IdStatutFormation ) ) ;
else
return query ;
}
/// <summary>
/// Ajouter un filtre pour récupérer les formations en fonction de l'identifiant d'une agence
/// </summary>
/// <param name="query"></param>
/// <param name="idAgence"></param>
/// <returns></returns>
private IQueryable < Formation > IdAgenceFilter ( IQueryable < Formation > query , long? idAgence )
{
if ( idAgence ! = null )
return query . Where ( formation = > formation . IdAgence = = idAgence ) ;
else
return query ;
}
/// <summary>
/// Ajouter un filtre pour récupérer les formations en fonction d'un intitulé
/// </summary>
/// <param name="query"></param>
/// <param name="intitule"></param>
/// <returns></returns>
private IQueryable < Formation > IntituleFilter ( IQueryable < Formation > query , string intitule )
{
if ( ! string . IsNullOrWhiteSpace ( intitule ) )
return query . Where ( formation = > formation . Intitule . ToLower ( ) . Contains ( intitule . ToLower ( ) ) ) ;
else
return query ;
}
/// <summary>
/// Ajouter un filtre pour récupérer les formations en fonction d'un intervalle de date
/// </summary>
/// <param name="query"></param>
/// <param name="dateDebut"></param>
/// <param name="dateFin"></param>
/// <returns></returns>
private IQueryable < Formation > DateFilter ( IQueryable < Formation > query , DateTime ? dateDebut , DateTime ? dateFin )
{
if ( dateDebut . HasValue & & dateFin . HasValue )
return query . Where ( formation = > formation . DateDebut > = dateDebut . Value & & formation . DateFin < = dateFin . Value . AddDays ( 1 ) ) ;
else if ( ! dateDebut . HasValue & & dateFin . HasValue )
return query . Where ( formation = > formation . DateFin < = dateFin . Value . AddDays ( 1 ) ) ;
else if ( dateDebut . HasValue & & ! dateFin . HasValue )
return query . Where ( formation = > formation . DateDebut > = dateDebut . Value ) ;
else
return query ;
}
/// <summary>
/// Ajouter une pagination
/// </summary>
/// <param name="query"></param>
/// <param name="parPage"></param>
/// <param name="numPage"></param>
/// <returns></returns>
private IQueryable < Formation > SkipAndTake ( IQueryable < Formation > query , int? parPage , int? numPage )
{
int skip , take ;
if ( ! parPage . HasValue | | parPage . Value < minParPage | | parPage . Value > maxParPage )
parPage = defaultParPage ;
if ( ! numPage . HasValue | | numPage . Value < = 0 )
numPage = defaultNumPage ;
skip = ( numPage . Value - 1 ) * parPage . Value ;
take = parPage . Value ;
return query . Skip ( skip ) . Take ( take ) ;
}
# endregion
}
}