using EPAServeur.Context; using EPAServeur.Exceptions; using EPAServeur.IServices; using EPAServeur.Models.EP; using IO.Swagger.DTO; using IO.Swagger.Enum; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace EPAServeur.Services { public class EngagementService : IEngagementService { #region Variables /// /// Accès et gestion de la base de données /// private readonly EpContext epContext; /// /// Accès et service collaborateur /// private readonly ICollaborateurService collaborateurService; /// /// Nombre d'éléments min à afficher par page /// private readonly int minParPage = 5; /// /// Nom d'éléments max à affichar par page /// private readonly int maxParPage = 100; /// /// Nombre d'éléments à afficher par défaut par page /// private readonly int defaultParPage = 15; /// /// Numéro de page min à afficher par défaut /// private readonly int defaultNumPage = 1; /// /// Ordonnancement par défaut /// private readonly bool defaultAsc = true; #endregion #region Contructeurs /// /// Constructeur de la classe EngagementService /// /// public EngagementService(EpContext _epContext, ICollaborateurService _collaborateurService) { epContext = _epContext; collaborateurService = _collaborateurService; } #endregion #region Méthodes Service /// /// Récupérer la liste des engagements de manière asynchrone /// /// /// /// /// /// /// /// /// public async Task> GetEngagementsAsync(List idBUs, List etatsEngagement, bool? asc, int? numPage, int? parPage, string texte, string tri) { IQueryable query; IEnumerable engagements; IEnumerable engagementDTOs; IEnumerable collaborateurDTOs; query = epContext.Engagement.Include(engagement => engagement.Ep); query = IdBUsFilter(query, idBUs); query = EtatsEngagementFilter(query, etatsEngagement); query = ActionFilter(query, texte); query = OrderByColumn(query, asc, tri); query = SkipAndTake(query, parPage, numPage); engagements = await query.ToListAsync(); collaborateurDTOs = await GetCollaborateurDTOs(engagements); engagementDTOs = engagements.Select(engagement => GetEngagementDTO(engagement, collaborateurDTOs)); return engagementDTOs; } public async Task GetEngagementsCountAsync(List idBUs, List etatsEngagement, bool? asc, int? numPage, int? parPage, string texte, string tri) { IQueryable query; long count; query = epContext.Engagement.Include(engagement => engagement.Ep); query = IdBUsFilter(query, idBUs); query = EtatsEngagementFilter(query, etatsEngagement); query = ActionFilter(query, texte); query = OrderByColumn(query, asc, tri); query = SkipAndTake(query, parPage, numPage); count = await query.CountAsync(); return count; } /// /// Donner une réponse à un engagement de manière asynchrone /// /// /// /// public async Task RepondreEngagementAsync(EngagementDTO engagementDTO, long idEngagement) { IEnumerable collaborateurDTOs; Engagement engagement; IsEngagementValide(engagementDTO); if (!engagementDTO.Id.HasValue || engagementDTO.Id.Value != idEngagement) throw new EngagementIncompatibleIdException("L'id de l'engagement à mettre à jour et l'engagement à mettre à jour sont incompatible."); engagement = await epContext.Engagement.Include(engagement => engagement.Ep).FirstOrDefaultAsync(engagement => engagement.IdEngagement == idEngagement); if (engagement == null) throw new EngagementNotFoundException(); collaborateurDTOs = await GetCollaborateurDTOs(engagement); engagement = SetReponseEngagement(engagement, engagementDTO); await epContext.SaveChangesAsync(); return GetEngagementDTO(engagement, collaborateurDTOs); } #endregion #region Méthodes Privée /// /// Vérifier si un objet EngagementDTO est valide pour ajout ou mise à jour /// /// Un objet EngagementDTO est valide si l'action, le dispositif, la modalité et la date limite n'est pas null, si l'EP est signé, et si l'EP est présent dans la base de données. /// /// private void IsEngagementValide(EngagementDTO engagementDTO) { // Vérifier que l'engagement n'est pas null if (engagementDTO == null) throw new EngagementInvalidException("Aucun engagement n'a été reçu."); // Vérfier que l'engagement a bien un EP if (engagementDTO.Ep == null || !engagementDTO.Ep.Id.HasValue) throw new EngagementInvalidException("Impossible de répondre à un engagement sans EP."); // Vérfier que l'ep a bien été signé par le collaborateur if (engagementDTO.Ep.Statut != StatutEp.Signe) throw new EngagementInvalidException("Impossible de répondre à un engagement d'un EP qui n'est pas en cours et qui n'a pas été signé par le collaborateur."); // Vérifier que l'engagement a bien une action if (string.IsNullOrWhiteSpace(engagementDTO.Action)) throw new EngagementInvalidException("L'action de l'engagement doit contenir au moins 1 caractère."); // Vérifier que l'engagement a bien un dispositif if (string.IsNullOrWhiteSpace(engagementDTO.Dispositif)) throw new EngagementInvalidException("Le dispostif de l'engagement doit contenir au moins 1 caractère."); // Vérifier que l'engagement a bien une modalité if (string.IsNullOrWhiteSpace(engagementDTO.Modalite)) throw new EngagementInvalidException("La modalité de l'engagement doit contenir au moins 1 caractère."); // Vérifier que l'engagement a bien une date limite if (!engagementDTO.DateLimite.HasValue) throw new EngagementInvalidException("Impossible de répondre à l'engagement sans date limite."); // Vérifier que l'engagement a bien raison expliquant pourquoi l'engagement n'est pas réalisable lorsque l'état de l'engagement n'est pas réalisable if (engagementDTO.EtatEngagement == EtatEngagement.NonRealisable && string.IsNullOrWhiteSpace(engagementDTO.RaisonNonRealisable)) throw new EngagementInvalidException("Impossible de répondre à l'engagement, une raison doit être rensignée lorsqu'un engagement n'est pas réalisé."); // Vérfier que l'EP lié à l'engagement est présent dans la BDD if (!epContext.Ep.Any(ep => ep.IdEP == engagementDTO.Ep.Id.Value)) throw new EngagementInvalidException("L'EP n'existe pas."); } /// /// Ajouter un ordonnancement croissant ou décroissant sur colonne /// /// /// /// private IQueryable OrderByColumn(IQueryable query, bool? asc, string columnName) { if (!asc.HasValue) asc = defaultAsc; if (string.IsNullOrWhiteSpace(columnName)) { if (asc.Value) return query.OrderBy(p => p.Action); return query.OrderByDescending(p => p.Action); } switch (columnName.ToLower()) { case "action": if (asc.Value) return query.OrderBy(p => p.Action); return query.OrderByDescending(p => p.Action); case "dispositif": if (asc.Value) return query.OrderBy(p => p.Dispositif); return query.OrderByDescending(p => p.Dispositif); case "modalite": if (asc.Value) return query.OrderBy(p => p.Modalite); return query.OrderByDescending(p => p.Modalite); case "date": if (asc.Value) return query.OrderBy(p => p.DateLimite); return query.OrderByDescending(p => p.DateLimite); default: if (asc.Value) return query.OrderBy(p => p.Action); return query.OrderByDescending(p => p.Action); } } /// /// Ajouter un filtre pour récupérer les engagements en fonction de plusieurs identifiants de Business Unit /// /// /// /// /// private IQueryable IdBUsFilter(IQueryable query, List idBUs) { if (idBUs == null || idBUs.Count == 0) throw new EngagementInvalidException("Aucune Business Unit n'a été reçu."); return query.Where(engagement => idBUs.Contains(engagement.Ep.IdBu)); } /// /// Ajouter un filtre pour récupérer les engagements en fonction de plusieurs états d'engagement /// /// /// /// private IQueryable EtatsEngagementFilter(IQueryable query, List etatsEngagement) { if (etatsEngagement == null || etatsEngagement.Count <= 0) return query; return query.Where(engagement => etatsEngagement.Contains(engagement.EtatEngagement)); } /// /// Ajouter un filtre pour récupérer les engagements en fonction d'une action /// /// /// /// private IQueryable ActionFilter(IQueryable query, string action) { if (string.IsNullOrWhiteSpace(action)) return query; return query.Where(engagement => engagement.Action.ToLower().Contains(action.ToLower())); } /// /// Ajouter une pagination /// /// /// /// /// private IQueryable SkipAndTake(IQueryable 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); } #region Object to DTO /// /// Récupère un objet EngagementDTO en fonction d'un objet Engagement et d'une liste de CollaborateurDTO /// /// /// private EngagementDTO GetEngagementDTO(Engagement engagement, IEnumerable collaborateurDTOs) { EngagementDTO engagementDTO = new EngagementDTO() { Id = engagement.IdEngagement, Action = engagement.Action, DateLimite = engagement.DateLimite, Dispositif = engagement.Dispositif, Modalite = engagement.Modalite, RaisonNonRealisable = engagement.RaisonNonRealisable, EtatEngagement = engagement.EtatEngagement, Ep = GetEpInformationDTO(engagement.Ep, collaborateurDTOs) }; return engagementDTO; } /// /// Récuperer une liste de CollaborateurDTO contenant les collaborateurs et les référents. Retourne null si l'engagement est null. /// /// /// private async Task> GetCollaborateurDTOs(Engagement engagement) { List guids = new List(); guids.Add((Guid?)engagement.Ep.IdCollaborateur); guids.Add(engagement.Ep.IdReferent); return await collaborateurService.GetCollaborateurDTOsAsync(guids); ; } /// /// Récuperer une liste de CollaborateurDTO contenant les collaborateurs et les référents. Retourne null s'il n'y a aucun engagement. /// /// /// private async Task> GetCollaborateurDTOs(IEnumerable engagements) { if (!engagements.Any()) return null; List guids = engagements.SelectMany(engagement => new[] { (Guid?)engagement.Ep.IdCollaborateur, engagement.Ep.IdReferent }).ToList(); return await collaborateurService.GetCollaborateurDTOsAsync(guids); } /// /// Récupère un objet EpInformationDTO en fonction d'un objet Ep et d'une liste de CollaborateurDTO /// /// /// private EpInformationDTO GetEpInformationDTO(Ep ep, IEnumerable collaborateurDTOs) { CollaborateurDTO collaborateur; CollaborateurDTO referent; collaborateur = collaborateurDTOs.FirstOrDefault(collaborateurDTO => collaborateurDTO.Id == ep.IdCollaborateur); referent = collaborateurDTOs.FirstOrDefault(collaborateurDTO => collaborateurDTO.Id == ep.IdReferent); EpInformationDTO epInformationDTO = new EpInformationDTO() { Id = ep.IdEP, Type = ep.TypeEP, Statut = ep.Statut, DateDisponibilite = ep.DateDisponibilite, DatePrevisionnelle = ep.DatePrevisionnelle, Obligatoire = ep.Obligatoire, Collaborateur = collaborateur, Referent = referent, }; return epInformationDTO; } #endregion #region DTO to Object /// /// Modifie la réponse d'un objet Engagement en fonction d'un objet EngagementDTO /// /// /// /// private Engagement SetReponseEngagement(Engagement engagement, EngagementDTO engagementDTO) { engagement.EtatEngagement = engagementDTO.EtatEngagement; switch (engagement.EtatEngagement) { case EtatEngagement.NonRealisable: engagement.RaisonNonRealisable = engagementDTO.RaisonNonRealisable; break; case EtatEngagement.DateLimitePassee: engagement.RaisonNonRealisable = "La date limite pour respecter l'engagement est passée."; break; default: engagement.RaisonNonRealisable = null; break; } return engagement; } #endregion #endregion } }