package dev.lions.unionflow.server.service; import dev.lions.unionflow.server.api.dto.config.request.ParametresLcbFtRequest; import dev.lions.unionflow.server.api.dto.config.response.ParametresLcbFtResponse; import dev.lions.unionflow.server.entity.Organisation; import dev.lions.unionflow.server.entity.ParametresLcbFt; import dev.lions.unionflow.server.repository.OrganisationRepository; import dev.lions.unionflow.server.repository.ParametresLcbFtRepository; import io.quarkus.cache.CacheResult; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.ws.rs.NotFoundException; import org.jboss.logging.Logger; import java.math.BigDecimal; import java.util.Optional; import java.util.UUID; /** * Service métier pour la gestion des paramètres LCB-FT (seuils anti-blanchiment). * * @author lions dev Team * @version 1.0 * @since 2026-03-13 */ @ApplicationScoped public class ParametresLcbFtService { private static final Logger LOG = Logger.getLogger(ParametresLcbFtService.class); private static final String CODE_DEVISE_DEFAULT = "XOF"; @Inject ParametresLcbFtRepository parametresRepository; @Inject OrganisationRepository organisationRepository; /** * Récupère les paramètres LCB-FT pour une organisation et une devise. * Avec cache pour performance (les seuils changent rarement). * * @param organisationId ID de l'organisation (null pour paramètres plateforme) * @param codeDevise Code devise ISO 4217 (XOF par défaut) * @return Paramètres LCB-FT ou paramètres plateforme par défaut */ @CacheResult(cacheName = "parametres-lcb-ft") public ParametresLcbFtResponse getParametres(UUID organisationId, String codeDevise) { if (codeDevise == null || codeDevise.isBlank()) { codeDevise = CODE_DEVISE_DEFAULT; } LOG.infof("Récupération paramètres LCB-FT pour organisation=%s, devise=%s", organisationId, codeDevise); Optional params = parametresRepository .findByOrganisationAndDevise(organisationId, codeDevise); if (params.isEmpty()) { LOG.warnf("Aucun paramètre LCB-FT trouvé pour organisation=%s, devise=%s", organisationId, codeDevise); throw new NotFoundException( "Paramètres LCB-FT non configurés pour cette organisation/devise"); } return toDTO(params.get()); } /** * Récupère uniquement le seuil de justification (pour validation rapide). * * @param organisationId ID de l'organisation * @param codeDevise Code devise (XOF par défaut) * @return Montant seuil au-dessus duquel origine des fonds est obligatoire */ @CacheResult(cacheName = "seuil-justification-lcb-ft") public BigDecimal getSeuilJustification(UUID organisationId, String codeDevise) { if (codeDevise == null || codeDevise.isBlank()) { codeDevise = CODE_DEVISE_DEFAULT; } LOG.debugf("Récupération seuil justification LCB-FT org=%s, devise=%s", organisationId, codeDevise); return parametresRepository.getSeuilJustification(organisationId, codeDevise) .orElse(BigDecimal.valueOf(500000)); // Fallback 500k XOF } /** * Crée ou met à jour les paramètres LCB-FT pour une organisation. */ @Transactional public ParametresLcbFtResponse saveOrUpdateParametres(ParametresLcbFtRequest request) { LOG.infof("Sauvegarde paramètres LCB-FT pour organisation=%s", request.getOrganisationId()); Organisation organisation = null; if (request.getOrganisationId() != null) { organisation = organisationRepository.findByIdOptional( UUID.fromString(request.getOrganisationId())) .orElseThrow(() -> new NotFoundException( "Organisation non trouvée: " + request.getOrganisationId())); } // Chercher paramètre existant String codeDevise = request.getCodeDevise() != null ? request.getCodeDevise() : CODE_DEVISE_DEFAULT; UUID orgId = organisation != null ? organisation.getId() : null; Optional existing = parametresRepository .findByOrganisationAndDevise(orgId, codeDevise); ParametresLcbFt params; if (existing.isPresent()) { // Mise à jour params = existing.get(); params.setMontantSeuilJustification(request.getMontantSeuilJustification()); params.setMontantSeuilValidationManuelle(request.getMontantSeuilValidationManuelle()); LOG.infof("Paramètres LCB-FT mis à jour : %s", params.getId()); } else { // Création params = ParametresLcbFt.builder() .organisation(organisation) .codeDevise(codeDevise) .montantSeuilJustification(request.getMontantSeuilJustification()) .montantSeuilValidationManuelle(request.getMontantSeuilValidationManuelle()) .build(); parametresRepository.persist(params); LOG.infof("Nouveaux paramètres LCB-FT créés : %s", params.getId()); } return toDTO(params); } /** * Convertit l'entité en DTO de réponse. */ private ParametresLcbFtResponse toDTO(ParametresLcbFt params) { ParametresLcbFtResponse response = ParametresLcbFtResponse.builder() .organisationId(params.getOrganisation() != null ? params.getOrganisation().getId().toString() : null) .organisationNom(params.getOrganisation() != null ? params.getOrganisation().getNom() : null) .montantSeuilJustification(params.getMontantSeuilJustification()) .montantSeuilValidationManuelle(params.getMontantSeuilValidationManuelle()) .codeDevise(params.getCodeDevise()) .estParametrePlateforme(params.getOrganisation() == null) .build(); // Set BaseResponse fields response.setId(params.getId()); response.setDateCreation(params.getDateCreation()); response.setDateModification(params.getDateModification()); response.setActif(params.getActif()); return response; } }