Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
using System.Text.Json;
|
||||
using Omika.App.Local.Models;
|
||||
using Omika.App.Local.Services;
|
||||
using Omika.Core.Contracts.Common;
|
||||
using Omika.Core.Contracts.Planning;
|
||||
|
||||
namespace Omika.Tests.Mobile.Local;
|
||||
|
||||
/// <summary>
|
||||
/// Rendez-vous de groupe : l'unité affichée est l'AFFECTATION
|
||||
/// (<c>RDV_Collaborateur</c>), jamais le noyau du rendez-vous. Une carte par
|
||||
/// collaborateur et par jour, avec la date, les heures et le collaborateur de la
|
||||
/// ligne réelle ; la fiche conserve l'affectation ouverte et expose, à titre
|
||||
/// informatif, les jours et les collaborateurs du rendez-vous.
|
||||
/// </summary>
|
||||
public class AgendaServiceAffectationTests : LocalTestBase
|
||||
{
|
||||
private static readonly DateTime Jour1 = new(2026, 8, 12);
|
||||
private static readonly DateTime Jour2 = new(2026, 8, 13);
|
||||
|
||||
private static readonly Guid CollaborateurA = Guid.Parse("11111111-1111-1111-1111-111111111111");
|
||||
private static readonly Guid CollaborateurB = Guid.Parse("22222222-2222-2222-2222-222222222222");
|
||||
|
||||
private readonly AgendaService _service;
|
||||
|
||||
public AgendaServiceAffectationTests()
|
||||
{
|
||||
_service = new AgendaService(
|
||||
RendezVousRepository,
|
||||
ClientRepository,
|
||||
SiteRepository,
|
||||
InterventionRepository,
|
||||
CollaborateurRepository,
|
||||
ApiClient,
|
||||
SessionService);
|
||||
}
|
||||
|
||||
private static AffectationCollaborateurDto Affectation(
|
||||
Guid affectationId,
|
||||
Guid collaborateurId,
|
||||
string nom,
|
||||
DateTime debut,
|
||||
DateTime fin)
|
||||
=> new()
|
||||
{
|
||||
Id = affectationId.ToString("D"),
|
||||
CollaborateurId = collaborateurId.ToString("D"),
|
||||
NomAffiche = nom,
|
||||
PeriodeDebut = debut,
|
||||
PeriodeFin = fin
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Rendez-vous groupé sur DEUX jours avec DEUX collaborateurs : quatre
|
||||
/// affectations, chacune avec son créneau.
|
||||
/// </summary>
|
||||
private async Task<(Guid RendezVousId, Guid AffectationAJour2, Guid AffectationBJour2)> PreparerGroupeAsync()
|
||||
{
|
||||
Guid rendezVousId = Guid.NewGuid();
|
||||
Guid aJour1 = Guid.NewGuid();
|
||||
Guid aJour2 = Guid.NewGuid();
|
||||
Guid bJour1 = Guid.NewGuid();
|
||||
Guid bJour2 = Guid.NewGuid();
|
||||
|
||||
var dto = new RendezVousDetailsDto
|
||||
{
|
||||
Id = rendezVousId.ToString(),
|
||||
Titre = "Chantier groupé",
|
||||
Debut = Jour1.AddHours(8),
|
||||
Fin = Jour2.AddHours(17),
|
||||
Statut = new ReferenceValueDto { Label = "Planifié" },
|
||||
EstGroupe = true,
|
||||
Collaborateurs =
|
||||
[
|
||||
Affectation(aJour1, CollaborateurA, "Alice Martin", Jour1.AddHours(8), Jour1.AddHours(12)),
|
||||
Affectation(aJour2, CollaborateurA, "Alice Martin", Jour2.AddHours(8), Jour2.AddHours(12)),
|
||||
Affectation(bJour1, CollaborateurB, "Bruno Petit", Jour1.AddHours(13), Jour1.AddHours(17)),
|
||||
Affectation(bJour2, CollaborateurB, "Bruno Petit", Jour2.AddHours(13), Jour2.AddHours(17))
|
||||
]
|
||||
};
|
||||
|
||||
await RendezVousRepository.UpsertAsync(new LocalRendezVous
|
||||
{
|
||||
Id = rendezVousId,
|
||||
PayloadJson = JsonSerializer.Serialize(dto),
|
||||
UpdatedAtUtc = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
return (rendezVousId, aJour2, bJour2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Agenda_UneCarteParAffectation_AvecLeBonCollaborateurEtLeBonCreneau()
|
||||
{
|
||||
// Arrange : aucune portée connue → toutes les affectations sont présentées.
|
||||
(Guid rendezVousId, _, _) = await PreparerGroupeAsync();
|
||||
|
||||
// Act
|
||||
IReadOnlyList<AgendaItem> result = await _service.GetRendezVousForRangeAsync(Jour1, Jour2.AddDays(1));
|
||||
|
||||
// Assert : une carte par affectation (2 collaborateurs × 2 jours).
|
||||
Assert.Equal(4, result.Count);
|
||||
|
||||
// La carte d'Alice au 2e jour porte BIEN le créneau du 2e jour (et non
|
||||
// celui du premier rendez-vous du groupe).
|
||||
AgendaItem aliceJour2 = Assert.Single(result, i =>
|
||||
i.CollaborateurNom == "Alice Martin" && i.Debut.Date == Jour2);
|
||||
Assert.Equal(Jour2.AddHours(8), aliceJour2.Debut);
|
||||
Assert.Equal(Jour2.AddHours(12), aliceJour2.Fin);
|
||||
|
||||
AgendaItem brunoJour2 = Assert.Single(result, i =>
|
||||
i.CollaborateurNom == "Bruno Petit" && i.Debut.Date == Jour2);
|
||||
Assert.Equal(Jour2.AddHours(13), brunoJour2.Debut);
|
||||
Assert.Equal(Jour2.AddHours(17), brunoJour2.Fin);
|
||||
|
||||
// Toutes les cartes se rattachent au même rendez-vous (noyau).
|
||||
Assert.All(result, item => Assert.Equal(rendezVousId, item.RendezVousGuid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Agenda_PorteeCollaborateur_NePresenteQueSesPropresCreneaux()
|
||||
{
|
||||
// Arrange : agenda personnel d'Alice (bootstrap local).
|
||||
await PreparerGroupeAsync();
|
||||
SessionService.Bootstrap = new LocalBootstrapState
|
||||
{
|
||||
Collaborateur = new Omika.Core.Contracts.Organisation.CollaborateurDetailsDto
|
||||
{
|
||||
Id = CollaborateurA.ToString("D"),
|
||||
Nom = "Martin",
|
||||
Prenom = "Alice"
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
IReadOnlyList<AgendaItem> result = await _service.GetRendezVousForRangeAsync(Jour1, Jour2.AddDays(1));
|
||||
|
||||
// Assert : uniquement les deux créneaux d'Alice (un par jour).
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.All(result, item => Assert.Equal("Alice Martin", item.CollaborateurNom));
|
||||
Assert.Equal([Jour1.AddHours(8), Jour2.AddHours(8)], result.Select(i => i.Debut).OrderBy(d => d).ToList());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fiche_AffectationPrecise_GardeLeCreneauEtLeCollaborateurDeLaCarte()
|
||||
{
|
||||
// Arrange : la fiche est ouverte depuis la carte « Bruno – 2e jour ».
|
||||
(Guid rendezVousId, _, Guid affectationBJour2) = await PreparerGroupeAsync();
|
||||
|
||||
// Act
|
||||
AgendaItem? item = await _service.GetRendezVousByIdAsync(
|
||||
rendezVousId,
|
||||
default,
|
||||
affectationBJour2.ToString("D"));
|
||||
|
||||
// Assert : créneau et collaborateur de l'affectation ouverte.
|
||||
Assert.NotNull(item);
|
||||
Assert.Equal(Jour2.AddHours(13), item!.Debut);
|
||||
Assert.Equal(Jour2.AddHours(17), item.Fin);
|
||||
Assert.Equal("Bruno Petit", item.CollaborateurNom);
|
||||
Assert.Equal(affectationBJour2.ToString("D"), item.AffectationId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fiche_Groupe_ExposeLesJoursEtTousLesCollaborateurs()
|
||||
{
|
||||
// Arrange
|
||||
(Guid rendezVousId, Guid affectationAJour2, _) = await PreparerGroupeAsync();
|
||||
|
||||
// Act
|
||||
AgendaItem? item = await _service.GetRendezVousByIdAsync(
|
||||
rendezVousId,
|
||||
default,
|
||||
affectationAJour2.ToString("D"));
|
||||
|
||||
// Assert : les deux jours du rendez-vous et les deux collaborateurs sont
|
||||
// exposés pour le bloc informatif de la fiche, avec pour chaque journée le
|
||||
// créneau réellement occupé (du premier démarrage à la dernière fin).
|
||||
Assert.NotNull(item);
|
||||
Assert.Equal([Jour1, Jour2], item!.JoursDuGroupe);
|
||||
Assert.Equal(2, item.JoursAvecHoraires.Count);
|
||||
Assert.Equal(Jour1.AddHours(8), item.JoursAvecHoraires[0].Debut);
|
||||
Assert.Equal(Jour1.AddHours(17), item.JoursAvecHoraires[0].Fin);
|
||||
Assert.Equal(Jour2.AddHours(8), item.JoursAvecHoraires[1].Debut);
|
||||
Assert.Equal(Jour2.AddHours(17), item.JoursAvecHoraires[1].Fin);
|
||||
Assert.Equal(2, item.Collaborateurs.Count);
|
||||
Assert.Contains("Alice Martin", item.Collaborateurs);
|
||||
Assert.Contains("Bruno Petit", item.Collaborateurs);
|
||||
Assert.True(item.AfficheBlocPeriode);
|
||||
|
||||
// Le collaborateur de l'affectation OUVERTE est identifié : c'est lui qui
|
||||
// sera exclu du bloc (sa propre fiche) et dont les journées sont présentées.
|
||||
Assert.Equal(CollaborateurA, item.CollaborateurOccurrenceGuid);
|
||||
|
||||
// Journées PAR collaborateur : Alice n'a que son créneau du matin, Bruno
|
||||
// celui de l'après-midi — aucun des deux n'hérite des heures de l'autre.
|
||||
Assert.Equal(2, item.JoursParCollaborateur.Count);
|
||||
JoursParCollaborateur joursAlice = Assert.Single(
|
||||
item.JoursParCollaborateur, j => j.CollaborateurGuid == CollaborateurA);
|
||||
Assert.Equal([Jour1, Jour2], joursAlice.Jours.Select(j => j.Jour).ToList());
|
||||
Assert.All(joursAlice.Jours, j =>
|
||||
{
|
||||
Assert.Equal(j.Jour.AddHours(8), j.Debut);
|
||||
Assert.Equal(j.Jour.AddHours(12), j.Fin);
|
||||
});
|
||||
|
||||
JoursParCollaborateur joursBruno = Assert.Single(
|
||||
item.JoursParCollaborateur, j => j.CollaborateurGuid == CollaborateurB);
|
||||
Assert.Equal([Jour1, Jour2], joursBruno.Jours.Select(j => j.Jour).ToList());
|
||||
Assert.All(joursBruno.Jours, j =>
|
||||
{
|
||||
Assert.Equal(j.Jour.AddHours(13), j.Debut);
|
||||
Assert.Equal(j.Jour.AddHours(17), j.Fin);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fiche_RendezVousSimple_NAffichePasLeBlocGroupe()
|
||||
{
|
||||
// Arrange : rendez-vous d'une journée, un seul collaborateur.
|
||||
Guid rendezVousId = Guid.NewGuid();
|
||||
Guid affectationId = Guid.NewGuid();
|
||||
var dto = new RendezVousDetailsDto
|
||||
{
|
||||
Id = rendezVousId.ToString(),
|
||||
Titre = "Visite",
|
||||
Debut = Jour1.AddHours(9),
|
||||
Fin = Jour1.AddHours(10),
|
||||
Collaborateurs =
|
||||
[
|
||||
Affectation(affectationId, CollaborateurA, "Alice Martin", Jour1.AddHours(9), Jour1.AddHours(10))
|
||||
]
|
||||
};
|
||||
|
||||
await RendezVousRepository.UpsertAsync(new LocalRendezVous
|
||||
{
|
||||
Id = rendezVousId,
|
||||
PayloadJson = JsonSerializer.Serialize(dto),
|
||||
UpdatedAtUtc = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
// Act
|
||||
AgendaItem? item = await _service.GetRendezVousByIdAsync(rendezVousId, default, affectationId.ToString("D"));
|
||||
|
||||
// Assert : bloc informatif masqué (un jour, un collaborateur).
|
||||
Assert.NotNull(item);
|
||||
Assert.False(item!.AfficheBlocPeriode);
|
||||
Assert.Single(item.JoursDuGroupe);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user