✅ 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.
310 lines
13 KiB
Java
310 lines
13 KiB
Java
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();
|
|
}
|
|
}
|
|
}
|