233 lines
10 KiB
Java
233 lines
10 KiB
Java
package dev.lions.unionflow.server.resource;
|
|
|
|
import dev.lions.unionflow.server.service.ApprovalService;
|
|
import dev.lions.unionflow.server.common.ErrorResponse;
|
|
import dev.lions.unionflow.server.api.dto.finance_workflow.request.ApproveTransactionRequest;
|
|
import dev.lions.unionflow.server.api.dto.finance_workflow.request.RejectTransactionRequest;
|
|
import dev.lions.unionflow.server.api.dto.finance_workflow.response.TransactionApprovalResponse;
|
|
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.tags.Tag;
|
|
import org.jboss.logging.Logger;
|
|
|
|
import java.time.LocalDateTime;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.UUID;
|
|
|
|
/**
|
|
* Resource REST pour la gestion des approbations de transactions
|
|
*
|
|
* @author UnionFlow Team
|
|
* @version 1.0
|
|
* @since 2026-03-13
|
|
*/
|
|
@Path("/api/finance/approvals")
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Consumes(MediaType.APPLICATION_JSON)
|
|
@Tag(name = "Finance - Approvals", description = "Gestion des approbations de transactions financières")
|
|
public class ApprovalResource {
|
|
|
|
private static final Logger LOG = Logger.getLogger(ApprovalResource.class);
|
|
|
|
@Inject
|
|
ApprovalService approvalService;
|
|
|
|
@POST
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN", "MEMBRE"})
|
|
@Operation(summary = "Demande une approbation de transaction",
|
|
description = "Crée une demande d'approbation pour une transaction financière")
|
|
public Response requestApproval(Map<String, Object> request) {
|
|
LOG.infof("POST /api/finance/approvals - Request approval");
|
|
|
|
try {
|
|
String transactionId = (String) request.get("transactionId");
|
|
String transactionType = (String) request.get("transactionType");
|
|
Number rawAmount = (Number) request.get("amount");
|
|
Double amount = rawAmount != null ? rawAmount.doubleValue() : null;
|
|
String organizationIdStr = (String) request.get("organizationId");
|
|
|
|
if (transactionId == null || transactionType == null || amount == null) {
|
|
return Response.status(Response.Status.BAD_REQUEST)
|
|
.entity(ErrorResponse.of("transactionId, transactionType et amount sont requis"))
|
|
.build();
|
|
}
|
|
|
|
UUID organizationId = organizationIdStr != null ? UUID.fromString(organizationIdStr) : null;
|
|
|
|
TransactionApprovalResponse approval = approvalService.requestApproval(
|
|
UUID.fromString(transactionId), transactionType, amount, organizationId);
|
|
return Response.status(Response.Status.CREATED).entity(approval).build();
|
|
} catch (IllegalArgumentException e) {
|
|
return Response.status(Response.Status.BAD_REQUEST)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors de la création de la demande d'approbation", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
@GET
|
|
@Path("/pending")
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
@Operation(summary = "Récupère les approbations en attente",
|
|
description = "Liste toutes les approbations de transactions en attente pour une organisation")
|
|
public Response getPendingApprovals(@QueryParam("organizationId") UUID organizationId) {
|
|
LOG.infof("GET /api/finance/approvals/pending?organizationId=%s", organizationId);
|
|
|
|
try {
|
|
List<TransactionApprovalResponse> approvals = approvalService.getPendingApprovals(organizationId);
|
|
return Response.ok(approvals).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors de la récupération des approbations en attente", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
@GET
|
|
@Path("/{approvalId}")
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
@Operation(summary = "Récupère une approbation par ID",
|
|
description = "Retourne les détails d'une approbation spécifique")
|
|
public Response getApprovalById(@PathParam("approvalId") UUID approvalId) {
|
|
LOG.infof("GET /api/finance/approvals/%s", approvalId);
|
|
|
|
try {
|
|
TransactionApprovalResponse approval = approvalService.getApprovalById(approvalId);
|
|
return Response.ok(approval).build();
|
|
} catch (NotFoundException e) {
|
|
return Response.status(Response.Status.NOT_FOUND)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors de la récupération de l'approbation", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
@POST
|
|
@Path("/{approvalId}/approve")
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
@Operation(summary = "Approuve une transaction",
|
|
description = "Approuve une demande de transaction avec un commentaire optionnel")
|
|
public Response approveTransaction(
|
|
@PathParam("approvalId") UUID approvalId,
|
|
@Valid ApproveTransactionRequest request) {
|
|
LOG.infof("POST /api/finance/approvals/%s/approve", approvalId);
|
|
|
|
try {
|
|
TransactionApprovalResponse approval = approvalService.approveTransaction(approvalId, request);
|
|
return Response.ok(approval).build();
|
|
} catch (NotFoundException e) {
|
|
return Response.status(Response.Status.NOT_FOUND)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (ForbiddenException e) {
|
|
return Response.status(Response.Status.FORBIDDEN)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors de l'approbation de la transaction", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
@POST
|
|
@Path("/{approvalId}/reject")
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
@Operation(summary = "Rejette une transaction",
|
|
description = "Rejette une demande de transaction avec une raison obligatoire")
|
|
public Response rejectTransaction(
|
|
@PathParam("approvalId") UUID approvalId,
|
|
@Valid RejectTransactionRequest request) {
|
|
LOG.infof("POST /api/finance/approvals/%s/reject", approvalId);
|
|
|
|
try {
|
|
TransactionApprovalResponse approval = approvalService.rejectTransaction(approvalId, request);
|
|
return Response.ok(approval).build();
|
|
} catch (NotFoundException e) {
|
|
return Response.status(Response.Status.NOT_FOUND)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (ForbiddenException e) {
|
|
return Response.status(Response.Status.FORBIDDEN)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors du rejet de la transaction", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
@GET
|
|
@Path("/history")
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
@Operation(summary = "Récupère l'historique des approbations",
|
|
description = "Liste l'historique des approbations avec filtres optionnels")
|
|
public Response getApprovalsHistory(
|
|
@QueryParam("organizationId") UUID organizationId,
|
|
@QueryParam("startDate") String startDateStr,
|
|
@QueryParam("endDate") String endDateStr,
|
|
@QueryParam("status") String status) {
|
|
LOG.infof("GET /api/finance/approvals/history?organizationId=%s&status=%s",
|
|
organizationId, status);
|
|
|
|
try {
|
|
LocalDateTime startDate = startDateStr != null ? LocalDateTime.parse(startDateStr) : null;
|
|
LocalDateTime endDate = endDateStr != null ? LocalDateTime.parse(endDateStr) : null;
|
|
|
|
List<TransactionApprovalResponse> approvals = approvalService.getApprovalsHistory(
|
|
organizationId, startDate, endDate, status);
|
|
|
|
return Response.ok(approvals).build();
|
|
} catch (IllegalArgumentException e) {
|
|
return Response.status(Response.Status.BAD_REQUEST)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors de la récupération de l'historique", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
@GET
|
|
@Path("/count/pending")
|
|
@RolesAllowed({"ADMIN_ORGANISATION", "SUPER_ADMIN"})
|
|
@Operation(summary = "Compte les approbations en attente",
|
|
description = "Retourne le nombre d'approbations en attente pour une organisation")
|
|
public Response countPendingApprovals(@QueryParam("organizationId") UUID organizationId) {
|
|
LOG.infof("GET /api/finance/approvals/count/pending?organizationId=%s", organizationId);
|
|
|
|
try {
|
|
long count = approvalService.countPendingApprovals(organizationId);
|
|
return Response.ok(new CountResponse(count)).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Erreur lors du comptage des approbations", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(ErrorResponse.of(e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
// Classe interne pour le comptage
|
|
record CountResponse(long count) {}
|
|
}
|