Files
lionsdev-client-impl-quarkus/src/main/java/dev/lions/audit/AuditService.java

248 lines
9.5 KiB
Java

package dev.lions.audit;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* Service de gestion des audits de maturité digitale
*/
@ApplicationScoped
public class AuditService {
@Inject
EntityManager em;
/**
* Récupère toutes les questions d'audit actives par catégorie
*/
public Map<String, List<AuditQuestion>> getQuestionsByCategory() {
List<AuditQuestion> questions = em.createQuery(
"SELECT q FROM AuditQuestion q WHERE q.active = true ORDER BY q.displayOrder",
AuditQuestion.class
).getResultList();
return questions.stream()
.collect(Collectors.groupingBy(AuditQuestion::getCategory));
}
/**
* Calcule le score d'un audit et génère les recommandations
*/
@Transactional
public AuditResponse processAuditResponse(AuditResponse response) {
Map<String, List<AuditQuestion>> questionsByCategory = getQuestionsByCategory();
Map<String, Integer> categoryScores = new HashMap<>();
Map<String, Integer> categoryMaxScores = new HashMap<>();
int totalScore = 0;
int maxPossibleScore = 0;
// Calcul des scores par catégorie
for (Map.Entry<String, List<AuditQuestion>> entry : questionsByCategory.entrySet()) {
String category = entry.getKey();
List<AuditQuestion> questions = entry.getValue();
int categoryScore = 0;
int categoryMaxScore = 0;
for (AuditQuestion question : questions) {
Integer answerIndex = response.getAnswers().get(question.getId());
if (answerIndex != null && answerIndex < question.getScores().size()) {
int questionScore = question.getScores().get(answerIndex) * question.getWeight();
categoryScore += questionScore;
totalScore += questionScore;
}
int maxQuestionScore = Collections.max(question.getScores()) * question.getWeight();
categoryMaxScore += maxQuestionScore;
maxPossibleScore += maxQuestionScore;
}
categoryScores.put(category, categoryScore);
categoryMaxScores.put(category, categoryMaxScore);
}
// Mise à jour des scores
response.setTotalScore(totalScore);
response.setMaxPossibleScore(maxPossibleScore);
response.setMaturityPercentage((double) totalScore / maxPossibleScore * 100);
response.setCategoryScores(categoryScores);
// Génération des recommandations
generateRecommendations(response, categoryScores, categoryMaxScores);
// Estimation budgétaire
estimateBudget(response, categoryScores);
// Sauvegarde
em.persist(response);
return response;
}
/**
* Génère les recommandations personnalisées
*/
private void generateRecommendations(AuditResponse response,
Map<String, Integer> categoryScores,
Map<String, Integer> categoryMaxScores) {
StringBuilder recommendations = new StringBuilder();
List<String> priorities = new ArrayList<>();
// Analyse par catégorie
for (Map.Entry<String, Integer> entry : categoryScores.entrySet()) {
String category = entry.getKey();
int score = entry.getValue();
int maxScore = categoryMaxScores.get(category);
double percentage = (double) score / maxScore * 100;
String categoryName = getCategoryDisplayName(category);
if (percentage < 30) {
recommendations.append("🚨 ").append(categoryName).append(" : Niveau critique - Digitalisation urgente nécessaire\n");
priorities.add("Digitaliser " + categoryName.toLowerCase());
} else if (percentage < 60) {
recommendations.append("⚠️ ").append(categoryName).append(" : Niveau faible - Améliorations importantes recommandées\n");
priorities.add("Améliorer " + categoryName.toLowerCase());
} else if (percentage < 80) {
recommendations.append("").append(categoryName).append(" : Niveau correct - Optimisations possibles\n");
} else {
recommendations.append("🏆 ").append(categoryName).append(" : Excellent niveau de digitalisation\n");
}
}
response.setRecommendations(recommendations.toString());
response.setPriorityActions(String.join(", ", priorities));
}
/**
* Estime le budget nécessaire selon les scores
*/
private void estimateBudget(AuditResponse response, Map<String, Integer> categoryScores) {
double budgetMin = 0;
double budgetMax = 0;
// Tarification par module selon le niveau de maturité
Map<String, Double[]> modulePricing = Map.of(
"commercial", new Double[]{150000.0, 300000.0}, // CRM
"stock", new Double[]{100000.0, 250000.0}, // Gestion stocks
"comptabilite", new Double[]{200000.0, 400000.0}, // Comptabilité
"rh", new Double[]{80000.0, 200000.0}, // RH
"infrastructure", new Double[]{100000.0, 300000.0} // IT
);
for (Map.Entry<String, Integer> entry : categoryScores.entrySet()) {
String category = entry.getKey();
int score = entry.getValue();
if (score < 50 && modulePricing.containsKey(category)) { // Besoin d'amélioration
Double[] pricing = modulePricing.get(category);
budgetMin += pricing[0];
budgetMax += pricing[1];
}
}
response.setEstimatedBudgetMin(budgetMin);
response.setEstimatedBudgetMax(budgetMax);
}
/**
* Récupère les audits non contactés pour le suivi commercial
*/
public List<AuditResponse> getUncontactedAudits() {
return em.createQuery(
"SELECT a FROM AuditResponse a WHERE a.contacted = false ORDER BY a.submittedAt DESC",
AuditResponse.class
).getResultList();
}
/**
* Marque un audit comme contacté
*/
@Transactional
public void markAsContacted(Long auditId, String notes) {
AuditResponse audit = em.find(AuditResponse.class, auditId);
if (audit != null) {
audit.setContacted(true);
audit.setContactedAt(java.time.LocalDateTime.now());
audit.setSalesNotes(notes);
}
}
/**
* Récupère un audit par ID
*/
public AuditResponse getAuditById(Long auditId) {
return em.find(AuditResponse.class, auditId);
}
/**
* Récupère les statistiques d'audit
*/
public Map<String, Object> getAuditStatistics() {
Map<String, Object> stats = new HashMap<>();
// Nombre total d'audits
Long totalAudits = em.createQuery("SELECT COUNT(a) FROM AuditResponse a", Long.class)
.getSingleResult();
stats.put("totalAudits", totalAudits);
// Audits cette semaine
Long weeklyAudits = em.createQuery(
"SELECT COUNT(a) FROM AuditResponse a WHERE a.submittedAt >= :weekStart", Long.class)
.setParameter("weekStart", java.time.LocalDateTime.now().minusDays(7))
.getSingleResult();
stats.put("weeklyAudits", weeklyAudits);
// Score moyen
Double avgScore = em.createQuery(
"SELECT AVG(a.maturityPercentage) FROM AuditResponse a", Double.class)
.getSingleResult();
stats.put("averageScore", avgScore != null ? avgScore : 0.0);
// Répartition par secteur
List<Object[]> sectorStats = em.createQuery(
"SELECT a.sector, COUNT(a) FROM AuditResponse a GROUP BY a.sector", Object[].class)
.getResultList();
Map<String, Long> sectorDistribution = new HashMap<>();
for (Object[] row : sectorStats) {
sectorDistribution.put((String) row[0], (Long) row[1]);
}
stats.put("sectorDistribution", sectorDistribution);
return stats;
}
/**
* Traite une demande de rendez-vous
*/
@Transactional
public void processMeetingRequest(MeetingRequestDTO request) {
// Ici on pourrait créer une entité MeetingRequest
// Pour l'instant, on met à jour les notes de l'audit
AuditResponse audit = em.find(AuditResponse.class, request.getAuditId());
if (audit != null) {
String meetingNote = String.format("RDV demandé: %s à %s (%s) - %s",
request.getPreferredDate(), request.getPreferredTime(),
request.getMeetingType(), request.getMessage());
audit.setSalesNotes(meetingNote);
}
}
private String getCategoryDisplayName(String category) {
return switch (category) {
case "commercial" -> "Gestion Commerciale";
case "stock" -> "Gestion des Stocks";
case "comptabilite" -> "Comptabilité";
case "rh" -> "Ressources Humaines";
case "infrastructure" -> "Infrastructure IT";
default -> category;
};
}
}