PHASE 2 - Développement complet des fonctionnalités Client et Coach
✅ NOUVELLES FONCTIONNALITÉS MAJEURES AJOUTÉES : 🔧 SERVICES ET INTERFACES : - ClientService interface avec toutes les opérations CRUD - CoachService interface avec toutes les opérations CRUD - ClientServiceImpl avec simulation complète - CoachServiceImpl avec simulation complète 📊 DTOs COMPLETS : - ClientDTO, CreateClientDTO, UpdateClientDTO - CoachDTO, CreateCoachDTO, UpdateCoachDTO - PagedResponseDTO générique pour pagination 🌐 REST CONTROLLERS : - ClientResource avec endpoints CRUD complets - CoachResource avec endpoints CRUD complets - Sécurité basée sur les rôles (@RolesAllowed) - Documentation OpenAPI complète 🧪 TESTS UNITAIRES EXHAUSTIFS : - PasswordServiceTest (25 tests) - EmailServiceSimpleTest (20 tests) - BaseEntityTest (15 tests) - ClientEntityTest (20 tests) - CoachEntityTest (25 tests) 🎯 FONCTIONNALITÉS MÉTIER : - Gestion complète du cycle de vie des clients - Conversion prospect → client - Gestion des coaches avec disponibilités - Système de notation des coaches - Filtrage et recherche avancée - Pagination et tri 📈 COUVERTURE DE TESTS : - 105+ nouveaux tests unitaires créés - Couverture fonctionnelle complète des services - Tests d'entités avec validation complète - Tests de performance inclus 🔒 SÉCURITÉ ET VALIDATION : - Validation Jakarta sur tous les DTOs - Gestion d'erreurs robuste avec GBCMException - Logging SLF4J détaillé - Mode simulation pour développement Cette phase ajoute les fonctionnalités core de gestion des clients et coaches, établissant une base solide pour l'application GBCM complète.
This commit is contained in:
309
src/main/java/com/gbcm/server/impl/resource/ClientResource.java
Normal file
309
src/main/java/com/gbcm/server/impl/resource/ClientResource.java
Normal file
@@ -0,0 +1,309 @@
|
||||
package com.gbcm.server.impl.resource;
|
||||
|
||||
import com.gbcm.server.api.dto.client.ClientDTO;
|
||||
import com.gbcm.server.api.dto.client.CreateClientDTO;
|
||||
import com.gbcm.server.api.dto.client.UpdateClientDTO;
|
||||
import com.gbcm.server.api.dto.common.PagedResponseDTO;
|
||||
import com.gbcm.server.api.enums.ServiceType;
|
||||
import com.gbcm.server.api.exception.GBCMException;
|
||||
import com.gbcm.server.api.service.ClientService;
|
||||
import com.gbcm.server.impl.entity.Client.ClientStatus;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Content;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Contrôleur REST pour la gestion des clients de la plateforme GBCM.
|
||||
* Expose tous les endpoints CRUD pour les clients avec sécurité basée sur les rôles.
|
||||
*
|
||||
* @author GBCM Development Team
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
@Path("/api/clients")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Tag(name = "Clients", description = "Gestion des clients GBCM")
|
||||
public class ClientResource {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClientResource.class);
|
||||
|
||||
@Inject
|
||||
ClientService clientService;
|
||||
|
||||
/**
|
||||
* Endpoint pour récupérer la liste paginée des clients.
|
||||
*
|
||||
* @param page numéro de page (commence à 0)
|
||||
* @param size taille de page
|
||||
* @param sort critères de tri
|
||||
* @param status filtre par statut
|
||||
* @param industry filtre par secteur d'activité
|
||||
* @param search terme de recherche
|
||||
* @return liste paginée des clients
|
||||
*/
|
||||
@GET
|
||||
@RolesAllowed({"ADMIN", "MANAGER", "COACH"})
|
||||
@Operation(
|
||||
summary = "Liste des clients",
|
||||
description = "Récupère la liste paginée des clients avec filtres optionnels"
|
||||
)
|
||||
@APIResponses({
|
||||
@APIResponse(
|
||||
responseCode = "200",
|
||||
description = "Liste récupérée avec succès",
|
||||
content = @Content(schema = @Schema(implementation = PagedResponseDTO.class))
|
||||
),
|
||||
@APIResponse(responseCode = "401", description = "Non authentifié"),
|
||||
@APIResponse(responseCode = "403", description = "Accès refusé"),
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
public Response getClients(
|
||||
@Parameter(description = "Numéro de page (commence à 0)", example = "0")
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
|
||||
@Parameter(description = "Taille de page", example = "20")
|
||||
@QueryParam("size") @DefaultValue("20") int size,
|
||||
|
||||
@Parameter(description = "Tri (ex: companyName,asc ou convertedAt,desc)")
|
||||
@QueryParam("sort") String sort,
|
||||
|
||||
@Parameter(description = "Filtre par statut")
|
||||
@QueryParam("status") ClientStatus status,
|
||||
|
||||
@Parameter(description = "Filtre par secteur d'activité")
|
||||
@QueryParam("industry") String industry,
|
||||
|
||||
@Parameter(description = "Terme de recherche (nom entreprise, email)")
|
||||
@QueryParam("search") String search
|
||||
) {
|
||||
try {
|
||||
logger.info("Récupération de la liste des clients - page: {}, size: {}", page, size);
|
||||
|
||||
PagedResponseDTO<ClientDTO> clients = clientService.getClients(page, size, sort, status, industry, search);
|
||||
|
||||
logger.info("Liste des clients récupérée avec succès - {} éléments", clients.getTotalElements());
|
||||
return Response.ok(clients).build();
|
||||
|
||||
} catch (GBCMException e) {
|
||||
logger.error("Erreur GBCM lors de la récupération des clients: {}", e.getMessage());
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Erreur: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur inattendue lors de la récupération des clients: {}", e.getMessage());
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur interne du serveur")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint pour récupérer un client par son ID.
|
||||
*
|
||||
* @param id l'identifiant du client
|
||||
* @return le client trouvé
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@RolesAllowed({"ADMIN", "MANAGER", "COACH", "CLIENT"})
|
||||
@Operation(
|
||||
summary = "Récupérer un client",
|
||||
description = "Récupère un client par son identifiant"
|
||||
)
|
||||
@APIResponses({
|
||||
@APIResponse(
|
||||
responseCode = "200",
|
||||
description = "Client trouvé",
|
||||
content = @Content(schema = @Schema(implementation = ClientDTO.class))
|
||||
),
|
||||
@APIResponse(responseCode = "401", description = "Non authentifié"),
|
||||
@APIResponse(responseCode = "403", description = "Accès refusé"),
|
||||
@APIResponse(responseCode = "404", description = "Client non trouvé"),
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
public Response getClientById(
|
||||
@Parameter(description = "Identifiant du client", required = true)
|
||||
@PathParam("id") Long id
|
||||
) {
|
||||
try {
|
||||
logger.info("Récupération du client avec l'ID: {}", id);
|
||||
|
||||
ClientDTO client = clientService.getClientById(id);
|
||||
|
||||
logger.info("Client récupéré avec succès: {}", client.getCompanyName());
|
||||
return Response.ok(client).build();
|
||||
|
||||
} catch (GBCMException e) {
|
||||
logger.warn("Client non trouvé avec l'ID {}: {}", id, e.getMessage());
|
||||
return Response.status(Response.Status.NOT_FOUND)
|
||||
.entity("Client non trouvé: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur inattendue lors de la récupération du client {}: {}", id, e.getMessage());
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur interne du serveur")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint pour créer un nouveau client.
|
||||
*
|
||||
* @param createClientDTO les données du nouveau client
|
||||
* @return le client créé
|
||||
*/
|
||||
@POST
|
||||
@RolesAllowed({"ADMIN", "MANAGER"})
|
||||
@Operation(
|
||||
summary = "Créer un client",
|
||||
description = "Crée un nouveau client dans le système"
|
||||
)
|
||||
@APIResponses({
|
||||
@APIResponse(
|
||||
responseCode = "201",
|
||||
description = "Client créé avec succès",
|
||||
content = @Content(schema = @Schema(implementation = ClientDTO.class))
|
||||
),
|
||||
@APIResponse(responseCode = "400", description = "Données invalides"),
|
||||
@APIResponse(responseCode = "401", description = "Non authentifié"),
|
||||
@APIResponse(responseCode = "403", description = "Accès refusé"),
|
||||
@APIResponse(responseCode = "409", description = "Client déjà existant"),
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
public Response createClient(
|
||||
@Parameter(description = "Données du nouveau client", required = true)
|
||||
@Valid CreateClientDTO createClientDTO
|
||||
) {
|
||||
try {
|
||||
logger.info("Création d'un nouveau client: {}", createClientDTO.getCompanyName());
|
||||
|
||||
ClientDTO client = clientService.createClient(createClientDTO);
|
||||
|
||||
logger.info("Client créé avec succès avec l'ID: {}", client.getId());
|
||||
return Response.status(Response.Status.CREATED).entity(client).build();
|
||||
|
||||
} catch (GBCMException e) {
|
||||
logger.error("Erreur GBCM lors de la création du client: {}", e.getMessage());
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Erreur: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur inattendue lors de la création du client: {}", e.getMessage());
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur interne du serveur")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint pour mettre à jour un client existant.
|
||||
*
|
||||
* @param id l'identifiant du client
|
||||
* @param updateClientDTO les données de mise à jour
|
||||
* @return le client mis à jour
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
@RolesAllowed({"ADMIN", "MANAGER", "CLIENT"})
|
||||
@Operation(
|
||||
summary = "Mettre à jour un client",
|
||||
description = "Met à jour les informations d'un client existant"
|
||||
)
|
||||
@APIResponses({
|
||||
@APIResponse(
|
||||
responseCode = "200",
|
||||
description = "Client mis à jour avec succès",
|
||||
content = @Content(schema = @Schema(implementation = ClientDTO.class))
|
||||
),
|
||||
@APIResponse(responseCode = "400", description = "Données invalides"),
|
||||
@APIResponse(responseCode = "401", description = "Non authentifié"),
|
||||
@APIResponse(responseCode = "403", description = "Accès refusé"),
|
||||
@APIResponse(responseCode = "404", description = "Client non trouvé"),
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
public Response updateClient(
|
||||
@Parameter(description = "Identifiant du client", required = true)
|
||||
@PathParam("id") Long id,
|
||||
|
||||
@Parameter(description = "Données de mise à jour", required = true)
|
||||
@Valid UpdateClientDTO updateClientDTO
|
||||
) {
|
||||
try {
|
||||
logger.info("Mise à jour du client avec l'ID: {}", id);
|
||||
|
||||
ClientDTO client = clientService.updateClient(id, updateClientDTO);
|
||||
|
||||
logger.info("Client mis à jour avec succès: {}", client.getCompanyName());
|
||||
return Response.ok(client).build();
|
||||
|
||||
} catch (GBCMException e) {
|
||||
logger.error("Erreur GBCM lors de la mise à jour du client {}: {}", id, e.getMessage());
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Erreur: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur inattendue lors de la mise à jour du client {}: {}", id, e.getMessage());
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur interne du serveur")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint pour supprimer un client (soft delete).
|
||||
*
|
||||
* @param id l'identifiant du client
|
||||
* @return confirmation de suppression
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@RolesAllowed({"ADMIN"})
|
||||
@Operation(
|
||||
summary = "Supprimer un client",
|
||||
description = "Supprime un client du système (suppression logique)"
|
||||
)
|
||||
@APIResponses({
|
||||
@APIResponse(responseCode = "204", description = "Client supprimé avec succès"),
|
||||
@APIResponse(responseCode = "401", description = "Non authentifié"),
|
||||
@APIResponse(responseCode = "403", description = "Accès refusé"),
|
||||
@APIResponse(responseCode = "404", description = "Client non trouvé"),
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
public Response deleteClient(
|
||||
@Parameter(description = "Identifiant du client", required = true)
|
||||
@PathParam("id") Long id
|
||||
) {
|
||||
try {
|
||||
logger.info("Suppression du client avec l'ID: {}", id);
|
||||
|
||||
clientService.deleteClient(id);
|
||||
|
||||
logger.info("Client supprimé avec succès: {}", id);
|
||||
return Response.noContent().build();
|
||||
|
||||
} catch (GBCMException e) {
|
||||
logger.error("Erreur GBCM lors de la suppression du client {}: {}", id, e.getMessage());
|
||||
return Response.status(Response.Status.NOT_FOUND)
|
||||
.entity("Client non trouvé: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur inattendue lors de la suppression du client {}: {}", id, e.getMessage());
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur interne du serveur")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user