chore(quarkus-327): bump to Quarkus 3.27.3 LTS, make pom autonomous, bump to 1.0.7

This commit is contained in:
2026-04-23 14:42:55 +00:00
parent 1496c83b6f
commit 7fa862b755
418 changed files with 48321 additions and 48305 deletions

286
.gitignore vendored
View File

@@ -1,143 +1,143 @@
# ==================================== # ====================================
# GITIGNORE POUR UNIONFLOW SERVER API # GITIGNORE POUR UNIONFLOW SERVER API
# ==================================== # ====================================
# ===== MAVEN ===== # ===== MAVEN =====
target/ target/
pom.xml.tag pom.xml.tag
pom.xml.releaseBackup pom.xml.releaseBackup
pom.xml.versionsBackup pom.xml.versionsBackup
pom.xml.next pom.xml.next
release.properties release.properties
dependency-reduced-pom.xml dependency-reduced-pom.xml
buildNumber.properties buildNumber.properties
.mvn/timing.properties .mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar .mvn/wrapper/maven-wrapper.jar
.flattened-pom.xml .flattened-pom.xml
# ===== QUARKUS ===== # ===== QUARKUS =====
.quarkus/ .quarkus/
quarkus.log quarkus.log
hs_err_pid* hs_err_pid*
# ===== JAVA COMPILED FILES ===== # ===== JAVA COMPILED FILES =====
*.class *.class
*.jar *.jar
*.war *.war
*.ear *.ear
*.nar *.nar
*.zip *.zip
*.tar.gz *.tar.gz
*.rar *.rar
# ===== IDE - ECLIPSE ===== # ===== IDE - ECLIPSE =====
.project .project
.classpath .classpath
.settings/ .settings/
.factorypath .factorypath
.metadata/ .metadata/
bin/ bin/
.apt_generated .apt_generated
.springBeans .springBeans
.sts4-cache .sts4-cache
# ===== IDE - INTELLIJ IDEA ===== # ===== IDE - INTELLIJ IDEA =====
.idea/ .idea/
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
out/ out/
# ===== IDE - NETBEANS ===== # ===== IDE - NETBEANS =====
nbproject/ nbproject/
nbbuild/ nbbuild/
nbdist/ nbdist/
.nb-gradle/ .nb-gradle/
nb-configuration.xml nb-configuration.xml
nbactions.xml nbactions.xml
# ===== IDE - VS CODE ===== # ===== IDE - VS CODE =====
.vscode/ .vscode/
*.code-workspace *.code-workspace
# ===== OS SPECIFIC ===== # ===== OS SPECIFIC =====
# Mac # Mac
.DS_Store .DS_Store
# Windows # Windows
Thumbs.db Thumbs.db
ehthumbs.db ehthumbs.db
Desktop.ini Desktop.ini
$RECYCLE.BIN/ $RECYCLE.BIN/
# Linux # Linux
*~ *~
# ===== LOGS ===== # ===== LOGS =====
*.log *.log
*.log.* *.log.*
logs/ logs/
log/ log/
# ===== TEMPORARY FILES ===== # ===== TEMPORARY FILES =====
*.tmp *.tmp
*.temp *.temp
*.bak *.bak
*.backup *.backup
*.old *.old
*.swp *.swp
*.swo *.swo
*.orig *.orig
*.rej *.rej
*~ *~
# ===== ENVIRONMENT & CONFIGURATION ===== # ===== ENVIRONMENT & CONFIGURATION =====
.env .env
.env.local .env.local
.env.* .env.*
*.local *.local
application-local.properties application-local.properties
# ===== SECURITY - KEYS & CERTIFICATES ===== # ===== SECURITY - KEYS & CERTIFICATES =====
*.key *.key
*.pem *.pem
*.crt *.crt
*.p12 *.p12
*.jks *.jks
*.keystore *.keystore
.certs/ .certs/
.certificates/ .certificates/
# ===== TEST COVERAGE ===== # ===== TEST COVERAGE =====
.jacoco/ .jacoco/
jacoco.exec jacoco.exec
coverage/ coverage/
.nyc_output/ .nyc_output/
# ===== GENERATED SOURCES ===== # ===== GENERATED SOURCES =====
src/gen/ src/gen/
generated-sources/ generated-sources/
generated-test-sources/ generated-test-sources/
# ===== BUILD ARTIFACTS ===== # ===== BUILD ARTIFACTS =====
dist/ dist/
build/ build/
out/ out/
# ===== NODE (if used for build tools) ===== # ===== NODE (if used for build tools) =====
node_modules/ node_modules/
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log* lerna-debug.log*
# ===== DOCKER ===== # ===== DOCKER =====
.dockerignore .dockerignore
# ===== MAVEN WRAPPER (if not using project wrapper) ===== # ===== MAVEN WRAPPER (if not using project wrapper) =====
# Uncomment if you don't want to commit Maven wrapper # Uncomment if you don't want to commit Maven wrapper
# .mvn/ # .mvn/
# mvnw # mvnw
# mvnw.cmd # mvnw.cmd

View File

@@ -1,276 +1,276 @@
# Classes sans Tests - UnionFlow Server API # Classes sans Tests - UnionFlow Server API
**Date d'analyse**: 2026-03-15 **Date d'analyse**: 2026-03-15
**Couverture globale**: 72% (4635 instructions manquées sur 16697) **Couverture globale**: 72% (4635 instructions manquées sur 16697)
**Classes sans tests**: 91 classes (0% de couverture) **Classes sans tests**: 91 classes (0% de couverture)
--- ---
## 1. DTOs REQUEST (dev.lions.unionflow.server.api.dto) ## 1. DTOs REQUEST (dev.lions.unionflow.server.api.dto)
### 1.1 Solidarité (8 classes - 0%) ### 1.1 Solidarité (8 classes - 0%)
- `dev.lions.unionflow.server.api.dto.solidarite.request.CreateCommentaireAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.CreateCommentaireAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.CreateDemandeAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.CreateDemandeAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.CreateEvaluationAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.CreateEvaluationAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.CreatePropositionAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.CreatePropositionAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.UpdateCommentaireAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.UpdateCommentaireAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.UpdateDemandeAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.UpdateDemandeAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.UpdateEvaluationAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.UpdateEvaluationAideRequest`
- `dev.lions.unionflow.server.api.dto.solidarite.request.UpdatePropositionAideRequest` - `dev.lions.unionflow.server.api.dto.solidarite.request.UpdatePropositionAideRequest`
### 1.2 Comptabilité (8 classes - 0%) ### 1.2 Comptabilité (8 classes - 0%)
- `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateCompteComptableRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateCompteComptableRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateEcritureComptableRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateEcritureComptableRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateJournalComptableRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateJournalComptableRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateLigneEcritureRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.CreateLigneEcritureRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateCompteComptableRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateCompteComptableRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateEcritureComptableRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateEcritureComptableRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateJournalComptableRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateJournalComptableRequest`
- `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateLigneEcritureRequest` - `dev.lions.unionflow.server.api.dto.comptabilite.request.UpdateLigneEcritureRequest`
### 1.3 Paiement (4 classes - 0%) ### 1.3 Paiement (4 classes - 0%)
- `dev.lions.unionflow.server.api.dto.paiement.request.CreatePaiementRequest` - `dev.lions.unionflow.server.api.dto.paiement.request.CreatePaiementRequest`
- `dev.lions.unionflow.server.api.dto.paiement.request.DeclarerPaiementManuelRequest` - `dev.lions.unionflow.server.api.dto.paiement.request.DeclarerPaiementManuelRequest`
- `dev.lions.unionflow.server.api.dto.paiement.request.InitierDepotEpargneRequest` - `dev.lions.unionflow.server.api.dto.paiement.request.InitierDepotEpargneRequest`
- `dev.lions.unionflow.server.api.dto.paiement.request.InitierPaiementEnLigneRequest` - `dev.lions.unionflow.server.api.dto.paiement.request.InitierPaiementEnLigneRequest`
### 1.4 Notification (4 classes - 0%) ### 1.4 Notification (4 classes - 0%)
- `dev.lions.unionflow.server.api.dto.notification.request.CreateNotificationRequest` - `dev.lions.unionflow.server.api.dto.notification.request.CreateNotificationRequest`
- `dev.lions.unionflow.server.api.dto.notification.request.CreateTemplateNotificationRequest` - `dev.lions.unionflow.server.api.dto.notification.request.CreateTemplateNotificationRequest`
- `dev.lions.unionflow.server.api.dto.notification.request.UpdateNotificationRequest` - `dev.lions.unionflow.server.api.dto.notification.request.UpdateNotificationRequest`
- `dev.lions.unionflow.server.api.dto.notification.request.UpdateTemplateNotificationRequest` - `dev.lions.unionflow.server.api.dto.notification.request.UpdateTemplateNotificationRequest`
### 1.5 Document (4 classes - 0%) ### 1.5 Document (4 classes - 0%)
- `dev.lions.unionflow.server.api.dto.document.request.CreateDocumentRequest` - `dev.lions.unionflow.server.api.dto.document.request.CreateDocumentRequest`
- `dev.lions.unionflow.server.api.dto.document.request.CreatePieceJointeRequest` - `dev.lions.unionflow.server.api.dto.document.request.CreatePieceJointeRequest`
- `dev.lions.unionflow.server.api.dto.document.request.UpdateDocumentRequest` - `dev.lions.unionflow.server.api.dto.document.request.UpdateDocumentRequest`
- `dev.lions.unionflow.server.api.dto.document.request.UpdatePieceJointeRequest` - `dev.lions.unionflow.server.api.dto.document.request.UpdatePieceJointeRequest`
### 1.6 Abonnement (2 classes - 0%) ### 1.6 Abonnement (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.abonnement.request.CreateAbonnementRequest` - `dev.lions.unionflow.server.api.dto.abonnement.request.CreateAbonnementRequest`
- `dev.lions.unionflow.server.api.dto.abonnement.request.UpdateAbonnementRequest` - `dev.lions.unionflow.server.api.dto.abonnement.request.UpdateAbonnementRequest`
### 1.7 Événement (2 classes - 0%) ### 1.7 Événement (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.evenement.request.CreateEvenementRequest` - `dev.lions.unionflow.server.api.dto.evenement.request.CreateEvenementRequest`
- `dev.lions.unionflow.server.api.dto.evenement.request.UpdateEvenementRequest` - `dev.lions.unionflow.server.api.dto.evenement.request.UpdateEvenementRequest`
### 1.8 Formule Abonnement (2 classes - 0%) ### 1.8 Formule Abonnement (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.formuleabonnement.request.CreateFormuleAbonnementRequest` - `dev.lions.unionflow.server.api.dto.formuleabonnement.request.CreateFormuleAbonnementRequest`
- `dev.lions.unionflow.server.api.dto.formuleabonnement.request.UpdateFormuleAbonnementRequest` - `dev.lions.unionflow.server.api.dto.formuleabonnement.request.UpdateFormuleAbonnementRequest`
### 1.9 Organisation (2 classes - 0%) ### 1.9 Organisation (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.organisation.request.CreateOrganisationRequest` - `dev.lions.unionflow.server.api.dto.organisation.request.CreateOrganisationRequest`
- `dev.lions.unionflow.server.api.dto.organisation.request.UpdateOrganisationRequest` - `dev.lions.unionflow.server.api.dto.organisation.request.UpdateOrganisationRequest`
### 1.10 Adresse (2 classes - 0%) ### 1.10 Adresse (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.adresse.request.CreateAdresseRequest` - `dev.lions.unionflow.server.api.dto.adresse.request.CreateAdresseRequest`
- `dev.lions.unionflow.server.api.dto.adresse.request.UpdateAdresseRequest` - `dev.lions.unionflow.server.api.dto.adresse.request.UpdateAdresseRequest`
### 1.11 Membre (2 classes - 0%) ### 1.11 Membre (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.membre.request.CreateMembreRequest` - `dev.lions.unionflow.server.api.dto.membre.request.CreateMembreRequest`
- `dev.lions.unionflow.server.api.dto.membre.request.UpdateMembreRequest` - `dev.lions.unionflow.server.api.dto.membre.request.UpdateMembreRequest`
### 1.12 Cotisation (2 classes - 0%) ### 1.12 Cotisation (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.cotisation.request.CreateCotisationRequest` - `dev.lions.unionflow.server.api.dto.cotisation.request.CreateCotisationRequest`
- `dev.lions.unionflow.server.api.dto.cotisation.request.UpdateCotisationRequest` - `dev.lions.unionflow.server.api.dto.cotisation.request.UpdateCotisationRequest`
### 1.13 Référence (2 classes - 0%) ### 1.13 Référence (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.reference.request.CreateTypeReferenceRequest` - `dev.lions.unionflow.server.api.dto.reference.request.CreateTypeReferenceRequest`
- `dev.lions.unionflow.server.api.dto.reference.request.UpdateTypeReferenceRequest` - `dev.lions.unionflow.server.api.dto.reference.request.UpdateTypeReferenceRequest`
### 1.14 Suggestion (2 classes - 0%) ### 1.14 Suggestion (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.suggestion.request.CreateSuggestionRequest` - `dev.lions.unionflow.server.api.dto.suggestion.request.CreateSuggestionRequest`
- `dev.lions.unionflow.server.api.dto.suggestion.request.UpdateSuggestionRequest` - `dev.lions.unionflow.server.api.dto.suggestion.request.UpdateSuggestionRequest`
### 1.15 Finance (2 classes - 0%) ### 1.15 Finance (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.finance.request.CreateAdhesionRequest` - `dev.lions.unionflow.server.api.dto.finance.request.CreateAdhesionRequest`
- `dev.lions.unionflow.server.api.dto.finance.request.UpdateAdhesionRequest` - `dev.lions.unionflow.server.api.dto.finance.request.UpdateAdhesionRequest`
### 1.16 User (2 classes - 0%) ### 1.16 User (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.user.request.CreateUserRequest` - `dev.lions.unionflow.server.api.dto.user.request.CreateUserRequest`
- `dev.lions.unionflow.server.api.dto.user.request.UpdateUserRequest` - `dev.lions.unionflow.server.api.dto.user.request.UpdateUserRequest`
### 1.17 Configuration (2 classes - 0%) ### 1.17 Configuration (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.config.request.CreateConfigurationRequest` - `dev.lions.unionflow.server.api.dto.config.request.CreateConfigurationRequest`
- `dev.lions.unionflow.server.api.dto.config.request.UpdateConfigurationRequest` - `dev.lions.unionflow.server.api.dto.config.request.UpdateConfigurationRequest`
### 1.18 Ticket (2 classes - 0%) ### 1.18 Ticket (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.ticket.request.CreateTicketRequest` - `dev.lions.unionflow.server.api.dto.ticket.request.CreateTicketRequest`
- `dev.lions.unionflow.server.api.dto.ticket.request.UpdateTicketRequest` - `dev.lions.unionflow.server.api.dto.ticket.request.UpdateTicketRequest`
### 1.19 Rôle (2 classes - 0%) ### 1.19 Rôle (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.role.request.CreateRoleRequest` - `dev.lions.unionflow.server.api.dto.role.request.CreateRoleRequest`
- `dev.lions.unionflow.server.api.dto.role.request.UpdateRoleRequest` - `dev.lions.unionflow.server.api.dto.role.request.UpdateRoleRequest`
### 1.20 Admin (1 classe - 0%) ### 1.20 Admin (1 classe - 0%)
- `dev.lions.unionflow.server.api.dto.admin.request.CreateAdminRequest` - `dev.lions.unionflow.server.api.dto.admin.request.CreateAdminRequest`
### 1.21 Favoris (1 classe - 0%) ### 1.21 Favoris (1 classe - 0%)
- `dev.lions.unionflow.server.api.dto.favoris.request.CreateFavoriRequest` - `dev.lions.unionflow.server.api.dto.favoris.request.CreateFavoriRequest`
--- ---
## 2. DTOs RESPONSE (dev.lions.unionflow.server.api.dto) ## 2. DTOs RESPONSE (dev.lions.unionflow.server.api.dto)
### 2.1 Paiement (1 classe - 0%) ### 2.1 Paiement (1 classe - 0%)
- `dev.lions.unionflow.server.api.dto.paiement.response.PaiementGatewayResponse` - `dev.lions.unionflow.server.api.dto.paiement.response.PaiementGatewayResponse`
### 2.2 Cotisation (1 classe - 0%) ### 2.2 Cotisation (1 classe - 0%)
- `dev.lions.unionflow.server.api.dto.cotisation.response.CotisationSummaryResponse` - `dev.lions.unionflow.server.api.dto.cotisation.response.CotisationSummaryResponse`
### 2.3 Adresse (1 classe - 0%) ### 2.3 Adresse (1 classe - 0%)
- `dev.lions.unionflow.server.api.dto.adresse.response.AdresseResponse` - `dev.lions.unionflow.server.api.dto.adresse.response.AdresseResponse`
### 2.4 Admin (1 classe - 0%) ### 2.4 Admin (1 classe - 0%)
- `dev.lions.unionflow.server.api.dto.admin.response.AdminResponse` - `dev.lions.unionflow.server.api.dto.admin.response.AdminResponse`
--- ---
## 3. AUTRES DTOs ## 3. AUTRES DTOs
### 3.1 Wave (2 classes - 0%) ### 3.1 Wave (2 classes - 0%)
- `dev.lions.unionflow.server.api.dto.wave.CompteWaveDTO` - `dev.lions.unionflow.server.api.dto.wave.CompteWaveDTO`
- `dev.lions.unionflow.server.api.dto.wave.TransactionWaveDTO` - `dev.lions.unionflow.server.api.dto.wave.TransactionWaveDTO`
--- ---
## 4. ENUMS (dev.lions.unionflow.server.api.enums) ## 4. ENUMS (dev.lions.unionflow.server.api.enums)
### 4.1 Mutuelle - Crédit (4 classes - 0%) ### 4.1 Mutuelle - Crédit (4 classes - 0%)
- `dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutDemandeCredit` - `dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutDemandeCredit`
- `dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutEcheanceCredit` - `dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutEcheanceCredit`
- `dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit` - `dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit`
- `dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeGarantie` - `dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeGarantie`
### 4.2 Mutuelle - Épargne (3 classes - 0%) ### 4.2 Mutuelle - Épargne (3 classes - 0%)
- `dev.lions.unionflow.server.api.enums.mutuelle.epargne.StatutCompteEpargne` - `dev.lions.unionflow.server.api.enums.mutuelle.epargne.StatutCompteEpargne`
- `dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeCompteEpargne` - `dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeCompteEpargne`
- `dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeTransactionEpargne` - `dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeTransactionEpargne`
### 4.3 Vote (3 classes - 0%) ### 4.3 Vote (3 classes - 0%)
- `dev.lions.unionflow.server.api.enums.vote.ModeScrutin` - `dev.lions.unionflow.server.api.enums.vote.ModeScrutin`
- `dev.lions.unionflow.server.api.enums.vote.StatutVote` - `dev.lions.unionflow.server.api.enums.vote.StatutVote`
- `dev.lions.unionflow.server.api.enums.vote.TypeVote` - `dev.lions.unionflow.server.api.enums.vote.TypeVote`
### 4.4 Tontine (3 classes - 0%) ### 4.4 Tontine (3 classes - 0%)
- `dev.lions.unionflow.server.api.enums.tontine.FrequenceTour` - `dev.lions.unionflow.server.api.enums.tontine.FrequenceTour`
- `dev.lions.unionflow.server.api.enums.tontine.StatutTontine` - `dev.lions.unionflow.server.api.enums.tontine.StatutTontine`
- `dev.lions.unionflow.server.api.enums.tontine.TypeTontine` - `dev.lions.unionflow.server.api.enums.tontine.TypeTontine`
### 4.5 Ayant Droit (2 classes - 0%) ### 4.5 Ayant Droit (2 classes - 0%)
- `dev.lions.unionflow.server.api.enums.ayantdroit.StatutAyantDroit` - `dev.lions.unionflow.server.api.enums.ayantdroit.StatutAyantDroit`
- `dev.lions.unionflow.server.api.enums.ayantdroit.TypeAyantDroit` - `dev.lions.unionflow.server.api.enums.ayantdroit.TypeAyantDroit`
### 4.6 Agricole (1 classe - 0%) ### 4.6 Agricole (1 classe - 0%)
- `dev.lions.unionflow.server.api.enums.agricole.StatutCampagneAgricole` - `dev.lions.unionflow.server.api.enums.agricole.StatutCampagneAgricole`
### 4.7 Collecte de Fonds (1 classe - 0%) ### 4.7 Collecte de Fonds (1 classe - 0%)
- `dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte` - `dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte`
### 4.8 Culte (1 classe - 0%) ### 4.8 Culte (1 classe - 0%)
- `dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux` - `dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux`
### 4.9 ONG (1 classe - 0%) ### 4.9 ONG (1 classe - 0%)
- `dev.lions.unionflow.server.api.enums.ong.StatutProjetOng` - `dev.lions.unionflow.server.api.enums.ong.StatutProjetOng`
### 4.10 Gouvernance (1 classe - 0%) ### 4.10 Gouvernance (1 classe - 0%)
- `dev.lions.unionflow.server.api.enums.gouvernance.NiveauEchelon` - `dev.lions.unionflow.server.api.enums.gouvernance.NiveauEchelon`
### 4.11 Registre (1 classe - 0%) ### 4.11 Registre (1 classe - 0%)
- `dev.lions.unionflow.server.api.enums.registre.StatutAgrement` - `dev.lions.unionflow.server.api.enums.registre.StatutAgrement`
--- ---
## RÉCAPITULATIF PAR CATÉGORIE ## RÉCAPITULATIF PAR CATÉGORIE
| Catégorie | Nombre de classes | % du total | | Catégorie | Nombre de classes | % du total |
|-----------|-------------------|------------| |-----------|-------------------|------------|
| **DTO Requests** | **62 classes** | **68%** | | **DTO Requests** | **62 classes** | **68%** |
| **Enums** | **21 classes** | **23%** | | **Enums** | **21 classes** | **23%** |
| **DTO Responses** | **4 classes** | **4%** | | **DTO Responses** | **4 classes** | **4%** |
| **Autres DTOs** | **2 classes** | **2%** | | **Autres DTOs** | **2 classes** | **2%** |
| **Autres** | **2 classes** | **2%** | | **Autres** | **2 classes** | **2%** |
| **TOTAL** | **91 classes** | **100%** | | **TOTAL** | **91 classes** | **100%** |
--- ---
## PRIORITÉS DE TEST ## PRIORITÉS DE TEST
### P0 - Haute Priorité (Core Business) ### P0 - Haute Priorité (Core Business)
1. **Solidarité** (8 requests) - Module métier principal 1. **Solidarité** (8 requests) - Module métier principal
2. **Comptabilité** (8 requests) - Gestion financière critique 2. **Comptabilité** (8 requests) - Gestion financière critique
3. **Paiement** (4 requests + 1 response) - Transactions financières 3. **Paiement** (4 requests + 1 response) - Transactions financières
4. **Mutuelle Crédit** (4 enums) - Microfinance core 4. **Mutuelle Crédit** (4 enums) - Microfinance core
5. **Mutuelle Épargne** (3 enums) - Microfinance core 5. **Mutuelle Épargne** (3 enums) - Microfinance core
### P1 - Priorité Moyenne (Features importantes) ### P1 - Priorité Moyenne (Features importantes)
6. **Notification** (4 requests) - Communication système 6. **Notification** (4 requests) - Communication système
7. **Document** (4 requests) - Gestion documentaire 7. **Document** (4 requests) - Gestion documentaire
8. **Événement** (2 requests) - Gestion événementielle 8. **Événement** (2 requests) - Gestion événementielle
9. **Organisation** (2 requests) - Structure organisationnelle 9. **Organisation** (2 requests) - Structure organisationnelle
10. **Membre** (2 requests) - Gestion des utilisateurs 10. **Membre** (2 requests) - Gestion des utilisateurs
### P2 - Priorité Basse (Features secondaires) ### P2 - Priorité Basse (Features secondaires)
11. **Abonnement** (2 requests) - Gestion des abonnements 11. **Abonnement** (2 requests) - Gestion des abonnements
12. **Tontine** (3 enums) - Feature spécifique 12. **Tontine** (3 enums) - Feature spécifique
13. **Vote** (3 enums) - Feature spécifique 13. **Vote** (3 enums) - Feature spécifique
14. **Autres requests** (20 requests restants) 14. **Autres requests** (20 requests restants)
15. **Enums divers** (11 enums restants) 15. **Enums divers** (11 enums restants)
--- ---
## PLAN D'ACTION ## PLAN D'ACTION
### Étape 1: Tests DTOs Request (62 classes) ### Étape 1: Tests DTOs Request (62 classes)
- Tester getters/setters - Tester getters/setters
- Tester validations Jakarta Bean Validation - Tester validations Jakarta Bean Validation
- Tester méthodes equals/hashCode/toString si présentes - Tester méthodes equals/hashCode/toString si présentes
### Étape 2: Tests DTOs Response (4 classes) ### Étape 2: Tests DTOs Response (4 classes)
- Tester constructeurs et builders - Tester constructeurs et builders
- Tester sérialisation JSON - Tester sérialisation JSON
### Étape 3: Tests Enums (21 classes) ### Étape 3: Tests Enums (21 classes)
- Tester valueOf() et values() - Tester valueOf() et values()
- Tester getters de valeurs - Tester getters de valeurs
- Tester méthodes utilitaires (fromString, etc.) - Tester méthodes utilitaires (fromString, etc.)
### Étape 4: Tests Autres (4 classes) ### Étape 4: Tests Autres (4 classes)
- Tests spécifiques selon le type de classe - Tests spécifiques selon le type de classe
--- ---
## TEMPLATES DE TEST RECOMMANDÉS ## TEMPLATES DE TEST RECOMMANDÉS
### Pour DTOs Request: ### Pour DTOs Request:
```java ```java
@Test @Test
void testCreateXxxRequest_AllFields() { void testCreateXxxRequest_AllFields() {
var request = new CreateXxxRequest(); var request = new CreateXxxRequest();
// Set all fields // Set all fields
// Assert all fields // Assert all fields
} }
@Test @Test
void testCreateXxxRequest_Validation() { void testCreateXxxRequest_Validation() {
var request = new CreateXxxRequest(); var request = new CreateXxxRequest();
// Test @NotNull, @Size, etc. // Test @NotNull, @Size, etc.
} }
``` ```
### Pour Enums: ### Pour Enums:
```java ```java
@Test @Test
void testEnumValues() { void testEnumValues() {
assertEquals(3, TypeXxx.values().length); assertEquals(3, TypeXxx.values().length);
} }
@Test @Test
void testEnumValueOf() { void testEnumValueOf() {
assertEquals(TypeXxx.VALUE1, TypeXxx.valueOf("VALUE1")); assertEquals(TypeXxx.VALUE1, TypeXxx.valueOf("VALUE1"));
} }
``` ```
--- ---
**Objectif**: Atteindre **100% de couverture** sur le module unionflow-server-api. **Objectif**: Atteindre **100% de couverture** sur le module unionflow-server-api.

1096
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,169 +1,169 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Script pour analyser le rapport JaCoCo et extraire les classes sans tests.""" """Script pour analyser le rapport JaCoCo et extraire les classes sans tests."""
import os import os
import re import re
from pathlib import Path from pathlib import Path
from html.parser import HTMLParser from html.parser import HTMLParser
class JaCoCoParser(HTMLParser): class JaCoCoParser(HTMLParser):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.current_package = "" self.current_package = ""
self.classes = [] self.classes = []
self.in_tbody = False self.in_tbody = False
self.current_row = {} self.current_row = {}
self.current_cell = "" self.current_cell = ""
self.cell_index = 0 self.cell_index = 0
def handle_starttag(self, tag, attrs): def handle_starttag(self, tag, attrs):
if tag == "tbody": if tag == "tbody":
self.in_tbody = True self.in_tbody = True
elif tag == "tr" and self.in_tbody: elif tag == "tr" and self.in_tbody:
self.current_row = {} self.current_row = {}
self.cell_index = 0 self.cell_index = 0
elif tag == "td" and self.in_tbody: elif tag == "td" and self.in_tbody:
self.current_cell = "" self.current_cell = ""
elif tag == "a" and self.in_tbody: elif tag == "a" and self.in_tbody:
for attr, value in attrs: for attr, value in attrs:
if attr == "href" and value.endswith(".html"): if attr == "href" and value.endswith(".html"):
self.current_row["href"] = value self.current_row["href"] = value
def handle_endtag(self, tag): def handle_endtag(self, tag):
if tag == "tbody": if tag == "tbody":
self.in_tbody = False self.in_tbody = False
elif tag == "tr" and self.in_tbody and self.current_row: elif tag == "tr" and self.in_tbody and self.current_row:
if "coverage" in self.current_row and self.current_row["coverage"] == "0 %": if "coverage" in self.current_row and self.current_row["coverage"] == "0 %":
self.classes.append(self.current_row.copy()) self.classes.append(self.current_row.copy())
elif tag == "td" and self.in_tbody: elif tag == "td" and self.in_tbody:
self.cell_index += 1 self.cell_index += 1
def handle_data(self, data): def handle_data(self, data):
if self.in_tbody: if self.in_tbody:
data = data.strip() data = data.strip()
if data and self.cell_index == 0: if data and self.cell_index == 0:
self.current_row["name"] = data self.current_row["name"] = data
elif data and "%" in data: elif data and "%" in data:
self.current_row["coverage"] = data self.current_row["coverage"] = data
def analyze_package(package_path, package_name): def analyze_package(package_path, package_name):
"""Analyse un fichier index.html de package.""" """Analyse un fichier index.html de package."""
index_file = os.path.join(package_path, "index.html") index_file = os.path.join(package_path, "index.html")
if not os.path.exists(index_file): if not os.path.exists(index_file):
return [] return []
with open(index_file, 'r', encoding='utf-8') as f: with open(index_file, 'r', encoding='utf-8') as f:
content = f.read() content = f.read()
parser = JaCoCoParser() parser = JaCoCoParser()
parser.current_package = package_name parser.current_package = package_name
parser.feed(content) parser.feed(content)
classes = [] classes = []
for row in parser.classes: for row in parser.classes:
if "name" in row: if "name" in row:
classes.append({ classes.append({
"package": package_name, "package": package_name,
"class": row["name"], "class": row["name"],
"coverage": row.get("coverage", "0 %") "coverage": row.get("coverage", "0 %")
}) })
return classes return classes
def main(): def main():
jacoco_dir = Path("target/site/jacoco") jacoco_dir = Path("target/site/jacoco")
if not jacoco_dir.exists(): if not jacoco_dir.exists():
print(f"Erreur: Le répertoire {jacoco_dir} n'existe pas.") print(f"Erreur: Le répertoire {jacoco_dir} n'existe pas.")
print("Veuillez exécuter 'mvn clean test' pour générer le rapport JaCoCo.") print("Veuillez exécuter 'mvn clean test' pour générer le rapport JaCoCo.")
return return
# Collecter tous les packages # Collecter tous les packages
all_classes = [] all_classes = []
for package_dir in jacoco_dir.iterdir(): for package_dir in jacoco_dir.iterdir():
if package_dir.is_dir() and not package_dir.name.startswith("."): if package_dir.is_dir() and not package_dir.name.startswith("."):
package_name = package_dir.name.replace("/", ".") package_name = package_dir.name.replace("/", ".")
classes = analyze_package(package_dir, package_name) classes = analyze_package(package_dir, package_name)
all_classes.extend(classes) all_classes.extend(classes)
# Trier par package et type # Trier par package et type
dto_requests = [] dto_requests = []
dto_responses = [] dto_responses = []
dto_other = [] dto_other = []
enums = [] enums = []
others = [] others = []
for cls in all_classes: for cls in all_classes:
pkg = cls["package"] pkg = cls["package"]
name = cls["class"] name = cls["class"]
if "enums" in pkg: if "enums" in pkg:
enums.append(cls) enums.append(cls)
elif "dto" in pkg: elif "dto" in pkg:
if ".request" in pkg: if ".request" in pkg:
dto_requests.append(cls) dto_requests.append(cls)
elif ".response" in pkg: elif ".response" in pkg:
dto_responses.append(cls) dto_responses.append(cls)
else: else:
dto_other.append(cls) dto_other.append(cls)
else: else:
others.append(cls) others.append(cls)
# Afficher les résultats # Afficher les résultats
print("=" * 80) print("=" * 80)
print("CLASSES SANS TESTS (0% de couverture)") print("CLASSES SANS TESTS (0% de couverture)")
print("=" * 80) print("=" * 80)
print() print()
if dto_requests: if dto_requests:
print("1. DTOs REQUEST (dev.lions.unionflow.server.api.dto)") print("1. DTOs REQUEST (dev.lions.unionflow.server.api.dto)")
print("-" * 80) print("-" * 80)
for cls in sorted(dto_requests, key=lambda x: (x["package"], x["class"])): for cls in sorted(dto_requests, key=lambda x: (x["package"], x["class"])):
print(f" {cls['package']}.{cls['class']}") print(f" {cls['package']}.{cls['class']}")
print(f" Type: DTO Request | Couverture: {cls['coverage']}") print(f" Type: DTO Request | Couverture: {cls['coverage']}")
print() print()
if dto_responses: if dto_responses:
print("2. DTOs RESPONSE (dev.lions.unionflow.server.api.dto)") print("2. DTOs RESPONSE (dev.lions.unionflow.server.api.dto)")
print("-" * 80) print("-" * 80)
for cls in sorted(dto_responses, key=lambda x: (x["package"], x["class"])): for cls in sorted(dto_responses, key=lambda x: (x["package"], x["class"])):
print(f" {cls['package']}.{cls['class']}") print(f" {cls['package']}.{cls['class']}")
print(f" Type: DTO Response | Couverture: {cls['coverage']}") print(f" Type: DTO Response | Couverture: {cls['coverage']}")
print() print()
if dto_other: if dto_other:
print("3. AUTRES DTOs") print("3. AUTRES DTOs")
print("-" * 80) print("-" * 80)
for cls in sorted(dto_other, key=lambda x: (x["package"], x["class"])): for cls in sorted(dto_other, key=lambda x: (x["package"], x["class"])):
print(f" {cls['package']}.{cls['class']}") print(f" {cls['package']}.{cls['class']}")
print(f" Type: DTO | Couverture: {cls['coverage']}") print(f" Type: DTO | Couverture: {cls['coverage']}")
print() print()
if enums: if enums:
print("4. ENUMS (dev.lions.unionflow.server.api.enums)") print("4. ENUMS (dev.lions.unionflow.server.api.enums)")
print("-" * 80) print("-" * 80)
for cls in sorted(enums, key=lambda x: (x["package"], x["class"])): for cls in sorted(enums, key=lambda x: (x["package"], x["class"])):
print(f" {cls['package']}.{cls['class']}") print(f" {cls['package']}.{cls['class']}")
print(f" Type: Enum | Couverture: {cls['coverage']}") print(f" Type: Enum | Couverture: {cls['coverage']}")
print() print()
if others: if others:
print("5. AUTRES") print("5. AUTRES")
print("-" * 80) print("-" * 80)
for cls in sorted(others, key=lambda x: (x["package"], x["class"])): for cls in sorted(others, key=lambda x: (x["package"], x["class"])):
print(f" {cls['package']}.{cls['class']}") print(f" {cls['package']}.{cls['class']}")
print(f" Type: Autre | Couverture: {cls['coverage']}") print(f" Type: Autre | Couverture: {cls['coverage']}")
print() print()
print("=" * 80) print("=" * 80)
print(f"TOTAL: {len(all_classes)} classes sans tests") print(f"TOTAL: {len(all_classes)} classes sans tests")
print(f" - DTO Requests: {len(dto_requests)}") print(f" - DTO Requests: {len(dto_requests)}")
print(f" - DTO Responses: {len(dto_responses)}") print(f" - DTO Responses: {len(dto_responses)}")
print(f" - Autres DTOs: {len(dto_other)}") print(f" - Autres DTOs: {len(dto_other)}")
print(f" - Enums: {len(enums)}") print(f" - Enums: {len(enums)}")
print(f" - Autres: {len(others)}") print(f" - Autres: {len(others)}")
print("=" * 80) print("=" * 80)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -1,359 +1,359 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE module PUBLIC <!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd"> "https://checkstyle.org/dtds/configuration_1_3.dtd">
<!-- <!--
Configuration Checkstyle pour UnionFlow Configuration Checkstyle pour UnionFlow
Basée sur Google Java Style Guide avec adaptations pour UnionFlow Basée sur Google Java Style Guide avec adaptations pour UnionFlow
Objectif : 100% de conformité (zéro violation) Objectif : 100% de conformité (zéro violation)
@author UnionFlow Team @author UnionFlow Team
@version 1.0 @version 1.0
@since 2025-01-10 @since 2025-01-10
--> -->
<module name="Checker"> <module name="Checker">
<property name="charset" value="UTF-8"/> <property name="charset" value="UTF-8"/>
<property name="severity" value="error"/> <property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/> <property name="fileExtensions" value="java, properties, xml"/>
<!-- Suppressions pour les fichiers générés --> <!-- Suppressions pour les fichiers générés -->
<module name="SuppressionFilter"> <module name="SuppressionFilter">
<property name="file" value="${org.checkstyle.google.suppressionfilter.config}" <property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
default="checkstyle-suppressions.xml" /> default="checkstyle-suppressions.xml" />
<property name="optional" value="true"/> <property name="optional" value="true"/>
</module> </module>
<!-- Vérifications au niveau des fichiers --> <!-- Vérifications au niveau des fichiers -->
<module name="FileTabCharacter"> <module name="FileTabCharacter">
<property name="eachLine" value="true"/> <property name="eachLine" value="true"/>
</module> </module>
<module name="LineLength"> <module name="LineLength">
<property name="fileExtensions" value="java"/> <property name="fileExtensions" value="java"/>
<property name="max" value="120"/> <property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module> </module>
<module name="NewlineAtEndOfFile"/> <module name="NewlineAtEndOfFile"/>
<!-- Vérifications au niveau des arbres syntaxiques --> <!-- Vérifications au niveau des arbres syntaxiques -->
<module name="TreeWalker"> <module name="TreeWalker">
<!-- Annotations --> <!-- Annotations -->
<module name="AnnotationLocation"> <module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/> <property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/> <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
</module> </module>
<module name="AnnotationLocation"> <module name="AnnotationLocation">
<property name="id" value="AnnotationLocationVariables"/> <property name="id" value="AnnotationLocationVariables"/>
<property name="tokens" value="VARIABLE_DEF"/> <property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/> <property name="allowSamelineMultipleAnnotations" value="true"/>
</module> </module>
<module name="AnnotationUseStyle"/> <module name="AnnotationUseStyle"/>
<module name="MissingOverride"/> <module name="MissingOverride"/>
<!-- Blocs --> <!-- Blocs -->
<module name="AvoidNestedBlocks"/> <module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"> <module name="EmptyBlock">
<property name="option" value="TEXT"/> <property name="option" value="TEXT"/>
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/> <property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module> </module>
<module name="EmptyCatchBlock"> <module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/> <property name="exceptionVariableName" value="expected"/>
</module> </module>
<module name="LeftCurly"/> <module name="LeftCurly"/>
<module name="NeedBraces"/> <module name="NeedBraces"/>
<module name="RightCurly"> <module name="RightCurly">
<property name="id" value="RightCurlySame"/> <property name="id" value="RightCurlySame"/>
<property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_DO"/> <property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_DO"/>
</module> </module>
<module name="RightCurly"> <module name="RightCurly">
<property name="id" value="RightCurlyAlone"/> <property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/> <property name="option" value="alone"/>
<property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT, INSTANCE_INIT"/> <property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT, INSTANCE_INIT"/>
</module> </module>
<!-- Conception de classe --> <!-- Conception de classe -->
<module name="FinalClass"/> <module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/> <module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/> <module name="InterfaceIsType"/>
<module name="OneTopLevelClass"/> <module name="OneTopLevelClass"/>
<module name="VisibilityModifier"> <module name="VisibilityModifier">
<property name="protectedAllowed" value="true"/> <property name="protectedAllowed" value="true"/>
<property name="packageAllowed" value="true"/> <property name="packageAllowed" value="true"/>
</module> </module>
<!-- Codage --> <!-- Codage -->
<module name="ArrayTrailingComma"/> <module name="ArrayTrailingComma"/>
<module name="AvoidEscapedUnicodeCharacters"> <module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/> <property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/> <property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/> <property name="allowNonPrintableEscapes" value="true"/>
</module> </module>
<module name="CovariantEquals"/> <module name="CovariantEquals"/>
<module name="DeclarationOrder"/> <module name="DeclarationOrder"/>
<module name="DefaultComesLast"/> <module name="DefaultComesLast"/>
<module name="EmptyStatement"/> <module name="EmptyStatement"/>
<module name="EqualsAvoidNull"/> <module name="EqualsAvoidNull"/>
<module name="EqualsHashCode"/> <module name="EqualsHashCode"/>
<module name="ExplicitInitialization"/> <module name="ExplicitInitialization"/>
<module name="FallThrough"/> <module name="FallThrough"/>
<module name="IllegalInstantiation"/> <module name="IllegalInstantiation"/>
<module name="IllegalToken"/> <module name="IllegalToken"/>
<module name="IllegalTokenText"> <module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/> <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format" value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/> <property name="format" value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message" value="Consider using special escape sequence instead of octal value or Unicode escaped value."/> <property name="message" value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
</module> </module>
<module name="InnerAssignment"/> <module name="InnerAssignment"/>
<module name="MagicNumber"> <module name="MagicNumber">
<property name="ignoreNumbers" value="-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 1000"/> <property name="ignoreNumbers" value="-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 1000"/>
<property name="ignoreHashCodeMethod" value="true"/> <property name="ignoreHashCodeMethod" value="true"/>
<property name="ignoreAnnotation" value="true"/> <property name="ignoreAnnotation" value="true"/>
<property name="ignoreFieldDeclaration" value="true"/> <property name="ignoreFieldDeclaration" value="true"/>
</module> </module>
<module name="MissingSwitchDefault"/> <module name="MissingSwitchDefault"/>
<module name="ModifiedControlVariable"/> <module name="ModifiedControlVariable"/>
<module name="MultipleStringLiterals"> <module name="MultipleStringLiterals">
<property name="allowedDuplicates" value="3"/> <property name="allowedDuplicates" value="3"/>
</module> </module>
<module name="MultipleVariableDeclarations"/> <module name="MultipleVariableDeclarations"/>
<module name="NoClone"/> <module name="NoClone"/>
<module name="NoFinalizer"/> <module name="NoFinalizer"/>
<module name="OneStatementPerLine"/> <module name="OneStatementPerLine"/>
<module name="OverloadMethodsDeclarationOrder"/> <module name="OverloadMethodsDeclarationOrder"/>
<module name="PackageDeclaration"/> <module name="PackageDeclaration"/>
<module name="ParameterAssignment"/> <module name="ParameterAssignment"/>
<module name="RequireThis"> <module name="RequireThis">
<property name="checkFields" value="false"/> <property name="checkFields" value="false"/>
<property name="checkMethods" value="false"/> <property name="checkMethods" value="false"/>
</module> </module>
<module name="SimplifyBooleanExpression"/> <module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/> <module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/> <module name="StringLiteralEquality"/>
<module name="UnnecessaryParentheses"/> <module name="UnnecessaryParentheses"/>
<module name="VariableDeclarationUsageDistance"/> <module name="VariableDeclarationUsageDistance"/>
<!-- Imports --> <!-- Imports -->
<module name="AvoidStarImport"/> <module name="AvoidStarImport"/>
<module name="AvoidStaticImport"> <module name="AvoidStaticImport">
<property name="excludes" value="org.assertj.core.api.Assertions.*,org.junit.jupiter.api.Assertions.*,org.mockito.Mockito.*"/> <property name="excludes" value="org.assertj.core.api.Assertions.*,org.junit.jupiter.api.Assertions.*,org.mockito.Mockito.*"/>
</module> </module>
<module name="CustomImportOrder"> <module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="true"/> <property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="true"/> <property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/> <property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/>
</module> </module>
<module name="IllegalImport"/> <module name="IllegalImport"/>
<module name="RedundantImport"/> <module name="RedundantImport"/>
<module name="UnusedImports"/> <module name="UnusedImports"/>
<!-- Javadoc --> <!-- Javadoc -->
<module name="AtclauseOrder"> <module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/> <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> <property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module> </module>
<module name="InvalidJavadocPosition"/> <module name="InvalidJavadocPosition"/>
<module name="JavadocMethod"> <module name="JavadocMethod">
<property name="allowMissingParamTags" value="false"/> <property name="allowMissingParamTags" value="false"/>
<property name="allowMissingReturnTag" value="false"/> <property name="allowMissingReturnTag" value="false"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/> <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
</module> </module>
<module name="JavadocParagraph"/> <module name="JavadocParagraph"/>
<module name="JavadocStyle"/> <module name="JavadocStyle"/>
<module name="JavadocTagContinuationIndentation"/> <module name="JavadocTagContinuationIndentation"/>
<module name="JavadocType"/> <module name="JavadocType"/>
<module name="MissingJavadocMethod"> <module name="MissingJavadocMethod">
<property name="minLineCount" value="2"/> <property name="minLineCount" value="2"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/> <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
</module> </module>
<module name="MissingJavadocType"/> <module name="MissingJavadocType"/>
<module name="NonEmptyAtclauseDescription"/> <module name="NonEmptyAtclauseDescription"/>
<module name="SingleLineJavadoc"> <module name="SingleLineJavadoc">
<property name="ignoreInlineTags" value="false"/> <property name="ignoreInlineTags" value="false"/>
</module> </module>
<module name="SummaryJavadoc"> <module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/> <property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module> </module>
<!-- Métriques --> <!-- Métriques -->
<module name="BooleanExpressionComplexity"> <module name="BooleanExpressionComplexity">
<property name="max" value="7"/> <property name="max" value="7"/>
</module> </module>
<module name="ClassDataAbstractionCoupling"> <module name="ClassDataAbstractionCoupling">
<property name="max" value="15"/> <property name="max" value="15"/>
</module> </module>
<module name="ClassFanOutComplexity"> <module name="ClassFanOutComplexity">
<property name="max" value="25"/> <property name="max" value="25"/>
</module> </module>
<module name="CyclomaticComplexity"> <module name="CyclomaticComplexity">
<property name="max" value="15"/> <property name="max" value="15"/>
</module> </module>
<module name="JavaNCSS"> <module name="JavaNCSS">
<property name="methodMaximum" value="80"/> <property name="methodMaximum" value="80"/>
<property name="classMaximum" value="2000"/> <property name="classMaximum" value="2000"/>
</module> </module>
<module name="NPathComplexity"> <module name="NPathComplexity">
<property name="max" value="200"/> <property name="max" value="200"/>
</module> </module>
<!-- Divers --> <!-- Divers -->
<module name="ArrayTypeStyle"/> <module name="ArrayTypeStyle"/>
<module name="CommentsIndentation"/> <module name="CommentsIndentation"/>
<module name="Indentation"> <module name="Indentation">
<property name="basicOffset" value="4"/> <property name="basicOffset" value="4"/>
<property name="braceAdjustment" value="0"/> <property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="4"/> <property name="caseIndent" value="4"/>
<property name="throwsIndent" value="8"/> <property name="throwsIndent" value="8"/>
<property name="lineWrappingIndentation" value="8"/> <property name="lineWrappingIndentation" value="8"/>
<property name="arrayInitIndent" value="4"/> <property name="arrayInitIndent" value="4"/>
</module> </module>
<module name="OuterTypeFilename"/> <module name="OuterTypeFilename"/>
<module name="TodoComment"> <module name="TodoComment">
<property name="format" value="(TODO)|(FIXME)"/> <property name="format" value="(TODO)|(FIXME)"/>
</module> </module>
<module name="TrailingComment"/> <module name="TrailingComment"/>
<module name="UncommentedMain"> <module name="UncommentedMain">
<property name="excludedClasses" value="\.Main$"/> <property name="excludedClasses" value="\.Main$"/>
</module> </module>
<module name="UpperEll"/> <module name="UpperEll"/>
<!-- Modificateurs --> <!-- Modificateurs -->
<module name="ModifierOrder"/> <module name="ModifierOrder"/>
<module name="RedundantModifier"/> <module name="RedundantModifier"/>
<!-- Conventions de nommage --> <!-- Conventions de nommage -->
<module name="AbbreviationAsWordInName"> <module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/> <property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="4"/> <property name="allowedAbbreviationLength" value="4"/>
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF, PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF"/> <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF, PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF"/>
</module> </module>
<module name="ClassTypeParameterName"> <module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern" value="Class type name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="ConstantName"/> <module name="ConstantName"/>
<module name="InterfaceTypeParameterName"> <module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern" value="Interface type name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="LocalFinalVariableName"/> <module name="LocalFinalVariableName"/>
<module name="LocalVariableName"> <module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/> <property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern" value="Local variable name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="MemberName"> <module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/> <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern" value="Member name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Member name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="MethodName"> <module name="MethodName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/> <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern" value="Method name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Method name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="MethodTypeParameterName"> <module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern" value="Method type name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="PackageName"> <module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/> <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern" value="Package name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Package name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="ParameterName"> <module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern" value="Parameter name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="StaticVariableName"/> <module name="StaticVariableName"/>
<module name="TypeName"> <module name="TypeName">
<message key="name.invalidPattern" value="Type name ''{0}'' must match pattern ''{1}''."/> <message key="name.invalidPattern" value="Type name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<!-- Taille --> <!-- Taille -->
<module name="AnonInnerLength"> <module name="AnonInnerLength">
<property name="max" value="30"/> <property name="max" value="30"/>
</module> </module>
<module name="ExecutableStatementCount"> <module name="ExecutableStatementCount">
<property name="max" value="50"/> <property name="max" value="50"/>
</module> </module>
<module name="LineLength"> <module name="LineLength">
<property name="max" value="120"/> <property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module> </module>
<module name="MethodCount"> <module name="MethodCount">
<property name="maxTotal" value="50"/> <property name="maxTotal" value="50"/>
<property name="maxPrivate" value="30"/> <property name="maxPrivate" value="30"/>
<property name="maxPackage" value="30"/> <property name="maxPackage" value="30"/>
<property name="maxProtected" value="30"/> <property name="maxProtected" value="30"/>
<property name="maxPublic" value="30"/> <property name="maxPublic" value="30"/>
</module> </module>
<module name="MethodLength"> <module name="MethodLength">
<property name="tokens" value="METHOD_DEF, CTOR_DEF"/> <property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
<property name="max" value="100"/> <property name="max" value="100"/>
</module> </module>
<module name="OuterTypeNumber"/> <module name="OuterTypeNumber"/>
<module name="ParameterNumber"> <module name="ParameterNumber">
<property name="max" value="8"/> <property name="max" value="8"/>
<property name="ignoreOverriddenMethods" value="true"/> <property name="ignoreOverriddenMethods" value="true"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF"/> <property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
</module> </module>
<!-- Espaces blancs --> <!-- Espaces blancs -->
<module name="EmptyForIteratorPad"/> <module name="EmptyForIteratorPad"/>
<module name="EmptyLineSeparator"> <module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/> <property name="allowNoEmptyLineBetweenFields" value="true"/>
</module> </module>
<module name="GenericWhitespace"> <module name="GenericWhitespace">
<message key="ws.followed" value="GenericWhitespace ''{0}'' is followed by whitespace."/> <message key="ws.followed" value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded" value="GenericWhitespace ''{0}'' is preceded with whitespace."/> <message key="ws.preceded" value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow" value="GenericWhitespace ''{0}'' should followed by whitespace."/> <message key="ws.illegalFollow" value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded" value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> <message key="ws.notPreceded" value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module> </module>
<module name="MethodParamPad"/> <module name="MethodParamPad"/>
<module name="NoLineWrap"/> <module name="NoLineWrap"/>
<module name="NoWhitespaceAfter"/> <module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/> <module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"> <module name="OperatorWrap">
<property name="option" value="NL"/> <property name="option" value="NL"/>
<property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/> <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
</module> </module>
<module name="ParenPad"/> <module name="ParenPad"/>
<module name="SeparatorWrap"> <module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot"/> <property name="id" value="SeparatorWrapDot"/>
<property name="tokens" value="DOT"/> <property name="tokens" value="DOT"/>
<property name="option" value="nl"/> <property name="option" value="nl"/>
</module> </module>
<module name="SeparatorWrap"> <module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma"/> <property name="id" value="SeparatorWrapComma"/>
<property name="tokens" value="COMMA"/> <property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/> <property name="option" value="EOL"/>
</module> </module>
<module name="SeparatorWrap"> <module name="SeparatorWrap">
<property name="id" value="SeparatorWrapEllipsis"/> <property name="id" value="SeparatorWrapEllipsis"/>
<property name="tokens" value="ELLIPSIS"/> <property name="tokens" value="ELLIPSIS"/>
<property name="option" value="EOL"/> <property name="option" value="EOL"/>
</module> </module>
<module name="SeparatorWrap"> <module name="SeparatorWrap">
<property name="id" value="SeparatorWrapArrayDeclarator"/> <property name="id" value="SeparatorWrapArrayDeclarator"/>
<property name="tokens" value="ARRAY_DECLARATOR"/> <property name="tokens" value="ARRAY_DECLARATOR"/>
<property name="option" value="EOL"/> <property name="option" value="EOL"/>
</module> </module>
<module name="SeparatorWrap"> <module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef"/> <property name="id" value="SeparatorWrapMethodRef"/>
<property name="tokens" value="METHOD_REF"/> <property name="tokens" value="METHOD_REF"/>
<property name="option" value="nl"/> <property name="option" value="nl"/>
</module> </module>
<module name="TypecastParenPad"/> <module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/> <module name="WhitespaceAfter"/>
<module name="WhitespaceAround"> <module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/> <property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/> <property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/> <property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/> <property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed" value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/> <message key="ws.notFollowed" value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded" value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/> <message key="ws.notPreceded" value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module> </module>
</module> </module>
</module> </module>

View File

@@ -1,2 +1,2 @@
config.stopBubbling = true config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true lombok.addLombokGeneratedAnnotation = true

View File

@@ -6,7 +6,7 @@
<groupId>dev.lions.unionflow</groupId> <groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-parent</artifactId> <artifactId>unionflow-parent</artifactId>
<version>1.0.5</version> <version>1.0.6</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>UnionFlow - Parent</name> <name>UnionFlow - Parent</name>

32
pom.xml
View File

@@ -4,23 +4,39 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <groupId>dev.lions.unionflow</groupId>
<groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-parent</artifactId>
<version>1.0.5</version>
<relativePath>parent-pom.xml</relativePath>
</parent>
<artifactId>unionflow-server-api</artifactId> <artifactId>unionflow-server-api</artifactId>
<version>1.0.7</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>UnionFlow Server API</name> <name>UnionFlow Server API</name>
<description>API définitions pour le serveur UnionFlow</description> <description>API définitions pour le serveur UnionFlow</description>
<distributionManagement>
<repository>
<id>gitea-lionsdev</id>
<url>https://git.lions.dev/api/packages/lionsdev/maven</url>
</repository>
</distributionManagement>
<repositories>
<repository>
<id>gitea-lionsdev</id>
<url>https://git.lions.dev/api/packages/lionsdev/maven</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
<properties> <properties>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.release>${java.version}</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<quarkus.platform.version>3.20.0</quarkus.platform.version> <quarkus.platform.version>3.27.3</quarkus.platform.version>
<lombok.version>1.18.38</lombok.version>
<jackson.version>2.18.2</jackson.version> <jackson.version>2.18.2</jackson.version>
<validation-api.version>3.0.2</validation-api.version> <validation-api.version>3.0.2</validation-api.version>
<microprofile-openapi.version>3.1.1</microprofile-openapi.version> <microprofile-openapi.version>3.1.1</microprofile-openapi.version>

View File

@@ -1,30 +1,30 @@
@echo off @echo off
REM Publie le parent pom + server-api sur le Gitea Package Registry REM Publie le parent pom + server-api sur le Gitea Package Registry
REM Usage : script\publish-api.bat REM Usage : script\publish-api.bat
REM Depuis : n'importe où dans le repo server-api REM Depuis : n'importe où dans le repo server-api
REM Prérequis: credentials dans %USERPROFILE%\.m2\settings.xml (server id: gitea-lionsdev) REM Prérequis: credentials dans %USERPROFILE%\.m2\settings.xml (server id: gitea-lionsdev)
set REGISTRY_URL=https://git.lions.dev/api/packages/lionsdev/maven set REGISTRY_URL=https://git.lions.dev/api/packages/lionsdev/maven
set REGISTRY_ID=gitea-lionsdev set REGISTRY_ID=gitea-lionsdev
cd /d "%~dp0\.." cd /d "%~dp0\.."
echo. echo.
echo [1/2] Publication du parent pom... echo [1/2] Publication du parent pom...
call mvn deploy:deploy-file ^ call mvn deploy:deploy-file ^
-DgroupId=dev.lions.unionflow ^ -DgroupId=dev.lions.unionflow ^
-DartifactId=unionflow-parent ^ -DartifactId=unionflow-parent ^
-Dversion=1.0.0 ^ -Dversion=1.0.0 ^
-Dpackaging=pom ^ -Dpackaging=pom ^
-Dfile=parent-pom.xml ^ -Dfile=parent-pom.xml ^
-DrepositoryId=%REGISTRY_ID% ^ -DrepositoryId=%REGISTRY_ID% ^
-Durl=%REGISTRY_URL% -Durl=%REGISTRY_URL%
if errorlevel 409 echo [WARN] Parent pom deja publie pour cette version, on continue. if errorlevel 409 echo [WARN] Parent pom deja publie pour cette version, on continue.
echo. echo.
echo [2/2] Publication du server-api... echo [2/2] Publication du server-api...
call mvn deploy -DskipTests call mvn deploy -DskipTests
if errorlevel 409 echo [WARN] Server-api deja publie - incrementer la version pour republier. if errorlevel 409 echo [WARN] Server-api deja publie - incrementer la version pour republier.
echo. echo.
echo Done -- https://git.lions.dev/lionsdev/-/packages echo Done -- https://git.lions.dev/lionsdev/-/packages

View File

@@ -1,82 +1,82 @@
package dev.lions.unionflow.server.api.dto.abonnement.request; package dev.lions.unionflow.server.api.dto.abonnement.request;
import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement; import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
import dev.lions.unionflow.server.api.enums.abonnement.TypePeriodeAbonnement; import dev.lions.unionflow.server.api.enums.abonnement.TypePeriodeAbonnement;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Future; import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un abonnement. * Requête de création d'un abonnement.
*/ */
@Builder @Builder
public record CreateAbonnementRequest( public record CreateAbonnementRequest(
@NotBlank(message = "Le numéro de référence est obligatoire") @Pattern(regexp = "^ABO-\\d{4}-[A-Z0-9]{8}$", message = "Format de référence invalide (ABO-YYYY-XXXXXXXX)") String numeroReference, @NotBlank(message = "Le numéro de référence est obligatoire") @Pattern(regexp = "^ABO-\\d{4}-[A-Z0-9]{8}$", message = "Format de référence invalide (ABO-YYYY-XXXXXXXX)") String numeroReference,
@NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId, @NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId,
String nomOrganisation, String nomOrganisation,
@NotNull(message = "L'identifiant de la formule est obligatoire") UUID formulaireId, @NotNull(message = "L'identifiant de la formule est obligatoire") UUID formulaireId,
String codeFormule, String codeFormule,
String nomFormule, String nomFormule,
TypeFormule typeFormule, TypeFormule typeFormule,
@NotNull(message = "Le statut est obligatoire") StatutAbonnement statut, @NotNull(message = "Le statut est obligatoire") StatutAbonnement statut,
@NotNull(message = "Le type d'abonnement est obligatoire") TypePeriodeAbonnement typeAbonnement, @NotNull(message = "Le type d'abonnement est obligatoire") TypePeriodeAbonnement typeAbonnement,
@NotNull(message = "La date de début est obligatoire") LocalDate dateDebut, @NotNull(message = "La date de début est obligatoire") LocalDate dateDebut,
@Future(message = "La date de fin doit être dans le futur") LocalDate dateFin, @Future(message = "La date de fin doit être dans le futur") LocalDate dateFin,
LocalDate dateProchainePeriode, LocalDate dateProchainePeriode,
@NotNull(message = "Le montant est obligatoire") @DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montant, @NotNull(message = "Le montant est obligatoire") @DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montant,
@NotBlank(message = "La devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres") String devise, @NotBlank(message = "La devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres") String devise,
@DecimalMin(value = "0.0", message = "La remise doit être positive") @DecimalMin(value = "100.0", message = "La remise ne peut pas dépasser 100%") BigDecimal remise, @DecimalMin(value = "0.0", message = "La remise doit être positive") @DecimalMin(value = "100.0", message = "La remise ne peut pas dépasser 100%") BigDecimal remise,
@DecimalMin(value = "0.0", message = "Le montant final doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montantFinal, @DecimalMin(value = "0.0", message = "Le montant final doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montantFinal,
Boolean renouvellementAutomatique, Boolean renouvellementAutomatique,
Boolean periodeEssaiUtilisee, Boolean periodeEssaiUtilisee,
LocalDate dateFinEssai, LocalDate dateFinEssai,
Integer maxMembres, Integer maxMembres,
Integer nombreMembresActuels, Integer nombreMembresActuels,
BigDecimal espaceStockageGB, BigDecimal espaceStockageGB,
BigDecimal espaceStockageUtilise, BigDecimal espaceStockageUtilise,
Boolean supportTechnique, Boolean supportTechnique,
String niveauSupport, String niveauSupport,
Boolean fonctionnalitesAvancees, Boolean fonctionnalitesAvancees,
Boolean apiAccess, Boolean apiAccess,
Boolean rapportsPersonnalises, Boolean rapportsPersonnalises,
Boolean integrationsTierces, Boolean integrationsTierces,
UUID responsableId, UUID responsableId,
String nomResponsable, String nomResponsable,
String emailResponsable, String emailResponsable,
String telephoneResponsable, String telephoneResponsable,
@Pattern(regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|AUTRE)$", message = "Mode de paiement invalide") String modePaiementPrefere, @Pattern(regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|AUTRE)$", message = "Mode de paiement invalide") String modePaiementPrefere,
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Format de numéro de téléphone invalide") String numeroPaiementMobile, @Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Format de numéro de téléphone invalide") String numeroPaiementMobile,
@Size(max = 5000, message = "L'historique ne peut pas dépasser 5000 caractères") String historiquePaiements, @Size(max = 5000, message = "L'historique ne peut pas dépasser 5000 caractères") String historiquePaiements,
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères") String notes, @Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères") String notes,
Boolean alertesActivees, Boolean alertesActivees,
Boolean notificationsEmail, Boolean notificationsEmail,
Boolean notificationsSMS) { Boolean notificationsSMS) {
} }

View File

@@ -1,77 +1,77 @@
package dev.lions.unionflow.server.api.dto.abonnement.request; package dev.lions.unionflow.server.api.dto.abonnement.request;
import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement; import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
import dev.lions.unionflow.server.api.enums.abonnement.TypePeriodeAbonnement; import dev.lions.unionflow.server.api.enums.abonnement.TypePeriodeAbonnement;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Future; import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'un abonnement. * Requête de mise à jour d'un abonnement.
*/ */
@Builder @Builder
public record UpdateAbonnementRequest( public record UpdateAbonnementRequest(
@Pattern(regexp = "^ABO-\\d{4}-[A-Z0-9]{8}$", message = "Format de référence invalide (ABO-YYYY-XXXXXXXX)") String numeroReference, @Pattern(regexp = "^ABO-\\d{4}-[A-Z0-9]{8}$", message = "Format de référence invalide (ABO-YYYY-XXXXXXXX)") String numeroReference,
UUID organisationId, UUID organisationId,
String nomOrganisation, String nomOrganisation,
UUID formulaireId, UUID formulaireId,
String codeFormule, String codeFormule,
String nomFormule, String nomFormule,
TypeFormule typeFormule, TypeFormule typeFormule,
StatutAbonnement statut, StatutAbonnement statut,
TypePeriodeAbonnement typeAbonnement, TypePeriodeAbonnement typeAbonnement,
LocalDate dateDebut, LocalDate dateDebut,
@Future(message = "La date de fin doit être dans le futur") LocalDate dateFin, @Future(message = "La date de fin doit être dans le futur") LocalDate dateFin,
LocalDate dateProchainePeriode, LocalDate dateProchainePeriode,
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montant, @DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montant,
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres") String devise, @Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres") String devise,
@DecimalMin(value = "0.0", message = "La remise doit être positive") @DecimalMin(value = "100.0", message = "La remise ne peut pas dépasser 100%") BigDecimal remise, @DecimalMin(value = "0.0", message = "La remise doit être positive") @DecimalMin(value = "100.0", message = "La remise ne peut pas dépasser 100%") BigDecimal remise,
@DecimalMin(value = "0.0", message = "Le montant final doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montantFinal, @DecimalMin(value = "0.0", message = "Le montant final doit être positif") @Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales") BigDecimal montantFinal,
Boolean renouvellementAutomatique, Boolean renouvellementAutomatique,
Boolean periodeEssaiUtilisee, Boolean periodeEssaiUtilisee,
LocalDate dateFinEssai, LocalDate dateFinEssai,
Integer maxMembres, Integer maxMembres,
Integer nombreMembresActuels, Integer nombreMembresActuels,
BigDecimal espaceStockageGB, BigDecimal espaceStockageGB,
BigDecimal espaceStockageUtilise, BigDecimal espaceStockageUtilise,
Boolean supportTechnique, Boolean supportTechnique,
String niveauSupport, String niveauSupport,
Boolean fonctionnalitesAvancees, Boolean fonctionnalitesAvancees,
Boolean apiAccess, Boolean apiAccess,
Boolean rapportsPersonnalises, Boolean rapportsPersonnalises,
Boolean integrationsTierces, Boolean integrationsTierces,
UUID responsableId, UUID responsableId,
String nomResponsable, String nomResponsable,
String emailResponsable, String emailResponsable,
String telephoneResponsable, String telephoneResponsable,
@Pattern(regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|AUTRE)$", message = "Mode de paiement invalide") String modePaiementPrefere, @Pattern(regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|AUTRE)$", message = "Mode de paiement invalide") String modePaiementPrefere,
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Format de numéro de téléphone invalide") String numeroPaiementMobile, @Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Format de numéro de téléphone invalide") String numeroPaiementMobile,
@Size(max = 5000, message = "L'historique ne peut pas dépasser 5000 caractères") String historiquePaiements, @Size(max = 5000, message = "L'historique ne peut pas dépasser 5000 caractères") String historiquePaiements,
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères") String notes, @Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères") String notes,
Boolean alertesActivees, Boolean alertesActivees,
Boolean notificationsEmail, Boolean notificationsEmail,
Boolean notificationsSMS) { Boolean notificationsSMS) {
} }

View File

@@ -1,133 +1,133 @@
package dev.lions.unionflow.server.api.dto.abonnement.response; package dev.lions.unionflow.server.api.dto.abonnement.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement; import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
import dev.lions.unionflow.server.api.enums.abonnement.TypePeriodeAbonnement; import dev.lions.unionflow.server.api.enums.abonnement.TypePeriodeAbonnement;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée pour un abonnement. * Réponse détaillée pour un abonnement.
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class AbonnementResponse extends BaseResponse { public class AbonnementResponse extends BaseResponse {
private String numeroReference; private String numeroReference;
private UUID organisationId; private UUID organisationId;
private String nomOrganisation; private String nomOrganisation;
private UUID formulaireId; private UUID formulaireId;
private String codeFormule; private String codeFormule;
private String nomFormule; private String nomFormule;
private TypeFormule typeFormule; private TypeFormule typeFormule;
private StatutAbonnement statut; private StatutAbonnement statut;
private TypePeriodeAbonnement typeAbonnement; private TypePeriodeAbonnement typeAbonnement;
private LocalDate dateDebut; private LocalDate dateDebut;
private LocalDate dateFin; private LocalDate dateFin;
private LocalDate dateProchainePeriode; private LocalDate dateProchainePeriode;
private BigDecimal montant; private BigDecimal montant;
private String devise; private String devise;
private BigDecimal remise; private BigDecimal remise;
private BigDecimal montantFinal; private BigDecimal montantFinal;
private Boolean renouvellementAutomatique; private Boolean renouvellementAutomatique;
private Boolean periodeEssaiUtilisee; private Boolean periodeEssaiUtilisee;
private LocalDate dateFinEssai; private LocalDate dateFinEssai;
private Integer maxMembres; private Integer maxMembres;
private Integer nombreMembresActuels; private Integer nombreMembresActuels;
private BigDecimal espaceStockageGB; private BigDecimal espaceStockageGB;
private BigDecimal espaceStockageUtilise; private BigDecimal espaceStockageUtilise;
private Boolean supportTechnique; private Boolean supportTechnique;
private String niveauSupport; private String niveauSupport;
private Boolean fonctionnalitesAvancees; private Boolean fonctionnalitesAvancees;
private Boolean apiAccess; private Boolean apiAccess;
private Boolean rapportsPersonnalises; private Boolean rapportsPersonnalises;
private Boolean integrationsTierces; private Boolean integrationsTierces;
private LocalDateTime dateDerniereUtilisation; private LocalDateTime dateDerniereUtilisation;
private Integer connexionsCeMois; private Integer connexionsCeMois;
private UUID responsableId; private UUID responsableId;
private String nomResponsable; private String nomResponsable;
private String emailResponsable; private String emailResponsable;
private String telephoneResponsable; private String telephoneResponsable;
private String modePaiementPrefere; private String modePaiementPrefere;
private String numeroPaiementMobile; private String numeroPaiementMobile;
private String historiquePaiements; private String historiquePaiements;
private String notes; private String notes;
private Boolean alertesActivees; private Boolean alertesActivees;
private Boolean notificationsEmail; private Boolean notificationsEmail;
private Boolean notificationsSMS; private Boolean notificationsSMS;
private LocalDateTime dateSuspension; private LocalDateTime dateSuspension;
private String raisonSuspension; private String raisonSuspension;
private LocalDateTime dateAnnulation; private LocalDateTime dateAnnulation;
private String raisonAnnulation; private String raisonAnnulation;
// === MÉTHODES UTILITAIRES === // === MÉTHODES UTILITAIRES ===
public boolean isActive() { public boolean isActive() {
return StatutAbonnement.ACTIF.equals(statut); return StatutAbonnement.ACTIF.equals(statut);
} }
public boolean isExpire() { public boolean isExpire() {
return StatutAbonnement.EXPIRE.equals(statut) || return StatutAbonnement.EXPIRE.equals(statut) ||
(dateFin != null && dateFin.isBefore(LocalDate.now())); (dateFin != null && dateFin.isBefore(LocalDate.now()));
} }
public boolean isSuspendu() { public boolean isSuspendu() {
return StatutAbonnement.SUSPENDU.equals(statut); return StatutAbonnement.SUSPENDU.equals(statut);
} }
public int getMembresRestants() { public int getMembresRestants() {
if (maxMembres == null) return 0; if (maxMembres == null) return 0;
int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0; int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0;
return Math.max(0, maxMembres - actuels); return Math.max(0, maxMembres - actuels);
} }
public boolean isQuotaAtteint() { public boolean isQuotaAtteint() {
if (maxMembres == null) return false; if (maxMembres == null) return false;
int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0; int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0;
return actuels >= maxMembres; return actuels >= maxMembres;
} }
public int getPourcentageUtilisation() { public int getPourcentageUtilisation() {
if (maxMembres == null || maxMembres == 0) return 0; if (maxMembres == null || maxMembres == 0) return 0;
int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0; int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0;
return (actuels * 100) / maxMembres; return (actuels * 100) / maxMembres;
} }
public long getJoursRestants() { public long getJoursRestants() {
if (dateFin == null) return -1; if (dateFin == null) return -1;
LocalDate maintenant = LocalDate.now(); LocalDate maintenant = LocalDate.now();
if (maintenant.isAfter(dateFin)) return 0; if (maintenant.isAfter(dateFin)) return 0;
return java.time.temporal.ChronoUnit.DAYS.between(maintenant, dateFin); return java.time.temporal.ChronoUnit.DAYS.between(maintenant, dateFin);
} }
public boolean isExpirationProche() { public boolean isExpirationProche() {
long joursRestants = getJoursRestants(); long joursRestants = getJoursRestants();
return joursRestants >= 0 && joursRestants <= 30; return joursRestants >= 0 && joursRestants <= 30;
} }
public boolean peutEtreRenouvele() { public boolean peutEtreRenouvele() {
return Boolean.TRUE.equals(renouvellementAutomatique) && !isExpire(); return Boolean.TRUE.equals(renouvellementAutomatique) && !isExpire();
} }
public String getStatutLibelle() { public String getStatutLibelle() {
return statut != null ? statut.name() : "INCONNU"; return statut != null ? statut.name() : "INCONNU";
} }
} }

View File

@@ -1,29 +1,29 @@
package dev.lions.unionflow.server.api.dto.admin.request; package dev.lions.unionflow.server.api.dto.admin.request;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un log d'audit. * Requête de création d'un log d'audit.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateAuditLogRequest( public record CreateAuditLogRequest(
String typeAction, String typeAction,
String severite, String severite,
String utilisateur, String utilisateur,
String role, String role,
String module, String module,
String description, String description,
String details, String details,
String ipAddress, String ipAddress,
String userAgent, String userAgent,
String sessionId, String sessionId,
LocalDateTime dateHeure, LocalDateTime dateHeure,
String donneesAvant, String donneesAvant,
String donneesApres, String donneesApres,
String entiteId, String entiteId,
String entiteType) { String entiteType) {
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.admin.response; package dev.lions.unionflow.server.api.dto.admin.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse pour les logs d'audit. * Réponse pour les logs d'audit.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
public class AuditLogResponse extends BaseResponse { public class AuditLogResponse extends BaseResponse {
private String typeAction; private String typeAction;
private String severite; private String severite;
private String utilisateur; private String utilisateur;
private String role; private String role;
private String module; private String module;
private String description; private String description;
private String details; private String details;
private String ipAddress; private String ipAddress;
private String userAgent; private String userAgent;
private String sessionId; private String sessionId;
private LocalDateTime dateHeure; private LocalDateTime dateHeure;
private String donneesAvant; private String donneesAvant;
private String donneesApres; private String donneesApres;
private String entiteId; private String entiteId;
private String entiteType; private String entiteType;
} }

View File

@@ -1,43 +1,43 @@
package dev.lions.unionflow.server.api.dto.adresse.request; package dev.lions.unionflow.server.api.dto.adresse.request;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
/** /**
* Requete de création d'une adresse. * Requete de création d'une adresse.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
*/ */
public record CreateAdresseRequest( public record CreateAdresseRequest(
@NotBlank(message = "Le type d'adresse est obligatoire") String typeAdresse, // Code depuis types_reference @NotBlank(message = "Le type d'adresse est obligatoire") String typeAdresse, // Code depuis types_reference
@NotBlank(message = "L'adresse est obligatoire") String adresse, @NotBlank(message = "L'adresse est obligatoire") String adresse,
String complementAdresse, String complementAdresse,
String codePostal, String codePostal,
@NotBlank(message = "La ville est obligatoire") String ville, @NotBlank(message = "La ville est obligatoire") String ville,
String region, String region,
@NotBlank(message = "Le pays est obligatoire") String pays, @NotBlank(message = "Le pays est obligatoire") String pays,
@DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90") @DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90") @Digits(integer = 3, fraction = 6) BigDecimal latitude, // Optionnel @DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90") @DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90") @Digits(integer = 3, fraction = 6) BigDecimal latitude, // Optionnel
@DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180") @DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180") @Digits(integer = 3, fraction = 6) BigDecimal longitude, // Optionnel @DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180") @DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180") @Digits(integer = 3, fraction = 6) BigDecimal longitude, // Optionnel
@NotNull(message = "L'indicateur principale est obligatoire") Boolean principale, @NotNull(message = "L'indicateur principale est obligatoire") Boolean principale,
String libelle, String libelle,
String notes, String notes,
UUID organisationId, // Exclusive: soit organisationId, soit membreId, soit evenementId UUID organisationId, // Exclusive: soit organisationId, soit membreId, soit evenementId
UUID membreId, UUID membreId,
UUID evenementId) { UUID evenementId) {
} }

View File

@@ -1,36 +1,36 @@
package dev.lions.unionflow.server.api.dto.adresse.request; package dev.lions.unionflow.server.api.dto.adresse.request;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
/** /**
* Requete de mise à jour d'une adresse. * Requete de mise à jour d'une adresse.
* Tous les champs sont optionnels pour permettre des mises à jour partielles. * Tous les champs sont optionnels pour permettre des mises à jour partielles.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
*/ */
public record UpdateAdresseRequest( public record UpdateAdresseRequest(
String typeAdresse, // Code depuis types_reference String typeAdresse, // Code depuis types_reference
String adresse, String adresse,
String complementAdresse, String complementAdresse,
String codePostal, String codePostal,
String ville, String ville,
String region, String region,
String pays, String pays,
@DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90") @DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90") @Digits(integer = 3, fraction = 6) BigDecimal latitude, @DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90") @DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90") @Digits(integer = 3, fraction = 6) BigDecimal latitude,
@DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180") @DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180") @Digits(integer = 3, fraction = 6) BigDecimal longitude, @DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180") @DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180") @Digits(integer = 3, fraction = 6) BigDecimal longitude,
Boolean principale, Boolean principale,
String libelle, String libelle,
String notes, String notes,
UUID organisationId, UUID organisationId,
UUID membreId, UUID membreId,
UUID evenementId) { UUID evenementId) {
} }

View File

@@ -1,42 +1,42 @@
package dev.lions.unionflow.server.api.dto.adresse.response; package dev.lions.unionflow.server.api.dto.adresse.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** /**
* DTO de réponse détaillée pour une adresse. * DTO de réponse détaillée pour une adresse.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
*/ */
@Getter @Getter
@Setter @Setter
public class AdresseResponse extends BaseResponse { public class AdresseResponse extends BaseResponse {
private String typeAdresse; // Code private String typeAdresse; // Code
private String typeAdresseLibelle; // Depuis types_reference private String typeAdresseLibelle; // Depuis types_reference
private String typeAdresseIcone; private String typeAdresseIcone;
private String adresse; private String adresse;
private String complementAdresse; private String complementAdresse;
private String codePostal; private String codePostal;
private String ville; private String ville;
private String region; private String region;
private String pays; private String pays;
private BigDecimal latitude; private BigDecimal latitude;
private BigDecimal longitude; private BigDecimal longitude;
private Boolean principale; private Boolean principale;
private String libelle; private String libelle;
private String notes; private String notes;
private UUID organisationId; private UUID organisationId;
private UUID membreId; private UUID membreId;
private UUID evenementId; private UUID evenementId;
private String adresseComplete; private String adresseComplete;
} }

View File

@@ -1,35 +1,35 @@
package dev.lions.unionflow.server.api.dto.agricole; package dev.lions.unionflow.server.api.dto.agricole;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.agricole.StatutCampagneAgricole; import dev.lions.unionflow.server.api.enums.agricole.StatutCampagneAgricole;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class CampagneAgricoleDTO extends BaseDTO { public class CampagneAgricoleDTO extends BaseDTO {
private String organisationCoopId; private String organisationCoopId;
// Exemple : "Campagne d'Arachide 2025/2026" // Exemple : "Campagne d'Arachide 2025/2026"
private String designation; private String designation;
private String typeCulturePrincipale; private String typeCulturePrincipale;
// Nombre d'hectares au total couvert par les membres de la coop // Nombre d'hectares au total couvert par les membres de la coop
private BigDecimal surfaceTotaleEstimeeHectares; private BigDecimal surfaceTotaleEstimeeHectares;
// Tonnes récoltées attendues vs réelles // Tonnes récoltées attendues vs réelles
private BigDecimal volumePrevisionnelTonnes; private BigDecimal volumePrevisionnelTonnes;
private BigDecimal volumeReelTonnes; private BigDecimal volumeReelTonnes;
private StatutCampagneAgricole statut; private StatutCampagneAgricole statut;
} }

View File

@@ -1,265 +1,265 @@
package dev.lions.unionflow.server.api.dto.analytics; package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse; import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique; import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* DTO pour les données analytics UnionFlow * DTO pour les données analytics UnionFlow
* *
* <p> * <p>
* Représente une donnée analytique avec sa valeur, sa métrique associée, sa * Représente une donnée analytique avec sa valeur, sa métrique associée, sa
* période d'analyse et * période d'analyse et
* ses métadonnées. * ses métadonnées.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-16 * @since 2025-01-16
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class AnalyticsDataResponse extends BaseDTO { public class AnalyticsDataResponse extends BaseDTO {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** Type de métrique analysée */ /** Type de métrique analysée */
@NotNull(message = "Le type de métrique est obligatoire") @NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique; private TypeMetrique typeMetrique;
/** Période d'analyse */ /** Période d'analyse */
@NotNull(message = "La période d'analyse est obligatoire") @NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse; private PeriodeAnalyse periodeAnalyse;
/** Valeur numérique de la métrique */ /** Valeur numérique de la métrique */
@NotNull(message = "La valeur est obligatoire") @NotNull(message = "La valeur est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur invalide")
private BigDecimal valeur; private BigDecimal valeur;
/** Valeur précédente pour comparaison */ /** Valeur précédente pour comparaison */
@DecimalMin(value = "0.0", message = "La valeur précédente doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur précédente doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur précédente invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur précédente invalide")
private BigDecimal valeurPrecedente; private BigDecimal valeurPrecedente;
/** Pourcentage d'évolution par rapport à la période précédente */ /** Pourcentage d'évolution par rapport à la période précédente */
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide") @Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
private BigDecimal pourcentageEvolution; private BigDecimal pourcentageEvolution;
/** Date de début de la période analysée */ /** Date de début de la période analysée */
@NotNull(message = "La date de début est obligatoire") @NotNull(message = "La date de début est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebut; private LocalDateTime dateDebut;
/** Date de fin de la période analysée */ /** Date de fin de la période analysée */
@NotNull(message = "La date de fin est obligatoire") @NotNull(message = "La date de fin est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFin; private LocalDateTime dateFin;
/** Date de calcul de la métrique */ /** Date de calcul de la métrique */
@NotNull(message = "La date de calcul est obligatoire") @NotNull(message = "La date de calcul est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateCalcul; private LocalDateTime dateCalcul;
/** Identifiant de l'organisation (optionnel pour filtrage) */ /** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId; private UUID organisationId;
/** Nom de l'organisation */ /** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation; private String nomOrganisation;
/** Identifiant de l'utilisateur qui a demandé le calcul */ /** Identifiant de l'utilisateur qui a demandé le calcul */
private UUID utilisateurId; private UUID utilisateurId;
/** Nom de l'utilisateur qui a demandé le calcul */ /** Nom de l'utilisateur qui a demandé le calcul */
@Size(max = 200, message = "Le nom de l'utilisateur ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de l'utilisateur ne peut pas dépasser 200 caractères")
private String nomUtilisateur; private String nomUtilisateur;
/** Libellé personnalisé de la métrique */ /** Libellé personnalisé de la métrique */
@Size(max = 300, message = "Le libellé personnalisé ne peut pas dépasser 300 caractères") @Size(max = 300, message = "Le libellé personnalisé ne peut pas dépasser 300 caractères")
private String libellePersonnalise; private String libellePersonnalise;
/** Description ou commentaire sur la métrique */ /** Description ou commentaire sur la métrique */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") @Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
private String description; private String description;
/** Données détaillées pour les graphiques (format JSON) */ /** Données détaillées pour les graphiques (format JSON) */
@Size(max = 10000, message = "Les données détaillées ne peuvent pas dépasser 10000 caractères") @Size(max = 10000, message = "Les données détaillées ne peuvent pas dépasser 10000 caractères")
private String donneesDetaillees; private String donneesDetaillees;
/** Configuration du graphique (couleurs, type, etc.) */ /** Configuration du graphique (couleurs, type, etc.) */
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères") @Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
private String configurationGraphique; private String configurationGraphique;
/** Métadonnées additionnelles */ /** Métadonnées additionnelles */
private Map<String, Object> metadonnees; private Map<String, Object> metadonnees;
/** Indicateur de fiabilité des données (0-100) */ /** Indicateur de fiabilité des données (0-100) */
@DecimalMin(value = "0.0", message = "L'indicateur de fiabilité doit être positif") @DecimalMin(value = "0.0", message = "L'indicateur de fiabilité doit être positif")
@DecimalMax(value = "100.0", message = "L'indicateur de fiabilité ne peut pas dépasser 100") @DecimalMax(value = "100.0", message = "L'indicateur de fiabilité ne peut pas dépasser 100")
@Digits(integer = 3, fraction = 1, message = "Format d'indicateur de fiabilité invalide") @Digits(integer = 3, fraction = 1, message = "Format d'indicateur de fiabilité invalide")
private BigDecimal indicateurFiabilite; private BigDecimal indicateurFiabilite;
/** Nombre d'éléments analysés pour calculer cette métrique */ /** Nombre d'éléments analysés pour calculer cette métrique */
@DecimalMin(value = "0", message = "Le nombre d'éléments doit être positif") @DecimalMin(value = "0", message = "Le nombre d'éléments doit être positif")
private Integer nombreElementsAnalyses; private Integer nombreElementsAnalyses;
/** Temps de calcul en millisecondes */ /** Temps de calcul en millisecondes */
@DecimalMin(value = "0", message = "Le temps de calcul doit être positif") @DecimalMin(value = "0", message = "Le temps de calcul doit être positif")
private Long tempsCalculMs; private Long tempsCalculMs;
/** Indicateur si la métrique est en temps réel */ /** Indicateur si la métrique est en temps réel */
@Builder.Default @Builder.Default
private Boolean tempsReel = false; private Boolean tempsReel = false;
/** Indicateur si la métrique nécessite une mise à jour */ /** Indicateur si la métrique nécessite une mise à jour */
@Builder.Default @Builder.Default
private Boolean necessiteMiseAJour = false; private Boolean necessiteMiseAJour = false;
/** Niveau de priorité de la métrique (1=faible, 5=critique) */ /** Niveau de priorité de la métrique (1=faible, 5=critique) */
@DecimalMin(value = "1", message = "Le niveau de priorité minimum est 1") @DecimalMin(value = "1", message = "Le niveau de priorité minimum est 1")
@DecimalMax(value = "5", message = "Le niveau de priorité maximum est 5") @DecimalMax(value = "5", message = "Le niveau de priorité maximum est 5")
private Integer niveauPriorite; private Integer niveauPriorite;
/** Tags pour catégoriser la métrique */ /** Tags pour catégoriser la métrique */
private List<String> tags; private List<String> tags;
// === MÉTHODES UTILITAIRES === // === MÉTHODES UTILITAIRES ===
/** /**
* Retourne le libellé à afficher (personnalisé ou par défaut) * Retourne le libellé à afficher (personnalisé ou par défaut)
* *
* @return Le libellé à afficher * @return Le libellé à afficher
*/ */
public String getLibelleAffichage() { public String getLibelleAffichage() {
return libellePersonnalise != null && !libellePersonnalise.trim().isEmpty() return libellePersonnalise != null && !libellePersonnalise.trim().isEmpty()
? libellePersonnalise ? libellePersonnalise
: typeMetrique.getLibelle(); : typeMetrique.getLibelle();
} }
/** /**
* Retourne l'unité de mesure de la métrique * Retourne l'unité de mesure de la métrique
* *
* @return L'unité de mesure * @return L'unité de mesure
*/ */
public String getUnite() { public String getUnite() {
return typeMetrique.getUnite(); return typeMetrique.getUnite();
} }
/** /**
* Retourne l'icône de la métrique * Retourne l'icône de la métrique
* *
* @return L'icône Material Design * @return L'icône Material Design
*/ */
public String getIcone() { public String getIcone() {
return typeMetrique.getIcone(); return typeMetrique.getIcone();
} }
/** /**
* Retourne la couleur de la métrique * Retourne la couleur de la métrique
* *
* @return Le code couleur hexadécimal * @return Le code couleur hexadécimal
*/ */
public String getCouleur() { public String getCouleur() {
return typeMetrique.getCouleur(); return typeMetrique.getCouleur();
} }
/** /**
* Vérifie si la métrique a évolué positivement * Vérifie si la métrique a évolué positivement
* *
* @return true si l'évolution est positive * @return true si l'évolution est positive
*/ */
public boolean hasEvolutionPositive() { public boolean hasEvolutionPositive() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0; return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0;
} }
/** /**
* Vérifie si la métrique a évolué négativement * Vérifie si la métrique a évolué négativement
* *
* @return true si l'évolution est négative * @return true si l'évolution est négative
*/ */
public boolean hasEvolutionNegative() { public boolean hasEvolutionNegative() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0; return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0;
} }
/** /**
* Vérifie si la métrique est stable (pas d'évolution) * Vérifie si la métrique est stable (pas d'évolution)
* *
* @return true si l'évolution est nulle * @return true si l'évolution est nulle
*/ */
public boolean isStable() { public boolean isStable() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) == 0; return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) == 0;
} }
/** /**
* Retourne la tendance sous forme de texte * Retourne la tendance sous forme de texte
* *
* @return "hausse", "baisse" ou "stable" * @return "hausse", "baisse" ou "stable"
*/ */
public String getTendance() { public String getTendance() {
if (hasEvolutionPositive()) if (hasEvolutionPositive())
return "hausse"; return "hausse";
if (hasEvolutionNegative()) if (hasEvolutionNegative())
return "baisse"; return "baisse";
return "stable"; return "stable";
} }
/** /**
* Vérifie si les données sont fiables (indicateur > 80) * Vérifie si les données sont fiables (indicateur > 80)
* *
* @return true si les données sont considérées comme fiables * @return true si les données sont considérées comme fiables
*/ */
public boolean isDonneesFiables() { public boolean isDonneesFiables() {
return indicateurFiabilite != null return indicateurFiabilite != null
&& indicateurFiabilite.compareTo(new BigDecimal("80.0")) >= 0; && indicateurFiabilite.compareTo(new BigDecimal("80.0")) >= 0;
} }
/** /**
* Vérifie si la métrique est critique (priorité >= 4) * Vérifie si la métrique est critique (priorité >= 4)
* *
* @return true si la métrique est critique * @return true si la métrique est critique
*/ */
public boolean isCritique() { public boolean isCritique() {
return niveauPriorite != null && niveauPriorite >= 4; return niveauPriorite != null && niveauPriorite >= 4;
} }
/** /**
* Constructeur avec les champs essentiels * Constructeur avec les champs essentiels
* *
* @param typeMetrique Le type de métrique * @param typeMetrique Le type de métrique
* @param periodeAnalyse La période d'analyse * @param periodeAnalyse La période d'analyse
* @param valeur La valeur de la métrique * @param valeur La valeur de la métrique
*/ */
public AnalyticsDataResponse( public AnalyticsDataResponse(
TypeMetrique typeMetrique, PeriodeAnalyse periodeAnalyse, BigDecimal valeur) { TypeMetrique typeMetrique, PeriodeAnalyse periodeAnalyse, BigDecimal valeur) {
super(); super();
this.typeMetrique = typeMetrique; this.typeMetrique = typeMetrique;
this.periodeAnalyse = periodeAnalyse; this.periodeAnalyse = periodeAnalyse;
this.valeur = valeur; this.valeur = valeur;
this.dateCalcul = LocalDateTime.now(); this.dateCalcul = LocalDateTime.now();
this.dateDebut = periodeAnalyse.getDateDebut(); this.dateDebut = periodeAnalyse.getDateDebut();
this.dateFin = periodeAnalyse.getDateFin(); this.dateFin = periodeAnalyse.getDateFin();
this.tempsReel = false; this.tempsReel = false;
this.necessiteMiseAJour = false; this.necessiteMiseAJour = false;
this.niveauPriorite = 3; // Priorité normale par défaut this.niveauPriorite = 3; // Priorité normale par défaut
this.indicateurFiabilite = new BigDecimal("95.0"); // Fiabilité élevée par défaut this.indicateurFiabilite = new BigDecimal("95.0"); // Fiabilité élevée par défaut
} }
} }

View File

@@ -1,350 +1,350 @@
package dev.lions.unionflow.server.api.dto.analytics; package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse; import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique; import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* DTO pour les widgets de tableau de bord analytics UnionFlow * DTO pour les widgets de tableau de bord analytics UnionFlow
* *
* <p>Représente un widget personnalisable affiché sur le tableau de bord avec sa configuration, sa * <p>Représente un widget personnalisable affiché sur le tableau de bord avec sa configuration, sa
* position et ses données. * position et ses données.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-16 * @since 2025-01-16
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class DashboardWidgetResponse extends BaseDTO { public class DashboardWidgetResponse extends BaseDTO {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** Titre du widget */ /** Titre du widget */
@NotBlank(message = "Le titre du widget est obligatoire") @NotBlank(message = "Le titre du widget est obligatoire")
@Size(min = 3, max = 200, message = "Le titre du widget doit contenir entre 3 et 200 caractères") @Size(min = 3, max = 200, message = "Le titre du widget doit contenir entre 3 et 200 caractères")
private String titre; private String titre;
/** Description du widget */ /** Description du widget */
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères") @Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
private String description; private String description;
/** Type de widget (kpi, chart, table, gauge, progress, text) */ /** Type de widget (kpi, chart, table, gauge, progress, text) */
@NotBlank(message = "Le type de widget est obligatoire") @NotBlank(message = "Le type de widget est obligatoire")
@Size(max = 50, message = "Le type de widget ne peut pas dépasser 50 caractères") @Size(max = 50, message = "Le type de widget ne peut pas dépasser 50 caractères")
private String typeWidget; private String typeWidget;
/** Type de métrique affiché */ /** Type de métrique affiché */
private TypeMetrique typeMetrique; private TypeMetrique typeMetrique;
/** Période d'analyse */ /** Période d'analyse */
private PeriodeAnalyse periodeAnalyse; private PeriodeAnalyse periodeAnalyse;
/** Identifiant de l'organisation (optionnel pour filtrage) */ /** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId; private UUID organisationId;
/** Nom de l'organisation */ /** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation; private String nomOrganisation;
/** Identifiant de l'utilisateur propriétaire */ /** Identifiant de l'utilisateur propriétaire */
@NotNull(message = "L'identifiant de l'utilisateur propriétaire est obligatoire") @NotNull(message = "L'identifiant de l'utilisateur propriétaire est obligatoire")
private UUID utilisateurProprietaireId; private UUID utilisateurProprietaireId;
/** Nom de l'utilisateur propriétaire */ /** Nom de l'utilisateur propriétaire */
@Size( @Size(
max = 200, max = 200,
message = "Le nom de l'utilisateur propriétaire ne peut pas dépasser 200 caractères") message = "Le nom de l'utilisateur propriétaire ne peut pas dépasser 200 caractères")
private String nomUtilisateurProprietaire; private String nomUtilisateurProprietaire;
/** Position X du widget sur la grille */ /** Position X du widget sur la grille */
@NotNull(message = "La position X est obligatoire") @NotNull(message = "La position X est obligatoire")
@DecimalMin(value = "0", message = "La position X doit être positive ou nulle") @DecimalMin(value = "0", message = "La position X doit être positive ou nulle")
private Integer positionX; private Integer positionX;
/** Position Y du widget sur la grille */ /** Position Y du widget sur la grille */
@NotNull(message = "La position Y est obligatoire") @NotNull(message = "La position Y est obligatoire")
@DecimalMin(value = "0", message = "La position Y doit être positive ou nulle") @DecimalMin(value = "0", message = "La position Y doit être positive ou nulle")
private Integer positionY; private Integer positionY;
/** Largeur du widget (en unités de grille) */ /** Largeur du widget (en unités de grille) */
@NotNull(message = "La largeur est obligatoire") @NotNull(message = "La largeur est obligatoire")
@DecimalMin(value = "1", message = "La largeur minimum est 1") @DecimalMin(value = "1", message = "La largeur minimum est 1")
@DecimalMax(value = "12", message = "La largeur maximum est 12") @DecimalMax(value = "12", message = "La largeur maximum est 12")
private Integer largeur; private Integer largeur;
/** Hauteur du widget (en unités de grille) */ /** Hauteur du widget (en unités de grille) */
@NotNull(message = "La hauteur est obligatoire") @NotNull(message = "La hauteur est obligatoire")
@DecimalMin(value = "1", message = "La hauteur minimum est 1") @DecimalMin(value = "1", message = "La hauteur minimum est 1")
@DecimalMax(value = "12", message = "La hauteur maximum est 12") @DecimalMax(value = "12", message = "La hauteur maximum est 12")
private Integer hauteur; private Integer hauteur;
/** Ordre d'affichage (z-index) */ /** Ordre d'affichage (z-index) */
@DecimalMin(value = "0", message = "L'ordre d'affichage doit être positif ou nul") @DecimalMin(value = "0", message = "L'ordre d'affichage doit être positif ou nul")
@Builder.Default @Builder.Default
private Integer ordreAffichage = 0; private Integer ordreAffichage = 0;
/** Configuration visuelle du widget */ /** Configuration visuelle du widget */
@Size(max = 5000, message = "La configuration visuelle ne peut pas dépasser 5000 caractères") @Size(max = 5000, message = "La configuration visuelle ne peut pas dépasser 5000 caractères")
private String configurationVisuelle; private String configurationVisuelle;
/** Couleur principale du widget */ /** Couleur principale du widget */
@Size(max = 7, message = "La couleur doit être au format #RRGGBB") @Size(max = 7, message = "La couleur doit être au format #RRGGBB")
private String couleurPrincipale; private String couleurPrincipale;
/** Couleur secondaire du widget */ /** Couleur secondaire du widget */
@Size(max = 7, message = "La couleur secondaire doit être au format #RRGGBB") @Size(max = 7, message = "La couleur secondaire doit être au format #RRGGBB")
private String couleurSecondaire; private String couleurSecondaire;
/** Icône du widget */ /** Icône du widget */
@Size(max = 50, message = "L'icône ne peut pas dépasser 50 caractères") @Size(max = 50, message = "L'icône ne peut pas dépasser 50 caractères")
private String icone; private String icone;
/** Indicateur si le widget est visible */ /** Indicateur si le widget est visible */
@Builder.Default private Boolean visible = true; @Builder.Default private Boolean visible = true;
/** Indicateur si le widget est redimensionnable */ /** Indicateur si le widget est redimensionnable */
@Builder.Default private Boolean redimensionnable = true; @Builder.Default private Boolean redimensionnable = true;
/** Indicateur si le widget est déplaçable */ /** Indicateur si le widget est déplaçable */
@Builder.Default private Boolean deplacable = true; @Builder.Default private Boolean deplacable = true;
/** Indicateur si le widget peut être supprimé */ /** Indicateur si le widget peut être supprimé */
@Builder.Default private Boolean supprimable = true; @Builder.Default private Boolean supprimable = true;
/** Indicateur si le widget se met à jour automatiquement */ /** Indicateur si le widget se met à jour automatiquement */
@Builder.Default private Boolean miseAJourAutomatique = true; @Builder.Default private Boolean miseAJourAutomatique = true;
/** Fréquence de mise à jour en secondes */ /** Fréquence de mise à jour en secondes */
@DecimalMin(value = "30", message = "La fréquence minimum est 30 secondes") @DecimalMin(value = "30", message = "La fréquence minimum est 30 secondes")
@Builder.Default @Builder.Default
private Integer frequenceMiseAJourSecondes = 300; // 5 minutes par défaut private Integer frequenceMiseAJourSecondes = 300; // 5 minutes par défaut
/** Date de dernière mise à jour des données */ /** Date de dernière mise à jour des données */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereMiseAJour; private LocalDateTime dateDerniereMiseAJour;
/** Prochaine mise à jour programmée */ /** Prochaine mise à jour programmée */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime prochaineMiseAJour; private LocalDateTime prochaineMiseAJour;
/** Données du widget (format JSON) */ /** Données du widget (format JSON) */
@Size(max = 50000, message = "Les données du widget ne peuvent pas dépasser 50000 caractères") @Size(max = 50000, message = "Les données du widget ne peuvent pas dépasser 50000 caractères")
private String donneesWidget; private String donneesWidget;
/** Configuration des filtres */ /** Configuration des filtres */
private Map<String, Object> configurationFiltres; private Map<String, Object> configurationFiltres;
/** Configuration des alertes */ /** Configuration des alertes */
private Map<String, Object> configurationAlertes; private Map<String, Object> configurationAlertes;
/** Seuil d'alerte bas */ /** Seuil d'alerte bas */
private Double seuilAlerteBas; private Double seuilAlerteBas;
/** Seuil d'alerte haut */ /** Seuil d'alerte haut */
private Double seuilAlerteHaut; private Double seuilAlerteHaut;
/** Indicateur si une alerte est active */ /** Indicateur si une alerte est active */
@Builder.Default private Boolean alerteActive = false; @Builder.Default private Boolean alerteActive = false;
/** Message d'alerte actuel */ /** Message d'alerte actuel */
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères") @Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
private String messageAlerte; private String messageAlerte;
/** Type d'alerte (info, warning, error, success) */ /** Type d'alerte (info, warning, error, success) */
@Size(max = 20, message = "Le type d'alerte ne peut pas dépasser 20 caractères") @Size(max = 20, message = "Le type d'alerte ne peut pas dépasser 20 caractères")
private String typeAlerte; private String typeAlerte;
/** Permissions d'accès au widget */ /** Permissions d'accès au widget */
@Size(max = 1000, message = "Les permissions ne peuvent pas dépasser 1000 caractères") @Size(max = 1000, message = "Les permissions ne peuvent pas dépasser 1000 caractères")
private String permissions; private String permissions;
/** Rôles autorisés à voir le widget */ /** Rôles autorisés à voir le widget */
@Size(max = 500, message = "Les rôles autorisés ne peuvent pas dépasser 500 caractères") @Size(max = 500, message = "Les rôles autorisés ne peuvent pas dépasser 500 caractères")
private String rolesAutorises; private String rolesAutorises;
/** Template personnalisé du widget */ /** Template personnalisé du widget */
@Size(max = 10000, message = "Le template personnalisé ne peut pas dépasser 10000 caractères") @Size(max = 10000, message = "Le template personnalisé ne peut pas dépasser 10000 caractères")
private String templatePersonnalise; private String templatePersonnalise;
/** CSS personnalisé du widget */ /** CSS personnalisé du widget */
@Size(max = 5000, message = "Le CSS personnalisé ne peut pas dépasser 5000 caractères") @Size(max = 5000, message = "Le CSS personnalisé ne peut pas dépasser 5000 caractères")
private String cssPersonnalise; private String cssPersonnalise;
/** JavaScript personnalisé du widget */ /** JavaScript personnalisé du widget */
@Size(max = 10000, message = "Le JavaScript personnalisé ne peut pas dépasser 10000 caractères") @Size(max = 10000, message = "Le JavaScript personnalisé ne peut pas dépasser 10000 caractères")
private String javascriptPersonnalise; private String javascriptPersonnalise;
/** Métadonnées additionnelles */ /** Métadonnées additionnelles */
private Map<String, Object> metadonnees; private Map<String, Object> metadonnees;
/** Nombre de vues du widget */ /** Nombre de vues du widget */
@DecimalMin(value = "0", message = "Le nombre de vues doit être positif") @DecimalMin(value = "0", message = "Le nombre de vues doit être positif")
@Builder.Default @Builder.Default
private Long nombreVues = 0L; private Long nombreVues = 0L;
/** Nombre d'interactions avec le widget */ /** Nombre d'interactions avec le widget */
@DecimalMin(value = "0", message = "Le nombre d'interactions doit être positif") @DecimalMin(value = "0", message = "Le nombre d'interactions doit être positif")
@Builder.Default @Builder.Default
private Long nombreInteractions = 0L; private Long nombreInteractions = 0L;
/** Temps moyen passé sur le widget (en secondes) */ /** Temps moyen passé sur le widget (en secondes) */
@DecimalMin(value = "0", message = "Le temps moyen doit être positif") @DecimalMin(value = "0", message = "Le temps moyen doit être positif")
private Integer tempsMoyenSecondes; private Integer tempsMoyenSecondes;
/** Taux d'erreur du widget (en pourcentage) */ /** Taux d'erreur du widget (en pourcentage) */
@DecimalMin(value = "0.0", message = "Le taux d'erreur doit être positif") @DecimalMin(value = "0.0", message = "Le taux d'erreur doit être positif")
@DecimalMax(value = "100.0", message = "Le taux d'erreur ne peut pas dépasser 100%") @DecimalMax(value = "100.0", message = "Le taux d'erreur ne peut pas dépasser 100%")
@Builder.Default @Builder.Default
private Double tauxErreur = 0.0; private Double tauxErreur = 0.0;
/** Date de dernière erreur */ /** Date de dernière erreur */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereErreur; private LocalDateTime dateDerniereErreur;
/** Message de dernière erreur */ /** Message de dernière erreur */
@Size(max = 1000, message = "Le message d'erreur ne peut pas dépasser 1000 caractères") @Size(max = 1000, message = "Le message d'erreur ne peut pas dépasser 1000 caractères")
private String messageDerniereErreur; private String messageDerniereErreur;
// === MÉTHODES UTILITAIRES === // === MÉTHODES UTILITAIRES ===
/** /**
* Retourne le libellé de la métrique si définie * Retourne le libellé de la métrique si définie
* *
* @return Le libellé de la métrique ou null * @return Le libellé de la métrique ou null
*/ */
public String getLibelleMetrique() { public String getLibelleMetrique() {
return typeMetrique != null ? typeMetrique.getLibelle() : null; return typeMetrique != null ? typeMetrique.getLibelle() : null;
} }
/** /**
* Retourne l'unité de mesure si métrique définie * Retourne l'unité de mesure si métrique définie
* *
* @return L'unité de mesure ou chaîne vide * @return L'unité de mesure ou chaîne vide
*/ */
public String getUnite() { public String getUnite() {
return typeMetrique != null ? typeMetrique.getUnite() : ""; return typeMetrique != null ? typeMetrique.getUnite() : "";
} }
/** /**
* Retourne l'icône de la métrique ou l'icône personnalisée * Retourne l'icône de la métrique ou l'icône personnalisée
* *
* @return L'icône à afficher * @return L'icône à afficher
*/ */
public String getIconeAffichage() { public String getIconeAffichage() {
if (icone != null && !icone.trim().isEmpty()) { if (icone != null && !icone.trim().isEmpty()) {
return icone; return icone;
} }
return typeMetrique != null ? typeMetrique.getIcone() : "dashboard"; return typeMetrique != null ? typeMetrique.getIcone() : "dashboard";
} }
/** /**
* Retourne la couleur de la métrique ou la couleur personnalisée * Retourne la couleur de la métrique ou la couleur personnalisée
* *
* @return La couleur à utiliser * @return La couleur à utiliser
*/ */
public String getCouleurAffichage() { public String getCouleurAffichage() {
if (couleurPrincipale != null && !couleurPrincipale.trim().isEmpty()) { if (couleurPrincipale != null && !couleurPrincipale.trim().isEmpty()) {
return couleurPrincipale; return couleurPrincipale;
} }
return typeMetrique != null ? typeMetrique.getCouleur() : "#757575"; return typeMetrique != null ? typeMetrique.getCouleur() : "#757575";
} }
/** /**
* Vérifie si le widget nécessite une mise à jour * Vérifie si le widget nécessite une mise à jour
* *
* @return true si une mise à jour est nécessaire * @return true si une mise à jour est nécessaire
*/ */
public boolean necessiteMiseAJour() { public boolean necessiteMiseAJour() {
return miseAJourAutomatique return miseAJourAutomatique
&& prochaineMiseAJour != null && prochaineMiseAJour != null
&& prochaineMiseAJour.isBefore(LocalDateTime.now()); && prochaineMiseAJour.isBefore(LocalDateTime.now());
} }
/** /**
* Vérifie si le widget est interactif * Vérifie si le widget est interactif
* *
* @return true si le widget permet des interactions * @return true si le widget permet des interactions
*/ */
public boolean isInteractif() { public boolean isInteractif() {
return "chart".equals(typeWidget) || "table".equals(typeWidget) || "gauge".equals(typeWidget); return "chart".equals(typeWidget) || "table".equals(typeWidget) || "gauge".equals(typeWidget);
} }
/** /**
* Vérifie si le widget affiche des données temps réel * Vérifie si le widget affiche des données temps réel
* *
* @return true si le widget est en temps réel * @return true si le widget est en temps réel
*/ */
/** Indique si la fréquence est en temps réel (pour couverture branches). */ /** Indique si la fréquence est en temps réel (pour couverture branches). */
private boolean isFrequenceTempsReel() { private boolean isFrequenceTempsReel() {
if (frequenceMiseAJourSecondes == null) return false; if (frequenceMiseAJourSecondes == null) return false;
return frequenceMiseAJourSecondes <= 60; return frequenceMiseAJourSecondes <= 60;
} }
public boolean isTempsReel() { public boolean isTempsReel() {
return isFrequenceTempsReel(); return isFrequenceTempsReel();
} }
/** /**
* Retourne la taille du widget (surface occupée) * Retourne la taille du widget (surface occupée)
* *
* @return La surface en unités de grille * @return La surface en unités de grille
*/ */
public int getTailleWidget() { public int getTailleWidget() {
return largeur * hauteur; return largeur * hauteur;
} }
/** /**
* Vérifie si le widget est grand (surface > 6) * Vérifie si le widget est grand (surface > 6)
* *
* @return true si le widget est considéré comme grand * @return true si le widget est considéré comme grand
*/ */
public boolean isWidgetGrand() { public boolean isWidgetGrand() {
return getTailleWidget() > 6; return getTailleWidget() > 6;
} }
/** /**
* Vérifie si le widget a des erreurs récentes (< 24h) * Vérifie si le widget a des erreurs récentes (< 24h)
* *
* @return true si des erreurs récentes sont détectées * @return true si des erreurs récentes sont détectées
*/ */
public boolean hasErreursRecentes() { public boolean hasErreursRecentes() {
return dateDerniereErreur != null return dateDerniereErreur != null
&& dateDerniereErreur.isAfter(LocalDateTime.now().minusHours(24)); && dateDerniereErreur.isAfter(LocalDateTime.now().minusHours(24));
} }
/** /**
* Retourne le statut du widget * Retourne le statut du widget
* *
* @return "actif", "erreur", "inactif" ou "maintenance" * @return "actif", "erreur", "inactif" ou "maintenance"
*/ */
/** Indique si le taux d'erreur déclenche le statut maintenance (pour couverture branches). */ /** Indique si le taux d'erreur déclenche le statut maintenance (pour couverture branches). */
private boolean isTauxErreurMaintenance() { private boolean isTauxErreurMaintenance() {
if (tauxErreur == null) return false; if (tauxErreur == null) return false;
return tauxErreur > 10.0; return tauxErreur > 10.0;
} }
public String getStatutWidget() { public String getStatutWidget() {
if (hasErreursRecentes()) return "erreur"; if (hasErreursRecentes()) return "erreur";
if (!visible) return "inactif"; if (!visible) return "inactif";
if (isTauxErreurMaintenance()) return "maintenance"; if (isTauxErreurMaintenance()) return "maintenance";
return "actif"; return "actif";
} }
} }

View File

@@ -1,309 +1,309 @@
package dev.lions.unionflow.server.api.dto.analytics; package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse; import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique; import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* DTO pour les tendances et évolutions des KPI UnionFlow * DTO pour les tendances et évolutions des KPI UnionFlow
* *
* <p>Représente l'évolution d'un KPI dans le temps avec les points de données historiques pour * <p>Représente l'évolution d'un KPI dans le temps avec les points de données historiques pour
* générer des graphiques de tendance. * générer des graphiques de tendance.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-16 * @since 2025-01-16
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class KPITrendResponse extends BaseDTO { public class KPITrendResponse extends BaseDTO {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** Type de métrique pour cette tendance */ /** Type de métrique pour cette tendance */
@NotNull(message = "Le type de métrique est obligatoire") @NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique; private TypeMetrique typeMetrique;
/** Période d'analyse globale */ /** Période d'analyse globale */
@NotNull(message = "La période d'analyse est obligatoire") @NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse; private PeriodeAnalyse periodeAnalyse;
/** Identifiant de l'organisation (optionnel) */ /** Identifiant de l'organisation (optionnel) */
private UUID organisationId; private UUID organisationId;
/** Nom de l'organisation */ /** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation; private String nomOrganisation;
/** Date de début de la période analysée */ /** Date de début de la période analysée */
@NotNull(message = "La date de début est obligatoire") @NotNull(message = "La date de début est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebut; private LocalDateTime dateDebut;
/** Date de fin de la période analysée */ /** Date de fin de la période analysée */
@NotNull(message = "La date de fin est obligatoire") @NotNull(message = "La date de fin est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFin; private LocalDateTime dateFin;
/** Points de données pour la tendance */ /** Points de données pour la tendance */
@NotNull(message = "Les points de données sont obligatoires") @NotNull(message = "Les points de données sont obligatoires")
private List<PointDonneeDTO> pointsDonnees; private List<PointDonneeDTO> pointsDonnees;
/** Valeur actuelle du KPI */ /** Valeur actuelle du KPI */
@NotNull(message = "La valeur actuelle est obligatoire") @NotNull(message = "La valeur actuelle est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur actuelle doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur actuelle doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur actuelle invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur actuelle invalide")
private BigDecimal valeurActuelle; private BigDecimal valeurActuelle;
/** Valeur minimale sur la période */ /** Valeur minimale sur la période */
@DecimalMin(value = "0.0", message = "La valeur minimale doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur minimale doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur minimale invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur minimale invalide")
private BigDecimal valeurMinimale; private BigDecimal valeurMinimale;
/** Valeur maximale sur la période */ /** Valeur maximale sur la période */
@DecimalMin(value = "0.0", message = "La valeur maximale doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur maximale doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur maximale invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur maximale invalide")
private BigDecimal valeurMaximale; private BigDecimal valeurMaximale;
/** Valeur moyenne sur la période */ /** Valeur moyenne sur la période */
@DecimalMin(value = "0.0", message = "La valeur moyenne doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur moyenne doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur moyenne invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur moyenne invalide")
private BigDecimal valeurMoyenne; private BigDecimal valeurMoyenne;
/** Écart-type des valeurs */ /** Écart-type des valeurs */
@DecimalMin(value = "0.0", message = "L'écart-type doit être positif ou nul") @DecimalMin(value = "0.0", message = "L'écart-type doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format d'écart-type invalide") @Digits(integer = 15, fraction = 4, message = "Format d'écart-type invalide")
private BigDecimal ecartType; private BigDecimal ecartType;
/** Coefficient de variation (écart-type / moyenne) */ /** Coefficient de variation (écart-type / moyenne) */
@DecimalMin(value = "0.0", message = "Le coefficient de variation doit être positif ou nul") @DecimalMin(value = "0.0", message = "Le coefficient de variation doit être positif ou nul")
@Digits(integer = 6, fraction = 4, message = "Format de coefficient de variation invalide") @Digits(integer = 6, fraction = 4, message = "Format de coefficient de variation invalide")
private BigDecimal coefficientVariation; private BigDecimal coefficientVariation;
/** Tendance générale (pente de la régression linéaire) */ /** Tendance générale (pente de la régression linéaire) */
@Digits(integer = 10, fraction = 6, message = "Format de tendance invalide") @Digits(integer = 10, fraction = 6, message = "Format de tendance invalide")
private BigDecimal tendanceGenerale; private BigDecimal tendanceGenerale;
/** Coefficient de corrélation R² */ /** Coefficient de corrélation R² */
@DecimalMin(value = "0.0", message = "Le coefficient de corrélation doit être positif ou nul") @DecimalMin(value = "0.0", message = "Le coefficient de corrélation doit être positif ou nul")
@DecimalMax(value = "1.0", message = "Le coefficient de corrélation ne peut pas dépasser 1") @DecimalMax(value = "1.0", message = "Le coefficient de corrélation ne peut pas dépasser 1")
@Digits(integer = 1, fraction = 6, message = "Format de coefficient de corrélation invalide") @Digits(integer = 1, fraction = 6, message = "Format de coefficient de corrélation invalide")
private BigDecimal coefficientCorrelation; private BigDecimal coefficientCorrelation;
/** Pourcentage d'évolution depuis le début de la période */ /** Pourcentage d'évolution depuis le début de la période */
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide") @Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
private BigDecimal pourcentageEvolutionGlobale; private BigDecimal pourcentageEvolutionGlobale;
/** Prédiction pour la prochaine période */ /** Prédiction pour la prochaine période */
@DecimalMin(value = "0.0", message = "La prédiction doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La prédiction doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de prédiction invalide") @Digits(integer = 15, fraction = 4, message = "Format de prédiction invalide")
private BigDecimal predictionProchainePeriode; private BigDecimal predictionProchainePeriode;
/** Marge d'erreur de la prédiction (en pourcentage) */ /** Marge d'erreur de la prédiction (en pourcentage) */
@DecimalMin(value = "0.0", message = "La marge d'erreur doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La marge d'erreur doit être positive ou nulle")
@DecimalMax(value = "100.0", message = "La marge d'erreur ne peut pas dépasser 100%") @DecimalMax(value = "100.0", message = "La marge d'erreur ne peut pas dépasser 100%")
@Digits(integer = 3, fraction = 2, message = "Format de marge d'erreur invalide") @Digits(integer = 3, fraction = 2, message = "Format de marge d'erreur invalide")
private BigDecimal margeErreurPrediction; private BigDecimal margeErreurPrediction;
/** Seuil d'alerte bas */ /** Seuil d'alerte bas */
@DecimalMin(value = "0.0", message = "Le seuil d'alerte bas doit être positif ou nul") @DecimalMin(value = "0.0", message = "Le seuil d'alerte bas doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte bas invalide") @Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte bas invalide")
private BigDecimal seuilAlerteBas; private BigDecimal seuilAlerteBas;
/** Seuil d'alerte haut */ /** Seuil d'alerte haut */
@DecimalMin(value = "0.0", message = "Le seuil d'alerte haut doit être positif ou nul") @DecimalMin(value = "0.0", message = "Le seuil d'alerte haut doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte haut invalide") @Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte haut invalide")
private BigDecimal seuilAlerteHaut; private BigDecimal seuilAlerteHaut;
/** Indicateur si une alerte est active */ /** Indicateur si une alerte est active */
@Builder.Default private Boolean alerteActive = false; @Builder.Default private Boolean alerteActive = false;
/** Type d'alerte (bas, haut, anomalie) */ /** Type d'alerte (bas, haut, anomalie) */
@Size(max = 50, message = "Le type d'alerte ne peut pas dépasser 50 caractères") @Size(max = 50, message = "Le type d'alerte ne peut pas dépasser 50 caractères")
private String typeAlerte; private String typeAlerte;
/** Message d'alerte */ /** Message d'alerte */
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères") @Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
private String messageAlerte; private String messageAlerte;
/** Configuration du graphique (couleurs, style, etc.) */ /** Configuration du graphique (couleurs, style, etc.) */
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères") @Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
private String configurationGraphique; private String configurationGraphique;
/** Intervalle de regroupement des données */ /** Intervalle de regroupement des données */
@Size(max = 20, message = "L'intervalle de regroupement ne peut pas dépasser 20 caractères") @Size(max = 20, message = "L'intervalle de regroupement ne peut pas dépasser 20 caractères")
private String intervalleRegroupement; private String intervalleRegroupement;
/** Format d'affichage des dates */ /** Format d'affichage des dates */
@Size(max = 20, message = "Le format de date ne peut pas dépasser 20 caractères") @Size(max = 20, message = "Le format de date ne peut pas dépasser 20 caractères")
private String formatDate; private String formatDate;
/** Date de dernière mise à jour */ /** Date de dernière mise à jour */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereMiseAJour; private LocalDateTime dateDerniereMiseAJour;
/** Fréquence de mise à jour en minutes */ /** Fréquence de mise à jour en minutes */
@DecimalMin(value = "1", message = "La fréquence de mise à jour minimum est 1 minute") @DecimalMin(value = "1", message = "La fréquence de mise à jour minimum est 1 minute")
private Integer frequenceMiseAJourMinutes; private Integer frequenceMiseAJourMinutes;
// === CLASSES INTERNES === // === CLASSES INTERNES ===
/** Classe interne représentant un point de données dans la tendance */ /** Classe interne représentant un point de données dans la tendance */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class PointDonneeDTO { public static class PointDonneeDTO {
/** Date du point de données */ /** Date du point de données */
@NotNull(message = "La date du point de données est obligatoire") @NotNull(message = "La date du point de données est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime date; private LocalDateTime date;
/** Valeur du point de données */ /** Valeur du point de données */
@NotNull(message = "La valeur du point de données est obligatoire") @NotNull(message = "La valeur du point de données est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur du point doit être positive ou nulle") @DecimalMin(value = "0.0", message = "La valeur du point doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur du point invalide") @Digits(integer = 15, fraction = 4, message = "Format de valeur du point invalide")
private BigDecimal valeur; private BigDecimal valeur;
/** Libellé du point (optionnel) */ /** Libellé du point (optionnel) */
@Size(max = 100, message = "Le libellé du point ne peut pas dépasser 100 caractères") @Size(max = 100, message = "Le libellé du point ne peut pas dépasser 100 caractères")
private String libelle; private String libelle;
/** Indicateur si le point est une anomalie */ /** Indicateur si le point est une anomalie */
@Builder.Default private Boolean anomalie = false; @Builder.Default private Boolean anomalie = false;
/** Indicateur si le point est une prédiction */ /** Indicateur si le point est une prédiction */
@Builder.Default private Boolean prediction = false; @Builder.Default private Boolean prediction = false;
/** Métadonnées additionnelles du point */ /** Métadonnées additionnelles du point */
private String metadonnees; private String metadonnees;
} }
// === MÉTHODES UTILITAIRES === // === MÉTHODES UTILITAIRES ===
/** /**
* Retourne le libellé de la métrique * Retourne le libellé de la métrique
* *
* @return Le libellé de la métrique * @return Le libellé de la métrique
*/ */
public String getLibelleMetrique() { public String getLibelleMetrique() {
return typeMetrique.getLibelle(); return typeMetrique.getLibelle();
} }
/** /**
* Retourne l'unité de mesure * Retourne l'unité de mesure
* *
* @return L'unité de mesure * @return L'unité de mesure
*/ */
public String getUnite() { public String getUnite() {
return typeMetrique.getUnite(); return typeMetrique.getUnite();
} }
/** /**
* Retourne l'icône de la métrique * Retourne l'icône de la métrique
* *
* @return L'icône Material Design * @return L'icône Material Design
*/ */
public String getIcone() { public String getIcone() {
return typeMetrique.getIcone(); return typeMetrique.getIcone();
} }
/** /**
* Retourne la couleur de la métrique * Retourne la couleur de la métrique
* *
* @return Le code couleur hexadécimal * @return Le code couleur hexadécimal
*/ */
public String getCouleur() { public String getCouleur() {
return typeMetrique.getCouleur(); return typeMetrique.getCouleur();
} }
/** /**
* Vérifie si la tendance est positive * Vérifie si la tendance est positive
* *
* @return true si la tendance générale est positive * @return true si la tendance générale est positive
*/ */
public boolean isTendancePositive() { public boolean isTendancePositive() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) > 0; return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) > 0;
} }
/** /**
* Vérifie si la tendance est négative * Vérifie si la tendance est négative
* *
* @return true si la tendance générale est négative * @return true si la tendance générale est négative
*/ */
public boolean isTendanceNegative() { public boolean isTendanceNegative() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) < 0; return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) < 0;
} }
/** /**
* Vérifie si la tendance est stable * Vérifie si la tendance est stable
* *
* @return true si la tendance générale est stable * @return true si la tendance générale est stable
*/ */
public boolean isTendanceStable() { public boolean isTendanceStable() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) == 0; return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) == 0;
} }
/** /**
* Retourne la volatilité du KPI (basée sur le coefficient de variation) * Retourne la volatilité du KPI (basée sur le coefficient de variation)
* *
* @return "faible", "moyenne" ou "élevée" * @return "faible", "moyenne" ou "élevée"
*/ */
public String getVolatilite() { public String getVolatilite() {
if (coefficientVariation == null) return "inconnue"; if (coefficientVariation == null) return "inconnue";
BigDecimal cv = coefficientVariation; BigDecimal cv = coefficientVariation;
if (cv.compareTo(new BigDecimal("0.1")) <= 0) return "faible"; if (cv.compareTo(new BigDecimal("0.1")) <= 0) return "faible";
if (cv.compareTo(new BigDecimal("0.3")) <= 0) return "moyenne"; if (cv.compareTo(new BigDecimal("0.3")) <= 0) return "moyenne";
return "élevée"; return "élevée";
} }
/** /**
* Vérifie si la prédiction est fiable (R² > 0.7) * Vérifie si la prédiction est fiable (R² > 0.7)
* *
* @return true si la prédiction est considérée comme fiable * @return true si la prédiction est considérée comme fiable
*/ */
public boolean isPredictionFiable() { public boolean isPredictionFiable() {
return coefficientCorrelation != null return coefficientCorrelation != null
&& coefficientCorrelation.compareTo(new BigDecimal("0.7")) >= 0; && coefficientCorrelation.compareTo(new BigDecimal("0.7")) >= 0;
} }
/** /**
* Retourne le nombre de points de données * Retourne le nombre de points de données
* *
* @return Le nombre de points de données * @return Le nombre de points de données
*/ */
public int getNombrePointsDonnees() { public int getNombrePointsDonnees() {
return pointsDonnees != null ? pointsDonnees.size() : 0; return pointsDonnees != null ? pointsDonnees.size() : 0;
} }
/** /**
* Vérifie si des anomalies ont été détectées * Vérifie si des anomalies ont été détectées
* *
* @return true si au moins un point est marqué comme anomalie * @return true si au moins un point est marqué comme anomalie
*/ */
public boolean hasAnomalies() { public boolean hasAnomalies() {
return pointsDonnees != null return pointsDonnees != null
&& pointsDonnees.stream().anyMatch(point -> Boolean.TRUE.equals(point.getAnomalie())); && pointsDonnees.stream().anyMatch(point -> Boolean.TRUE.equals(point.getAnomalie()));
} }
} }

View File

@@ -1,333 +1,333 @@
package dev.lions.unionflow.server.api.dto.analytics; package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.FormatExport; import dev.lions.unionflow.server.api.enums.analytics.FormatExport;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse; import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique; import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* DTO pour la configuration des rapports analytics UnionFlow * DTO pour la configuration des rapports analytics UnionFlow
* *
* <p>Représente la configuration d'un rapport personnalisé avec ses métriques, sa mise en forme et * <p>Représente la configuration d'un rapport personnalisé avec ses métriques, sa mise en forme et
* ses paramètres d'export. * ses paramètres d'export.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-16 * @since 2025-01-16
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class ReportConfigDTO extends BaseDTO { public class ReportConfigDTO extends BaseDTO {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** Nom du rapport */ /** Nom du rapport */
@NotBlank(message = "Le nom du rapport est obligatoire") @NotBlank(message = "Le nom du rapport est obligatoire")
@Size(min = 3, max = 200, message = "Le nom du rapport doit contenir entre 3 et 200 caractères") @Size(min = 3, max = 200, message = "Le nom du rapport doit contenir entre 3 et 200 caractères")
private String nom; private String nom;
/** Description du rapport */ /** Description du rapport */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") @Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
private String description; private String description;
/** Type de rapport (executif, analytique, technique, operationnel) */ /** Type de rapport (executif, analytique, technique, operationnel) */
@NotBlank(message = "Le type de rapport est obligatoire") @NotBlank(message = "Le type de rapport est obligatoire")
@Size(max = 50, message = "Le type de rapport ne peut pas dépasser 50 caractères") @Size(max = 50, message = "Le type de rapport ne peut pas dépasser 50 caractères")
private String typeRapport; private String typeRapport;
/** Période d'analyse par défaut */ /** Période d'analyse par défaut */
@NotNull(message = "La période d'analyse est obligatoire") @NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse; private PeriodeAnalyse periodeAnalyse;
/** Date de début personnalisée (si période personnalisée) */ /** Date de début personnalisée (si période personnalisée) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebutPersonnalisee; private LocalDateTime dateDebutPersonnalisee;
/** Date de fin personnalisée (si période personnalisée) */ /** Date de fin personnalisée (si période personnalisée) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFinPersonnalisee; private LocalDateTime dateFinPersonnalisee;
/** Identifiant de l'organisation (optionnel pour filtrage) */ /** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId; private UUID organisationId;
/** Nom de l'organisation */ /** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation; private String nomOrganisation;
/** Identifiant de l'utilisateur créateur */ /** Identifiant de l'utilisateur créateur */
@NotNull(message = "L'identifiant de l'utilisateur créateur est obligatoire") @NotNull(message = "L'identifiant de l'utilisateur créateur est obligatoire")
private UUID utilisateurCreateurId; private UUID utilisateurCreateurId;
/** Nom de l'utilisateur créateur */ /** Nom de l'utilisateur créateur */
@Size(max = 200, message = "Le nom de l'utilisateur créateur ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de l'utilisateur créateur ne peut pas dépasser 200 caractères")
private String nomUtilisateurCreateur; private String nomUtilisateurCreateur;
/** Métriques incluses dans le rapport */ /** Métriques incluses dans le rapport */
@NotNull(message = "Les métriques sont obligatoires") @NotNull(message = "Les métriques sont obligatoires")
@Valid @Valid
private List<MetriqueConfigDTO> metriques; private List<MetriqueConfigDTO> metriques;
/** Sections du rapport */ /** Sections du rapport */
@Valid private List<SectionRapportDTO> sections; @Valid private List<SectionRapportDTO> sections;
/** Format d'export par défaut */ /** Format d'export par défaut */
@NotNull(message = "Le format d'export est obligatoire") @NotNull(message = "Le format d'export est obligatoire")
private FormatExport formatExport; private FormatExport formatExport;
/** Formats d'export autorisés */ /** Formats d'export autorisés */
private List<FormatExport> formatsExportAutorises; private List<FormatExport> formatsExportAutorises;
/** Modèle de rapport à utiliser */ /** Modèle de rapport à utiliser */
@Size(max = 100, message = "Le modèle de rapport ne peut pas dépasser 100 caractères") @Size(max = 100, message = "Le modèle de rapport ne peut pas dépasser 100 caractères")
private String modeleRapport; private String modeleRapport;
/** Configuration de la mise en page */ /** Configuration de la mise en page */
@Size( @Size(
max = 2000, max = 2000,
message = "La configuration de mise en page ne peut pas dépasser 2000 caractères") message = "La configuration de mise en page ne peut pas dépasser 2000 caractères")
private String configurationMiseEnPage; private String configurationMiseEnPage;
/** Logo personnalisé (URL ou base64) */ /** Logo personnalisé (URL ou base64) */
@Size(max = 5000, message = "Le logo personnalisé ne peut pas dépasser 5000 caractères") @Size(max = 5000, message = "Le logo personnalisé ne peut pas dépasser 5000 caractères")
private String logoPersonnalise; private String logoPersonnalise;
/** Couleurs personnalisées du rapport */ /** Couleurs personnalisées du rapport */
private Map<String, String> couleursPersonnalisees; private Map<String, String> couleursPersonnalisees;
/** Indicateur si le rapport est public */ /** Indicateur si le rapport est public */
@Builder.Default private Boolean rapportPublic = false; @Builder.Default private Boolean rapportPublic = false;
/** Indicateur si le rapport est automatique */ /** Indicateur si le rapport est automatique */
@Builder.Default private Boolean rapportAutomatique = false; @Builder.Default private Boolean rapportAutomatique = false;
/** Fréquence de génération automatique (en heures) */ /** Fréquence de génération automatique (en heures) */
@DecimalMin(value = "1", message = "La fréquence minimum est 1 heure") @DecimalMin(value = "1", message = "La fréquence minimum est 1 heure")
private Integer frequenceGenerationHeures; private Integer frequenceGenerationHeures;
/** Prochaine génération automatique */ /** Prochaine génération automatique */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime prochaineGeneration; private LocalDateTime prochaineGeneration;
/** Liste des destinataires pour l'envoi automatique */ /** Liste des destinataires pour l'envoi automatique */
private List<String> destinatairesEmail; private List<String> destinatairesEmail;
/** Objet de l'email pour l'envoi automatique */ /** Objet de l'email pour l'envoi automatique */
@Size(max = 200, message = "L'objet de l'email ne peut pas dépasser 200 caractères") @Size(max = 200, message = "L'objet de l'email ne peut pas dépasser 200 caractères")
private String objetEmail; private String objetEmail;
/** Corps de l'email pour l'envoi automatique */ /** Corps de l'email pour l'envoi automatique */
@Size(max = 2000, message = "Le corps de l'email ne peut pas dépasser 2000 caractères") @Size(max = 2000, message = "Le corps de l'email ne peut pas dépasser 2000 caractères")
private String corpsEmail; private String corpsEmail;
/** Paramètres de filtrage avancé */ /** Paramètres de filtrage avancé */
private Map<String, Object> parametresFiltrage; private Map<String, Object> parametresFiltrage;
/** Tags pour catégoriser le rapport */ /** Tags pour catégoriser le rapport */
private List<String> tags; private List<String> tags;
/** Niveau de confidentialité (1=public, 5=confidentiel) */ /** Niveau de confidentialité (1=public, 5=confidentiel) */
@DecimalMin(value = "1", message = "Le niveau de confidentialité minimum est 1") @DecimalMin(value = "1", message = "Le niveau de confidentialité minimum est 1")
@DecimalMax(value = "5", message = "Le niveau de confidentialité maximum est 5") @DecimalMax(value = "5", message = "Le niveau de confidentialité maximum est 5")
@Builder.Default @Builder.Default
private Integer niveauConfidentialite = 1; private Integer niveauConfidentialite = 1;
/** Date de dernière génération */ /** Date de dernière génération */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereGeneration; private LocalDateTime dateDerniereGeneration;
/** Nombre de générations effectuées */ /** Nombre de générations effectuées */
@DecimalMin(value = "0", message = "Le nombre de générations doit être positif") @DecimalMin(value = "0", message = "Le nombre de générations doit être positif")
@Builder.Default @Builder.Default
private Integer nombreGenerations = 0; private Integer nombreGenerations = 0;
/** Taille moyenne des rapports générés (en KB) */ /** Taille moyenne des rapports générés (en KB) */
@DecimalMin(value = "0", message = "La taille moyenne doit être positive") @DecimalMin(value = "0", message = "La taille moyenne doit être positive")
private Long tailleMoyenneKB; private Long tailleMoyenneKB;
/** Temps moyen de génération (en secondes) */ /** Temps moyen de génération (en secondes) */
@DecimalMin(value = "0", message = "Le temps moyen de génération doit être positif") @DecimalMin(value = "0", message = "Le temps moyen de génération doit être positif")
private Integer tempsMoyenGenerationSecondes; private Integer tempsMoyenGenerationSecondes;
// === CLASSES INTERNES === // === CLASSES INTERNES ===
/** Configuration d'une métrique dans le rapport */ /** Configuration d'une métrique dans le rapport */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class MetriqueConfigDTO { public static class MetriqueConfigDTO {
/** Type de métrique */ /** Type de métrique */
@NotNull(message = "Le type de métrique est obligatoire") @NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique; private TypeMetrique typeMetrique;
/** Libellé personnalisé */ /** Libellé personnalisé */
@Size(max = 200, message = "Le libellé personnalisé ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le libellé personnalisé ne peut pas dépasser 200 caractères")
private String libellePersonnalise; private String libellePersonnalise;
/** Position dans le rapport (ordre d'affichage) */ /** Position dans le rapport (ordre d'affichage) */
@DecimalMin(value = "1", message = "La position minimum est 1") @DecimalMin(value = "1", message = "La position minimum est 1")
private Integer position; private Integer position;
/** Taille d'affichage (1=petit, 2=moyen, 3=grand) */ /** Taille d'affichage (1=petit, 2=moyen, 3=grand) */
@DecimalMin(value = "1", message = "La taille minimum est 1") @DecimalMin(value = "1", message = "La taille minimum est 1")
@DecimalMax(value = "3", message = "La taille maximum est 3") @DecimalMax(value = "3", message = "La taille maximum est 3")
@Builder.Default @Builder.Default
private Integer tailleAffichage = 2; private Integer tailleAffichage = 2;
/** Couleur personnalisée */ /** Couleur personnalisée */
@Size(max = 7, message = "La couleur doit être au format #RRGGBB") @Size(max = 7, message = "La couleur doit être au format #RRGGBB")
private String couleurPersonnalisee; private String couleurPersonnalisee;
/** Indicateur si la métrique inclut un graphique */ /** Indicateur si la métrique inclut un graphique */
@Builder.Default private Boolean inclureGraphique = true; @Builder.Default private Boolean inclureGraphique = true;
/** Type de graphique (line, bar, pie, area) */ /** Type de graphique (line, bar, pie, area) */
@Size(max = 20, message = "Le type de graphique ne peut pas dépasser 20 caractères") @Size(max = 20, message = "Le type de graphique ne peut pas dépasser 20 caractères")
@Builder.Default @Builder.Default
private String typeGraphique = "line"; private String typeGraphique = "line";
/** Indicateur si la métrique inclut la tendance */ /** Indicateur si la métrique inclut la tendance */
@Builder.Default private Boolean inclureTendance = true; @Builder.Default private Boolean inclureTendance = true;
/** Indicateur si la métrique inclut la comparaison */ /** Indicateur si la métrique inclut la comparaison */
@Builder.Default private Boolean inclureComparaison = true; @Builder.Default private Boolean inclureComparaison = true;
/** Seuils d'alerte personnalisés */ /** Seuils d'alerte personnalisés */
private Map<String, Object> seuilsAlerte; private Map<String, Object> seuilsAlerte;
/** Filtres spécifiques à cette métrique */ /** Filtres spécifiques à cette métrique */
private Map<String, Object> filtresSpecifiques; private Map<String, Object> filtresSpecifiques;
} }
/** Configuration d'une section du rapport */ /** Configuration d'une section du rapport */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class SectionRapportDTO { public static class SectionRapportDTO {
/** Nom de la section */ /** Nom de la section */
@NotBlank(message = "Le nom de la section est obligatoire") @NotBlank(message = "Le nom de la section est obligatoire")
@Size(max = 200, message = "Le nom de la section ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom de la section ne peut pas dépasser 200 caractères")
private String nom; private String nom;
/** Description de la section */ /** Description de la section */
@Size(max = 500, message = "La description de la section ne peut pas dépasser 500 caractères") @Size(max = 500, message = "La description de la section ne peut pas dépasser 500 caractères")
private String description; private String description;
/** Position de la section dans le rapport */ /** Position de la section dans le rapport */
@DecimalMin(value = "1", message = "La position minimum est 1") @DecimalMin(value = "1", message = "La position minimum est 1")
private Integer position; private Integer position;
/** Type de section (resume, metriques, graphiques, tableaux, analyse) */ /** Type de section (resume, metriques, graphiques, tableaux, analyse) */
@NotBlank(message = "Le type de section est obligatoire") @NotBlank(message = "Le type de section est obligatoire")
@Size(max = 50, message = "Le type de section ne peut pas dépasser 50 caractères") @Size(max = 50, message = "Le type de section ne peut pas dépasser 50 caractères")
private String typeSection; private String typeSection;
/** Métriques incluses dans cette section */ /** Métriques incluses dans cette section */
private List<TypeMetrique> metriquesIncluses; private List<TypeMetrique> metriquesIncluses;
/** Configuration spécifique de la section */ /** Configuration spécifique de la section */
private Map<String, Object> configurationSection; private Map<String, Object> configurationSection;
/** Indicateur si la section est visible */ /** Indicateur si la section est visible */
@Builder.Default private Boolean visible = true; @Builder.Default private Boolean visible = true;
/** Indicateur si la section peut être réduite */ /** Indicateur si la section peut être réduite */
@Builder.Default private Boolean pliable = false; @Builder.Default private Boolean pliable = false;
} }
// === MÉTHODES UTILITAIRES === // === MÉTHODES UTILITAIRES ===
/** /**
* Retourne le nombre de métriques configurées * Retourne le nombre de métriques configurées
* *
* @return Le nombre de métriques * @return Le nombre de métriques
*/ */
public int getNombreMetriques() { public int getNombreMetriques() {
return metriques != null ? metriques.size() : 0; return metriques != null ? metriques.size() : 0;
} }
/** /**
* Retourne le nombre de sections configurées * Retourne le nombre de sections configurées
* *
* @return Le nombre de sections * @return Le nombre de sections
*/ */
public int getNombreSections() { public int getNombreSections() {
return sections != null ? sections.size() : 0; return sections != null ? sections.size() : 0;
} }
/** /**
* Vérifie si le rapport utilise une période personnalisée * Vérifie si le rapport utilise une période personnalisée
* *
* @return true si la période est personnalisée * @return true si la période est personnalisée
*/ */
public boolean isPeriodePersonnalisee() { public boolean isPeriodePersonnalisee() {
return periodeAnalyse == PeriodeAnalyse.PERIODE_PERSONNALISEE; return periodeAnalyse == PeriodeAnalyse.PERIODE_PERSONNALISEE;
} }
/** /**
* Vérifie si le rapport est confidentiel (niveau >= 4) * Vérifie si le rapport est confidentiel (niveau >= 4)
* *
* @return true si le rapport est confidentiel * @return true si le rapport est confidentiel
*/ */
/** Indique si le niveau de confidentialité est élevé (pour couverture branches). */ /** Indique si le niveau de confidentialité est élevé (pour couverture branches). */
private boolean isNiveauConfidentiel() { private boolean isNiveauConfidentiel() {
if (niveauConfidentialite == null) return false; if (niveauConfidentialite == null) return false;
return niveauConfidentialite >= 4; return niveauConfidentialite >= 4;
} }
public boolean isConfidentiel() { public boolean isConfidentiel() {
return isNiveauConfidentiel(); return isNiveauConfidentiel();
} }
/** /**
* Vérifie si le rapport nécessite une génération * Vérifie si le rapport nécessite une génération
* *
* @return true si la prochaine génération est due * @return true si la prochaine génération est due
*/ */
public boolean necessiteGeneration() { public boolean necessiteGeneration() {
return rapportAutomatique return rapportAutomatique
&& prochaineGeneration != null && prochaineGeneration != null
&& prochaineGeneration.isBefore(LocalDateTime.now()); && prochaineGeneration.isBefore(LocalDateTime.now());
} }
/** /**
* Retourne la fréquence de génération en texte * Retourne la fréquence de génération en texte
* *
* @return La fréquence sous forme de texte * @return La fréquence sous forme de texte
*/ */
public String getFrequenceTexte() { public String getFrequenceTexte() {
if (frequenceGenerationHeures == null) return "Manuelle"; if (frequenceGenerationHeures == null) return "Manuelle";
return switch (frequenceGenerationHeures) { return switch (frequenceGenerationHeures) {
case 1 -> "Toutes les heures"; case 1 -> "Toutes les heures";
case 24 -> "Quotidienne"; case 24 -> "Quotidienne";
case 168 -> "Hebdomadaire"; // 24 * 7 case 168 -> "Hebdomadaire"; // 24 * 7
case 720 -> "Mensuelle"; // 24 * 30 case 720 -> "Mensuelle"; // 24 * 30
default -> "Toutes les " + frequenceGenerationHeures + " heures"; default -> "Toutes les " + frequenceGenerationHeures + " heures";
}; };
} }
} }

View File

@@ -1,32 +1,32 @@
package dev.lions.unionflow.server.api.dto.auth.request; package dev.lions.unionflow.server.api.dto.auth.request;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête d'authentification utilisateur. * Requête d'authentification utilisateur.
* *
* @param username Email ou nom d'utilisateur * @param username Email ou nom d'utilisateur
* @param password Mot de passe * @param password Mot de passe
* @param typeCompte Type de compte (MEMBRE, ADMIN, etc.) * @param typeCompte Type de compte (MEMBRE, ADMIN, etc.)
* @param rememberMe Se souvenir de moi * @param rememberMe Se souvenir de moi
* @author UnionFlow Team * @author UnionFlow Team
* @version 2.0 * @version 2.0
* @since 2026-02-28 * @since 2026-02-28
*/ */
@Builder @Builder
public record LoginRequest( public record LoginRequest(
@NotBlank(message = "L'email ou nom d'utilisateur est requis") @NotBlank(message = "L'email ou nom d'utilisateur est requis")
@Size(min = 3, max = 100, message = "L'email ou nom d'utilisateur doit contenir entre 3 et 100 caractères") @Size(min = 3, max = 100, message = "L'email ou nom d'utilisateur doit contenir entre 3 et 100 caractères")
String username, String username,
@NotBlank(message = "Le mot de passe est requis") @NotBlank(message = "Le mot de passe est requis")
@Size(min = 6, message = "Le mot de passe doit contenir au moins 6 caractères") @Size(min = 6, message = "Le mot de passe doit contenir au moins 6 caractères")
String password, String password,
@NotBlank(message = "Le type de compte est requis") @NotBlank(message = "Le type de compte est requis")
String typeCompte, String typeCompte,
Boolean rememberMe) { Boolean rememberMe) {
} }

View File

@@ -1,90 +1,90 @@
package dev.lions.unionflow.server.api.dto.auth.response; package dev.lions.unionflow.server.api.dto.auth.response;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse d'authentification contenant le token JWT et les informations utilisateur. * Réponse d'authentification contenant le token JWT et les informations utilisateur.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 2.0 * @version 2.0
* @since 2026-02-28 * @since 2026-02-28
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class LoginResponse { public class LoginResponse {
private String accessToken; private String accessToken;
private String refreshToken; private String refreshToken;
@Builder.Default @Builder.Default
private String tokenType = "Bearer"; private String tokenType = "Bearer";
private Long expiresIn; private Long expiresIn;
private LocalDateTime expirationDate; private LocalDateTime expirationDate;
private UserInfo user; private UserInfo user;
/** /**
* Vérifie si le token est expiré. * Vérifie si le token est expiré.
* *
* @return true si le token est expiré * @return true si le token est expiré
*/ */
public boolean isExpired() { public boolean isExpired() {
return expirationDate != null && LocalDateTime.now().isAfter(expirationDate); return expirationDate != null && LocalDateTime.now().isAfter(expirationDate);
} }
/** /**
* Informations de l'utilisateur connecté. * Informations de l'utilisateur connecté.
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class UserInfo { public static class UserInfo {
private UUID id; private UUID id;
private String nom; private String nom;
private String prenom; private String prenom;
private String email; private String email;
private String username; private String username;
private String typeCompte; private String typeCompte;
private List<String> roles; private List<String> roles;
private List<String> permissions; private List<String> permissions;
private EntiteInfo entite; private EntiteInfo entite;
/** /**
* Retourne le nom complet de l'utilisateur. * Retourne le nom complet de l'utilisateur.
* *
* @return Prénom + Nom ou nom d'utilisateur si absent * @return Prénom + Nom ou nom d'utilisateur si absent
*/ */
public String getNomComplet() { public String getNomComplet() {
if (prenom != null && nom != null) { if (prenom != null && nom != null) {
return prenom + " " + nom; return prenom + " " + nom;
} }
return nom != null ? nom : username; return nom != null ? nom : username;
} }
} }
/** /**
* Informations sur l'entité (organisation/membre) de l'utilisateur. * Informations sur l'entité (organisation/membre) de l'utilisateur.
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class EntiteInfo { public static class EntiteInfo {
private UUID id; private UUID id;
private String nom; private String nom;
private String type; private String type;
private String pays; private String pays;
private String ville; private String ville;
} }
} }

View File

@@ -1,42 +1,42 @@
package dev.lions.unionflow.server.api.dto.ayantdroit; package dev.lions.unionflow.server.api.dto.ayantdroit;
import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente; import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Past; import jakarta.validation.constraints.Past;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDate; import java.time.LocalDate;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class AyantDroitRequest { public class AyantDroitRequest {
@NotBlank(message = "L'Id du membre principal rattaché est obligatoire") @NotBlank(message = "L'Id du membre principal rattaché est obligatoire")
private String membrePrincipalId; private String membrePrincipalId;
@NotBlank(message = "Le prénom est obligatoire") @NotBlank(message = "Le prénom est obligatoire")
private String prenom; private String prenom;
@NotBlank(message = "Le nom est obligatoire") @NotBlank(message = "Le nom est obligatoire")
private String nom; private String nom;
@NotNull(message = "La date de naissance est obligatoire pour l'âge limite") @NotNull(message = "La date de naissance est obligatoire pour l'âge limite")
@Past(message = "La date de naissance doit être dans le passé") @Past(message = "La date de naissance doit être dans le passé")
private LocalDate dateNaissance; private LocalDate dateNaissance;
private String sexe; private String sexe;
private String pieceIdentite; private String pieceIdentite;
@NotNull(message = "Le lien de parenté / bénéfice est requis") @NotNull(message = "Le lien de parenté / bénéfice est requis")
private LienParente lienParente; private LienParente lienParente;
// Id document du livret de famille ou certificat médical / scolaire // Id document du livret de famille ou certificat médical / scolaire
private String justificatifLienId; private String justificatifLienId;
} }

View File

@@ -1,40 +1,40 @@
package dev.lions.unionflow.server.api.dto.ayantdroit; package dev.lions.unionflow.server.api.dto.ayantdroit;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente; import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente;
import dev.lions.unionflow.server.api.enums.ayantdroit.StatutAyantDroit; import dev.lions.unionflow.server.api.enums.ayantdroit.StatutAyantDroit;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDate; import java.time.LocalDate;
import java.math.BigDecimal; import java.math.BigDecimal;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class AyantDroitResponse extends BaseDTO { public class AyantDroitResponse extends BaseDTO {
private String membrePrincipalId; private String membrePrincipalId;
private String numeroCarteBeneficiaire; private String numeroCarteBeneficiaire;
private String prenom; private String prenom;
private String nom; private String nom;
private LocalDate dateNaissance; private LocalDate dateNaissance;
private Integer ageActuel; private Integer ageActuel;
private String sexe; private String sexe;
private String pieceIdentite; private String pieceIdentite;
private LienParente lienParente; private LienParente lienParente;
// Prise en charge (%) par rapport à la couverture du Membre Principal // Prise en charge (%) par rapport à la couverture du Membre Principal
private BigDecimal pourcentageCouvertureSante; private BigDecimal pourcentageCouvertureSante;
private StatutAyantDroit statut; private StatutAyantDroit statut;
} }

View File

@@ -1,28 +1,28 @@
package dev.lions.unionflow.server.api.dto.backup.request; package dev.lions.unionflow.server.api.dto.backup.request;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* Request pour créer une sauvegarde * Request pour créer une sauvegarde
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class CreateBackupRequest { public class CreateBackupRequest {
@NotBlank(message = "Le nom de la sauvegarde est requis") @NotBlank(message = "Le nom de la sauvegarde est requis")
private String name; private String name;
private String description; private String description;
private String type; // AUTO, MANUAL, RESTORE_POINT private String type; // AUTO, MANUAL, RESTORE_POINT
private Boolean includeDatabase; private Boolean includeDatabase;
private Boolean includeFiles; private Boolean includeFiles;
private Boolean includeConfiguration; private Boolean includeConfiguration;
} }

View File

@@ -1,28 +1,28 @@
package dev.lions.unionflow.server.api.dto.backup.request; package dev.lions.unionflow.server.api.dto.backup.request;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.UUID; import java.util.UUID;
/** /**
* Request pour restaurer une sauvegarde * Request pour restaurer une sauvegarde
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class RestoreBackupRequest { public class RestoreBackupRequest {
@NotNull(message = "L'ID de la sauvegarde est requis") @NotNull(message = "L'ID de la sauvegarde est requis")
private UUID backupId; private UUID backupId;
private Boolean restoreDatabase; private Boolean restoreDatabase;
private Boolean restoreFiles; private Boolean restoreFiles;
private Boolean restoreConfiguration; private Boolean restoreConfiguration;
private Boolean createRestorePoint; // Créer un point de restauration avant private Boolean createRestorePoint; // Créer un point de restauration avant
} }

View File

@@ -1,25 +1,25 @@
package dev.lions.unionflow.server.api.dto.backup.request; package dev.lions.unionflow.server.api.dto.backup.request;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* Request pour mettre à jour la configuration des sauvegardes automatiques * Request pour mettre à jour la configuration des sauvegardes automatiques
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class UpdateBackupConfigRequest { public class UpdateBackupConfigRequest {
private Boolean autoBackupEnabled; private Boolean autoBackupEnabled;
private String frequency; // HOURLY, DAILY, WEEKLY private String frequency; // HOURLY, DAILY, WEEKLY
private String retention; // "7 jours", "30 jours", "90 jours", "1 an" private String retention; // "7 jours", "30 jours", "90 jours", "1 an"
private Integer retentionDays; private Integer retentionDays;
private String backupTime; // Format HH:mm pour sauvegarde quotidienne private String backupTime; // Format HH:mm pour sauvegarde quotidienne
private Boolean includeDatabase; private Boolean includeDatabase;
private Boolean includeFiles; private Boolean includeFiles;
private Boolean includeConfiguration; private Boolean includeConfiguration;
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.backup.response; package dev.lions.unionflow.server.api.dto.backup.response;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
* Response contenant la configuration des sauvegardes automatiques * Response contenant la configuration des sauvegardes automatiques
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class BackupConfigResponse { public class BackupConfigResponse {
private Boolean autoBackupEnabled; private Boolean autoBackupEnabled;
private String frequency; // HOURLY, DAILY, WEEKLY private String frequency; // HOURLY, DAILY, WEEKLY
private String retention; // "7 jours", "30 jours", etc. private String retention; // "7 jours", "30 jours", etc.
private Integer retentionDays; private Integer retentionDays;
private String backupTime; // HH:mm private String backupTime; // HH:mm
private Boolean includeDatabase; private Boolean includeDatabase;
private Boolean includeFiles; private Boolean includeFiles;
private Boolean includeConfiguration; private Boolean includeConfiguration;
private LocalDateTime lastBackup; private LocalDateTime lastBackup;
private LocalDateTime nextScheduledBackup; private LocalDateTime nextScheduledBackup;
private Integer totalBackups; private Integer totalBackups;
private Long totalSizeBytes; private Long totalSizeBytes;
private String totalSizeFormatted; private String totalSizeFormatted;
} }

View File

@@ -1,37 +1,37 @@
package dev.lions.unionflow.server.api.dto.backup.response; package dev.lions.unionflow.server.api.dto.backup.response;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
/** /**
* Response représentant une sauvegarde * Response représentant une sauvegarde
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class BackupResponse { public class BackupResponse {
private UUID id; private UUID id;
private String name; private String name;
private String description; private String description;
private String type; // AUTO, MANUAL, RESTORE_POINT private String type; // AUTO, MANUAL, RESTORE_POINT
private Long sizeBytes; private Long sizeBytes;
private String sizeFormatted; // ex: "2.3 GB" private String sizeFormatted; // ex: "2.3 GB"
private String status; // PENDING, IN_PROGRESS, COMPLETED, FAILED private String status; // PENDING, IN_PROGRESS, COMPLETED, FAILED
private LocalDateTime createdAt; private LocalDateTime createdAt;
private LocalDateTime completedAt; private LocalDateTime completedAt;
private String createdBy; private String createdBy;
private Boolean includesDatabase; private Boolean includesDatabase;
private Boolean includesFiles; private Boolean includesFiles;
private Boolean includesConfiguration; private Boolean includesConfiguration;
private String filePath; private String filePath;
private String errorMessage; // Si status = FAILED private String errorMessage; // Si status = FAILED
} }

View File

@@ -1,164 +1,164 @@
package dev.lions.unionflow.server.api.dto.base; package dev.lions.unionflow.server.api.dto.base;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** /**
* Classe de base pour tous les DTOs UnionFlow Fournit les propriétés communes * Classe de base pour tous les DTOs UnionFlow Fournit les propriétés communes
* d'audit et de gestion * d'audit et de gestion
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-10 * @since 2025-01-10
*/ */
@Getter @Getter
@Setter @Setter
public abstract class BaseDTO implements Serializable { public abstract class BaseDTO implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** Identifiant unique UUID */ /** Identifiant unique UUID */
private UUID id; private UUID id;
/** Date de création de l'enregistrement */ /** Date de création de l'enregistrement */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime dateCreation; public LocalDateTime dateCreation;
/** Date de dernière modification */ /** Date de dernière modification */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime dateModification; public LocalDateTime dateModification;
/** Utilisateur qui a créé l'enregistrement */ /** Utilisateur qui a créé l'enregistrement */
private String creePar; private String creePar;
/** Utilisateur qui a modifié l'enregistrement en dernier */ /** Utilisateur qui a modifié l'enregistrement en dernier */
private String modifiePar; private String modifiePar;
/** Version pour gestion de la concurrence optimiste */ /** Version pour gestion de la concurrence optimiste */
private Long version; private Long version;
/** Indicateur si l'enregistrement est actif */ /** Indicateur si l'enregistrement est actif */
private Boolean actif; private Boolean actif;
// Constructeur par défaut // Constructeur par défaut
public BaseDTO() { public BaseDTO() {
this.dateCreation = LocalDateTime.now(); this.dateCreation = LocalDateTime.now();
this.actif = true; this.actif = true;
this.version = 0L; this.version = 0L;
} }
// Getters et Setters générés automatiquement par Lombok @Getter/@Setter // Getters et Setters générés automatiquement par Lombok @Getter/@Setter
// Méthodes utilitaires // Méthodes utilitaires
/** /**
* Marque l'entité comme nouvellement créée * Marque l'entité comme nouvellement créée
* *
* @param utilisateur L'utilisateur qui crée l'entité * @param utilisateur L'utilisateur qui crée l'entité
*/ */
public void marquerCommeNouveau(String utilisateur) { public void marquerCommeNouveau(String utilisateur) {
LocalDateTime maintenant = LocalDateTime.now(); LocalDateTime maintenant = LocalDateTime.now();
this.dateCreation = maintenant; this.dateCreation = maintenant;
this.dateModification = maintenant; this.dateModification = maintenant;
this.creePar = utilisateur; this.creePar = utilisateur;
this.modifiePar = utilisateur; this.modifiePar = utilisateur;
this.version = 0L; this.version = 0L;
this.actif = true; this.actif = true;
} }
/** /**
* Marque l'entité comme modifiée * Marque l'entité comme modifiée
* *
* @param utilisateur L'utilisateur qui modifie l'entité * @param utilisateur L'utilisateur qui modifie l'entité
*/ */
public void marquerCommeModifie(String utilisateur) { public void marquerCommeModifie(String utilisateur) {
this.dateModification = LocalDateTime.now(); this.dateModification = LocalDateTime.now();
this.modifiePar = utilisateur; this.modifiePar = utilisateur;
if (this.version != null) { if (this.version != null) {
this.version++; this.version++;
} }
} }
/** /**
* Désactive l'entité (soft delete) * Désactive l'entité (soft delete)
* *
* @param utilisateur L'utilisateur qui désactive l'entité * @param utilisateur L'utilisateur qui désactive l'entité
*/ */
public void desactiver(String utilisateur) { public void desactiver(String utilisateur) {
this.actif = false; this.actif = false;
marquerCommeModifie(utilisateur); marquerCommeModifie(utilisateur);
} }
/** /**
* Réactive l'entité * Réactive l'entité
* *
* @param utilisateur L'utilisateur qui réactive l'entité * @param utilisateur L'utilisateur qui réactive l'entité
*/ */
public void reactiver(String utilisateur) { public void reactiver(String utilisateur) {
this.actif = true; this.actif = true;
marquerCommeModifie(utilisateur); marquerCommeModifie(utilisateur);
} }
/** /**
* Vérifie si l'entité est nouvelle (pas encore persistée) * Vérifie si l'entité est nouvelle (pas encore persistée)
* *
* @return true si l'entité est nouvelle * @return true si l'entité est nouvelle
*/ */
public boolean isNouveau() { public boolean isNouveau() {
return id == null; return id == null;
} }
/** /**
* Vérifie si l'entité est active * Vérifie si l'entité est active
* *
* @return true si l'entité est active * @return true si l'entité est active
*/ */
public boolean isActif() { public boolean isActif() {
return Boolean.TRUE.equals(actif); return Boolean.TRUE.equals(actif);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null || getClass() != obj.getClass()) if (obj == null || getClass() != obj.getClass())
return false; return false;
BaseDTO baseDTO = (BaseDTO) obj; BaseDTO baseDTO = (BaseDTO) obj;
return id != null && id.equals(baseDTO.id); return id != null && id.equals(baseDTO.id);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return id != null ? id.hashCode() : 0; return id != null ? id.hashCode() : 0;
} }
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() return getClass().getSimpleName()
+ "{" + "{"
+ "id=" + "id="
+ id + id
+ ", dateCreation=" + ", dateCreation="
+ dateCreation + dateCreation
+ ", dateModification=" + ", dateModification="
+ dateModification + dateModification
+ ", creePar='" + ", creePar='"
+ creePar + creePar
+ '\'' + '\''
+ ", modifiePar='" + ", modifiePar='"
+ modifiePar + modifiePar
+ '\'' + '\''
+ ", version=" + ", version="
+ version + version
+ ", actif=" + ", actif="
+ actif + actif
+ '}'; + '}';
} }
} }

View File

@@ -1,79 +1,79 @@
package dev.lions.unionflow.server.api.dto.base; package dev.lions.unionflow.server.api.dto.base;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** /**
* Classe de base pour les DTOs de réponse. * Classe de base pour les DTOs de réponse.
* *
* <p> * <p>
* Contient les champs d'audit communs à toutes * Contient les champs d'audit communs à toutes
* les réponses : identifiant, dates de * les réponses : identifiant, dates de
* création/modification, créateur, et version. * création/modification, créateur, et version.
* *
* <p> * <p>
* Les DTOs de type Request ne doivent * Les DTOs de type Request ne doivent
* <b>pas</b> hériter de cette classe (utiliser * <b>pas</b> hériter de cette classe (utiliser
* des {@code record} sans héritage). * des {@code record} sans héritage).
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
* @since 2026-02-21 * @since 2026-02-21
*/ */
@Getter @Getter
@Setter @Setter
public abstract class BaseResponse { public abstract class BaseResponse {
/** Identifiant unique de l'entité. */ /** Identifiant unique de l'entité. */
private UUID id; private UUID id;
/** Date de création de l'entité. */ /** Date de création de l'entité. */
private LocalDateTime dateCreation; private LocalDateTime dateCreation;
/** Date de dernière modification. */ /** Date de dernière modification. */
private LocalDateTime dateModification; private LocalDateTime dateModification;
/** Email du créateur. */ /** Email du créateur. */
private String creePar; private String creePar;
/** Email du dernier modificateur. */ /** Email du dernier modificateur. */
private String modifiePar; private String modifiePar;
/** Version pour l'optimistic locking. */ /** Version pour l'optimistic locking. */
private Long version; private Long version;
/** État actif/inactif (soft-delete). */ /** État actif/inactif (soft-delete). */
private Boolean actif; private Boolean actif;
/** /**
* Comparaison basée sur l'ID. * Comparaison basée sur l'ID.
* Deux BaseResponse sont égaux si leurs IDs sont égaux et non null. * Deux BaseResponse sont égaux si leurs IDs sont égaux et non null.
* *
* @param obj Objet à comparer * @param obj Objet à comparer
* @return true si les objets ont le même ID * @return true si les objets ont le même ID
*/ */
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj == null || getClass() != obj.getClass()) { if (obj == null || getClass() != obj.getClass()) {
return false; return false;
} }
BaseResponse that = (BaseResponse) obj; BaseResponse that = (BaseResponse) obj;
return id != null && id.equals(that.id); return id != null && id.equals(that.id);
} }
/** /**
* Hash code basé sur l'ID. * Hash code basé sur l'ID.
* *
* @return Hash code de l'ID, ou 0 si ID null * @return Hash code de l'ID, ou 0 si ID null
*/ */
@Override @Override
public int hashCode() { public int hashCode() {
return id != null ? id.hashCode() : 0; return id != null ? id.hashCode() : 0;
} }
} }

View File

@@ -1,59 +1,59 @@
package dev.lions.unionflow.server.api.dto.base; package dev.lions.unionflow.server.api.dto.base;
import java.util.List; import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* Réponse paginée générique. * Réponse paginée générique.
* *
* <p> * <p>
* Encapsule une liste d'éléments avec les * Encapsule une liste d'éléments avec les
* métadonnées de pagination (page, taille, * métadonnées de pagination (page, taille,
* total). Utilisable pour tout type de réponse * total). Utilisable pour tout type de réponse
* paginée. * paginée.
* *
* @param <T> type des éléments de la page * @param <T> type des éléments de la page
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
* @since 2026-02-21 * @since 2026-02-21
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public class PageResponse<T> { public class PageResponse<T> {
/** Éléments de la page courante. */ /** Éléments de la page courante. */
private final List<T> contenu; private final List<T> contenu;
/** Numéro de page courant (0-indexed). */ /** Numéro de page courant (0-indexed). */
private final int page; private final int page;
/** Taille de la page demandée. */ /** Taille de la page demandée. */
private final int taille; private final int taille;
/** Nombre total d'éléments. */ /** Nombre total d'éléments. */
private final long totalElements; private final long totalElements;
/** Nombre total de pages. */ /** Nombre total de pages. */
private final int totalPages; private final int totalPages;
/** /**
* Indique s'il existe une page suivante. * Indique s'il existe une page suivante.
* *
* @return {@code true} si une page suivante * @return {@code true} si une page suivante
* existe * existe
*/ */
public boolean hasNext() { public boolean hasNext() {
return page < totalPages - 1; return page < totalPages - 1;
} }
/** /**
* Indique s'il existe une page précédente. * Indique s'il existe une page précédente.
* *
* @return {@code true} si une page précédente * @return {@code true} si une page précédente
* existe * existe
*/ */
public boolean hasPrevious() { public boolean hasPrevious() {
return page > 0; return page > 0;
} }
} }

View File

@@ -1,45 +1,45 @@
package dev.lions.unionflow.server.api.dto.collectefonds; package dev.lions.unionflow.server.api.dto.collectefonds;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte; import dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Campagne de levée de fonds (Crowdfunding / ONG)") @Schema(description = "Campagne de levée de fonds (Crowdfunding / ONG)")
public class CampagneCollecteResponse extends BaseDTO { public class CampagneCollecteResponse extends BaseDTO {
private String organisationId; private String organisationId;
private String titre; private String titre;
private String courteDescription; private String courteDescription;
private String htmlDescriptionComplete; private String htmlDescriptionComplete;
private String imageBanniereUrl; private String imageBanniereUrl;
@Schema(description = "Objectif monétaire escompté") @Schema(description = "Objectif monétaire escompté")
private BigDecimal objectifFinancier; private BigDecimal objectifFinancier;
@Schema(description = "Somme totale déjà récoltée sur cette campagne") @Schema(description = "Somme totale déjà récoltée sur cette campagne")
private BigDecimal montantCollecteActuel; private BigDecimal montantCollecteActuel;
private Integer nombreDonateurs; private Integer nombreDonateurs;
private StatutCampagneCollecte statut; private StatutCampagneCollecte statut;
private LocalDateTime dateOuverture; private LocalDateTime dateOuverture;
private LocalDateTime dateCloturePrevue; private LocalDateTime dateCloturePrevue;
// Si la page est visible pour les non-membres (donateurs externes) // Si la page est visible pour les non-membres (donateurs externes)
private Boolean estPublique; private Boolean estPublique;
} }

View File

@@ -1,42 +1,42 @@
package dev.lions.unionflow.server.api.dto.collectefonds; package dev.lions.unionflow.server.api.dto.collectefonds;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave; import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Don transactionnel reçu pour une campagne de collecte") @Schema(description = "Don transactionnel reçu pour une campagne de collecte")
public class ContributionCollecteDTO extends BaseDTO { public class ContributionCollecteDTO extends BaseDTO {
private String campagneId; private String campagneId;
@Schema(description = "Id du membre (Null si le don est public/externe)") @Schema(description = "Id du membre (Null si le don est public/externe)")
private String membreDonateurId; private String membreDonateurId;
@Schema(description = "Nom affiché si don public ou pour le mur de contributeurs") @Schema(description = "Nom affiché si don public ou pour le mur de contributeurs")
private String aliasDonateur; private String aliasDonateur;
private Boolean estAnonyme; private Boolean estAnonyme;
private BigDecimal montantSoutien; private BigDecimal montantSoutien;
private String messageSoutien; private String messageSoutien;
private LocalDateTime dateContribution; private LocalDateTime dateContribution;
// Lien avec la passerelle de paiement // Lien avec la passerelle de paiement
private String transactionPaiementId; private String transactionPaiementId;
private StatutTransactionWave statutPaiement; private StatutTransactionWave statutPaiement;
} }

View File

@@ -1,125 +1,125 @@
package dev.lions.unionflow.server.api.dto.common; package dev.lions.unionflow.server.api.dto.common;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List; import java.util.List;
/** /**
* DTO générique pour les réponses paginées de l'API. * DTO générique pour les réponses paginées de l'API.
* Utilisé par tous les endpoints REST qui renvoient des données paginées. * Utilisé par tous les endpoints REST qui renvoient des données paginées.
* *
* @param <T> Type des éléments dans la liste * @param <T> Type des éléments dans la liste
* @author UnionFlow Team * @author UnionFlow Team
* @version 2.0 * @version 2.0
*/ */
public class PagedResponse<T> { public class PagedResponse<T> {
@JsonProperty("data") @JsonProperty("data")
private List<T> data; private List<T> data;
@JsonProperty("total") @JsonProperty("total")
private Long total; private Long total;
@JsonProperty("page") @JsonProperty("page")
private Integer page; private Integer page;
@JsonProperty("size") @JsonProperty("size")
private Integer size; private Integer size;
@JsonProperty("totalPages") @JsonProperty("totalPages")
private Integer totalPages; private Integer totalPages;
// Constructeurs // Constructeurs
public PagedResponse() { public PagedResponse() {
} }
public PagedResponse(List<T> data, Long total, Integer page, Integer size) { public PagedResponse(List<T> data, Long total, Integer page, Integer size) {
this.data = data; this.data = data;
this.total = total; this.total = total;
this.page = page; this.page = page;
this.size = size; this.size = size;
this.totalPages = calculateTotalPages(total, size); this.totalPages = calculateTotalPages(total, size);
} }
public PagedResponse(List<T> data, Long total, Integer page, Integer size, Integer totalPages) { public PagedResponse(List<T> data, Long total, Integer page, Integer size, Integer totalPages) {
this.data = data; this.data = data;
this.total = total; this.total = total;
this.page = page; this.page = page;
this.size = size; this.size = size;
this.totalPages = totalPages; this.totalPages = totalPages;
} }
// Méthode utilitaire pour calculer le nombre de pages // Méthode utilitaire pour calculer le nombre de pages
private Integer calculateTotalPages(Long total, Integer size) { private Integer calculateTotalPages(Long total, Integer size) {
if (size == null || size == 0 || total == null) { if (size == null || size == 0 || total == null) {
return 0; return 0;
} }
return (int) Math.ceil((double) total / size); return (int) Math.ceil((double) total / size);
} }
// Getters et setters // Getters et setters
public List<T> getData() { public List<T> getData() {
return data; return data;
} }
public void setData(List<T> data) { public void setData(List<T> data) {
this.data = data; this.data = data;
} }
public Long getTotal() { public Long getTotal() {
return total; return total;
} }
public void setTotal(Long total) { public void setTotal(Long total) {
this.total = total; this.total = total;
this.totalPages = calculateTotalPages(total, this.size); this.totalPages = calculateTotalPages(total, this.size);
} }
public Integer getPage() { public Integer getPage() {
return page; return page;
} }
public void setPage(Integer page) { public void setPage(Integer page) {
this.page = page; this.page = page;
} }
public Integer getSize() { public Integer getSize() {
return size; return size;
} }
public void setSize(Integer size) { public void setSize(Integer size) {
this.size = size; this.size = size;
this.totalPages = calculateTotalPages(this.total, size); this.totalPages = calculateTotalPages(this.total, size);
} }
public Integer getTotalPages() { public Integer getTotalPages() {
return totalPages; return totalPages;
} }
public void setTotalPages(Integer totalPages) { public void setTotalPages(Integer totalPages) {
this.totalPages = totalPages; this.totalPages = totalPages;
} }
// Méthodes utilitaires // Méthodes utilitaires
public boolean hasNext() { public boolean hasNext() {
return page != null && totalPages != null && page < totalPages - 1; return page != null && totalPages != null && page < totalPages - 1;
} }
public boolean hasPrevious() { public boolean hasPrevious() {
return page != null && page > 0; return page != null && page > 0;
} }
public boolean isEmpty() { public boolean isEmpty() {
return data == null || data.isEmpty(); return data == null || data.isEmpty();
} }
@Override @Override
public String toString() { public String toString() {
return "PagedResponse{" + return "PagedResponse{" +
"total=" + total + "total=" + total +
", page=" + page + ", page=" + page +
", size=" + size + ", size=" + size +
", totalPages=" + totalPages + ", totalPages=" + totalPages +
", itemsCount=" + (data != null ? data.size() : 0) + ", itemsCount=" + (data != null ? data.size() : 0) +
'}'; '}';
} }
} }

View File

@@ -1,27 +1,27 @@
package dev.lions.unionflow.server.api.dto.communication.request; package dev.lions.unionflow.server.api.dto.communication.request;
import dev.lions.unionflow.server.api.enums.communication.ConversationType; import dev.lions.unionflow.server.api.enums.communication.ConversationType;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Builder; import lombok.Builder;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* Request DTO pour créer une conversation * Request DTO pour créer une conversation
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-16 * @since 2026-03-16
*/ */
@Builder @Builder
public record CreateConversationRequest( public record CreateConversationRequest(
@NotBlank @Size(max = 255) String name, @NotBlank @Size(max = 255) String name,
@Size(max = 1000) String description, @Size(max = 1000) String description,
@NotNull ConversationType type, @NotNull ConversationType type,
@NotEmpty List<UUID> participantIds, @NotEmpty List<UUID> participantIds,
UUID organisationId UUID organisationId
) {} ) {}

View File

@@ -1,29 +1,29 @@
package dev.lions.unionflow.server.api.dto.communication.request; package dev.lions.unionflow.server.api.dto.communication.request;
import dev.lions.unionflow.server.api.enums.communication.MessagePriority; import dev.lions.unionflow.server.api.enums.communication.MessagePriority;
import dev.lions.unionflow.server.api.enums.communication.MessageType; import dev.lions.unionflow.server.api.enums.communication.MessageType;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Builder; import lombok.Builder;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* Request DTO pour envoyer un message * Request DTO pour envoyer un message
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-16 * @since 2026-03-16
*/ */
@Builder @Builder
public record SendMessageRequest( public record SendMessageRequest(
@NotNull UUID conversationId, @NotNull UUID conversationId,
@NotBlank @Size(max = 10000) String content, @NotBlank @Size(max = 10000) String content,
MessageType type, MessageType type,
MessagePriority priority, MessagePriority priority,
List<UUID> recipientIds, List<UUID> recipientIds,
List<String> recipientRoles, List<String> recipientRoles,
List<String> attachments List<String> attachments
) {} ) {}

View File

@@ -1,28 +1,28 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable; import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un compte comptable. * Requête de création d'un compte comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateCompteComptableRequest( public record CreateCompteComptableRequest(
@NotBlank(message = "Le numéro de compte est obligatoire") String numeroCompte, @NotBlank(message = "Le numéro de compte est obligatoire") String numeroCompte,
@NotBlank(message = "Le libellé est obligatoire") String libelle, @NotBlank(message = "Le libellé est obligatoire") String libelle,
@NotNull(message = "Le type de compte est obligatoire") TypeCompteComptable typeCompte, @NotNull(message = "Le type de compte est obligatoire") TypeCompteComptable typeCompte,
@NotNull(message = "La classe comptable est obligatoire") @Min(value = 1, message = "La classe comptable doit être entre 1 et 7") @Max(value = 7, message = "La classe comptable doit être entre 1 et 7") Integer classeComptable, @NotNull(message = "La classe comptable est obligatoire") @Min(value = 1, message = "La classe comptable doit être entre 1 et 7") @Max(value = 7, message = "La classe comptable doit être entre 1 et 7") Integer classeComptable,
BigDecimal soldeInitial, BigDecimal soldeInitial,
BigDecimal soldeActuel, BigDecimal soldeActuel,
Boolean compteCollectif, Boolean compteCollectif,
Boolean compteAnalytique, Boolean compteAnalytique,
String description) { String description) {
} }

View File

@@ -1,41 +1,41 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une écriture comptable. * Requête de création d'une écriture comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateEcritureComptableRequest( public record CreateEcritureComptableRequest(
@NotBlank(message = "Le numéro de pièce est obligatoire") String numeroPiece, @NotBlank(message = "Le numéro de pièce est obligatoire") String numeroPiece,
@NotNull(message = "La date de l'écriture est obligatoire") LocalDate dateEcriture, @NotNull(message = "La date de l'écriture est obligatoire") LocalDate dateEcriture,
@NotBlank(message = "Le libellé est obligatoire") String libelle, @NotBlank(message = "Le libellé est obligatoire") String libelle,
String reference, String reference,
String lettrage, String lettrage,
Boolean pointe, Boolean pointe,
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit, @DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit,
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit, @DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
String commentaire, String commentaire,
@NotNull(message = "Le journal est obligatoire") UUID journalId, @NotNull(message = "Le journal est obligatoire") UUID journalId,
UUID organisationId, UUID organisationId,
UUID paiementId, UUID paiementId,
List<CreateLigneEcritureRequest> lignes) { List<CreateLigneEcritureRequest> lignes) {
} }

View File

@@ -1,24 +1,24 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable; import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un journal comptable. * Requête de création d'un journal comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateJournalComptableRequest( public record CreateJournalComptableRequest(
@NotBlank(message = "Le code du journal est obligatoire") String code, @NotBlank(message = "Le code du journal est obligatoire") String code,
@NotBlank(message = "Le libellé est obligatoire") String libelle, @NotBlank(message = "Le libellé est obligatoire") String libelle,
@NotNull(message = "Le type de journal est obligatoire") TypeJournalComptable typeJournal, @NotNull(message = "Le type de journal est obligatoire") TypeJournalComptable typeJournal,
LocalDate dateDebut, LocalDate dateDebut,
LocalDate dateFin, LocalDate dateFin,
String statut, String statut,
String description) { String description) {
} }

View File

@@ -1,30 +1,30 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une ligne d'écriture comptable. * Requête de création d'une ligne d'écriture comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateLigneEcritureRequest( public record CreateLigneEcritureRequest(
@NotNull(message = "Le numéro de ligne est obligatoire") @Min(value = 1, message = "Le numéro de ligne doit être positif") Integer numeroLigne, @NotNull(message = "Le numéro de ligne est obligatoire") @Min(value = 1, message = "Le numéro de ligne doit être positif") Integer numeroLigne,
@DecimalMin(value = "0.0", message = "Le montant débit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit, @DecimalMin(value = "0.0", message = "Le montant débit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit,
@DecimalMin(value = "0.0", message = "Le montant crédit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit, @DecimalMin(value = "0.0", message = "Le montant crédit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
String libelle, String libelle,
String reference, String reference,
@NotNull(message = "L'écriture est obligatoire") UUID ecritureId, @NotNull(message = "L'écriture est obligatoire") UUID ecritureId,
@NotNull(message = "Le compte comptable est obligatoire") UUID compteComptableId) { @NotNull(message = "Le compte comptable est obligatoire") UUID compteComptableId) {
} }

View File

@@ -1,26 +1,26 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable; import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import java.math.BigDecimal; import java.math.BigDecimal;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'un compte comptable. * Requête de mise à jour d'un compte comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateCompteComptableRequest( public record UpdateCompteComptableRequest(
String numeroCompte, String numeroCompte,
String libelle, String libelle,
TypeCompteComptable typeCompte, TypeCompteComptable typeCompte,
@Min(value = 1, message = "La classe comptable doit être entre 1 et 7") @Max(value = 7, message = "La classe comptable doit être entre 1 et 7") Integer classeComptable, @Min(value = 1, message = "La classe comptable doit être entre 1 et 7") @Max(value = 7, message = "La classe comptable doit être entre 1 et 7") Integer classeComptable,
BigDecimal soldeInitial, BigDecimal soldeInitial,
BigDecimal soldeActuel, BigDecimal soldeActuel,
Boolean compteCollectif, Boolean compteCollectif,
Boolean compteAnalytique, Boolean compteAnalytique,
String description) { String description) {
} }

View File

@@ -1,34 +1,34 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une écriture comptable. * Requête de mise à jour d'une écriture comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateEcritureComptableRequest( public record UpdateEcritureComptableRequest(
String numeroPiece, String numeroPiece,
LocalDate dateEcriture, LocalDate dateEcriture,
String libelle, String libelle,
String reference, String reference,
String lettrage, String lettrage,
Boolean pointe, Boolean pointe,
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit, @DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit,
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit, @DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
String commentaire, String commentaire,
UUID journalId, UUID journalId,
UUID paiementId, UUID paiementId,
List<UpdateLigneEcritureRequest> lignes) { List<UpdateLigneEcritureRequest> lignes) {
} }

View File

@@ -1,21 +1,21 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable; import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'un journal comptable. * Requête de mise à jour d'un journal comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateJournalComptableRequest( public record UpdateJournalComptableRequest(
String libelle, String libelle,
TypeJournalComptable typeJournal, TypeJournalComptable typeJournal,
LocalDate dateDebut, LocalDate dateDebut,
LocalDate dateFin, LocalDate dateFin,
String statut, String statut,
String description) { String description) {
} }

View File

@@ -1,24 +1,24 @@
package dev.lions.unionflow.server.api.dto.comptabilite.request; package dev.lions.unionflow.server.api.dto.comptabilite.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une ligne d'écriture comptable. * Requête de mise à jour d'une ligne d'écriture comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateLigneEcritureRequest( public record UpdateLigneEcritureRequest(
@Min(value = 1, message = "Le numéro de ligne doit être positif") Integer numeroLigne, @Min(value = 1, message = "Le numéro de ligne doit être positif") Integer numeroLigne,
@DecimalMin(value = "0.0", message = "Le montant débit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit, @DecimalMin(value = "0.0", message = "Le montant débit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit,
@DecimalMin(value = "0.0", message = "Le montant crédit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit, @DecimalMin(value = "0.0", message = "Le montant crédit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
String libelle, String libelle,
String reference, String reference,
UUID compteComptableId) { UUID compteComptableId) {
} }

View File

@@ -1,35 +1,35 @@
package dev.lions.unionflow.server.api.dto.comptabilite.response; package dev.lions.unionflow.server.api.dto.comptabilite.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable; import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
import java.math.BigDecimal; import java.math.BigDecimal;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée d'un compte comptable. * Réponse détaillée d'un compte comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class CompteComptableResponse extends BaseResponse { public class CompteComptableResponse extends BaseResponse {
private String numeroCompte; private String numeroCompte;
private String libelle; private String libelle;
private TypeCompteComptable typeCompte; private TypeCompteComptable typeCompte;
private Integer classeComptable; private Integer classeComptable;
private BigDecimal soldeInitial; private BigDecimal soldeInitial;
private BigDecimal soldeActuel; private BigDecimal soldeActuel;
private Boolean compteCollectif; private Boolean compteCollectif;
private Boolean compteAnalytique; private Boolean compteAnalytique;
private String description; private String description;
} }

View File

@@ -1,41 +1,41 @@
package dev.lions.unionflow.server.api.dto.comptabilite.response; package dev.lions.unionflow.server.api.dto.comptabilite.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée d'une écriture comptable. * Réponse détaillée d'une écriture comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class EcritureComptableResponse extends BaseResponse { public class EcritureComptableResponse extends BaseResponse {
private String numeroPiece; private String numeroPiece;
private LocalDate dateEcriture; private LocalDate dateEcriture;
private String libelle; private String libelle;
private String reference; private String reference;
private String lettrage; private String lettrage;
private Boolean pointe; private Boolean pointe;
private BigDecimal montantDebit; private BigDecimal montantDebit;
private BigDecimal montantCredit; private BigDecimal montantCredit;
private String commentaire; private String commentaire;
private UUID journalId; private UUID journalId;
private UUID organisationId; private UUID organisationId;
private UUID paiementId; private UUID paiementId;
private List<LigneEcritureResponse> lignes; private List<LigneEcritureResponse> lignes;
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.comptabilite.response; package dev.lions.unionflow.server.api.dto.comptabilite.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable; import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée d'un journal comptable. * Réponse détaillée d'un journal comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class JournalComptableResponse extends BaseResponse { public class JournalComptableResponse extends BaseResponse {
private String code; private String code;
private String libelle; private String libelle;
private TypeJournalComptable typeJournal; private TypeJournalComptable typeJournal;
private LocalDate dateDebut; private LocalDate dateDebut;
private LocalDate dateFin; private LocalDate dateFin;
private String statut; private String statut;
private String description; private String description;
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.comptabilite.response; package dev.lions.unionflow.server.api.dto.comptabilite.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée d'une ligne d'écriture comptable. * Réponse détaillée d'une ligne d'écriture comptable.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class LigneEcritureResponse extends BaseResponse { public class LigneEcritureResponse extends BaseResponse {
private Integer numeroLigne; private Integer numeroLigne;
private BigDecimal montantDebit; private BigDecimal montantDebit;
private BigDecimal montantCredit; private BigDecimal montantCredit;
private String libelle; private String libelle;
private String reference; private String reference;
private UUID ecritureId; private UUID ecritureId;
private UUID compteComptableId; private UUID compteComptableId;
} }

View File

@@ -1,22 +1,22 @@
package dev.lions.unionflow.server.api.dto.config.request; package dev.lions.unionflow.server.api.dto.config.request;
import java.util.Map; import java.util.Map;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une configuration. * Requête de création d'une configuration.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateConfigurationRequest( public record CreateConfigurationRequest(
String cle, String cle,
String valeur, String valeur,
String type, String type,
String categorie, String categorie,
String description, String description,
Boolean modifiable, Boolean modifiable,
Boolean visible, Boolean visible,
Map<String, Object> metadonnees) { Map<String, Object> metadonnees) {
} }

View File

@@ -1,50 +1,50 @@
package dev.lions.unionflow.server.api.dto.config.request; package dev.lions.unionflow.server.api.dto.config.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* Requête de création/mise à jour des paramètres LCB-FT (Lutte contre le Blanchiment et le Financement du Terrorisme). * Requête de création/mise à jour des paramètres LCB-FT (Lutte contre le Blanchiment et le Financement du Terrorisme).
* Définit les seuils au-dessus desquels les justifications d'origine des fonds sont obligatoires. * Définit les seuils au-dessus desquels les justifications d'origine des fonds sont obligatoires.
* *
* @author lions dev Team * @author lions dev Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Paramètres LCB-FT (seuils de vigilance)") @Schema(description = "Paramètres LCB-FT (seuils de vigilance)")
public class ParametresLcbFtRequest { public class ParametresLcbFtRequest {
@Schema(description = "ID de l'organisation (null pour paramètres plateforme)") @Schema(description = "ID de l'organisation (null pour paramètres plateforme)")
private String organisationId; private String organisationId;
@NotNull(message = "Le montant seuil de justification est obligatoire") @NotNull(message = "Le montant seuil de justification est obligatoire")
@DecimalMin(value = "0", message = "Le montant doit être positif ou nul") @DecimalMin(value = "0", message = "Le montant doit être positif ou nul")
@Schema(description = "Montant au-dessus duquel l'origine des fonds est obligatoire (ex. 500000 XOF)", example = "500000") @Schema(description = "Montant au-dessus duquel l'origine des fonds est obligatoire (ex. 500000 XOF)", example = "500000")
private BigDecimal montantSeuilJustification; private BigDecimal montantSeuilJustification;
@NotNull(message = "Le montant seuil de validation manuelle est obligatoire") @NotNull(message = "Le montant seuil de validation manuelle est obligatoire")
@DecimalMin(value = "0", message = "Le montant doit être positif ou nul") @DecimalMin(value = "0", message = "Le montant doit être positif ou nul")
@Schema(description = "Montant au-dessus duquel une validation manuelle est requise (ex. 1000000 XOF)", example = "1000000") @Schema(description = "Montant au-dessus duquel une validation manuelle est requise (ex. 1000000 XOF)", example = "1000000")
private BigDecimal montantSeuilValidationManuelle; private BigDecimal montantSeuilValidationManuelle;
@NotBlank(message = "Le code devise est obligatoire") @NotBlank(message = "Le code devise est obligatoire")
@Size(max = 3, message = "Le code devise doit faire 3 caractères (ISO 4217)") @Size(max = 3, message = "Le code devise doit faire 3 caractères (ISO 4217)")
@Schema(description = "Code devise ISO 4217 (ex. XOF, EUR, USD)", example = "XOF") @Schema(description = "Code devise ISO 4217 (ex. XOF, EUR, USD)", example = "XOF")
private String codeDevise; private String codeDevise;
@Schema(description = "Notes ou commentaires sur la configuration") @Schema(description = "Notes ou commentaires sur la configuration")
private String notes; private String notes;
} }

View File

@@ -1,22 +1,22 @@
package dev.lions.unionflow.server.api.dto.config.request; package dev.lions.unionflow.server.api.dto.config.request;
import java.util.Map; import java.util.Map;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une configuration. * Requête de mise à jour d'une configuration.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateConfigurationRequest( public record UpdateConfigurationRequest(
String cle, String cle,
String valeur, String valeur,
String type, String type,
String categorie, String categorie,
String description, String description,
Boolean modifiable, Boolean modifiable,
Boolean visible, Boolean visible,
Map<String, Object> metadonnees) { Map<String, Object> metadonnees) {
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.config.response; package dev.lions.unionflow.server.api.dto.config.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.util.Map; import java.util.Map;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse contenant les données d'une configuration. * Réponse contenant les données d'une configuration.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class ConfigurationResponse extends BaseResponse { public class ConfigurationResponse extends BaseResponse {
private String cle; private String cle;
private String valeur; private String valeur;
private String type; private String type;
private String categorie; private String categorie;
private String description; private String description;
private Boolean modifiable; private Boolean modifiable;
private Boolean visible; private Boolean visible;
private Map<String, Object> metadonnees; private Map<String, Object> metadonnees;
} }

View File

@@ -1,49 +1,49 @@
package dev.lions.unionflow.server.api.dto.config.response; package dev.lions.unionflow.server.api.dto.config.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* Réponse contenant les paramètres LCB-FT (Lutte contre le Blanchiment et le Financement du Terrorisme). * Réponse contenant les paramètres LCB-FT (Lutte contre le Blanchiment et le Financement du Terrorisme).
* Retourne les seuils configurés pour une organisation ou la plateforme. * Retourne les seuils configurés pour une organisation ou la plateforme.
* *
* @author lions dev Team * @author lions dev Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Paramètres LCB-FT avec seuils de vigilance") @Schema(description = "Paramètres LCB-FT avec seuils de vigilance")
public class ParametresLcbFtResponse extends BaseResponse { public class ParametresLcbFtResponse extends BaseResponse {
@Schema(description = "ID de l'organisation (null si paramètres plateforme)") @Schema(description = "ID de l'organisation (null si paramètres plateforme)")
private String organisationId; private String organisationId;
@Schema(description = "Nom de l'organisation (null si paramètres plateforme)") @Schema(description = "Nom de l'organisation (null si paramètres plateforme)")
private String organisationNom; private String organisationNom;
@Schema(description = "Montant au-dessus duquel l'origine des fonds est obligatoire", example = "500000") @Schema(description = "Montant au-dessus duquel l'origine des fonds est obligatoire", example = "500000")
private BigDecimal montantSeuilJustification; private BigDecimal montantSeuilJustification;
@Schema(description = "Montant au-dessus duquel une validation manuelle est requise", example = "1000000") @Schema(description = "Montant au-dessus duquel une validation manuelle est requise", example = "1000000")
private BigDecimal montantSeuilValidationManuelle; private BigDecimal montantSeuilValidationManuelle;
@Schema(description = "Code devise ISO 4217", example = "XOF") @Schema(description = "Code devise ISO 4217", example = "XOF")
private String codeDevise; private String codeDevise;
@Schema(description = "Notes ou commentaires sur la configuration") @Schema(description = "Notes ou commentaires sur la configuration")
private String notes; private String notes;
@Schema(description = "Indique si ces paramètres s'appliquent à toute la plateforme") @Schema(description = "Indique si ces paramètres s'appliquent à toute la plateforme")
private Boolean estParametrePlateforme; private Boolean estParametrePlateforme;
} }

View File

@@ -1,62 +1,62 @@
package dev.lions.unionflow.server.api.dto.cotisation.request; package dev.lions.unionflow.server.api.dto.cotisation.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une nouvelle cotisation. * Requête de création d'une nouvelle cotisation.
* *
* @param membreId Identifiant du membre concerné. * @param membreId Identifiant du membre concerné.
* @param typeCotisation Type de cotisation (MENSUELLE, etc.). * @param typeCotisation Type de cotisation (MENSUELLE, etc.).
* @param libelle Libellé de la cotisation. * @param libelle Libellé de la cotisation.
* @param description Description détaillée. * @param description Description détaillée.
* @param montantDu Montant total à payer. * @param montantDu Montant total à payer.
* @param codeDevise Code ISO de la devise (par défaut XOF). * @param codeDevise Code ISO de la devise (par défaut XOF).
* @param dateEcheance Date limite de paiement. * @param dateEcheance Date limite de paiement.
* @param periode Période concernée (ex: Janvier 2025). * @param periode Période concernée (ex: Janvier 2025).
* @param annee Année de référence. * @param annee Année de référence.
* @param mois Mois de référence (1-12, optionnel). * @param mois Mois de référence (1-12, optionnel).
* @param recurrente Indique si la cotisation est récurrente. * @param recurrente Indique si la cotisation est récurrente.
* @param observations Commentaires libres. * @param observations Commentaires libres.
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-02-22 * @since 2026-02-22
*/ */
@Builder @Builder
public record CreateCotisationRequest( public record CreateCotisationRequest(
@NotNull(message = "L'identifiant du membre est obligatoire") UUID membreId, @NotNull(message = "L'identifiant du membre est obligatoire") UUID membreId,
@NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId, @NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId,
@NotBlank(message = "Le type de cotisation est obligatoire") String typeCotisation, @NotBlank(message = "Le type de cotisation est obligatoire") String typeCotisation,
@NotBlank(message = "Le libellé est obligatoire") @Size(max = 100) String libelle, @NotBlank(message = "Le libellé est obligatoire") @Size(max = 100) String libelle,
@Size(max = 500) String description, @Size(max = 500) String description,
@NotNull(message = "Le montant dû est obligatoire") @DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal montantDu, @NotNull(message = "Le montant dû est obligatoire") @DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal montantDu,
@Size(min = 3, max = 3) String codeDevise, @Size(min = 3, max = 3) String codeDevise,
@NotNull(message = "La date d'échéance est obligatoire") LocalDate dateEcheance, @NotNull(message = "La date d'échéance est obligatoire") LocalDate dateEcheance,
@Size(max = 50) String periode, @Size(max = 50) String periode,
@Min(2020) @Max(2100) Integer annee, @Min(2020) @Max(2100) Integer annee,
@Min(1) @Max(12) Integer mois, @Min(1) @Max(12) Integer mois,
Boolean recurrente, Boolean recurrente,
@Size(max = 1000) String observations) { @Size(max = 1000) String observations) {
} }

View File

@@ -1,48 +1,48 @@
package dev.lions.unionflow.server.api.dto.cotisation.request; package dev.lions.unionflow.server.api.dto.cotisation.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une cotisation existante. * Requête de mise à jour d'une cotisation existante.
* *
* @param libelle Nouveau libellé. * @param libelle Nouveau libellé.
* @param description Nouvelle description. * @param description Nouvelle description.
* @param montantDu Nouveau montant dû (si non payé). * @param montantDu Nouveau montant dû (si non payé).
* @param dateEcheance Nouvelle date d'échéance. * @param dateEcheance Nouvelle date d'échéance.
* @param observations Nouvelles observations. * @param observations Nouvelles observations.
* @param statut Nouveau statut (validation métier requise). * @param statut Nouveau statut (validation métier requise).
* @param annee Année de référence. * @param annee Année de référence.
* @param mois Mois de référence. * @param mois Mois de référence.
* @param recurrente État de récurrence. * @param recurrente État de récurrence.
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-02-22 * @since 2026-02-22
*/ */
@Builder @Builder
public record UpdateCotisationRequest( public record UpdateCotisationRequest(
@Size(max = 100) String libelle, @Size(max = 100) String libelle,
@Size(max = 500) String description, @Size(max = 500) String description,
@DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal montantDu, @DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal montantDu,
LocalDate dateEcheance, LocalDate dateEcheance,
@Size(max = 1000) String observations, @Size(max = 1000) String observations,
String statut, String statut,
@Min(2020) @Max(2100) Integer annee, @Min(2020) @Max(2100) Integer annee,
@Min(1) @Max(12) Integer mois, @Min(1) @Max(12) Integer mois,
Boolean recurrente) { Boolean recurrente) {
} }

View File

@@ -1,129 +1,129 @@
package dev.lions.unionflow.server.api.dto.cotisation.response; package dev.lions.unionflow.server.api.dto.cotisation.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée pour une cotisation. * Réponse détaillée pour une cotisation.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-02-22 * @since 2026-02-22
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class CotisationResponse extends BaseResponse { public class CotisationResponse extends BaseResponse {
private String numeroReference; private String numeroReference;
private UUID membreId; private UUID membreId;
private String nomMembre; private String nomMembre;
/** Nom complet (prénom + nom) pour affichage */ /** Nom complet (prénom + nom) pour affichage */
private String nomCompletMembre; private String nomCompletMembre;
private String numeroMembre; private String numeroMembre;
/** Initiales du membre (ex: JD pour Jean Dupont) */ /** Initiales du membre (ex: JD pour Jean Dupont) */
private String initialesMembre; private String initialesMembre;
/** Type / statut du membre (ex: Actif, En attente) */ /** Type / statut du membre (ex: Actif, En attente) */
private String typeMembre; private String typeMembre;
private UUID organisationId; private UUID organisationId;
private String nomOrganisation; private String nomOrganisation;
/** Région de l'organisation (affichage liste) */ /** Région de l'organisation (affichage liste) */
private String regionOrganisation; private String regionOrganisation;
/** Classe CSS icône PrimeFaces pour l'organisation (ex: pi-building) */ /** Classe CSS icône PrimeFaces pour l'organisation (ex: pi-building) */
private String iconeOrganisation; private String iconeOrganisation;
private String typeCotisation; private String typeCotisation;
/** Alias pour tri/filtre (type de cotisation) */ /** Alias pour tri/filtre (type de cotisation) */
private String type; private String type;
private String typeCotisationLibelle; private String typeCotisationLibelle;
/** Libellé du type pour affichage (alias typeCotisationLibelle) */ /** Libellé du type pour affichage (alias typeCotisationLibelle) */
private String typeLibelle; private String typeLibelle;
/** Sévérité PrimeFaces pour le tag type (info, success, warn, error, secondary) */ /** Sévérité PrimeFaces pour le tag type (info, success, warn, error, secondary) */
private String typeSeverity; private String typeSeverity;
/** Classe icône PrimeFaces pour le type (ex: pi-calendar) */ /** Classe icône PrimeFaces pour le type (ex: pi-calendar) */
private String typeIcon; private String typeIcon;
private String libelle; private String libelle;
private String description; private String description;
private BigDecimal montantDu; private BigDecimal montantDu;
/** Alias pour tri/filtre (montant du) */ /** Alias pour tri/filtre (montant du) */
private BigDecimal montant; private BigDecimal montant;
/** Montant formaté pour affichage (ex: "5 000") */ /** Montant formaté pour affichage (ex: "5 000") */
private String montantFormatte; private String montantFormatte;
private BigDecimal montantPaye; private BigDecimal montantPaye;
private BigDecimal montantRestant; private BigDecimal montantRestant;
private String codeDevise; private String codeDevise;
private String statut; private String statut;
private String statutLibelle; private String statutLibelle;
/** Sévérité PrimeFaces pour le tag statut */ /** Sévérité PrimeFaces pour le tag statut */
private String statutSeverity; private String statutSeverity;
/** Classe icône PrimeFaces pour le statut (ex: pi-check) */ /** Classe icône PrimeFaces pour le statut (ex: pi-check) */
private String statutIcon; private String statutIcon;
private LocalDate dateEcheance; private LocalDate dateEcheance;
/** Date d'échéance formatée pour affichage */ /** Date d'échéance formatée pour affichage */
private String dateEcheanceFormattee; private String dateEcheanceFormattee;
/** Classe CSS couleur pour le retard (ex: text-red-500) */ /** Classe CSS couleur pour le retard (ex: text-red-500) */
private String retardCouleur; private String retardCouleur;
/** Texte affiché pour le retard (ex: "X jours de retard") */ /** Texte affiché pour le retard (ex: "X jours de retard") */
private String retardTexte; private String retardTexte;
/** Date de paiement formatée pour affichage */ /** Date de paiement formatée pour affichage */
private String datePaiementFormattee; private String datePaiementFormattee;
/** Icône PrimeFaces pour le mode de paiement */ /** Icône PrimeFaces pour le mode de paiement */
private String modePaiementIcon; private String modePaiementIcon;
/** Libellé du mode de paiement */ /** Libellé du mode de paiement */
private String modePaiementLibelle; private String modePaiementLibelle;
private LocalDateTime datePaiement; private LocalDateTime datePaiement;
private String periode; private String periode;
private Integer annee; private Integer annee;
private Integer mois; private Integer mois;
private String observations; private String observations;
private Boolean recurrente; private Boolean recurrente;
private Integer nombreRappels; private Integer nombreRappels;
private LocalDateTime dateDernierRappel; private LocalDateTime dateDernierRappel;
private UUID valideParId; private UUID valideParId;
private String nomValidateur; private String nomValidateur;
private LocalDateTime dateValidation; private LocalDateTime dateValidation;
private Integer pourcentagePaiement; private Integer pourcentagePaiement;
private Long joursRetard; private Long joursRetard;
private Boolean enRetard; private Boolean enRetard;
// === MÉTHODES DE FORMATAGE === // === MÉTHODES DE FORMATAGE ===
public String getMontantDuFormatte() { public String getMontantDuFormatte() {
if (montantDu == null) return "0 FCFA"; if (montantDu == null) return "0 FCFA";
return String.format(java.util.Locale.US, "%,.0f %s", montantDu, codeDevise != null ? codeDevise : "FCFA"); return String.format(java.util.Locale.US, "%,.0f %s", montantDu, codeDevise != null ? codeDevise : "FCFA");
} }
public String getMontantPayeFormatte() { public String getMontantPayeFormatte() {
if (montantPaye == null) return "0 FCFA"; if (montantPaye == null) return "0 FCFA";
return String.format(java.util.Locale.US, "%,.0f %s", montantPaye, codeDevise != null ? codeDevise : "FCFA"); return String.format(java.util.Locale.US, "%,.0f %s", montantPaye, codeDevise != null ? codeDevise : "FCFA");
} }
public String getMontantRestantFormatte() { public String getMontantRestantFormatte() {
if (montantRestant == null) return "0 FCFA"; if (montantRestant == null) return "0 FCFA";
return String.format(java.util.Locale.US, "%,.0f %s", montantRestant, codeDevise != null ? codeDevise : "FCFA"); return String.format(java.util.Locale.US, "%,.0f %s", montantRestant, codeDevise != null ? codeDevise : "FCFA");
} }
public boolean isMontantRestantPositif() { public boolean isMontantRestantPositif() {
return montantRestant != null && montantRestant.signum() > 0; return montantRestant != null && montantRestant.signum() > 0;
} }
/** Alias de {@link #modePaiementLibelle} pour #{cotisation.methodePaiementLibelle}. */ /** Alias de {@link #modePaiementLibelle} pour #{cotisation.methodePaiementLibelle}. */
public String getMethodePaiementLibelle() { public String getMethodePaiementLibelle() {
return modePaiementLibelle; return modePaiementLibelle;
} }
// Informations de paiement // Informations de paiement
private String methodePaiement; // WAVE_MONEY, VIREMENT, ESPECES, CARTE, MOBILE_MONEY private String methodePaiement; // WAVE_MONEY, VIREMENT, ESPECES, CARTE, MOBILE_MONEY
private String referencePaiement; // Référence externe du paiement private String referencePaiement; // Référence externe du paiement
private String waveSessionId; // ID de session Wave Money pour prélèvements private String waveSessionId; // ID de session Wave Money pour prélèvements
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.culte; package dev.lions.unionflow.server.api.dto.culte;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux; import dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class DonReligieuxDTO extends BaseDTO { public class DonReligieuxDTO extends BaseDTO {
private String institutionId; // Mosquée, Église, Paroisse... private String institutionId; // Mosquée, Église, Paroisse...
// Si relié spécifiquement à un fidèle enregistré // Si relié spécifiquement à un fidèle enregistré
private String fideleId; private String fideleId;
private TypeDonReligieux typeDon; private TypeDonReligieux typeDon;
private BigDecimal montant; private BigDecimal montant;
private LocalDateTime dateEncaissement; private LocalDateTime dateEncaissement;
// Utile pour la zakat (Nissab de l'année concernée) ou la dîme périodique // Utile pour la zakat (Nissab de l'année concernée) ou la dîme périodique
private String periodeOuNatureAssociee; private String periodeOuNatureAssociee;
} }

View File

@@ -1,122 +1,122 @@
package dev.lions.unionflow.server.api.dto.dashboard; package dev.lions.unionflow.server.api.dto.dashboard;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* DTO principal pour toutes les données du dashboard * DTO principal pour toutes les données du dashboard
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class DashboardDataResponse { public class DashboardDataResponse {
@JsonProperty("stats") @JsonProperty("stats")
private DashboardStatsResponse stats; private DashboardStatsResponse stats;
@JsonProperty("recentActivities") @JsonProperty("recentActivities")
private List<RecentActivityResponse> recentActivities; private List<RecentActivityResponse> recentActivities;
@JsonProperty("upcomingEvents") @JsonProperty("upcomingEvents")
private List<UpcomingEventResponse> upcomingEvents; private List<UpcomingEventResponse> upcomingEvents;
@JsonProperty("userPreferences") @JsonProperty("userPreferences")
private Map<String, Object> userPreferences; private Map<String, Object> userPreferences;
@JsonProperty("organizationId") @JsonProperty("organizationId")
private String organizationId; private String organizationId;
@JsonProperty("userId") @JsonProperty("userId")
private String userId; private String userId;
// Méthodes utilitaires // Méthodes utilitaires
public Integer getTodayEventsCount() { public Integer getTodayEventsCount() {
if (upcomingEvents == null) { if (upcomingEvents == null) {
return 0; return 0;
} }
return (int) upcomingEvents.stream() return (int) upcomingEvents.stream()
.filter(event -> event.getIsToday() != null && event.getIsToday()) .filter(event -> event.getIsToday() != null && event.getIsToday())
.count(); .count();
} }
public Integer getTomorrowEventsCount() { public Integer getTomorrowEventsCount() {
if (upcomingEvents == null) { if (upcomingEvents == null) {
return 0; return 0;
} }
return (int) upcomingEvents.stream() return (int) upcomingEvents.stream()
.filter(event -> event.getIsTomorrow() != null && event.getIsTomorrow()) .filter(event -> event.getIsTomorrow() != null && event.getIsTomorrow())
.count(); .count();
} }
public Integer getRecentActivitiesCount() { public Integer getRecentActivitiesCount() {
if (recentActivities == null) { if (recentActivities == null) {
return 0; return 0;
} }
return (int) recentActivities.stream() return (int) recentActivities.stream()
.filter(activity -> activity.getIsRecent() != null && activity.getIsRecent()) .filter(activity -> activity.getIsRecent() != null && activity.getIsRecent())
.count(); .count();
} }
public Integer getTodayActivitiesCount() { public Integer getTodayActivitiesCount() {
if (recentActivities == null) { if (recentActivities == null) {
return 0; return 0;
} }
return (int) recentActivities.stream() return (int) recentActivities.stream()
.filter(activity -> activity.getIsToday() != null && activity.getIsToday()) .filter(activity -> activity.getIsToday() != null && activity.getIsToday())
.count(); .count();
} }
public Boolean getHasUpcomingEvents() { public Boolean getHasUpcomingEvents() {
return upcomingEvents != null && !upcomingEvents.isEmpty(); return upcomingEvents != null && !upcomingEvents.isEmpty();
} }
public Boolean getHasRecentActivities() { public Boolean getHasRecentActivities() {
return recentActivities != null && !recentActivities.isEmpty(); return recentActivities != null && !recentActivities.isEmpty();
} }
public String getThemePreference() { public String getThemePreference() {
if (userPreferences == null) { if (userPreferences == null) {
return "royal_teal"; return "royal_teal";
} }
return (String) userPreferences.getOrDefault("theme", "royal_teal"); return (String) userPreferences.getOrDefault("theme", "royal_teal");
} }
public String getLanguagePreference() { public String getLanguagePreference() {
if (userPreferences == null) { if (userPreferences == null) {
return "fr"; return "fr";
} }
return (String) userPreferences.getOrDefault("language", "fr"); return (String) userPreferences.getOrDefault("language", "fr");
} }
public Boolean getNotificationsEnabled() { public Boolean getNotificationsEnabled() {
if (userPreferences == null) { if (userPreferences == null) {
return true; return true;
} }
return (Boolean) userPreferences.getOrDefault("notifications", true); return (Boolean) userPreferences.getOrDefault("notifications", true);
} }
public Boolean getAutoRefreshEnabled() { public Boolean getAutoRefreshEnabled() {
if (userPreferences == null) { if (userPreferences == null) {
return true; return true;
} }
return (Boolean) userPreferences.getOrDefault("autoRefresh", true); return (Boolean) userPreferences.getOrDefault("autoRefresh", true);
} }
public Integer getRefreshInterval() { public Integer getRefreshInterval() {
if (userPreferences == null) { if (userPreferences == null) {
return 300; // 5 minutes par défaut return 300; // 5 minutes par défaut
} }
return (Integer) userPreferences.getOrDefault("refreshInterval", 300); return (Integer) userPreferences.getOrDefault("refreshInterval", 300);
} }
} }

View File

@@ -1,119 +1,119 @@
package dev.lions.unionflow.server.api.dto.dashboard; package dev.lions.unionflow.server.api.dto.dashboard;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* DTO pour les statistiques du dashboard * DTO pour les statistiques du dashboard
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class DashboardStatsResponse { public class DashboardStatsResponse {
@JsonProperty("totalMembers") @JsonProperty("totalMembers")
private Integer totalMembers; private Integer totalMembers;
@JsonProperty("activeMembers") @JsonProperty("activeMembers")
private Integer activeMembers; private Integer activeMembers;
@JsonProperty("totalEvents") @JsonProperty("totalEvents")
private Integer totalEvents; private Integer totalEvents;
@JsonProperty("upcomingEvents") @JsonProperty("upcomingEvents")
private Integer upcomingEvents; private Integer upcomingEvents;
@JsonProperty("totalContributions") @JsonProperty("totalContributions")
private Integer totalContributions; private Integer totalContributions;
@JsonProperty("totalContributionAmount") @JsonProperty("totalContributionAmount")
private Double totalContributionAmount; private Double totalContributionAmount;
@JsonProperty("pendingRequests") @JsonProperty("pendingRequests")
private Integer pendingRequests; private Integer pendingRequests;
@JsonProperty("completedProjects") @JsonProperty("completedProjects")
private Integer completedProjects; private Integer completedProjects;
@JsonProperty("monthlyGrowth") @JsonProperty("monthlyGrowth")
private Double monthlyGrowth; private Double monthlyGrowth;
@JsonProperty("engagementRate") @JsonProperty("engagementRate")
private Double engagementRate; private Double engagementRate;
@JsonProperty("lastUpdated") @JsonProperty("lastUpdated")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime lastUpdated; private LocalDateTime lastUpdated;
/** /**
* Nombre total d'organisations dans le système (SuperAdmin uniquement) * Nombre total d'organisations dans le système (SuperAdmin uniquement)
*/ */
@JsonProperty("totalOrganizations") @JsonProperty("totalOrganizations")
private Integer totalOrganizations; private Integer totalOrganizations;
/** /**
* Répartition des organisations par type * Répartition des organisations par type
* Exemple: {"Mutuelle": 15, "Coopérative": 8, "Tontine": 5, "Autre": 3} * Exemple: {"Mutuelle": 15, "Coopérative": 8, "Tontine": 5, "Autre": 3}
*/ */
@JsonProperty("organizationTypeDistribution") @JsonProperty("organizationTypeDistribution")
private Map<String, Integer> organizationTypeDistribution; private Map<String, Integer> organizationTypeDistribution;
/** /**
* Données historiques mensuelles pour les graphiques (12 derniers mois) * Données historiques mensuelles pour les graphiques (12 derniers mois)
*/ */
@JsonProperty("monthlyHistoricalData") @JsonProperty("monthlyHistoricalData")
private List<MonthlyStatDTO> monthlyHistoricalData; private List<MonthlyStatDTO> monthlyHistoricalData;
// Méthodes utilitaires // Méthodes utilitaires
public String getFormattedContributionAmount() { public String getFormattedContributionAmount() {
if (totalContributionAmount == null) { if (totalContributionAmount == null) {
return "0"; return "0";
} }
if (totalContributionAmount >= 1_000_000) { if (totalContributionAmount >= 1_000_000) {
return String.format("%.1fM", totalContributionAmount / 1_000_000); return String.format("%.1fM", totalContributionAmount / 1_000_000);
} else if (totalContributionAmount >= 1_000) { } else if (totalContributionAmount >= 1_000) {
return String.format("%.0fK", totalContributionAmount / 1_000); return String.format("%.0fK", totalContributionAmount / 1_000);
} else { } else {
return String.format("%.0f", totalContributionAmount); return String.format("%.0f", totalContributionAmount);
} }
} }
public Boolean getHasGrowth() { public Boolean getHasGrowth() {
return monthlyGrowth != null && monthlyGrowth > 0; return monthlyGrowth != null && monthlyGrowth > 0;
} }
public Boolean getIsHighEngagement() { public Boolean getIsHighEngagement() {
return engagementRate != null && engagementRate > 0.7; return engagementRate != null && engagementRate > 0.7;
} }
public Double getInactiveMembers() { public Double getInactiveMembers() {
if (totalMembers == null || activeMembers == null) { if (totalMembers == null || activeMembers == null) {
return 0.0; return 0.0;
} }
return (double) (totalMembers - activeMembers); return (double) (totalMembers - activeMembers);
} }
public Double getActiveMemberPercentage() { public Double getActiveMemberPercentage() {
if (totalMembers == null || activeMembers == null || totalMembers == 0) { if (totalMembers == null || activeMembers == null || totalMembers == 0) {
return 0.0; return 0.0;
} }
return (double) activeMembers / totalMembers * 100; return (double) activeMembers / totalMembers * 100;
} }
public Double getEngagementPercentage() { public Double getEngagementPercentage() {
if (engagementRate == null) { if (engagementRate == null) {
return 0.0; return 0.0;
} }
return engagementRate * 100; return engagementRate * 100;
} }
} }

View File

@@ -1,70 +1,70 @@
package dev.lions.unionflow.server.api.dto.dashboard; package dev.lions.unionflow.server.api.dto.dashboard;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO pour les statistiques mensuelles historiques * DTO pour les statistiques mensuelles historiques
* Utilisé pour générer des graphiques de croissance sur 12 mois * Utilisé pour générer des graphiques de croissance sur 12 mois
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 2.0 * @version 2.0
* @since 2026-03-07 * @since 2026-03-07
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class MonthlyStatDTO { public class MonthlyStatDTO {
/** /**
* Mois au format "2026-01", "2026-02", etc. * Mois au format "2026-01", "2026-02", etc.
*/ */
@JsonProperty("month") @JsonProperty("month")
private String month; private String month;
/** /**
* Nombre de membres ce mois-là * Nombre de membres ce mois-là
*/ */
@JsonProperty("totalMembers") @JsonProperty("totalMembers")
private Integer totalMembers; private Integer totalMembers;
/** /**
* Nombre de membres actifs ce mois-là * Nombre de membres actifs ce mois-là
*/ */
@JsonProperty("activeMembers") @JsonProperty("activeMembers")
private Integer activeMembers; private Integer activeMembers;
/** /**
* Montant total des contributions ce mois-là * Montant total des contributions ce mois-là
*/ */
@JsonProperty("contributionAmount") @JsonProperty("contributionAmount")
private Double contributionAmount; private Double contributionAmount;
/** /**
* Nombre d'événements organisés ce mois-là * Nombre d'événements organisés ce mois-là
*/ */
@JsonProperty("eventsCount") @JsonProperty("eventsCount")
private Integer eventsCount; private Integer eventsCount;
/** /**
* Taux d'engagement ce mois-là * Taux d'engagement ce mois-là
*/ */
@JsonProperty("engagementRate") @JsonProperty("engagementRate")
private Double engagementRate; private Double engagementRate;
/** /**
* Nombre de nouveaux membres ce mois-là * Nombre de nouveaux membres ce mois-là
*/ */
@JsonProperty("newMembers") @JsonProperty("newMembers")
private Integer newMembers; private Integer newMembers;
/** /**
* Nombre de cotisations payées ce mois-là * Nombre de cotisations payées ce mois-là
*/ */
@JsonProperty("contributionsCount") @JsonProperty("contributionsCount")
private Integer contributionsCount; private Integer contributionsCount;
} }

View File

@@ -1,130 +1,130 @@
package dev.lions.unionflow.server.api.dto.dashboard; package dev.lions.unionflow.server.api.dto.dashboard;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
/** /**
* DTO pour les activités récentes du dashboard * DTO pour les activités récentes du dashboard
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class RecentActivityResponse { public class RecentActivityResponse {
@JsonProperty("id") @JsonProperty("id")
private String id; private String id;
@JsonProperty("type") @JsonProperty("type")
private String type; private String type;
@JsonProperty("title") @JsonProperty("title")
private String title; private String title;
@JsonProperty("description") @JsonProperty("description")
private String description; private String description;
@JsonProperty("userName") @JsonProperty("userName")
private String userName; private String userName;
@JsonProperty("timestamp") @JsonProperty("timestamp")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime timestamp; private LocalDateTime timestamp;
@JsonProperty("userAvatar") @JsonProperty("userAvatar")
private String userAvatar; private String userAvatar;
@JsonProperty("actionUrl") @JsonProperty("actionUrl")
private String actionUrl; private String actionUrl;
// Méthodes utilitaires // Méthodes utilitaires
public String getTimeAgo() { public String getTimeAgo() {
if (timestamp == null) { if (timestamp == null) {
return ""; return "";
} }
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
long minutes = ChronoUnit.MINUTES.between(timestamp, now); long minutes = ChronoUnit.MINUTES.between(timestamp, now);
long hours = ChronoUnit.HOURS.between(timestamp, now); long hours = ChronoUnit.HOURS.between(timestamp, now);
long days = ChronoUnit.DAYS.between(timestamp, now); long days = ChronoUnit.DAYS.between(timestamp, now);
if (minutes < 60) { if (minutes < 60) {
return minutes + "min"; return minutes + "min";
} else if (hours < 24) { } else if (hours < 24) {
return hours + "h"; return hours + "h";
} else if (days < 7) { } else if (days < 7) {
return days + "j"; return days + "j";
} else { } else {
long weeks = days / 7; long weeks = days / 7;
return weeks + "sem"; return weeks + "sem";
} }
} }
public String getActivityIcon() { public String getActivityIcon() {
if (type == null) { if (type == null) {
return "help_outline"; return "help_outline";
} }
switch (type.toLowerCase()) { switch (type.toLowerCase()) {
case "member": case "member":
return "person"; return "person";
case "event": case "event":
return "event"; return "event";
case "contribution": case "contribution":
return "payment"; return "payment";
case "organization": case "organization":
return "business"; return "business";
case "system": case "system":
return "settings"; return "settings";
default: default:
return "info"; return "info";
} }
} }
public String getActivityColor() { public String getActivityColor() {
if (type == null) { if (type == null) {
return "#6B7280"; // grey return "#6B7280"; // grey
} }
switch (type.toLowerCase()) { switch (type.toLowerCase()) {
case "member": case "member":
return "#10B981"; // success return "#10B981"; // success
case "event": case "event":
return "#3B82F6"; // info return "#3B82F6"; // info
case "contribution": case "contribution":
return "#008B8B"; // teal blue return "#008B8B"; // teal blue
case "organization": case "organization":
return "#4169E1"; // royal blue return "#4169E1"; // royal blue
case "system": case "system":
return "#6B7280"; // grey return "#6B7280"; // grey
default: default:
return "#6B7280"; // grey return "#6B7280"; // grey
} }
} }
public Boolean getIsRecent() { public Boolean getIsRecent() {
if (timestamp == null) { if (timestamp == null) {
return false; return false;
} }
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
long hours = ChronoUnit.HOURS.between(timestamp, now); long hours = ChronoUnit.HOURS.between(timestamp, now);
return hours < 24; return hours < 24;
} }
public Boolean getIsToday() { public Boolean getIsToday() {
if (timestamp == null) { if (timestamp == null) {
return false; return false;
} }
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
return timestamp.toLocalDate().equals(now.toLocalDate()); return timestamp.toLocalDate().equals(now.toLocalDate());
} }
} }

View File

@@ -1,183 +1,183 @@
package dev.lions.unionflow.server.api.dto.dashboard; package dev.lions.unionflow.server.api.dto.dashboard;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.List; import java.util.List;
/** /**
* DTO pour les événements à venir du dashboard * DTO pour les événements à venir du dashboard
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class UpcomingEventResponse { public class UpcomingEventResponse {
@JsonProperty("id") @JsonProperty("id")
private String id; private String id;
@JsonProperty("title") @JsonProperty("title")
private String title; private String title;
@JsonProperty("description") @JsonProperty("description")
private String description; private String description;
@JsonProperty("startDate") @JsonProperty("startDate")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime startDate; private LocalDateTime startDate;
@JsonProperty("endDate") @JsonProperty("endDate")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime endDate; private LocalDateTime endDate;
@JsonProperty("location") @JsonProperty("location")
private String location; private String location;
@JsonProperty("maxParticipants") @JsonProperty("maxParticipants")
private Integer maxParticipants; private Integer maxParticipants;
@JsonProperty("currentParticipants") @JsonProperty("currentParticipants")
private Integer currentParticipants; private Integer currentParticipants;
@JsonProperty("status") @JsonProperty("status")
private String status; private String status;
@JsonProperty("imageUrl") @JsonProperty("imageUrl")
private String imageUrl; private String imageUrl;
@JsonProperty("tags") @JsonProperty("tags")
private List<String> tags; private List<String> tags;
// Méthodes utilitaires // Méthodes utilitaires
public String getDaysUntilEvent() { public String getDaysUntilEvent() {
return getDaysUntilEvent(LocalDateTime.now()); return getDaysUntilEvent(LocalDateTime.now());
} }
/** /**
* Version testable avec une date de référence fixe (même package). * Version testable avec une date de référence fixe (même package).
*/ */
String getDaysUntilEvent(LocalDateTime now) { String getDaysUntilEvent(LocalDateTime now) {
if (startDate == null) { if (startDate == null) {
return ""; return "";
} }
long days = ChronoUnit.DAYS.between(now.toLocalDate(), startDate.toLocalDate()); long days = ChronoUnit.DAYS.between(now.toLocalDate(), startDate.toLocalDate());
long hours = ChronoUnit.HOURS.between(now, startDate); long hours = ChronoUnit.HOURS.between(now, startDate);
if (days < 0) { if (days < 0) {
return "En cours"; return "En cours";
} }
if (days == 0) { if (days == 0) {
// Vérifier si l'événement est déjà passé (même si moins d'1h) // Vérifier si l'événement est déjà passé (même si moins d'1h)
if (startDate.isBefore(now)) { if (startDate.isBefore(now)) {
return "En cours"; return "En cours";
} else if (hours < 2) { } else if (hours < 2) {
return "Bientôt"; return "Bientôt";
} else { } else {
return "Aujourd'hui"; return "Aujourd'hui";
} }
} else if (days == 1) { } else if (days == 1) {
return "Demain"; return "Demain";
} else if (days < 7) { } else if (days < 7) {
return "Dans " + days + " jours"; return "Dans " + days + " jours";
} else { } else {
long weeks = days / 7; long weeks = days / 7;
return "Dans " + weeks + " semaine" + (weeks > 1 ? "s" : ""); return "Dans " + weeks + " semaine" + (weeks > 1 ? "s" : "");
} }
} }
public Double getFillPercentage() { public Double getFillPercentage() {
if (maxParticipants == null || currentParticipants == null || maxParticipants == 0) { if (maxParticipants == null || currentParticipants == null || maxParticipants == 0) {
return 0.0; return 0.0;
} }
return (double) currentParticipants / maxParticipants * 100; return (double) currentParticipants / maxParticipants * 100;
} }
public Boolean getIsFull() { public Boolean getIsFull() {
if (maxParticipants == null || currentParticipants == null) { if (maxParticipants == null || currentParticipants == null) {
return false; return false;
} }
return currentParticipants >= maxParticipants; return currentParticipants >= maxParticipants;
} }
public Boolean getIsAlmostFull() { public Boolean getIsAlmostFull() {
Double fillPercentage = getFillPercentage(); Double fillPercentage = getFillPercentage();
return fillPercentage >= 80.0 && fillPercentage < 100.0; return fillPercentage >= 80.0 && fillPercentage < 100.0;
} }
public Boolean getIsToday() { public Boolean getIsToday() {
if (startDate == null) { if (startDate == null) {
return false; return false;
} }
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
return startDate.toLocalDate().equals(now.toLocalDate()); return startDate.toLocalDate().equals(now.toLocalDate());
} }
public Boolean getIsTomorrow() { public Boolean getIsTomorrow() {
if (startDate == null) { if (startDate == null) {
return false; return false;
} }
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
return startDate.toLocalDate().equals(now.toLocalDate().plusDays(1)); return startDate.toLocalDate().equals(now.toLocalDate().plusDays(1));
} }
public String getStatusColor() { public String getStatusColor() {
if (status == null) { if (status == null) {
return "#6B7280"; // grey return "#6B7280"; // grey
} }
switch (status.toLowerCase()) { switch (status.toLowerCase()) {
case "confirmed": case "confirmed":
return "#10B981"; // success return "#10B981"; // success
case "open": case "open":
return "#3B82F6"; // info return "#3B82F6"; // info
case "cancelled": case "cancelled":
return "#EF4444"; // error return "#EF4444"; // error
case "postponed": case "postponed":
return "#F59E0B"; // warning return "#F59E0B"; // warning
default: default:
return "#6B7280"; // grey return "#6B7280"; // grey
} }
} }
public String getStatusLabel() { public String getStatusLabel() {
if (status == null) { if (status == null) {
return "Inconnu"; return "Inconnu";
} }
switch (status.toLowerCase()) { switch (status.toLowerCase()) {
case "confirmed": case "confirmed":
return "Confirmé"; return "Confirmé";
case "open": case "open":
return "Ouvert"; return "Ouvert";
case "cancelled": case "cancelled":
return "Annulé"; return "Annulé";
case "postponed": case "postponed":
return "Reporté"; return "Reporté";
default: default:
return status; return status;
} }
} }
public Integer getAvailableSpots() { public Integer getAvailableSpots() {
if (maxParticipants == null || currentParticipants == null) { if (maxParticipants == null || currentParticipants == null) {
return 0; return 0;
} }
return Math.max(0, maxParticipants - currentParticipants); return Math.max(0, maxParticipants - currentParticipants);
} }
public String getParticipationSummary() { public String getParticipationSummary() {
if (maxParticipants == null || currentParticipants == null) { if (maxParticipants == null || currentParticipants == null) {
return "0/0 participants"; return "0/0 participants";
} }
return currentParticipants + "/" + maxParticipants + " participants"; return currentParticipants + "/" + maxParticipants + " participants";
} }
} }

View File

@@ -1,26 +1,26 @@
package dev.lions.unionflow.server.api.dto.document.request; package dev.lions.unionflow.server.api.dto.document.request;
import dev.lions.unionflow.server.api.enums.document.TypeDocument; import dev.lions.unionflow.server.api.enums.document.TypeDocument;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un document. * Requête de création d'un document.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateDocumentRequest( public record CreateDocumentRequest(
@NotBlank(message = "Le nom du fichier est obligatoire") String nomFichier, @NotBlank(message = "Le nom du fichier est obligatoire") String nomFichier,
String nomOriginal, String nomOriginal,
@NotBlank(message = "Le chemin de stockage est obligatoire") String cheminStockage, @NotBlank(message = "Le chemin de stockage est obligatoire") String cheminStockage,
String typeMime, String typeMime,
@NotNull(message = "La taille est obligatoire") @Min(value = 0, message = "La taille doit être positive") Long tailleOctets, @NotNull(message = "La taille est obligatoire") @Min(value = 0, message = "La taille doit être positive") Long tailleOctets,
TypeDocument typeDocument, TypeDocument typeDocument,
String hashMd5, String hashMd5,
String hashSha256, String hashSha256,
String description) { String description) {
} }

View File

@@ -1,22 +1,22 @@
package dev.lions.unionflow.server.api.dto.document.request; package dev.lions.unionflow.server.api.dto.document.request;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une pièce jointe. * Requête de création d'une pièce jointe.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreatePieceJointeRequest( public record CreatePieceJointeRequest(
@NotNull(message = "L'ordre est obligatoire") @Min(value = 1, message = "L'ordre doit être positif") Integer ordre, @NotNull(message = "L'ordre est obligatoire") @Min(value = 1, message = "L'ordre doit être positif") Integer ordre,
String libelle, String libelle,
String commentaire, String commentaire,
@NotNull(message = "Le document est obligatoire") UUID documentId, @NotNull(message = "Le document est obligatoire") UUID documentId,
@NotNull(message = "Le type entité est obligatoire") String typeEntiteRattachee, @NotNull(message = "Le type entité est obligatoire") String typeEntiteRattachee,
@NotNull(message = "L'ID entité est obligatoire") UUID entiteRattacheeId) { @NotNull(message = "L'ID entité est obligatoire") UUID entiteRattacheeId) {
} }

View File

@@ -1,18 +1,18 @@
package dev.lions.unionflow.server.api.dto.document.request; package dev.lions.unionflow.server.api.dto.document.request;
import dev.lions.unionflow.server.api.enums.document.TypeDocument; import dev.lions.unionflow.server.api.enums.document.TypeDocument;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'un document. * Requête de mise à jour d'un document.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateDocumentRequest( public record UpdateDocumentRequest(
String nomFichier, String nomFichier,
String nomOriginal, String nomOriginal,
TypeDocument typeDocument, TypeDocument typeDocument,
String description) { String description) {
} }

View File

@@ -1,17 +1,17 @@
package dev.lions.unionflow.server.api.dto.document.request; package dev.lions.unionflow.server.api.dto.document.request;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une pièce jointe. * Requête de mise à jour d'une pièce jointe.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdatePieceJointeRequest( public record UpdatePieceJointeRequest(
@Min(value = 1, message = "L'ordre doit être positif") Integer ordre, @Min(value = 1, message = "L'ordre doit être positif") Integer ordre,
String libelle, String libelle,
String commentaire) { String commentaire) {
} }

View File

@@ -1,36 +1,36 @@
package dev.lions.unionflow.server.api.dto.document.response; package dev.lions.unionflow.server.api.dto.document.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import dev.lions.unionflow.server.api.enums.document.TypeDocument; import dev.lions.unionflow.server.api.enums.document.TypeDocument;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée d'un document. * Réponse détaillée d'un document.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class DocumentResponse extends BaseResponse { public class DocumentResponse extends BaseResponse {
private String nomFichier; private String nomFichier;
private String nomOriginal; private String nomOriginal;
private String cheminStockage; private String cheminStockage;
private String typeMime; private String typeMime;
private Long tailleOctets; private Long tailleOctets;
private TypeDocument typeDocument; private TypeDocument typeDocument;
private String hashMd5; private String hashMd5;
private String hashSha256; private String hashSha256;
private String description; private String description;
private Integer nombreTelechargements; private Integer nombreTelechargements;
private String tailleFormatee; private String tailleFormatee;
} }

View File

@@ -1,31 +1,31 @@
package dev.lions.unionflow.server.api.dto.document.response; package dev.lions.unionflow.server.api.dto.document.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse contenant les données d'une pièce jointe. * Réponse contenant les données d'une pièce jointe.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class PieceJointeResponse extends BaseResponse { public class PieceJointeResponse extends BaseResponse {
private Integer ordre; private Integer ordre;
private String libelle; private String libelle;
private String commentaire; private String commentaire;
private UUID documentId; private UUID documentId;
private String typeEntiteRattachee; private String typeEntiteRattachee;
private UUID entiteRattacheeId; private UUID entiteRattacheeId;
} }

View File

@@ -1,70 +1,70 @@
package dev.lions.unionflow.server.api.dto.evenement.request; package dev.lions.unionflow.server.api.dto.evenement.request;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement; import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement; import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier; import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import dev.lions.unionflow.server.api.validation.ValidationConstants; import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un événement. * Requête de création d'un événement.
*/ */
@Builder @Builder
public record CreateEvenementRequest( public record CreateEvenementRequest(
@NotBlank(message = "Le titre" @NotBlank(message = "Le titre"
+ ValidationConstants.OBLIGATOIRE_MESSAGE) @Size(min = ValidationConstants.TITRE_MIN_LENGTH, max = ValidationConstants.TITRE_MAX_LENGTH, message = ValidationConstants.TITRE_SIZE_MESSAGE) String titre, + ValidationConstants.OBLIGATOIRE_MESSAGE) @Size(min = ValidationConstants.TITRE_MIN_LENGTH, max = ValidationConstants.TITRE_MAX_LENGTH, message = ValidationConstants.TITRE_SIZE_MESSAGE) String titre,
@Size(max = ValidationConstants.DESCRIPTION_COURTE_MAX_LENGTH, message = ValidationConstants.DESCRIPTION_COURTE_SIZE_MESSAGE) String description, @Size(max = ValidationConstants.DESCRIPTION_COURTE_MAX_LENGTH, message = ValidationConstants.DESCRIPTION_COURTE_SIZE_MESSAGE) String description,
@NotNull(message = "Le type d'événement est obligatoire") TypeEvenementMetier typeEvenement, @NotNull(message = "Le type d'événement est obligatoire") TypeEvenementMetier typeEvenement,
@NotNull(message = "Le statut est obligatoire") StatutEvenement statut, @NotNull(message = "Le statut est obligatoire") StatutEvenement statut,
PrioriteEvenement priorite, PrioriteEvenement priorite,
@NotNull(message = "La date de début est obligatoire") @FutureOrPresent(message = "La date de début ne peut pas être dans le passé") LocalDate dateDebut, @NotNull(message = "La date de début est obligatoire") @FutureOrPresent(message = "La date de début ne peut pas être dans le passé") LocalDate dateDebut,
LocalDate dateFin, LocalDate dateFin,
LocalTime heureDebut, LocalTime heureDebut,
LocalTime heureFin, LocalTime heureFin,
@NotBlank(message = "Le lieu est obligatoire") @Size(max = 100) String lieu, @NotBlank(message = "Le lieu est obligatoire") @Size(max = 100) String lieu,
@Size(max = 200) String adresse, @Size(max = 200) String adresse,
@Size(max = 50) String ville, @Size(max = 50) String ville,
@Size(max = 50) String region, @Size(max = 50) String region,
@DecimalMin(value = "-90.0") @DecimalMax(value = "90.0") BigDecimal latitude, @DecimalMin(value = "-90.0") @DecimalMax(value = "90.0") BigDecimal latitude,
@DecimalMin(value = "-180.0") @DecimalMax(value = "180.0") BigDecimal longitude, @DecimalMin(value = "-180.0") @DecimalMax(value = "180.0") BigDecimal longitude,
@NotNull(message = "L'association organisatrice est obligatoire") UUID associationId, @NotNull(message = "L'association organisatrice est obligatoire") UUID associationId,
@Size(max = 100) String organisateur, @Size(max = 100) String organisateur,
@Email(message = "Format d'email invalide") @Size(max = 100) String emailOrganisateur, @Email(message = "Format d'email invalide") @Size(max = 100) String emailOrganisateur,
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$") String telephoneOrganisateur, @Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$") String telephoneOrganisateur,
@Min(value = 1) @Max(value = 10000) Integer capaciteMax, @Min(value = 1) @Max(value = 10000) Integer capaciteMax,
@DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal budget, @DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal budget,
@DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal coutReel, @DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal coutReel,
@Pattern(regexp = ValidationConstants.DEVISE_PATTERN, message = ValidationConstants.DEVISE_MESSAGE) String codeDevise, @Pattern(regexp = ValidationConstants.DEVISE_PATTERN, message = ValidationConstants.DEVISE_MESSAGE) String codeDevise,
Boolean inscriptionObligatoire, Boolean inscriptionObligatoire,
LocalDate dateLimiteInscription, LocalDate dateLimiteInscription,
Boolean evenementPublic, Boolean evenementPublic,
Boolean recurrent, Boolean recurrent,
String frequenceRecurrence, String frequenceRecurrence,
@Size(max = 500) String instructions, @Size(max = 500) String instructions,
@Size(max = 500) String materielNecessaire, @Size(max = 500) String materielNecessaire,
@Size(max = 100) String conditionsMeteo, @Size(max = 100) String conditionsMeteo,
@Size(max = 255) String imageUrl, @Size(max = 255) String imageUrl,
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$") String couleurTheme) { @Pattern(regexp = "^#[0-9A-Fa-f]{6}$") String couleurTheme) {
} }

View File

@@ -1,65 +1,65 @@
package dev.lions.unionflow.server.api.dto.evenement.request; package dev.lions.unionflow.server.api.dto.evenement.request;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement; import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement; import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier; import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import dev.lions.unionflow.server.api.validation.ValidationConstants; import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'un événement. * Requête de mise à jour d'un événement.
*/ */
@Builder @Builder
public record UpdateEvenementRequest( public record UpdateEvenementRequest(
@Size(min = ValidationConstants.TITRE_MIN_LENGTH, max = ValidationConstants.TITRE_MAX_LENGTH, message = ValidationConstants.TITRE_SIZE_MESSAGE) String titre, @Size(min = ValidationConstants.TITRE_MIN_LENGTH, max = ValidationConstants.TITRE_MAX_LENGTH, message = ValidationConstants.TITRE_SIZE_MESSAGE) String titre,
@Size(max = ValidationConstants.DESCRIPTION_COURTE_MAX_LENGTH, message = ValidationConstants.DESCRIPTION_COURTE_SIZE_MESSAGE) String description, @Size(max = ValidationConstants.DESCRIPTION_COURTE_MAX_LENGTH, message = ValidationConstants.DESCRIPTION_COURTE_SIZE_MESSAGE) String description,
TypeEvenementMetier typeEvenement, TypeEvenementMetier typeEvenement,
StatutEvenement statut, StatutEvenement statut,
PrioriteEvenement priorite, PrioriteEvenement priorite,
LocalDate dateDebut, LocalDate dateDebut,
LocalDate dateFin, LocalDate dateFin,
LocalTime heureDebut, LocalTime heureDebut,
LocalTime heureFin, LocalTime heureFin,
@NotBlank(message = "Le lieu est obligatoire") @Size(max = 100) String lieu, @NotBlank(message = "Le lieu est obligatoire") @Size(max = 100) String lieu,
@Size(max = 200) String adresse, @Size(max = 200) String adresse,
@Size(max = 50) String ville, @Size(max = 50) String ville,
@Size(max = 50) String region, @Size(max = 50) String region,
@DecimalMin(value = "-90.0") @DecimalMax(value = "90.0") BigDecimal latitude, @DecimalMin(value = "-90.0") @DecimalMax(value = "90.0") BigDecimal latitude,
@DecimalMin(value = "-180.0") @DecimalMax(value = "180.0") BigDecimal longitude, @DecimalMin(value = "-180.0") @DecimalMax(value = "180.0") BigDecimal longitude,
@Size(max = 100) String organisateur, @Size(max = 100) String organisateur,
@Email(message = "Format d'email invalide") @Size(max = 100) String emailOrganisateur, @Email(message = "Format d'email invalide") @Size(max = 100) String emailOrganisateur,
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$") String telephoneOrganisateur, @Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$") String telephoneOrganisateur,
@Min(value = 1) @Max(value = 10000) Integer capaciteMax, @Min(value = 1) @Max(value = 10000) Integer capaciteMax,
@DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal budget, @DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal budget,
@DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal coutReel, @DecimalMin(value = ValidationConstants.MONTANT_MIN_VALUE, message = ValidationConstants.MONTANT_POSITIF_MESSAGE) @Digits(integer = ValidationConstants.MONTANT_INTEGER_DIGITS, fraction = ValidationConstants.MONTANT_FRACTION_DIGITS, message = ValidationConstants.MONTANT_DIGITS_MESSAGE) BigDecimal coutReel,
@Pattern(regexp = ValidationConstants.DEVISE_PATTERN, message = ValidationConstants.DEVISE_MESSAGE) String codeDevise, @Pattern(regexp = ValidationConstants.DEVISE_PATTERN, message = ValidationConstants.DEVISE_MESSAGE) String codeDevise,
Boolean inscriptionObligatoire, Boolean inscriptionObligatoire,
LocalDate dateLimiteInscription, LocalDate dateLimiteInscription,
Boolean evenementPublic, Boolean evenementPublic,
Boolean recurrent, Boolean recurrent,
String frequenceRecurrence, String frequenceRecurrence,
@Size(max = 500) String instructions, @Size(max = 500) String instructions,
@Size(max = 500) String materielNecessaire, @Size(max = 500) String materielNecessaire,
@Size(max = 100) String conditionsMeteo, @Size(max = 100) String conditionsMeteo,
@Size(max = 255) String imageUrl, @Size(max = 255) String imageUrl,
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$") String couleurTheme) { @Pattern(regexp = "^#[0-9A-Fa-f]{6}$") String couleurTheme) {
} }

View File

@@ -1,277 +1,277 @@
package dev.lions.unionflow.server.api.dto.evenement.response; package dev.lions.unionflow.server.api.dto.evenement.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement; import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement; import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier; import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée pour un événement. * Réponse détaillée pour un événement.
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class EvenementResponse extends BaseResponse { public class EvenementResponse extends BaseResponse {
private String titre; private String titre;
private String description; private String description;
private TypeEvenementMetier typeEvenement; private TypeEvenementMetier typeEvenement;
private StatutEvenement statut; private StatutEvenement statut;
private PrioriteEvenement priorite; private PrioriteEvenement priorite;
// Décommenter si l'on a besoin du @JsonFormat, sinon on garde le standard // Décommenter si l'on a besoin du @JsonFormat, sinon on garde le standard
// @JsonFormat(pattern = "yyyy-MM-dd") // @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateDebut; private LocalDate dateDebut;
// @JsonFormat(pattern = "yyyy-MM-dd") // @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateFin; private LocalDate dateFin;
// @JsonFormat(pattern = "HH:mm") // @JsonFormat(pattern = "HH:mm")
private LocalTime heureDebut; private LocalTime heureDebut;
// @JsonFormat(pattern = "HH:mm") // @JsonFormat(pattern = "HH:mm")
private LocalTime heureFin; private LocalTime heureFin;
private String lieu; private String lieu;
private String adresse; private String adresse;
private String ville; private String ville;
private String region; private String region;
private BigDecimal latitude; private BigDecimal latitude;
private BigDecimal longitude; private BigDecimal longitude;
private UUID associationId; private UUID associationId;
private String nomAssociation; private String nomAssociation;
private String organisateur; private String organisateur;
private String emailOrganisateur; private String emailOrganisateur;
private String telephoneOrganisateur; private String telephoneOrganisateur;
private Integer capaciteMax; private Integer capaciteMax;
private Integer participantsInscrits; private Integer participantsInscrits;
private Integer participantsPresents; private Integer participantsPresents;
private BigDecimal budget; private BigDecimal budget;
private BigDecimal coutReel; private BigDecimal coutReel;
private String codeDevise; private String codeDevise;
private Boolean inscriptionObligatoire; private Boolean inscriptionObligatoire;
// @JsonFormat(pattern = "yyyy-MM-dd") // @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateLimiteInscription; private LocalDate dateLimiteInscription;
private Boolean evenementPublic; private Boolean evenementPublic;
private Boolean recurrent; private Boolean recurrent;
private String frequenceRecurrence; private String frequenceRecurrence;
private String instructions; private String instructions;
private String materielNecessaire; private String materielNecessaire;
private String conditionsMeteo; private String conditionsMeteo;
private String imageUrl; private String imageUrl;
private String couleurTheme; private String couleurTheme;
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateAnnulation; private LocalDateTime dateAnnulation;
private String raisonAnnulation; private String raisonAnnulation;
private String nomAnnulateur; private String nomAnnulateur;
private Long annulePar; private Long annulePar;
// === METHODES UTILITAIRES === // === METHODES UTILITAIRES ===
public boolean estEnCours() { public boolean estEnCours() {
return StatutEvenement.EN_COURS.equals(statut); return StatutEvenement.EN_COURS.equals(statut);
} }
public boolean estTermine() { public boolean estTermine() {
return StatutEvenement.TERMINE.equals(statut); return StatutEvenement.TERMINE.equals(statut);
} }
public boolean estAnnule() { public boolean estAnnule() {
return StatutEvenement.ANNULE.equals(statut); return StatutEvenement.ANNULE.equals(statut);
} }
public boolean estComplet() { public boolean estComplet() {
return capaciteMax != null return capaciteMax != null
&& participantsInscrits != null && participantsInscrits != null
&& participantsInscrits >= capaciteMax; && participantsInscrits >= capaciteMax;
} }
public int getPlacesDisponibles() { public int getPlacesDisponibles() {
if (capaciteMax == null || participantsInscrits == null) { if (capaciteMax == null || participantsInscrits == null) {
return 0; return 0;
} }
return Math.max(0, capaciteMax - participantsInscrits); return Math.max(0, capaciteMax - participantsInscrits);
} }
public int getTauxRemplissage() { public int getTauxRemplissage() {
if (capaciteMax == null || capaciteMax == 0 || participantsInscrits == null) { if (capaciteMax == null || capaciteMax == 0 || participantsInscrits == null) {
return 0; return 0;
} }
return (participantsInscrits * 100) / capaciteMax; return (participantsInscrits * 100) / capaciteMax;
} }
public int getTauxPresence() { public int getTauxPresence() {
if (participantsInscrits == null || participantsInscrits == 0 || participantsPresents == null) { if (participantsInscrits == null || participantsInscrits == 0 || participantsPresents == null) {
return 0; return 0;
} }
return (participantsPresents * 100) / participantsInscrits; return (participantsPresents * 100) / participantsInscrits;
} }
public boolean sontInscriptionsOuvertes() { public boolean sontInscriptionsOuvertes() {
if (estAnnule() || estTermine()) { if (estAnnule() || estTermine()) {
return false; return false;
} }
if (dateLimiteInscription != null && LocalDate.now().isAfter(dateLimiteInscription)) { if (dateLimiteInscription != null && LocalDate.now().isAfter(dateLimiteInscription)) {
return false; return false;
} }
return !estComplet(); return !estComplet();
} }
public long getDureeEnHeures() { public long getDureeEnHeures() {
if (heureDebut == null || heureFin == null) { if (heureDebut == null || heureFin == null) {
return 0; return 0;
} }
return heureDebut.until(heureFin, java.time.temporal.ChronoUnit.HOURS); return heureDebut.until(heureFin, java.time.temporal.ChronoUnit.HOURS);
} }
public boolean estEvenementMultiJours() { public boolean estEvenementMultiJours() {
return dateFin != null && !dateDebut.equals(dateFin); return dateFin != null && !dateDebut.equals(dateFin);
} }
public String getTypeEvenementLibelle() { public String getTypeEvenementLibelle() {
return typeEvenement != null ? typeEvenement.getLibelle() : "Non défini"; return typeEvenement != null ? typeEvenement.getLibelle() : "Non défini";
} }
public String getTypeEvenementIcon() { public String getTypeEvenementIcon() {
if (typeEvenement == null) return "pi pi-calendar"; if (typeEvenement == null) return "pi pi-calendar";
return switch (typeEvenement) { return switch (typeEvenement) {
case ASSEMBLEE_GENERALE -> "pi pi-building"; case ASSEMBLEE_GENERALE -> "pi pi-building";
case FORMATION -> "pi pi-book"; case FORMATION -> "pi pi-book";
case REUNION_BUREAU -> "pi pi-users"; case REUNION_BUREAU -> "pi pi-users";
case CONFERENCE -> "pi pi-microphone"; case CONFERENCE -> "pi pi-microphone";
case ATELIER -> "pi pi-wrench"; case ATELIER -> "pi pi-wrench";
case CEREMONIE -> "pi pi-flag"; case CEREMONIE -> "pi pi-flag";
case ACTIVITE_SOCIALE, ACTION_CARITATIVE, AUTRE -> "pi pi-calendar"; case ACTIVITE_SOCIALE, ACTION_CARITATIVE, AUTRE -> "pi pi-calendar";
}; };
} }
public String getTypeEvenementSeverity() { public String getTypeEvenementSeverity() {
if (typeEvenement == null) return "secondary"; if (typeEvenement == null) return "secondary";
return switch (typeEvenement) { return switch (typeEvenement) {
case ASSEMBLEE_GENERALE -> "warning"; case ASSEMBLEE_GENERALE -> "warning";
case FORMATION -> "info"; case FORMATION -> "info";
case ACTIVITE_SOCIALE, ACTION_CARITATIVE, REUNION_BUREAU, CONFERENCE, ATELIER, CEREMONIE, AUTRE -> "secondary"; case ACTIVITE_SOCIALE, ACTION_CARITATIVE, REUNION_BUREAU, CONFERENCE, ATELIER, CEREMONIE, AUTRE -> "secondary";
}; };
} }
public String getStatutLibelle() { public String getStatutLibelle() {
return statut != null ? statut.getLibelle() : "Non défini"; return statut != null ? statut.getLibelle() : "Non défini";
} }
public String getStatutSeverity() { public String getStatutSeverity() {
if (statut == null) return "secondary"; if (statut == null) return "secondary";
return switch (statut) { return switch (statut) {
case PLANIFIE -> "info"; case PLANIFIE -> "info";
case EN_COURS -> "success"; case EN_COURS -> "success";
case TERMINE, CONFIRME -> "secondary"; case TERMINE, CONFIRME -> "secondary";
case ANNULE -> "danger"; case ANNULE -> "danger";
case REPORTE -> "warning"; case REPORTE -> "warning";
}; };
} }
public String getDateDebutFormatee() { public String getDateDebutFormatee() {
return dateDebut != null ? dateDebut.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) : ""; return dateDebut != null ? dateDebut.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) : "";
} }
public String getHeureDebutFormatee() { public String getHeureDebutFormatee() {
return heureDebut != null ? heureDebut.format(DateTimeFormatter.ofPattern("HH:mm")) : ""; return heureDebut != null ? heureDebut.format(DateTimeFormatter.ofPattern("HH:mm")) : "";
} }
public String getHeureFinFormatee() { public String getHeureFinFormatee() {
return heureFin != null ? heureFin.format(DateTimeFormatter.ofPattern("HH:mm")) : ""; return heureFin != null ? heureFin.format(DateTimeFormatter.ofPattern("HH:mm")) : "";
} }
public String getStatutIcon() { public String getStatutIcon() {
if (statut == null) return "pi pi-question"; if (statut == null) return "pi pi-question";
return switch (statut) { return switch (statut) {
case PLANIFIE -> "pi pi-clock"; case PLANIFIE -> "pi pi-clock";
case CONFIRME -> "pi pi-check-circle"; case CONFIRME -> "pi pi-check-circle";
case EN_COURS -> "pi pi-play"; case EN_COURS -> "pi pi-play";
case TERMINE -> "pi pi-check"; case TERMINE -> "pi pi-check";
case ANNULE -> "pi pi-times"; case ANNULE -> "pi pi-times";
case REPORTE -> "pi pi-refresh"; case REPORTE -> "pi pi-refresh";
}; };
} }
public String getPrioriteSeverity() { public String getPrioriteSeverity() {
if (priorite == null) return "secondary"; if (priorite == null) return "secondary";
return switch (priorite) { return switch (priorite) {
case CRITIQUE -> "danger"; case CRITIQUE -> "danger";
case HAUTE -> "warning"; case HAUTE -> "warning";
case NORMALE -> "info"; case NORMALE -> "info";
case BASSE -> "secondary"; case BASSE -> "secondary";
}; };
} }
public String getBudgetFormate() { public String getBudgetFormate() {
if (budget == null) return ""; if (budget == null) return "";
return String.format(java.util.Locale.US, "%,.0f %s", budget, codeDevise != null ? codeDevise : "FCFA"); return String.format(java.util.Locale.US, "%,.0f %s", budget, codeDevise != null ? codeDevise : "FCFA");
} }
public String getPrioriteLibelle() { public String getPrioriteLibelle() {
return priorite != null ? priorite.getLibelle() : "Normale"; return priorite != null ? priorite.getLibelle() : "Normale";
} }
public String getAdresseComplete() { public String getAdresseComplete() {
StringBuilder adresseComplete = new StringBuilder(); StringBuilder adresseComplete = new StringBuilder();
if (lieu != null && !lieu.trim().isEmpty()) { if (lieu != null && !lieu.trim().isEmpty()) {
adresseComplete.append(lieu); adresseComplete.append(lieu);
} }
if (adresse != null && !adresse.trim().isEmpty()) { if (adresse != null && !adresse.trim().isEmpty()) {
if (adresseComplete.length() > 0) if (adresseComplete.length() > 0)
adresseComplete.append(", "); adresseComplete.append(", ");
adresseComplete.append(adresse); adresseComplete.append(adresse);
} }
if (ville != null && !ville.trim().isEmpty()) { if (ville != null && !ville.trim().isEmpty()) {
if (adresseComplete.length() > 0) if (adresseComplete.length() > 0)
adresseComplete.append(", "); adresseComplete.append(", ");
adresseComplete.append(ville); adresseComplete.append(ville);
} }
if (region != null && !region.trim().isEmpty()) { if (region != null && !region.trim().isEmpty()) {
if (adresseComplete.length() > 0) if (adresseComplete.length() > 0)
adresseComplete.append(", "); adresseComplete.append(", ");
adresseComplete.append(region); adresseComplete.append(region);
} }
return adresseComplete.toString(); return adresseComplete.toString();
} }
public boolean hasCoordonnees() { public boolean hasCoordonnees() {
return latitude != null && longitude != null; return latitude != null && longitude != null;
} }
public BigDecimal getEcartBudgetaire() { public BigDecimal getEcartBudgetaire() {
if (budget == null || coutReel == null) { if (budget == null || coutReel == null) {
return BigDecimal.ZERO; return BigDecimal.ZERO;
} }
return budget.subtract(coutReel); return budget.subtract(coutReel);
} }
public boolean estBudgetDepasse() { public boolean estBudgetDepasse() {
return getEcartBudgetaire().compareTo(BigDecimal.ZERO) < 0; return getEcartBudgetaire().compareTo(BigDecimal.ZERO) < 0;
} }
} }

View File

@@ -1,26 +1,26 @@
package dev.lions.unionflow.server.api.dto.favoris.request; package dev.lions.unionflow.server.api.dto.favoris.request;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un favori. * Requête de création d'un favori.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateFavoriRequest( public record CreateFavoriRequest(
UUID utilisateurId, UUID utilisateurId,
String typeFavori, String typeFavori,
String titre, String titre,
String description, String description,
String url, String url,
String icon, String icon,
String couleur, String couleur,
String categorie, String categorie,
Integer ordre, Integer ordre,
Integer nbVisites, Integer nbVisites,
String derniereVisite, String derniereVisite,
Boolean estPlusUtilise) { Boolean estPlusUtilise) {
} }

View File

@@ -1,37 +1,37 @@
package dev.lions.unionflow.server.api.dto.favoris.response; package dev.lions.unionflow.server.api.dto.favoris.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.util.UUID; import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.Builder; import lombok.Builder;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
/** /**
* Réponse pour un favori utilisateur. * Réponse pour un favori utilisateur.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class FavoriResponse extends BaseResponse { public class FavoriResponse extends BaseResponse {
private UUID utilisateurId; private UUID utilisateurId;
private String typeFavori; private String typeFavori;
private String titre; private String titre;
private String description; private String description;
private String url; private String url;
private String icon; private String icon;
private String couleur; private String couleur;
private String categorie; private String categorie;
private Integer ordre; private Integer ordre;
private Integer nbVisites; private Integer nbVisites;
private String derniereVisite; private String derniereVisite;
private Boolean estPlusUtilise; private Boolean estPlusUtilise;
} }

View File

@@ -1,33 +1,33 @@
package dev.lions.unionflow.server.api.dto.finance.request; package dev.lions.unionflow.server.api.dto.finance.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une adhésion. * Requête de création d'une adhésion.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record CreateAdhesionRequest( public record CreateAdhesionRequest(
@NotBlank(message = "Le numéro de référence est obligatoire") @Size(max = 50, message = "Le numéro de référence ne peut pas dépasser 50 caractères") String numeroReference, @NotBlank(message = "Le numéro de référence est obligatoire") @Size(max = 50, message = "Le numéro de référence ne peut pas dépasser 50 caractères") String numeroReference,
@NotNull(message = "L'identifiant du membre est obligatoire") UUID membreId, @NotNull(message = "L'identifiant du membre est obligatoire") UUID membreId,
@NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId, @NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId,
@NotNull(message = "La date de demande est obligatoire") LocalDate dateDemande, @NotNull(message = "La date de demande est obligatoire") LocalDate dateDemande,
@NotNull(message = "Les frais d'adhésion sont obligatoires") @DecimalMin(value = "0.0", inclusive = false, message = "Les frais d'adhésion doivent être positifs") @Digits(integer = 10, fraction = 2, message = "Format de montant invalide") BigDecimal fraisAdhesion, @NotNull(message = "Les frais d'adhésion sont obligatoires") @DecimalMin(value = "0.0", inclusive = false, message = "Les frais d'adhésion doivent être positifs") @Digits(integer = 10, fraction = 2, message = "Format de montant invalide") BigDecimal fraisAdhesion,
@NotBlank(message = "Le code devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$", message = "Le code devise doit être un code ISO à 3 lettres") String codeDevise, @NotBlank(message = "Le code devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$", message = "Le code devise doit être un code ISO à 3 lettres") String codeDevise,
@Size(max = 1000, message = "Les observations ne peuvent pas dépasser 1000 caractères") String observations) { @Size(max = 1000, message = "Les observations ne peuvent pas dépasser 1000 caractères") String observations) {
} }

View File

@@ -1,38 +1,38 @@
package dev.lions.unionflow.server.api.dto.finance.request; package dev.lions.unionflow.server.api.dto.finance.request;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une adhésion. * Requête de mise à jour d'une adhésion.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Builder @Builder
public record UpdateAdhesionRequest( public record UpdateAdhesionRequest(
@DecimalMin(value = "0.0", message = "Le montant payé ne peut pas être négatif") @Digits(integer = 10, fraction = 2, message = "Format de montant invalide") BigDecimal montantPaye, @DecimalMin(value = "0.0", message = "Le montant payé ne peut pas être négatif") @Digits(integer = 10, fraction = 2, message = "Format de montant invalide") BigDecimal montantPaye,
@Pattern(regexp = "^(EN_ATTENTE|APPROUVEE|REJETEE|ANNULEE|EN_PAIEMENT|PAYEE)$", message = "Statut invalide") String statut, @Pattern(regexp = "^(EN_ATTENTE|APPROUVEE|REJETEE|ANNULEE|EN_PAIEMENT|PAYEE)$", message = "Statut invalide") String statut,
LocalDate dateApprobation, LocalDate dateApprobation,
LocalDateTime datePaiement, LocalDateTime datePaiement,
@Pattern(regexp = "^(ESPECES|VIREMENT|CHEQUE|WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|CARTE_BANCAIRE)$", message = "Méthode de paiement invalide") String methodePaiement, @Pattern(regexp = "^(ESPECES|VIREMENT|CHEQUE|WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|CARTE_BANCAIRE)$", message = "Méthode de paiement invalide") String methodePaiement,
@Size(max = 100, message = "La référence de paiement ne peut pas dépasser 100 caractères") String referencePaiement, @Size(max = 100, message = "La référence de paiement ne peut pas dépasser 100 caractères") String referencePaiement,
@Size(max = 1000, message = "Le motif de rejet ne peut pas dépasser 1000 caractères") String motifRejet, @Size(max = 1000, message = "Le motif de rejet ne peut pas dépasser 1000 caractères") String motifRejet,
@Size(max = 1000, message = "Les observations ne peuvent pas dépasser 1000 caractères") String observations, @Size(max = 1000, message = "Les observations ne peuvent pas dépasser 1000 caractères") String observations,
@Size(max = 255, message = "Le nom de l'approbateur ne peut pas dépasser 255 caractères") String approuvePar, @Size(max = 255, message = "Le nom de l'approbateur ne peut pas dépasser 255 caractères") String approuvePar,
LocalDate dateValidation) { LocalDate dateValidation) {
} }

View File

@@ -1,171 +1,171 @@
package dev.lions.unionflow.server.api.dto.finance.response; package dev.lions.unionflow.server.api.dto.finance.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse contenant les données d'une adhésion. * Réponse contenant les données d'une adhésion.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class AdhesionResponse extends BaseResponse { public class AdhesionResponse extends BaseResponse {
private String numeroReference; private String numeroReference;
private UUID membreId; private UUID membreId;
private String numeroMembre; private String numeroMembre;
private String nomMembre; private String nomMembre;
private String emailMembre; private String emailMembre;
private UUID organisationId; private UUID organisationId;
private String nomOrganisation; private String nomOrganisation;
private LocalDate dateDemande; private LocalDate dateDemande;
private BigDecimal fraisAdhesion; private BigDecimal fraisAdhesion;
private BigDecimal montantPaye; private BigDecimal montantPaye;
private String codeDevise; private String codeDevise;
private String statut; private String statut;
private LocalDate dateApprobation; private LocalDate dateApprobation;
private LocalDateTime datePaiement; private LocalDateTime datePaiement;
private String methodePaiement; private String methodePaiement;
private String referencePaiement; private String referencePaiement;
private String motifRejet; private String motifRejet;
private String observations; private String observations;
private String approuvePar; private String approuvePar;
private LocalDate dateValidation; private LocalDate dateValidation;
// Méthodes utilitaires héritées de l'ancien DTO // Méthodes utilitaires héritées de l'ancien DTO
public boolean isPayeeIntegralement() { public boolean isPayeeIntegralement() {
return montantPaye != null && fraisAdhesion != null && montantPaye.compareTo(fraisAdhesion) >= 0; return montantPaye != null && fraisAdhesion != null && montantPaye.compareTo(fraisAdhesion) >= 0;
} }
public boolean isEnAttentePaiement() { public boolean isEnAttentePaiement() {
return "APPROUVEE".equals(statut) && !isPayeeIntegralement(); return "APPROUVEE".equals(statut) && !isPayeeIntegralement();
} }
public BigDecimal getMontantRestant() { public BigDecimal getMontantRestant() {
if (fraisAdhesion == null) if (fraisAdhesion == null)
return BigDecimal.ZERO; return BigDecimal.ZERO;
if (montantPaye == null) if (montantPaye == null)
return fraisAdhesion; return fraisAdhesion;
BigDecimal restant = fraisAdhesion.subtract(montantPaye); BigDecimal restant = fraisAdhesion.subtract(montantPaye);
return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO; return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO;
} }
public int getPourcentagePaiement() { public int getPourcentagePaiement() {
if (fraisAdhesion == null || fraisAdhesion.compareTo(BigDecimal.ZERO) == 0) if (fraisAdhesion == null || fraisAdhesion.compareTo(BigDecimal.ZERO) == 0)
return 0; return 0;
if (montantPaye == null) if (montantPaye == null)
return 0; return 0;
return montantPaye.multiply(BigDecimal.valueOf(100)).divide(fraisAdhesion, 0, java.math.RoundingMode.HALF_UP) return montantPaye.multiply(BigDecimal.valueOf(100)).divide(fraisAdhesion, 0, java.math.RoundingMode.HALF_UP)
.intValue(); .intValue();
} }
public long getJoursDepuisDemande() { public long getJoursDepuisDemande() {
if (dateDemande == null) if (dateDemande == null)
return 0; return 0;
return ChronoUnit.DAYS.between(dateDemande, LocalDate.now()); return ChronoUnit.DAYS.between(dateDemande, LocalDate.now());
} }
public String getStatutLibelle() { public String getStatutLibelle() {
if (statut == null) if (statut == null)
return "Non défini"; return "Non défini";
return switch (statut) { return switch (statut) {
case "EN_ATTENTE" -> "En attente"; case "EN_ATTENTE" -> "En attente";
case "APPROUVEE" -> "Approuvée"; case "APPROUVEE" -> "Approuvée";
case "REJETEE" -> "Rejetée"; case "REJETEE" -> "Rejetée";
case "ANNULEE" -> "Annulée"; case "ANNULEE" -> "Annulée";
case "EN_PAIEMENT" -> "En paiement"; case "EN_PAIEMENT" -> "En paiement";
case "PAYEE" -> "Payée"; case "PAYEE" -> "Payée";
default -> statut; default -> statut;
}; };
} }
public String getStatutSeverity() { public String getStatutSeverity() {
if (statut == null) if (statut == null)
return "secondary"; return "secondary";
return switch (statut) { return switch (statut) {
case "APPROUVEE", "PAYEE" -> "success"; case "APPROUVEE", "PAYEE" -> "success";
case "EN_ATTENTE", "EN_PAIEMENT" -> "warning"; case "EN_ATTENTE", "EN_PAIEMENT" -> "warning";
case "REJETEE" -> "danger"; case "REJETEE" -> "danger";
case "ANNULEE" -> "secondary"; case "ANNULEE" -> "secondary";
default -> "secondary"; default -> "secondary";
}; };
} }
public String getStatutIcon() { public String getStatutIcon() {
if (statut == null) if (statut == null)
return "pi-circle"; return "pi-circle";
return switch (statut) { return switch (statut) {
case "APPROUVEE", "PAYEE" -> "pi-check"; case "APPROUVEE", "PAYEE" -> "pi-check";
case "EN_ATTENTE" -> "pi-clock"; case "EN_ATTENTE" -> "pi-clock";
case "EN_PAIEMENT" -> "pi-credit-card"; case "EN_PAIEMENT" -> "pi-credit-card";
case "REJETEE" -> "pi-times"; case "REJETEE" -> "pi-times";
case "ANNULEE" -> "pi-ban"; case "ANNULEE" -> "pi-ban";
default -> "pi-circle"; default -> "pi-circle";
}; };
} }
public String getMethodePaiementLibelle() { public String getMethodePaiementLibelle() {
if (methodePaiement == null) if (methodePaiement == null)
return "Non défini"; return "Non défini";
return switch (methodePaiement) { return switch (methodePaiement) {
case "ESPECES" -> "Espèces"; case "ESPECES" -> "Espèces";
case "VIREMENT" -> "Virement bancaire"; case "VIREMENT" -> "Virement bancaire";
case "CHEQUE" -> "Chèque"; case "CHEQUE" -> "Chèque";
case "WAVE_MONEY" -> "Wave Money"; case "WAVE_MONEY" -> "Wave Money";
case "ORANGE_MONEY" -> "Orange Money"; case "ORANGE_MONEY" -> "Orange Money";
case "FREE_MONEY" -> "Free Money"; case "FREE_MONEY" -> "Free Money";
case "CARTE_BANCAIRE" -> "Carte bancaire"; case "CARTE_BANCAIRE" -> "Carte bancaire";
default -> methodePaiement; default -> methodePaiement;
}; };
} }
public String getDateDemandeFormatee() { public String getDateDemandeFormatee() {
if (dateDemande == null) if (dateDemande == null)
return ""; return "";
return dateDemande.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")); return dateDemande.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
} }
public String getDateApprobationFormatee() { public String getDateApprobationFormatee() {
if (dateApprobation == null) if (dateApprobation == null)
return ""; return "";
return dateApprobation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")); return dateApprobation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
} }
public String getDatePaiementFormatee() { public String getDatePaiementFormatee() {
if (datePaiement == null) if (datePaiement == null)
return ""; return "";
return datePaiement.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")); return datePaiement.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
} }
public String getFraisAdhesionFormatte() { public String getFraisAdhesionFormatte() {
if (fraisAdhesion == null) if (fraisAdhesion == null)
return "0 FCFA"; return "0 FCFA";
return String.format("%,.0f FCFA", fraisAdhesion.doubleValue()); return String.format("%,.0f FCFA", fraisAdhesion.doubleValue());
} }
public String getMontantPayeFormatte() { public String getMontantPayeFormatte() {
if (montantPaye == null) if (montantPaye == null)
return "0 FCFA"; return "0 FCFA";
return String.format("%,.0f FCFA", montantPaye.doubleValue()); return String.format("%,.0f FCFA", montantPaye.doubleValue());
} }
public String getMontantRestantFormatte() { public String getMontantRestantFormatte() {
return String.format("%,.0f FCFA", getMontantRestant().doubleValue()); return String.format("%,.0f FCFA", getMontantRestant().doubleValue());
} }
} }

View File

@@ -1,24 +1,24 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.request; package dev.lions.unionflow.server.api.dto.finance_workflow.request;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de requête pour approuver une transaction * DTO de requête pour approuver une transaction
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class ApproveTransactionRequest { public class ApproveTransactionRequest {
@Size(max = 1000, message = "Le commentaire ne peut pas dépasser 1000 caractères") @Size(max = 1000, message = "Le commentaire ne peut pas dépasser 1000 caractères")
private String comment; private String comment;
} }

View File

@@ -1,42 +1,42 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.request; package dev.lions.unionflow.server.api.dto.finance_workflow.request;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de requête pour créer une ligne budgétaire * DTO de requête pour créer une ligne budgétaire
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class CreateBudgetLineRequest { public class CreateBudgetLineRequest {
@NotBlank(message = "La catégorie est requise") @NotBlank(message = "La catégorie est requise")
@Pattern(regexp = "^(CONTRIBUTIONS|SAVINGS|SOLIDARITY|EVENTS|OPERATIONAL|INVESTMENTS|OTHER)$", @Pattern(regexp = "^(CONTRIBUTIONS|SAVINGS|SOLIDARITY|EVENTS|OPERATIONAL|INVESTMENTS|OTHER)$",
message = "Catégorie invalide") message = "Catégorie invalide")
private String category; private String category;
@NotBlank(message = "Le nom est requis") @NotBlank(message = "Le nom est requis")
@Size(max = 200, message = "Le nom ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom ne peut pas dépasser 200 caractères")
private String name; private String name;
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères") @Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
private String description; private String description;
@NotNull(message = "Le montant prévu est requis") @NotNull(message = "Le montant prévu est requis")
@DecimalMin(value = "0.0", message = "Le montant prévu doit être positif") @DecimalMin(value = "0.0", message = "Le montant prévu doit être positif")
@Digits(integer = 14, fraction = 2, message = "Format du montant invalide") @Digits(integer = 14, fraction = 2, message = "Format du montant invalide")
private BigDecimal amountPlanned; private BigDecimal amountPlanned;
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères") @Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères")
private String notes; private String notes;
} }

View File

@@ -1,58 +1,58 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.request; package dev.lions.unionflow.server.api.dto.finance_workflow.request;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de requête pour créer un budget * DTO de requête pour créer un budget
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class CreateBudgetRequest { public class CreateBudgetRequest {
@NotBlank(message = "Le nom est requis") @NotBlank(message = "Le nom est requis")
@Size(max = 200, message = "Le nom ne peut pas dépasser 200 caractères") @Size(max = 200, message = "Le nom ne peut pas dépasser 200 caractères")
private String name; private String name;
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") @Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
private String description; private String description;
@NotNull(message = "L'ID de l'organisation est requis") @NotNull(message = "L'ID de l'organisation est requis")
private UUID organizationId; private UUID organizationId;
@NotBlank(message = "La période est requise") @NotBlank(message = "La période est requise")
@Pattern(regexp = "^(MONTHLY|QUARTERLY|SEMIANNUAL|ANNUAL)$", @Pattern(regexp = "^(MONTHLY|QUARTERLY|SEMIANNUAL|ANNUAL)$",
message = "Période invalide") message = "Période invalide")
private String period; private String period;
@NotNull(message = "L'année est requise") @NotNull(message = "L'année est requise")
@Min(value = 2020, message = "L'année doit être >= 2020") @Min(value = 2020, message = "L'année doit être >= 2020")
@Max(value = 2100, message = "L'année doit être <= 2100") @Max(value = 2100, message = "L'année doit être <= 2100")
private Integer year; private Integer year;
@Min(value = 1, message = "Le mois doit être entre 1 et 12") @Min(value = 1, message = "Le mois doit être entre 1 et 12")
@Max(value = 12, message = "Le mois doit être entre 1 et 12") @Max(value = 12, message = "Le mois doit être entre 1 et 12")
private Integer month; private Integer month;
@NotNull(message = "Au moins une ligne budgétaire est requise") @NotNull(message = "Au moins une ligne budgétaire est requise")
@Size(min = 1, message = "Au moins une ligne budgétaire est requise") @Size(min = 1, message = "Au moins une ligne budgétaire est requise")
@Valid @Valid
@Builder.Default @Builder.Default
private List<CreateBudgetLineRequest> lines = new ArrayList<>(); private List<CreateBudgetLineRequest> lines = new ArrayList<>();
@Pattern(regexp = "^[A-Z]{3}$", message = "Code devise invalide (doit être ISO 3 lettres)") @Pattern(regexp = "^[A-Z]{3}$", message = "Code devise invalide (doit être ISO 3 lettres)")
private String currency; // Optionnel, défaut XOF private String currency; // Optionnel, défaut XOF
} }

View File

@@ -1,26 +1,26 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.request; package dev.lions.unionflow.server.api.dto.finance_workflow.request;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de requête pour rejeter une transaction * DTO de requête pour rejeter une transaction
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class RejectTransactionRequest { public class RejectTransactionRequest {
@NotBlank(message = "La raison du rejet est requise") @NotBlank(message = "La raison du rejet est requise")
@Size(min = 10, max = 1000, message = "La raison doit contenir entre 10 et 1000 caractères") @Size(min = 10, max = 1000, message = "La raison doit contenir entre 10 et 1000 caractères")
private String reason; private String reason;
} }

View File

@@ -1,44 +1,44 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.response; package dev.lions.unionflow.server.api.dto.finance_workflow.response;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de réponse pour une action d'approbateur * DTO de réponse pour une action d'approbateur
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class ApproverActionResponse { public class ApproverActionResponse {
private UUID id; private UUID id;
@NotNull @NotNull
private UUID approverId; private UUID approverId;
@NotBlank @NotBlank
private String approverName; private String approverName;
@NotBlank @NotBlank
private String approverRole; private String approverRole;
@NotBlank @NotBlank
private String decision; // PENDING, APPROVED, REJECTED private String decision; // PENDING, APPROVED, REJECTED
private String comment; private String comment;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime decidedAt; private LocalDateTime decidedAt;
} }

View File

@@ -1,47 +1,47 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.response; package dev.lions.unionflow.server.api.dto.finance_workflow.response;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de réponse pour une ligne budgétaire * DTO de réponse pour une ligne budgétaire
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class BudgetLineResponse { public class BudgetLineResponse {
private UUID id; private UUID id;
@NotBlank @NotBlank
private String category; // CONTRIBUTIONS, SAVINGS, SOLIDARITY, etc. private String category; // CONTRIBUTIONS, SAVINGS, SOLIDARITY, etc.
@NotBlank @NotBlank
private String name; private String name;
private String description; private String description;
@NotNull @NotNull
private BigDecimal amountPlanned; private BigDecimal amountPlanned;
@NotNull @NotNull
private BigDecimal amountRealized; private BigDecimal amountRealized;
private String notes; private String notes;
// Champs calculés // Champs calculés
private Double realizationRate; private Double realizationRate;
private BigDecimal variance; private BigDecimal variance;
private Boolean isOverBudget; private Boolean isOverBudget;
} }

View File

@@ -1,92 +1,92 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.response; package dev.lions.unionflow.server.api.dto.finance_workflow.response;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de réponse pour un budget * DTO de réponse pour un budget
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class BudgetResponse { public class BudgetResponse {
private UUID id; private UUID id;
@NotBlank @NotBlank
private String name; private String name;
private String description; private String description;
@NotNull @NotNull
private UUID organizationId; private UUID organizationId;
@NotBlank @NotBlank
private String period; // MONTHLY, QUARTERLY, SEMIANNUAL, ANNUAL private String period; // MONTHLY, QUARTERLY, SEMIANNUAL, ANNUAL
@NotNull @NotNull
private Integer year; private Integer year;
private Integer month; private Integer month;
@NotBlank @NotBlank
private String status; // DRAFT, ACTIVE, CLOSED, CANCELLED private String status; // DRAFT, ACTIVE, CLOSED, CANCELLED
@Builder.Default @Builder.Default
private List<BudgetLineResponse> lines = new ArrayList<>(); private List<BudgetLineResponse> lines = new ArrayList<>();
@NotNull @NotNull
private BigDecimal totalPlanned; private BigDecimal totalPlanned;
@NotNull @NotNull
private BigDecimal totalRealized; private BigDecimal totalRealized;
@NotBlank @NotBlank
private String currency; private String currency;
@NotNull @NotNull
private UUID createdById; private UUID createdById;
@NotNull @NotNull
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime createdAt; private LocalDateTime createdAt;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime approvedAt; private LocalDateTime approvedAt;
private UUID approvedById; private UUID approvedById;
@NotNull @NotNull
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate; private LocalDate startDate;
@NotNull @NotNull
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate; private LocalDate endDate;
private String metadata; private String metadata;
// Champs calculés // Champs calculés
private Double realizationRate; private Double realizationRate;
private BigDecimal variance; private BigDecimal variance;
private Double varianceRate; private Double varianceRate;
private Boolean isOverBudget; private Boolean isOverBudget;
private Boolean isActive; private Boolean isActive;
private Boolean isCurrentPeriod; private Boolean isCurrentPeriod;
} }

View File

@@ -1,81 +1,81 @@
package dev.lions.unionflow.server.api.dto.finance_workflow.response; package dev.lions.unionflow.server.api.dto.finance_workflow.response;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* DTO de réponse pour une approbation de transaction * DTO de réponse pour une approbation de transaction
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-13 * @since 2026-03-13
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class TransactionApprovalResponse { public class TransactionApprovalResponse {
private UUID id; private UUID id;
@NotNull @NotNull
private UUID transactionId; private UUID transactionId;
@NotBlank @NotBlank
private String transactionType; // CONTRIBUTION, DEPOSIT, WITHDRAWAL, etc. private String transactionType; // CONTRIBUTION, DEPOSIT, WITHDRAWAL, etc.
@NotNull @NotNull
private BigDecimal amount; private BigDecimal amount;
@NotBlank @NotBlank
private String currency; private String currency;
@NotNull @NotNull
private UUID requesterId; private UUID requesterId;
@NotBlank @NotBlank
private String requesterName; private String requesterName;
private UUID organizationId; private UUID organizationId;
@NotBlank @NotBlank
private String requiredLevel; // NONE, LEVEL1, LEVEL2, LEVEL3 private String requiredLevel; // NONE, LEVEL1, LEVEL2, LEVEL3
@NotBlank @NotBlank
private String status; // PENDING, APPROVED, VALIDATED, REJECTED, EXPIRED, CANCELLED private String status; // PENDING, APPROVED, VALIDATED, REJECTED, EXPIRED, CANCELLED
@Builder.Default @Builder.Default
private List<ApproverActionResponse> approvers = new ArrayList<>(); private List<ApproverActionResponse> approvers = new ArrayList<>();
private String rejectionReason; private String rejectionReason;
@NotNull @NotNull
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime createdAt; private LocalDateTime createdAt;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime expiresAt; private LocalDateTime expiresAt;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime completedAt; private LocalDateTime completedAt;
private String metadata; private String metadata;
// Champs calculés // Champs calculés
private Integer approvalCount; private Integer approvalCount;
private Integer requiredApprovals; private Integer requiredApprovals;
private Boolean hasAllApprovals; private Boolean hasAllApprovals;
private Boolean isExpired; private Boolean isExpired;
private Boolean isPending; private Boolean isPending;
private Boolean isCompleted; private Boolean isCompleted;
} }

View File

@@ -1,51 +1,51 @@
package dev.lions.unionflow.server.api.dto.formuleabonnement.request; package dev.lions.unionflow.server.api.dto.formuleabonnement.request;
import dev.lions.unionflow.server.api.enums.formuleabonnement.StatutFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.StatutFormule;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'une formule d'abonnement. * Requête de création d'une formule d'abonnement.
*/ */
@Builder @Builder
public record CreateFormuleAbonnementRequest( public record CreateFormuleAbonnementRequest(
@NotBlank(message = "Le nom de la formule est obligatoire") @Size(min = 2, max = 100, message = "Le nom de la formule doit contenir entre 2 et 100 caractères") String nom, @NotBlank(message = "Le nom de la formule est obligatoire") @Size(min = 2, max = 100, message = "Le nom de la formule doit contenir entre 2 et 100 caractères") String nom,
@NotBlank(message = "Le code de la formule est obligatoire") @Pattern(regexp = "^[A-Z_]{2,20}$", message = "Le code doit contenir uniquement des lettres majuscules et underscores") String code, @NotBlank(message = "Le code de la formule est obligatoire") @Pattern(regexp = "^[A-Z_]{2,20}$", message = "Le code doit contenir uniquement des lettres majuscules et underscores") String code,
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") String description, @Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") String description,
@NotNull(message = "Le type de formule est obligatoire") TypeFormule type, @NotNull(message = "Le type de formule est obligatoire") TypeFormule type,
@NotNull(message = "Le statut est obligatoire") StatutFormule statut, @NotNull(message = "Le statut est obligatoire") StatutFormule statut,
@NotNull(message = "Le prix mensuel est obligatoire") @DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal prixMensuel, @NotNull(message = "Le prix mensuel est obligatoire") @DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal prixMensuel,
@DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal prixAnnuel, @DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal prixAnnuel,
@NotBlank(message = "La devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$") String devise, @NotBlank(message = "La devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$") String devise,
@NotNull(message = "Le nombre maximum de membres est obligatoire") Integer maxMembres, @NotNull(message = "Le nombre maximum de membres est obligatoire") Integer maxMembres,
@NotNull(message = "Le nombre maximum d'administrateurs est obligatoire") Integer maxAdministrateurs, @NotNull(message = "Le nombre maximum d'administrateurs est obligatoire") Integer maxAdministrateurs,
@NotNull(message = "L'espace de stockage est obligatoire") @DecimalMin(value = "0.1", message = "L'espace de stockage doit être d'au moins 0.1 GB") BigDecimal espaceStockageGB, @NotNull(message = "L'espace de stockage est obligatoire") @DecimalMin(value = "0.1", message = "L'espace de stockage doit être d'au moins 0.1 GB") BigDecimal espaceStockageGB,
@NotNull(message = "Le support technique doit être spécifié") Boolean supportTechnique, @NotNull(message = "Le support technique doit être spécifié") Boolean supportTechnique,
@Pattern(regexp = "^(EMAIL|CHAT|TELEPHONE|PREMIUM)$", message = "Le niveau de support doit être EMAIL, CHAT, TELEPHONE ou PREMIUM") String niveauSupport, @Pattern(regexp = "^(EMAIL|CHAT|TELEPHONE|PREMIUM)$", message = "Le niveau de support doit être EMAIL, CHAT, TELEPHONE ou PREMIUM") String niveauSupport,
Boolean fonctionnalitesAvancees, Boolean fonctionnalitesAvancees,
Boolean apiAccess, Boolean apiAccess,
Boolean rapportsPersonnalises, Boolean rapportsPersonnalises,
Boolean integrationsTierces, Boolean integrationsTierces,
Boolean sauvegardeAutomatique, Boolean sauvegardeAutomatique,
Boolean multiLangues, Boolean multiLangues,
Boolean personnalisationInterface, Boolean personnalisationInterface,
Boolean formationIncluse, Boolean formationIncluse,
Integer heuresFormation, Integer heuresFormation,
Boolean populaire, Boolean populaire,
Boolean recommandee, Boolean recommandee,
Integer periodeEssaiJours, Integer periodeEssaiJours,
LocalDate dateDebutValidite, LocalDate dateDebutValidite,
LocalDate dateFinValidite, LocalDate dateFinValidite,
Integer ordreAffichage, Integer ordreAffichage,
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "La couleur doit être un code hexadécimal valide") String couleur, @Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "La couleur doit être un code hexadécimal valide") String couleur,
@Size(max = 50, message = "Le nom de l'icône ne peut pas dépasser 50 caractères") String icone, @Size(max = 50, message = "Le nom de l'icône ne peut pas dépasser 50 caractères") String icone,
@Size(max = 500, message = "Les notes ne peuvent pas dépasser 500 caractères") String notes) { @Size(max = 500, message = "Les notes ne peuvent pas dépasser 500 caractères") String notes) {
} }

View File

@@ -1,49 +1,49 @@
package dev.lions.unionflow.server.api.dto.formuleabonnement.request; package dev.lions.unionflow.server.api.dto.formuleabonnement.request;
import dev.lions.unionflow.server.api.enums.formuleabonnement.StatutFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.StatutFormule;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de mise à jour d'une formule d'abonnement. * Requête de mise à jour d'une formule d'abonnement.
*/ */
@Builder @Builder
public record UpdateFormuleAbonnementRequest( public record UpdateFormuleAbonnementRequest(
@Size(min = 2, max = 100, message = "Le nom de la formule doit contenir entre 2 et 100 caractères") String nom, @Size(min = 2, max = 100, message = "Le nom de la formule doit contenir entre 2 et 100 caractères") String nom,
@Pattern(regexp = "^[A-Z_]{2,20}$", message = "Le code doit contenir uniquement des lettres majuscules et underscores") String code, @Pattern(regexp = "^[A-Z_]{2,20}$", message = "Le code doit contenir uniquement des lettres majuscules et underscores") String code,
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") String description, @Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") String description,
TypeFormule type, TypeFormule type,
StatutFormule statut, StatutFormule statut,
@DecimalMin(value = "0.0", inclusive = false, message = "Le prix mensuel doit être positif") @Digits(integer = 10, fraction = 2) BigDecimal prixMensuel, @DecimalMin(value = "0.0", inclusive = false, message = "Le prix mensuel doit être positif") @Digits(integer = 10, fraction = 2) BigDecimal prixMensuel,
@DecimalMin(value = "0.0", inclusive = false, message = "Le prix annuel doit être positif") @Digits(integer = 10, fraction = 2) BigDecimal prixAnnuel, @DecimalMin(value = "0.0", inclusive = false, message = "Le prix annuel doit être positif") @Digits(integer = 10, fraction = 2) BigDecimal prixAnnuel,
@Pattern(regexp = "^[A-Z]{3}$") String devise, @Pattern(regexp = "^[A-Z]{3}$") String devise,
Integer maxMembres, Integer maxMembres,
Integer maxAdministrateurs, Integer maxAdministrateurs,
@DecimalMin(value = "0.1", message = "L'espace de stockage doit être d'au moins 0.1 GB") BigDecimal espaceStockageGB, @DecimalMin(value = "0.1", message = "L'espace de stockage doit être d'au moins 0.1 GB") BigDecimal espaceStockageGB,
Boolean supportTechnique, Boolean supportTechnique,
@Pattern(regexp = "^(EMAIL|CHAT|TELEPHONE|PREMIUM)$", message = "Le niveau de support doit être EMAIL, CHAT, TELEPHONE ou PREMIUM") String niveauSupport, @Pattern(regexp = "^(EMAIL|CHAT|TELEPHONE|PREMIUM)$", message = "Le niveau de support doit être EMAIL, CHAT, TELEPHONE ou PREMIUM") String niveauSupport,
Boolean fonctionnalitesAvancees, Boolean fonctionnalitesAvancees,
Boolean apiAccess, Boolean apiAccess,
Boolean rapportsPersonnalises, Boolean rapportsPersonnalises,
Boolean integrationsTierces, Boolean integrationsTierces,
Boolean sauvegardeAutomatique, Boolean sauvegardeAutomatique,
Boolean multiLangues, Boolean multiLangues,
Boolean personnalisationInterface, Boolean personnalisationInterface,
Boolean formationIncluse, Boolean formationIncluse,
Integer heuresFormation, Integer heuresFormation,
Boolean populaire, Boolean populaire,
Boolean recommandee, Boolean recommandee,
Integer periodeEssaiJours, Integer periodeEssaiJours,
LocalDate dateDebutValidite, LocalDate dateDebutValidite,
LocalDate dateFinValidite, LocalDate dateFinValidite,
Integer ordreAffichage, Integer ordreAffichage,
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "La couleur doit être un code hexadécimal valide") String couleur, @Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "La couleur doit être un code hexadécimal valide") String couleur,
@Size(max = 50, message = "Le nom de l'icône ne peut pas dépasser 50 caractères") String icone, @Size(max = 50, message = "Le nom de l'icône ne peut pas dépasser 50 caractères") String icone,
@Size(max = 500, message = "Les notes ne peuvent pas dépasser 500 caractères") String notes) { @Size(max = 500, message = "Les notes ne peuvent pas dépasser 500 caractères") String notes) {
} }

View File

@@ -1,161 +1,161 @@
package dev.lions.unionflow.server.api.dto.formuleabonnement.response; package dev.lions.unionflow.server.api.dto.formuleabonnement.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import dev.lions.unionflow.server.api.enums.formuleabonnement.StatutFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.StatutFormule;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule; import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse détaillée pour une formule d'abonnement. * Réponse détaillée pour une formule d'abonnement.
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class FormuleAbonnementResponse extends BaseResponse { public class FormuleAbonnementResponse extends BaseResponse {
private String nom; private String nom;
private String code; private String code;
private String description; private String description;
private TypeFormule type; private TypeFormule type;
private StatutFormule statut; private StatutFormule statut;
private BigDecimal prixMensuel; private BigDecimal prixMensuel;
private BigDecimal prixAnnuel; private BigDecimal prixAnnuel;
@Builder.Default @Builder.Default
private String devise = "XOF"; private String devise = "XOF";
private Integer maxMembres; private Integer maxMembres;
private Integer maxAdministrateurs; private Integer maxAdministrateurs;
private BigDecimal espaceStockageGB; private BigDecimal espaceStockageGB;
private Boolean supportTechnique; private Boolean supportTechnique;
private String niveauSupport; private String niveauSupport;
private Boolean fonctionnalitesAvancees; private Boolean fonctionnalitesAvancees;
private Boolean apiAccess; private Boolean apiAccess;
private Boolean rapportsPersonnalises; private Boolean rapportsPersonnalises;
private Boolean integrationsTierces; private Boolean integrationsTierces;
private Boolean sauvegardeAutomatique; private Boolean sauvegardeAutomatique;
private Boolean multiLangues; private Boolean multiLangues;
private Boolean personnalisationInterface; private Boolean personnalisationInterface;
private Boolean formationIncluse; private Boolean formationIncluse;
private Integer heuresFormation; private Integer heuresFormation;
private Boolean populaire; private Boolean populaire;
private Boolean recommandee; private Boolean recommandee;
private Integer periodeEssaiJours; private Integer periodeEssaiJours;
private LocalDate dateDebutValidite; private LocalDate dateDebutValidite;
private LocalDate dateFinValidite; private LocalDate dateFinValidite;
private Integer ordreAffichage; private Integer ordreAffichage;
private String couleur; private String couleur;
private String icone; private String icone;
private String notes; private String notes;
public boolean isActive() { public boolean isActive() {
return StatutFormule.ACTIVE.equals(statut); return StatutFormule.ACTIVE.equals(statut);
} }
public boolean isInactive() { public boolean isInactive() {
return StatutFormule.INACTIVE.equals(statut); return StatutFormule.INACTIVE.equals(statut);
} }
public boolean isArchivee() { public boolean isArchivee() {
return StatutFormule.ARCHIVEE.equals(statut); return StatutFormule.ARCHIVEE.equals(statut);
} }
public boolean isValide() { public boolean isValide() {
if (!isActive()) if (!isActive())
return false; return false;
LocalDate aujourd = LocalDate.now(); LocalDate aujourd = LocalDate.now();
if (dateDebutValidite != null && aujourd.isBefore(dateDebutValidite)) if (dateDebutValidite != null && aujourd.isBefore(dateDebutValidite))
return false; return false;
if (dateFinValidite != null && aujourd.isAfter(dateFinValidite)) if (dateFinValidite != null && aujourd.isAfter(dateFinValidite))
return false; return false;
return true; return true;
} }
public BigDecimal getEconomieAnnuelle() { public BigDecimal getEconomieAnnuelle() {
if (prixMensuel == null || prixAnnuel == null) if (prixMensuel == null || prixAnnuel == null)
return BigDecimal.ZERO; return BigDecimal.ZERO;
BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12)); BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12));
return coutMensuelAnnuel.subtract(prixAnnuel); return coutMensuelAnnuel.subtract(prixAnnuel);
} }
public int getPourcentageEconomieAnnuelle() { public int getPourcentageEconomieAnnuelle() {
if (prixMensuel == null || prixAnnuel == null) if (prixMensuel == null || prixAnnuel == null)
return 0; return 0;
BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12)); BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12));
if (coutMensuelAnnuel.compareTo(BigDecimal.ZERO) > 0) { if (coutMensuelAnnuel.compareTo(BigDecimal.ZERO) > 0) {
return getEconomieAnnuelle() return getEconomieAnnuelle()
.multiply(BigDecimal.valueOf(100)) .multiply(BigDecimal.valueOf(100))
.divide(coutMensuelAnnuel, 0, java.math.RoundingMode.HALF_UP) .divide(coutMensuelAnnuel, 0, java.math.RoundingMode.HALF_UP)
.intValue(); .intValue();
} }
return 0; return 0;
} }
public boolean hasPeriodeEssai() { public boolean hasPeriodeEssai() {
return periodeEssaiJours != null && periodeEssaiJours > 0; return periodeEssaiJours != null && periodeEssaiJours > 0;
} }
public boolean hasFormation() { public boolean hasFormation() {
return Boolean.TRUE.equals(formationIncluse) && heuresFormation != null && heuresFormation > 0; return Boolean.TRUE.equals(formationIncluse) && heuresFormation != null && heuresFormation > 0;
} }
public boolean isMiseEnAvant() { public boolean isMiseEnAvant() {
return Boolean.TRUE.equals(populaire) || Boolean.TRUE.equals(recommandee); return Boolean.TRUE.equals(populaire) || Boolean.TRUE.equals(recommandee);
} }
public String getBadge() { public String getBadge() {
if (Boolean.TRUE.equals(populaire)) if (Boolean.TRUE.equals(populaire))
return "POPULAIRE"; return "POPULAIRE";
if (Boolean.TRUE.equals(recommandee)) if (Boolean.TRUE.equals(recommandee))
return "RECOMMANDÉE"; return "RECOMMANDÉE";
if (hasPeriodeEssai()) if (hasPeriodeEssai())
return "ESSAI GRATUIT"; return "ESSAI GRATUIT";
return null; return null;
} }
public int getScoreFonctionnalites() { public int getScoreFonctionnalites() {
if (supportTechnique == null && sauvegardeAutomatique == null && fonctionnalitesAvancees == null if (supportTechnique == null && sauvegardeAutomatique == null && fonctionnalitesAvancees == null
&& apiAccess == null && rapportsPersonnalises == null && integrationsTierces == null && apiAccess == null && rapportsPersonnalises == null && integrationsTierces == null
&& multiLangues == null && personnalisationInterface == null) { && multiLangues == null && personnalisationInterface == null) {
return 0; return 0;
} }
int score = 0; int score = 0;
int total = 0; int total = 0;
if (Boolean.TRUE.equals(supportTechnique)) score += 10; if (Boolean.TRUE.equals(supportTechnique)) score += 10;
total += 10; total += 10;
if (Boolean.TRUE.equals(sauvegardeAutomatique)) score += 10; if (Boolean.TRUE.equals(sauvegardeAutomatique)) score += 10;
total += 10; total += 10;
if (Boolean.TRUE.equals(fonctionnalitesAvancees)) score += 15; if (Boolean.TRUE.equals(fonctionnalitesAvancees)) score += 15;
total += 15; total += 15;
if (Boolean.TRUE.equals(apiAccess)) score += 15; if (Boolean.TRUE.equals(apiAccess)) score += 15;
total += 15; total += 15;
if (Boolean.TRUE.equals(rapportsPersonnalises)) score += 15; if (Boolean.TRUE.equals(rapportsPersonnalises)) score += 15;
total += 15; total += 15;
if (Boolean.TRUE.equals(integrationsTierces)) score += 15; if (Boolean.TRUE.equals(integrationsTierces)) score += 15;
total += 15; total += 15;
if (Boolean.TRUE.equals(multiLangues)) score += 10; if (Boolean.TRUE.equals(multiLangues)) score += 10;
total += 10; total += 10;
if (Boolean.TRUE.equals(personnalisationInterface)) score += 10; if (Boolean.TRUE.equals(personnalisationInterface)) score += 10;
total += 10; total += 10;
return (score * 100) / total; return (score * 100) / total;
} }
public String getCssClass() { public String getCssClass() {
if (type == null) if (type == null)
return "formule-default"; return "formule-default";
return switch (type) { return switch (type) {
case BASIC -> "formule-basic"; case BASIC -> "formule-basic";
case STANDARD -> "formule-standard"; case STANDARD -> "formule-standard";
case PREMIUM -> "formule-premium"; case PREMIUM -> "formule-premium";
case ENTERPRISE -> "formule-enterprise"; case ENTERPRISE -> "formule-enterprise";
}; };
} }
} }

View File

@@ -1,29 +1,29 @@
package dev.lions.unionflow.server.api.dto.gouvernance; package dev.lions.unionflow.server.api.dto.gouvernance;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.gouvernance.NiveauEchelon; import dev.lions.unionflow.server.api.enums.gouvernance.NiveauEchelon;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class EchelonOrganigrammeDTO extends BaseDTO { public class EchelonOrganigrammeDTO extends BaseDTO {
// L'Id physique de l'organisation dans le système (une organisation == un // L'Id physique de l'organisation dans le système (une organisation == un
// échelon) // échelon)
private String organisationId; private String organisationId;
// L'organisation mère / chapeau de cet échelon // L'organisation mère / chapeau de cet échelon
private String echelonParentId; private String echelonParentId;
private NiveauEchelon niveau; private NiveauEchelon niveau;
private String designation; private String designation;
private String zoneGeographiqueOuDelegation; private String zoneGeographiqueOuDelegation;
} }

View File

@@ -1,42 +1,42 @@
package dev.lions.unionflow.server.api.dto.lcbft; package dev.lions.unionflow.server.api.dto.lcbft;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
* DTO de réponse pour une alerte LCB-FT. * DTO de réponse pour une alerte LCB-FT.
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2026-03-15 * @since 2026-03-15
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class AlerteLcbFtResponse { public class AlerteLcbFtResponse {
private String id; private String id;
private String organisationId; private String organisationId;
private String organisationNom; private String organisationNom;
private String membreId; private String membreId;
private String membreNomComplet; private String membreNomComplet;
private String typeAlerte; private String typeAlerte;
private LocalDateTime dateAlerte; private LocalDateTime dateAlerte;
private String description; private String description;
private String details; private String details;
private BigDecimal montant; private BigDecimal montant;
private BigDecimal seuil; private BigDecimal seuil;
private String typeOperation; private String typeOperation;
private String transactionRef; private String transactionRef;
private String severite; private String severite;
private Boolean traitee; private Boolean traitee;
private LocalDateTime dateTraitement; private LocalDateTime dateTraitement;
private String traitePar; private String traitePar;
private String commentaireTraitement; private String commentaireTraitement;
} }

View File

@@ -1,226 +1,226 @@
package dev.lions.unionflow.server.api.dto.membre; package dev.lions.unionflow.server.api.dto.membre;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
/** /**
* DTO pour les critères de recherche avancée des membres Permet de filtrer les membres selon de * DTO pour les critères de recherche avancée des membres Permet de filtrer les membres selon de
* multiples critères * multiples critères
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-19 * @since 2025-01-19
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Critères de recherche avancée pour les membres") @Schema(description = "Critères de recherche avancée pour les membres")
public class MembreSearchCriteria { public class MembreSearchCriteria {
/** Terme de recherche général (nom, prénom, email) */ /** Terme de recherche général (nom, prénom, email) */
@Schema(description = "Terme de recherche général dans nom, prénom ou email", example = "marie") @Schema(description = "Terme de recherche général dans nom, prénom ou email", example = "marie")
@Size(max = 100, message = "Le terme de recherche ne peut pas dépasser 100 caractères") @Size(max = 100, message = "Le terme de recherche ne peut pas dépasser 100 caractères")
private String query; private String query;
/** Recherche par nom exact ou partiel */ /** Recherche par nom exact ou partiel */
@Schema(description = "Filtre par nom (recherche partielle)", example = "Dupont") @Schema(description = "Filtre par nom (recherche partielle)", example = "Dupont")
@Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères") @Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères")
private String nom; private String nom;
/** Recherche par prénom exact ou partiel */ /** Recherche par prénom exact ou partiel */
@Schema(description = "Filtre par prénom (recherche partielle)", example = "Marie") @Schema(description = "Filtre par prénom (recherche partielle)", example = "Marie")
@Size(max = 50, message = "Le prénom ne peut pas dépasser 50 caractères") @Size(max = 50, message = "Le prénom ne peut pas dépasser 50 caractères")
private String prenom; private String prenom;
/** Recherche par email exact ou partiel */ /** Recherche par email exact ou partiel */
@Schema(description = "Filtre par email (recherche partielle)", example = "@unionflow.com") @Schema(description = "Filtre par email (recherche partielle)", example = "@unionflow.com")
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères") @Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
private String email; private String email;
/** Filtre par numéro de téléphone */ /** Filtre par numéro de téléphone */
@Schema(description = "Filtre par numéro de téléphone", example = "+221") @Schema(description = "Filtre par numéro de téléphone", example = "+221")
@Size(max = 20, message = "Le téléphone ne peut pas dépasser 20 caractères") @Size(max = 20, message = "Le téléphone ne peut pas dépasser 20 caractères")
private String telephone; private String telephone;
/** Liste des IDs d'organisations */ /** Liste des IDs d'organisations */
@Schema(description = "Liste des IDs d'organisations à inclure") @Schema(description = "Liste des IDs d'organisations à inclure")
private List<UUID> organisationIds; private List<UUID> organisationIds;
/** Liste des rôles à rechercher */ /** Liste des rôles à rechercher */
@Schema(description = "Liste des rôles à rechercher", example = "[\"PRESIDENT\", \"SECRETAIRE\"]") @Schema(description = "Liste des rôles à rechercher", example = "[\"PRESIDENT\", \"SECRETAIRE\"]")
private List<String> roles; private List<String> roles;
/** Filtre par statut d'activité */ /** Filtre par statut d'activité */
@Schema(description = "Filtre par statut d'activité", example = "ACTIF") @Schema(description = "Filtre par statut d'activité", example = "ACTIF")
@Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide") @Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
private String statut; private String statut;
/** Date d'adhésion minimum */ /** Date d'adhésion minimum */
@Schema(description = "Date d'adhésion minimum", example = "2020-01-01") @Schema(description = "Date d'adhésion minimum", example = "2020-01-01")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateAdhesionMin; private LocalDate dateAdhesionMin;
/** Date d'adhésion maximum */ /** Date d'adhésion maximum */
@Schema(description = "Date d'adhésion maximum", example = "2025-12-31") @Schema(description = "Date d'adhésion maximum", example = "2025-12-31")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateAdhesionMax; private LocalDate dateAdhesionMax;
/** Âge minimum */ /** Âge minimum */
@Schema(description = "Âge minimum", example = "18") @Schema(description = "Âge minimum", example = "18")
@Min(value = 0, message = "L'âge minimum doit être positif") @Min(value = 0, message = "L'âge minimum doit être positif")
@Max(value = 120, message = "L'âge minimum ne peut pas dépasser 120 ans") @Max(value = 120, message = "L'âge minimum ne peut pas dépasser 120 ans")
private Integer ageMin; private Integer ageMin;
/** Âge maximum */ /** Âge maximum */
@Schema(description = "Âge maximum", example = "65") @Schema(description = "Âge maximum", example = "65")
@Min(value = 0, message = "L'âge maximum doit être positif") @Min(value = 0, message = "L'âge maximum doit être positif")
@Max(value = 120, message = "L'âge maximum ne peut pas dépasser 120 ans") @Max(value = 120, message = "L'âge maximum ne peut pas dépasser 120 ans")
private Integer ageMax; private Integer ageMax;
/** Filtre par région */ /** Filtre par région */
@Schema(description = "Filtre par région", example = "Dakar") @Schema(description = "Filtre par région", example = "Dakar")
@Size(max = 50, message = "La région ne peut pas dépasser 50 caractères") @Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
private String region; private String region;
/** Filtre par ville */ /** Filtre par ville */
@Schema(description = "Filtre par ville", example = "Dakar") @Schema(description = "Filtre par ville", example = "Dakar")
@Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères") @Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
private String ville; private String ville;
/** Filtre par profession */ /** Filtre par profession */
@Schema(description = "Filtre par profession", example = "Ingénieur") @Schema(description = "Filtre par profession", example = "Ingénieur")
@Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères") @Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
private String profession; private String profession;
/** Filtre par nationalité */ /** Filtre par nationalité */
@Schema(description = "Filtre par nationalité", example = "Sénégalaise") @Schema(description = "Filtre par nationalité", example = "Sénégalaise")
@Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères") @Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
private String nationalite; private String nationalite;
/** Filtre membres du bureau uniquement */ /** Filtre membres du bureau uniquement */
@Schema(description = "Filtre pour les membres du bureau uniquement") @Schema(description = "Filtre pour les membres du bureau uniquement")
private Boolean membreBureau; private Boolean membreBureau;
/** Filtre responsables uniquement */ /** Filtre responsables uniquement */
@Schema(description = "Filtre pour les responsables uniquement") @Schema(description = "Filtre pour les responsables uniquement")
private Boolean responsable; private Boolean responsable;
/** Inclure les membres inactifs dans la recherche */ /** Inclure les membres inactifs dans la recherche */
@Schema(description = "Inclure les membres inactifs", defaultValue = "false") @Schema(description = "Inclure les membres inactifs", defaultValue = "false")
@Builder.Default @Builder.Default
private Boolean includeInactifs = false; private Boolean includeInactifs = false;
/** /**
* Vérifie si au moins un critère de recherche est défini * Vérifie si au moins un critère de recherche est défini
* *
* @return true si au moins un critère est défini * @return true si au moins un critère est défini
*/ */
public boolean hasAnyCriteria() { public boolean hasAnyCriteria() {
return query != null && !query.trim().isEmpty() return query != null && !query.trim().isEmpty()
|| nom != null && !nom.trim().isEmpty() || nom != null && !nom.trim().isEmpty()
|| prenom != null && !prenom.trim().isEmpty() || prenom != null && !prenom.trim().isEmpty()
|| email != null && !email.trim().isEmpty() || email != null && !email.trim().isEmpty()
|| telephone != null && !telephone.trim().isEmpty() || telephone != null && !telephone.trim().isEmpty()
|| organisationIds != null && !organisationIds.isEmpty() || organisationIds != null && !organisationIds.isEmpty()
|| roles != null && !roles.isEmpty() || roles != null && !roles.isEmpty()
|| statut != null && !statut.trim().isEmpty() || statut != null && !statut.trim().isEmpty()
|| dateAdhesionMin != null || dateAdhesionMin != null
|| dateAdhesionMax != null || dateAdhesionMax != null
|| ageMin != null || ageMin != null
|| ageMax != null || ageMax != null
|| region != null && !region.trim().isEmpty() || region != null && !region.trim().isEmpty()
|| ville != null && !ville.trim().isEmpty() || ville != null && !ville.trim().isEmpty()
|| profession != null && !profession.trim().isEmpty() || profession != null && !profession.trim().isEmpty()
|| nationalite != null && !nationalite.trim().isEmpty() || nationalite != null && !nationalite.trim().isEmpty()
|| membreBureau != null || membreBureau != null
|| responsable != null; || responsable != null;
} }
/** /**
* Valide la cohérence des critères de recherche * Valide la cohérence des critères de recherche
* *
* @return true si les critères sont cohérents * @return true si les critères sont cohérents
*/ */
public boolean isValid() { public boolean isValid() {
// Validation des dates // Validation des dates
if (dateAdhesionMin != null && dateAdhesionMax != null) { if (dateAdhesionMin != null && dateAdhesionMax != null) {
if (dateAdhesionMin.isAfter(dateAdhesionMax)) { if (dateAdhesionMin.isAfter(dateAdhesionMax)) {
return false; return false;
} }
} }
// Validation des âges // Validation des âges
if (ageMin != null && ageMax != null) { if (ageMin != null && ageMax != null) {
if (ageMin > ageMax) { if (ageMin > ageMax) {
return false; return false;
} }
} }
return true; return true;
} }
/** Nettoie les chaînes de caractères (trim et null si vide) */ /** Nettoie les chaînes de caractères (trim et null si vide) */
public void sanitize() { public void sanitize() {
query = sanitizeString(query); query = sanitizeString(query);
nom = sanitizeString(nom); nom = sanitizeString(nom);
prenom = sanitizeString(prenom); prenom = sanitizeString(prenom);
email = sanitizeString(email); email = sanitizeString(email);
telephone = sanitizeString(telephone); telephone = sanitizeString(telephone);
statut = sanitizeString(statut); statut = sanitizeString(statut);
region = sanitizeString(region); region = sanitizeString(region);
ville = sanitizeString(ville); ville = sanitizeString(ville);
profession = sanitizeString(profession); profession = sanitizeString(profession);
nationalite = sanitizeString(nationalite); nationalite = sanitizeString(nationalite);
} }
private String sanitizeString(String str) { private String sanitizeString(String str) {
if (str == null) return null; if (str == null) return null;
str = str.trim(); str = str.trim();
return str.isEmpty() ? null : str; return str.isEmpty() ? null : str;
} }
/** /**
* Retourne une description textuelle des critères actifs * Retourne une description textuelle des critères actifs
* *
* @return Description des critères * @return Description des critères
*/ */
public String getDescription() { public String getDescription() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (query != null) sb.append("Recherche: '").append(query).append("' "); if (query != null) sb.append("Recherche: '").append(query).append("' ");
if (nom != null) sb.append("Nom: '").append(nom).append("' "); if (nom != null) sb.append("Nom: '").append(nom).append("' ");
if (prenom != null) sb.append("Prénom: '").append(prenom).append("' "); if (prenom != null) sb.append("Prénom: '").append(prenom).append("' ");
if (email != null) sb.append("Email: '").append(email).append("' "); if (email != null) sb.append("Email: '").append(email).append("' ");
if (statut != null) sb.append("Statut: ").append(statut).append(" "); if (statut != null) sb.append("Statut: ").append(statut).append(" ");
if (organisationIds != null && !organisationIds.isEmpty()) { if (organisationIds != null && !organisationIds.isEmpty()) {
sb.append("Organisations: ").append(organisationIds.size()).append(" "); sb.append("Organisations: ").append(organisationIds.size()).append(" ");
} }
if (roles != null && !roles.isEmpty()) { if (roles != null && !roles.isEmpty()) {
sb.append("Rôles: ").append(String.join(", ", roles)).append(" "); sb.append("Rôles: ").append(String.join(", ", roles)).append(" ");
} }
if (dateAdhesionMin != null) sb.append("Adhésion >= ").append(dateAdhesionMin).append(" "); if (dateAdhesionMin != null) sb.append("Adhésion >= ").append(dateAdhesionMin).append(" ");
if (dateAdhesionMax != null) sb.append("Adhésion <= ").append(dateAdhesionMax).append(" "); if (dateAdhesionMax != null) sb.append("Adhésion <= ").append(dateAdhesionMax).append(" ");
if (ageMin != null) sb.append("Âge >= ").append(ageMin).append(" "); if (ageMin != null) sb.append("Âge >= ").append(ageMin).append(" ");
if (ageMax != null) sb.append("Âge <= ").append(ageMax).append(" "); if (ageMax != null) sb.append("Âge <= ").append(ageMax).append(" ");
if (region != null) sb.append("Région: '").append(region).append("' "); if (region != null) sb.append("Région: '").append(region).append("' ");
if (ville != null) sb.append("Ville: '").append(ville).append("' "); if (ville != null) sb.append("Ville: '").append(ville).append("' ");
if (profession != null) sb.append("Profession: '").append(profession).append("' "); if (profession != null) sb.append("Profession: '").append(profession).append("' ");
if (nationalite != null) sb.append("Nationalité: '").append(nationalite).append("' "); if (nationalite != null) sb.append("Nationalité: '").append(nationalite).append("' ");
if (Boolean.TRUE.equals(membreBureau)) sb.append("Membre bureau "); if (Boolean.TRUE.equals(membreBureau)) sb.append("Membre bureau ");
if (Boolean.TRUE.equals(responsable)) sb.append("Responsable "); if (Boolean.TRUE.equals(responsable)) sb.append("Responsable ");
return sb.toString().trim(); return sb.toString().trim();
} }
} }

View File

@@ -1,227 +1,227 @@
package dev.lions.unionflow.server.api.dto.membre; package dev.lions.unionflow.server.api.dto.membre;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse; import dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse;
import java.util.List; import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
/** /**
* DTO pour les résultats de recherche avancée des membres Contient les * DTO pour les résultats de recherche avancée des membres Contient les
* résultats paginés et les * résultats paginés et les
* métadonnées de recherche * métadonnées de recherche
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 1.0 * @version 1.0
* @since 2025-01-19 * @since 2025-01-19
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Résultats de recherche avancée des membres avec pagination") @Schema(description = "Résultats de recherche avancée des membres avec pagination")
public class MembreSearchResultDTO { public class MembreSearchResultDTO {
/** Liste des membres trouvés */ /** Liste des membres trouvés */
@Schema(description = "Liste des membres correspondant aux critères") @Schema(description = "Liste des membres correspondant aux critères")
private List<MembreSummaryResponse> membres; private List<MembreSummaryResponse> membres;
/** Nombre total de résultats (toutes pages confondues) */ /** Nombre total de résultats (toutes pages confondues) */
@Schema(description = "Nombre total de résultats trouvés", example = "247") @Schema(description = "Nombre total de résultats trouvés", example = "247")
private long totalElements; private long totalElements;
/** Nombre total de pages */ /** Nombre total de pages */
@Schema(description = "Nombre total de pages", example = "13") @Schema(description = "Nombre total de pages", example = "13")
private int totalPages; private int totalPages;
/** Numéro de la page actuelle (0-based) */ /** Numéro de la page actuelle (0-based) */
@Schema(description = "Numéro de la page actuelle", example = "0") @Schema(description = "Numéro de la page actuelle", example = "0")
private int currentPage; private int currentPage;
/** Taille de la page */ /** Taille de la page */
@Schema(description = "Nombre d'éléments par page", example = "20") @Schema(description = "Nombre d'éléments par page", example = "20")
private int pageSize; private int pageSize;
/** Nombre d'éléments sur la page actuelle */ /** Nombre d'éléments sur la page actuelle */
@Schema(description = "Nombre d'éléments sur cette page", example = "20") @Schema(description = "Nombre d'éléments sur cette page", example = "20")
private int numberOfElements; private int numberOfElements;
/** Indique s'il y a une page suivante */ /** Indique s'il y a une page suivante */
@Schema(description = "Indique s'il y a une page suivante") @Schema(description = "Indique s'il y a une page suivante")
private boolean hasNext; private boolean hasNext;
/** Indique s'il y a une page précédente */ /** Indique s'il y a une page précédente */
@Schema(description = "Indique s'il y a une page précédente") @Schema(description = "Indique s'il y a une page précédente")
private boolean hasPrevious; private boolean hasPrevious;
/** Indique si c'est la première page */ /** Indique si c'est la première page */
@Schema(description = "Indique si c'est la première page") @Schema(description = "Indique si c'est la première page")
@JsonProperty("isFirst") @JsonProperty("isFirst")
private boolean isFirst; private boolean isFirst;
/** Indique si c'est la dernière page */ /** Indique si c'est la dernière page */
@Schema(description = "Indique si c'est la dernière page") @Schema(description = "Indique si c'est la dernière page")
@JsonProperty("isLast") @JsonProperty("isLast")
private boolean isLast; private boolean isLast;
/** Critères de recherche utilisés */ /** Critères de recherche utilisés */
@Schema(description = "Critères de recherche qui ont été appliqués") @Schema(description = "Critères de recherche qui ont été appliqués")
private MembreSearchCriteria criteria; private MembreSearchCriteria criteria;
/** Temps d'exécution de la recherche en millisecondes */ /** Temps d'exécution de la recherche en millisecondes */
@Schema(description = "Temps d'exécution de la recherche en ms", example = "45") @Schema(description = "Temps d'exécution de la recherche en ms", example = "45")
private long executionTimeMs; private long executionTimeMs;
/** Statistiques de recherche */ /** Statistiques de recherche */
@Schema(description = "Statistiques sur les résultats de recherche") @Schema(description = "Statistiques sur les résultats de recherche")
private SearchStatistics statistics; private SearchStatistics statistics;
/** Statistiques sur les résultats de recherche */ /** Statistiques sur les résultats de recherche */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Statistiques sur les résultats de recherche") @Schema(description = "Statistiques sur les résultats de recherche")
public static class SearchStatistics { public static class SearchStatistics {
/** Répartition par statut */ /** Répartition par statut */
@Schema(description = "Nombre de membres actifs dans les résultats") @Schema(description = "Nombre de membres actifs dans les résultats")
private long membresActifs; private long membresActifs;
@Schema(description = "Nombre de membres inactifs dans les résultats") @Schema(description = "Nombre de membres inactifs dans les résultats")
private long membresInactifs; private long membresInactifs;
/** Répartition par âge */ /** Répartition par âge */
@Schema(description = "Âge moyen des membres trouvés") @Schema(description = "Âge moyen des membres trouvés")
private double ageMoyen; private double ageMoyen;
@Schema(description = "Âge minimum des membres trouvés") @Schema(description = "Âge minimum des membres trouvés")
private int ageMin; private int ageMin;
@Schema(description = "Âge maximum des membres trouvés") @Schema(description = "Âge maximum des membres trouvés")
private int ageMax; private int ageMax;
/** Répartition par organisation */ /** Répartition par organisation */
@Schema(description = "Nombre d'organisations représentées") @Schema(description = "Nombre d'organisations représentées")
private long nombreOrganisations; private long nombreOrganisations;
/** Répartition par région */ /** Répartition par région */
@Schema(description = "Nombre de régions représentées") @Schema(description = "Nombre de régions représentées")
private long nombreRegions; private long nombreRegions;
/** Ancienneté moyenne */ /** Ancienneté moyenne */
@Schema(description = "Ancienneté moyenne en années") @Schema(description = "Ancienneté moyenne en années")
private double ancienneteMoyenne; private double ancienneteMoyenne;
} }
/** Calcule et met à jour les indicateurs de pagination */ /** Calcule et met à jour les indicateurs de pagination */
public void calculatePaginationFlags() { public void calculatePaginationFlags() {
this.isFirst = currentPage == 0; this.isFirst = currentPage == 0;
this.isLast = currentPage >= totalPages - 1; this.isLast = currentPage >= totalPages - 1;
this.hasPrevious = currentPage > 0; this.hasPrevious = currentPage > 0;
this.hasNext = currentPage < totalPages - 1; this.hasNext = currentPage < totalPages - 1;
this.numberOfElements = membres != null ? membres.size() : 0; this.numberOfElements = membres != null ? membres.size() : 0;
} }
/** /**
* Vérifie si les résultats sont vides * Vérifie si les résultats sont vides
* *
* @return true si aucun résultat * @return true si aucun résultat
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return membres == null || membres.isEmpty(); return membres == null || membres.isEmpty();
} }
/** /**
* Retourne le numéro de la page suivante (1-based pour affichage) * Retourne le numéro de la page suivante (1-based pour affichage)
* *
* @return Numéro de page suivante ou -1 si pas de page suivante * @return Numéro de page suivante ou -1 si pas de page suivante
*/ */
public int getNextPageNumber() { public int getNextPageNumber() {
return hasNext ? currentPage + 2 : -1; return hasNext ? currentPage + 2 : -1;
} }
/** /**
* Retourne le numéro de la page précédente (1-based pour affichage) * Retourne le numéro de la page précédente (1-based pour affichage)
* *
* @return Numéro de page précédente ou -1 si pas de page précédente * @return Numéro de page précédente ou -1 si pas de page précédente
*/ */
public int getPreviousPageNumber() { public int getPreviousPageNumber() {
return hasPrevious ? currentPage : -1; return hasPrevious ? currentPage : -1;
} }
/** /**
* Retourne une description textuelle des résultats * Retourne une description textuelle des résultats
* *
* @return Description des résultats * @return Description des résultats
*/ */
public String getResultDescription() { public String getResultDescription() {
if (isEmpty()) { if (isEmpty()) {
return "Aucun membre trouvé"; return "Aucun membre trouvé";
} }
if (totalElements == 1) { if (totalElements == 1) {
return "1 membre trouvé"; return "1 membre trouvé";
} }
if (totalPages == 1) { if (totalPages == 1) {
return String.format("%d membres trouvés", totalElements); return String.format("%d membres trouvés", totalElements);
} }
int startElement = currentPage * pageSize + 1; int startElement = currentPage * pageSize + 1;
int endElement = Math.min(startElement + numberOfElements - 1, (int) totalElements); int endElement = Math.min(startElement + numberOfElements - 1, (int) totalElements);
return String.format( return String.format(
"Membres %d-%d sur %d (page %d/%d)", "Membres %d-%d sur %d (page %d/%d)",
startElement, endElement, totalElements, currentPage + 1, totalPages); startElement, endElement, totalElements, currentPage + 1, totalPages);
} }
/** /**
* Factory method pour créer un résultat vide * Factory method pour créer un résultat vide
* *
* @param criteria Critères de recherche * @param criteria Critères de recherche
* @return Résultat vide * @return Résultat vide
*/ */
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria) { public static MembreSearchResultDTO empty(MembreSearchCriteria criteria) {
return empty(criteria, 20, 0); return empty(criteria, 20, 0);
} }
/** /**
* Factory method pour créer un résultat vide avec pageSize spécifique * Factory method pour créer un résultat vide avec pageSize spécifique
* *
* @param criteria Critères de recherche * @param criteria Critères de recherche
* @param pageSize Taille de la page * @param pageSize Taille de la page
* @param currentPage Page actuelle * @param currentPage Page actuelle
* @return Résultat vide * @return Résultat vide
*/ */
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria, int pageSize, int currentPage) { public static MembreSearchResultDTO empty(MembreSearchCriteria criteria, int pageSize, int currentPage) {
MembreSearchResultDTO result = new MembreSearchResultDTO(); MembreSearchResultDTO result = new MembreSearchResultDTO();
result.setMembres(List.of()); result.setMembres(List.of());
result.setTotalElements(0L); result.setTotalElements(0L);
result.setTotalPages(0); result.setTotalPages(0);
result.setCurrentPage(currentPage); result.setCurrentPage(currentPage);
result.setPageSize(pageSize); result.setPageSize(pageSize);
result.setNumberOfElements(0); result.setNumberOfElements(0);
result.setHasNext(false); result.setHasNext(false);
result.setHasPrevious(false); result.setHasPrevious(false);
result.isFirst = true; // Assignation directe pour éviter les problèmes avec les setters Lombok result.isFirst = true; // Assignation directe pour éviter les problèmes avec les setters Lombok
result.isLast = true; // Assignation directe pour éviter les problèmes avec les setters Lombok result.isLast = true; // Assignation directe pour éviter les problèmes avec les setters Lombok
result.setCriteria(criteria); result.setCriteria(criteria);
result.setExecutionTimeMs(0L); result.setExecutionTimeMs(0L);
// Initialiser statistics avec des valeurs vides // Initialiser statistics avec des valeurs vides
result.setStatistics(SearchStatistics.builder() result.setStatistics(SearchStatistics.builder()
.membresActifs(0) .membresActifs(0)
.membresInactifs(0) .membresInactifs(0)
.ageMoyen(0.0) .ageMoyen(0.0)
.ageMin(0) .ageMin(0)
.ageMax(0) .ageMax(0)
.nombreOrganisations(0) .nombreOrganisations(0)
.nombreRegions(0) .nombreRegions(0)
.ancienneteMoyenne(0.0) .ancienneteMoyenne(0.0)
.build()); .build());
return result; return result;
} }
} }

View File

@@ -1,52 +1,52 @@
package dev.lions.unionflow.server.api.dto.membre.request; package dev.lions.unionflow.server.api.dto.membre.request;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête de création d'un membre. * Requête de création d'un membre.
* *
* <p> * <p>
* Immutable via {@code record}. Exclut l'ID, * Immutable via {@code record}. Exclut l'ID,
* les champs d'audit, et le numéroMembre * les champs d'audit, et le numéroMembre
* (généré côté serveur). * (généré côté serveur).
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
* @since 2026-02-21 * @since 2026-02-21
* @param prenom prénom * @param prenom prénom
* @param nom nom de famille * @param nom nom de famille
* @param email email * @param email email
* @param telephone téléphone * @param telephone téléphone
* @param telephoneWave numéro Wave * @param telephoneWave numéro Wave
* @param dateNaissance date de naissance * @param dateNaissance date de naissance
* @param profession profession * @param profession profession
* @param photoUrl URL de la photo * @param photoUrl URL de la photo
* @param statutMatrimonial statut matrimonial * @param statutMatrimonial statut matrimonial
* @param nationalite nationalité * @param nationalite nationalité
* @param typeIdentite type pièce d'identité * @param typeIdentite type pièce d'identité
* @param numeroIdentite numéro d'identité * @param numeroIdentite numéro d'identité
* @param organisationId ID de l'organisation (obligatoire pour ADMIN_ORGANISATION) * @param organisationId ID de l'organisation (obligatoire pour ADMIN_ORGANISATION)
*/ */
@Builder @Builder
public record CreateMembreRequest( public record CreateMembreRequest(
@NotBlank @Size(max = 100) String prenom, @NotBlank @Size(max = 100) String prenom,
@NotBlank @Size(max = 100) String nom, @NotBlank @Size(max = 100) String nom,
@NotBlank @Email @Size(max = 255) String email, @NotBlank @Email @Size(max = 255) String email,
@Size(max = 20) String telephone, @Size(max = 20) String telephone,
@Size(max = 20) String telephoneWave, @Size(max = 20) String telephoneWave,
@NotNull LocalDate dateNaissance, @NotNull LocalDate dateNaissance,
@Size(max = 100) String profession, @Size(max = 100) String profession,
@Size(max = 500) String photoUrl, @Size(max = 500) String photoUrl,
@Size(max = 50) String statutMatrimonial, @Size(max = 50) String statutMatrimonial,
@Size(max = 100) String nationalite, @Size(max = 100) String nationalite,
@Size(max = 50) String typeIdentite, @Size(max = 50) String typeIdentite,
@Size(max = 100) String numeroIdentite, @Size(max = 100) String numeroIdentite,
UUID organisationId) { UUID organisationId) {
} }

View File

@@ -1,26 +1,26 @@
package dev.lions.unionflow.server.api.dto.membre.request; package dev.lions.unionflow.server.api.dto.membre.request;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder; import lombok.Builder;
/** /**
* Requête pour mettre à jour un membre existant. * Requête pour mettre à jour un membre existant.
*/ */
@Builder @Builder
public record UpdateMembreRequest( public record UpdateMembreRequest(
@NotBlank @Size(max = 100) String prenom, @NotBlank @Size(max = 100) String prenom,
@NotBlank @Size(max = 100) String nom, @NotBlank @Size(max = 100) String nom,
@NotBlank @Email @Size(max = 255) String email, @NotBlank @Email @Size(max = 255) String email,
@Size(max = 20) String telephone, @Size(max = 20) String telephone,
@Size(max = 20) String telephoneWave, @Size(max = 20) String telephoneWave,
@NotNull LocalDate dateNaissance, @NotNull LocalDate dateNaissance,
@Size(max = 100) String profession, @Size(max = 100) String profession,
@Size(max = 500) String photoUrl, @Size(max = 500) String photoUrl,
@Size(max = 50) String statutMatrimonial, @Size(max = 50) String statutMatrimonial,
@Size(max = 100) String nationalite, @Size(max = 100) String nationalite,
@Size(max = 50) String typeIdentite, @Size(max = 50) String typeIdentite,
@Size(max = 100) String numeroIdentite, @Size(max = 100) String numeroIdentite,
Boolean actif) { Boolean actif) {
} }

View File

@@ -1,136 +1,136 @@
package dev.lions.unionflow.server.api.dto.membre.response; package dev.lions.unionflow.server.api.dto.membre.response;
import dev.lions.unionflow.server.api.dto.base.BaseResponse; import dev.lions.unionflow.server.api.dto.base.BaseResponse;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.UUID; import java.util.UUID;
import java.util.List; import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
/** /**
* Réponse contenant les données d'un membre. * Réponse contenant les données d'un membre.
* *
* <p> * <p>
* Classe Lombok (getters/setters) pour la * Classe Lombok (getters/setters) pour la
* compatibilité avec les frameworks d'affichage * compatibilité avec les frameworks d'affichage
* (PrimeFaces, etc.). * (PrimeFaces, etc.).
* *
* @author UnionFlow Team * @author UnionFlow Team
* @version 3.0 * @version 3.0
* @since 2026-02-21 * @since 2026-02-21
*/ */
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class MembreResponse extends BaseResponse { public class MembreResponse extends BaseResponse {
// ── Identité ─────────────────────────────── // ── Identité ───────────────────────────────
private String numeroMembre; private String numeroMembre;
private UUID keycloakId; private UUID keycloakId;
private String prenom; private String prenom;
private String nom; private String nom;
private String nomComplet; private String nomComplet;
private String email; private String email;
private String telephone; private String telephone;
private String telephoneWave; private String telephoneWave;
private LocalDate dateNaissance; private LocalDate dateNaissance;
private int age; private int age;
// ── Personnel ────────────────────────────── // ── Personnel ──────────────────────────────
private String profession; private String profession;
private String photoUrl; private String photoUrl;
private String statutMatrimonial; private String statutMatrimonial;
private String statutMatrimonialLibelle; private String statutMatrimonialLibelle;
private String nationalite; private String nationalite;
private String typeIdentite; private String typeIdentite;
private String typeIdentiteLibelle; private String typeIdentiteLibelle;
private String numeroIdentite; private String numeroIdentite;
// ── KYC / LCB-FT ─────────────────────────── // ── KYC / LCB-FT ───────────────────────────
private String niveauVigilanceKyc; private String niveauVigilanceKyc;
private String statutKyc; private String statutKyc;
private LocalDate dateVerificationIdentite; private LocalDate dateVerificationIdentite;
// ── Statut ───────────────────────────────── // ── Statut ─────────────────────────────────
private String statutCompte; private String statutCompte;
private String statutCompteLibelle; private String statutCompteLibelle;
private String statutCompteSeverity; private String statutCompteSeverity;
private List<String> roles; private List<String> roles;
// ── Adhésion (contexte organisation) ─────── // ── Adhésion (contexte organisation) ───────
private UUID organisationId; private UUID organisationId;
private String organisationNom; private String organisationNom;
private LocalDate dateAdhesion; private LocalDate dateAdhesion;
// ── Adresse principale ───────────────────── // ── Adresse principale ─────────────────────
private String adresse; private String adresse;
private String ville; private String ville;
private String codePostal; private String codePostal;
// ── Notes / biographie ───────────────────── // ── Notes / biographie ─────────────────────
private String notes; private String notes;
// ── Statistiques ─────────────────────────── // ── Statistiques ───────────────────────────
private int nombreEvenementsParticipes; private int nombreEvenementsParticipes;
// ── Provisionnement (retourné une seule fois à la création) ──── // ── Provisionnement (retourné une seule fois à la création) ────
/** Mot de passe temporaire généré lors du provisionnement Keycloak. /** Mot de passe temporaire généré lors du provisionnement Keycloak.
* Null pour toutes les autres opérations. L'utilisateur devra le changer à la première connexion. */ * Null pour toutes les autres opérations. L'utilisateur devra le changer à la première connexion. */
private String motDePasseTemporaire; private String motDePasseTemporaire;
// ── Méthodes calculées pour la compatibilité JSF EL ──────────── // ── Méthodes calculées pour la compatibilité JSF EL ────────────
/** Initiales (première lettre prénom + première lettre nom) pour les avatars JSF. */ /** Initiales (première lettre prénom + première lettre nom) pour les avatars JSF. */
public String getInitiales() { public String getInitiales() {
String p = (prenom != null && !prenom.isEmpty()) ? prenom.substring(0, 1).toUpperCase() : ""; String p = (prenom != null && !prenom.isEmpty()) ? prenom.substring(0, 1).toUpperCase() : "";
String n = (nom != null && !nom.isEmpty()) ? nom.substring(0, 1).toUpperCase() : ""; String n = (nom != null && !nom.isEmpty()) ? nom.substring(0, 1).toUpperCase() : "";
return p + n; return p + n;
} }
/** Date d'adhésion formatée "dd/MM/yyyy" pour #{membre.dateAdhesionFormatee}. */ /** Date d'adhésion formatée "dd/MM/yyyy" pour #{membre.dateAdhesionFormatee}. */
public String getDateAdhesionFormatee() { public String getDateAdhesionFormatee() {
if (dateAdhesion == null) return null; if (dateAdhesion == null) return null;
return dateAdhesion.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")); return dateAdhesion.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
} }
/** Alias de statutCompte pour #{membre.statut}. */ /** Alias de statutCompte pour #{membre.statut}. */
public String getStatut() { public String getStatut() {
return statutCompte; return statutCompte;
} }
/** Alias de statutCompteSeverity pour #{membre.statutSeverity}. */ /** Alias de statutCompteSeverity pour #{membre.statutSeverity}. */
public String getStatutSeverity() { public String getStatutSeverity() {
return statutCompteSeverity; return statutCompteSeverity;
} }
/** Libellé du rôle principal calculé depuis les rôles. */ /** Libellé du rôle principal calculé depuis les rôles. */
public String getTypeMembre() { public String getTypeMembre() {
if (roles == null || roles.isEmpty()) return "Membre"; if (roles == null || roles.isEmpty()) return "Membre";
if (roles.contains("PRESIDENT")) return "Président"; if (roles.contains("PRESIDENT")) return "Président";
if (roles.contains("VICE_PRESIDENT")) return "Vice-Président"; if (roles.contains("VICE_PRESIDENT")) return "Vice-Président";
if (roles.contains("SECRETAIRE")) return "Secrétaire"; if (roles.contains("SECRETAIRE")) return "Secrétaire";
if (roles.contains("TRESORIER")) return "Trésorier"; if (roles.contains("TRESORIER")) return "Trésorier";
if (roles.contains("ADMIN_ORGANISATION")) return "Administrateur"; if (roles.contains("ADMIN_ORGANISATION")) return "Administrateur";
if (roles.contains("MODERATEUR")) return "Modérateur"; if (roles.contains("MODERATEUR")) return "Modérateur";
return "Membre"; return "Membre";
} }
/** Severity PrimeUI calculée depuis les rôles. */ /** Severity PrimeUI calculée depuis les rôles. */
public String getTypeSeverity() { public String getTypeSeverity() {
if (roles == null || roles.isEmpty()) return "secondary"; if (roles == null || roles.isEmpty()) return "secondary";
if (roles.contains("PRESIDENT")) return "primary"; if (roles.contains("PRESIDENT")) return "primary";
if (roles.contains("VICE_PRESIDENT")) return "primary"; if (roles.contains("VICE_PRESIDENT")) return "primary";
if (roles.contains("SECRETAIRE")) return "info"; if (roles.contains("SECRETAIRE")) return "info";
if (roles.contains("TRESORIER")) return "warning"; if (roles.contains("TRESORIER")) return "warning";
if (roles.contains("ADMIN_ORGANISATION")) return "danger"; if (roles.contains("ADMIN_ORGANISATION")) return "danger";
if (roles.contains("MODERATEUR")) return "warning"; if (roles.contains("MODERATEUR")) return "warning";
return "secondary"; return "secondary";
} }
} }

View File

@@ -1,49 +1,49 @@
package dev.lions.unionflow.server.api.dto.mutuelle.credit; package dev.lions.unionflow.server.api.dto.mutuelle.credit;
import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit; import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit;
import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeGarantie; import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeGarantie;
import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Requête initiale pour une demande de financement (Crédit)") @Schema(description = "Requête initiale pour une demande de financement (Crédit)")
public class DemandeCreditRequest { public class DemandeCreditRequest {
@NotBlank(message = "L'ID du demandeur est obligatoire") @NotBlank(message = "L'ID du demandeur est obligatoire")
private String membreId; private String membreId;
@NotNull(message = "Le type de crédit est obligatoire") @NotNull(message = "Le type de crédit est obligatoire")
private TypeCredit typeCredit; private TypeCredit typeCredit;
@NotNull(message = "Le montant demandé est obligatoire") @NotNull(message = "Le montant demandé est obligatoire")
@DecimalMin(value = "1.0", message = "Le montant demandé doit être positif") @DecimalMin(value = "1.0", message = "Le montant demandé doit être positif")
private BigDecimal montantDemande; private BigDecimal montantDemande;
@Min(value = 1, message = "La durée (en mois) doit être au moins de 1 mois") @Min(value = 1, message = "La durée (en mois) doit être au moins de 1 mois")
private Integer dureeMois; private Integer dureeMois;
@Schema(description = "Compte épargne adossé (si remboursement automatique ou nantissement)") @Schema(description = "Compte épargne adossé (si remboursement automatique ou nantissement)")
private String compteLieId; private String compteLieId;
@NotBlank(message = "Le motif détaillé du financement est requis (Plan d'affaires, usage...)") @NotBlank(message = "Le motif détaillé du financement est requis (Plan d'affaires, usage...)")
private String justificationDetaillee; private String justificationDetaillee;
@Schema(description = "Liste des IDs de documents justificatifs attachés au dossier") @Schema(description = "Liste des IDs de documents justificatifs attachés au dossier")
private List<String> documentIds; private List<String> documentIds;
@Schema(description = "Liste des garanties proposées avec la demande") @Schema(description = "Liste des garanties proposées avec la demande")
private List<GarantieDemandeDTO> garantiesProposees; private List<GarantieDemandeDTO> garantiesProposees;
} }

View File

@@ -1,48 +1,48 @@
package dev.lions.unionflow.server.api.dto.mutuelle.credit; package dev.lions.unionflow.server.api.dto.mutuelle.credit;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutDemandeCredit; import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutDemandeCredit;
import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit; import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Réponse avec le tableau de bord résumé d'un dossier de crédit") @Schema(description = "Réponse avec le tableau de bord résumé d'un dossier de crédit")
public class DemandeCreditResponse extends BaseDTO { public class DemandeCreditResponse extends BaseDTO {
private String numeroDossier; private String numeroDossier;
private String membreId; private String membreId;
private TypeCredit typeCredit; private TypeCredit typeCredit;
private String compteLieId; private String compteLieId;
private BigDecimal montantDemande; private BigDecimal montantDemande;
private Integer dureeMoisDemande; private Integer dureeMoisDemande;
// Conditions actées par le comité de crédit (peuvent différer de la demande) // Conditions actées par le comité de crédit (peuvent différer de la demande)
private BigDecimal montantApprouve; private BigDecimal montantApprouve;
private Integer dureeMoisApprouvee; private Integer dureeMoisApprouvee;
private BigDecimal tauxInteretAnnuel; // Pourcentage private BigDecimal tauxInteretAnnuel; // Pourcentage
private BigDecimal coutTotalCredit; // Total Intérêts private BigDecimal coutTotalCredit; // Total Intérêts
private StatutDemandeCredit statut; private StatutDemandeCredit statut;
private String notesComite; private String notesComite;
private LocalDate dateSoumission; private LocalDate dateSoumission;
private LocalDate dateValidation; private LocalDate dateValidation;
private LocalDate datePremierEcheance; private LocalDate datePremierEcheance;
@Schema(description = "Aperçu des échéances générées pour le tableau d'amortissement") @Schema(description = "Aperçu des échéances générées pour le tableau d'amortissement")
private List<EcheanceCreditDTO> echeancier; private List<EcheanceCreditDTO> echeancier;
} }

View File

@@ -1,44 +1,44 @@
package dev.lions.unionflow.server.api.dto.mutuelle.credit; package dev.lions.unionflow.server.api.dto.mutuelle.credit;
import dev.lions.unionflow.server.api.dto.base.BaseDTO; import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutEcheanceCredit; import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutEcheanceCredit;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
@Schema(description = "Représente une ligne unique du tableau d'amortissement d'un crédit") @Schema(description = "Représente une ligne unique du tableau d'amortissement d'un crédit")
public class EcheanceCreditDTO extends BaseDTO { public class EcheanceCreditDTO extends BaseDTO {
private String demandeCreditId; private String demandeCreditId;
@Schema(description = "Indice de l'échéance (ex: mois 1, 2, 3...)") @Schema(description = "Indice de l'échéance (ex: mois 1, 2, 3...)")
private Integer ordre; private Integer ordre;
private LocalDate dateEcheancePrevue; private LocalDate dateEcheancePrevue;
private LocalDate datePaiementEffectif; private LocalDate datePaiementEffectif;
private BigDecimal capitalAmorti; private BigDecimal capitalAmorti;
private BigDecimal interetsDeLaPeriode; private BigDecimal interetsDeLaPeriode;
private BigDecimal montantTotalExigible; private BigDecimal montantTotalExigible;
private BigDecimal capitalRestantDu; private BigDecimal capitalRestantDu;
// Pénalités éventuelles additionnelles liées au retard // Pénalités éventuelles additionnelles liées au retard
private BigDecimal penalitesRetard; private BigDecimal penalitesRetard;
// Somme physiquement encaissée pour cette traite à l'instant T // Somme physiquement encaissée pour cette traite à l'instant T
private BigDecimal montantRegle; private BigDecimal montantRegle;
private StatutEcheanceCredit statut; private StatutEcheanceCredit statut;
} }

Some files were not shown because too many files have changed in this diff Show More