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

|
||||

|
||||

|
||||
|
||||
Module API partagé UnionFlow - DTOs, Request/Response, Validation, Enums.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Vue d'ensemble
|
||||
|
||||
Ce module contient les **contrats d'API** partagés entre :
|
||||
- **Backend Quarkus** (unionflow-server-impl-quarkus)
|
||||
- **Frontend Web** (unionflow-client-quarkus-primefaces-freya)
|
||||
- **Mobile Flutter** (unionflow-mobile-apps) - via génération TypeScript/JSON
|
||||
|
||||
### Avantages
|
||||
|
||||
✅ **Type-safety** : Contrats Java typés
|
||||
✅ **Validation centralisée** : Contraintes Jakarta Bean Validation
|
||||
✅ **DRY** : Zéro duplication entre projets
|
||||
✅ **Versioning** : Maven semantic versioning
|
||||
✅ **Documentation** : Javadoc complète
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Structure
|
||||
|
||||
```
|
||||
src/main/java/dev/lions/unionflow/server/api/
|
||||
├── dto/ # Data Transfer Objects
|
||||
│ ├── base/ # DTOs de base
|
||||
│ │ ├── BaseRequest.java
|
||||
│ │ └── BaseResponse.java
|
||||
│ ├── dashboard/ # Dashboard
|
||||
│ │ ├── DashboardStatsResponse.java
|
||||
│ │ ├── MembreDashboardSyntheseResponse.java
|
||||
│ │ └── UpcomingEventResponse.java
|
||||
│ ├── membre/ # Membres
|
||||
│ │ ├── request/
|
||||
│ │ │ └── CreateMembreRequest.java
|
||||
│ │ └── response/
|
||||
│ │ ├── MembreResponse.java
|
||||
│ └── MembreSummaryResponse.java
|
||||
│ ├── finance/ # Finance Workflow
|
||||
│ │ ├── request/
|
||||
│ │ │ ├── ApproveTransactionRequest.java
|
||||
│ │ │ └── RejectTransactionRequest.java
|
||||
│ │ └── response/
|
||||
│ │ ├── AdhesionResponse.java
|
||||
│ │ ├── TransactionApprovalResponse.java
|
||||
│ │ └── BudgetResponse.java
|
||||
│ ├── cotisation/ # Cotisations
|
||||
│ ├── evenement/ # Événements
|
||||
│ ├── solidarite/ # Demandes d'aide
|
||||
│ └── notification/ # Notifications
|
||||
├── enums/ # Énumérations
|
||||
│ ├── membre/
|
||||
│ │ ├── StatutMembre.java
|
||||
│ │ └── TypeMembre.java
|
||||
│ ├── finance/
|
||||
│ │ ├── StatutApprobation.java
|
||||
│ │ ├── TypeTransaction.java
|
||||
│ │ └── BudgetPeriod.java
|
||||
│ ├── paiement/
|
||||
│ │ ├── StatutPaiement.java
|
||||
│ │ └── ModePaiement.java
|
||||
│ └── notification/
|
||||
│ └── TypeNotification.java
|
||||
├── validation/ # Validateurs custom
|
||||
│ ├── annotations/ # Annotations validation
|
||||
│ │ ├── @ValidEmail
|
||||
│ │ ├── @ValidPhoneNumber
|
||||
│ │ └── @ValidAmount
|
||||
│ ├── validators/ # Implémentations
|
||||
│ │ ├── EmailValidator.java
|
||||
│ │ └── AmountValidator.java
|
||||
│ └── ValidationConstants.java # Constantes (regex, limites)
|
||||
└── exception/ # Exceptions API
|
||||
├── ApiException.java
|
||||
├── ValidationException.java
|
||||
└── ErrorResponse.java
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
### Maven Dependency
|
||||
|
||||
Ajouter à votre `pom.xml` :
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>dev.lions.unionflow</groupId>
|
||||
<artifactId>unionflow-server-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Repository Gitea (Maven Registry)
|
||||
|
||||
Configurer `~/.m2/settings.xml` :
|
||||
|
||||
```xml
|
||||
<settings>
|
||||
<servers>
|
||||
<server>
|
||||
<id>gitea-lionsdev</id>
|
||||
<username>${env.GITEA_USERNAME}</username>
|
||||
<password>${env.GITEA_TOKEN}</password>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>gitea-lionsdev</id>
|
||||
<url>https://git.lions.dev/api/packages/lionsdev/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</settings>
|
||||
```
|
||||
|
||||
### Variables d'environnement
|
||||
|
||||
```bash
|
||||
export GITEA_USERNAME=lionsdev
|
||||
export GITEA_TOKEN=your-gitea-token
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Utilisation
|
||||
|
||||
### 1. DTOs Request/Response
|
||||
|
||||
#### Exemple : Créer un membre
|
||||
|
||||
**Request DTO** :
|
||||
|
||||
```java
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateMembreRequest {
|
||||
|
||||
@NotBlank(message = "Le nom est requis")
|
||||
@Size(min = 2, max = 100)
|
||||
private String nom;
|
||||
|
||||
@NotBlank(message = "Le prénom est requis")
|
||||
@Size(min = 2, max = 100)
|
||||
private String prenom;
|
||||
|
||||
@ValidEmail
|
||||
private String email;
|
||||
|
||||
@ValidPhoneNumber
|
||||
private String telephone;
|
||||
|
||||
@NotNull
|
||||
private UUID organisationId;
|
||||
|
||||
private TypeMembre typeMembre = TypeMembre.MEMBRE;
|
||||
}
|
||||
```
|
||||
|
||||
**Response DTO** :
|
||||
|
||||
```java
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MembreResponse extends BaseResponse {
|
||||
|
||||
private UUID id;
|
||||
private String nom;
|
||||
private String prenom;
|
||||
private String email;
|
||||
private String telephone;
|
||||
private StatutMembre statut;
|
||||
private TypeMembre type;
|
||||
private String numeroMembre;
|
||||
private LocalDate dateAdhesion;
|
||||
private UUID organisationId;
|
||||
private String organisationNom;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Backend** :
|
||||
|
||||
```java
|
||||
@POST
|
||||
@Path("/membres")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response createMembre(@Valid CreateMembreRequest request) {
|
||||
MembreResponse response = membreService.create(request);
|
||||
return Response.status(201).entity(response).build();
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Frontend (REST Client)** :
|
||||
|
||||
```java
|
||||
@Path("/api/v1/membres")
|
||||
@RegisterRestClient(configKey = "unionflow-backend")
|
||||
public interface MembreRestClient {
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
MembreResponse createMembre(@Valid CreateMembreRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Validation
|
||||
|
||||
#### Annotations standard (Jakarta Bean Validation)
|
||||
|
||||
```java
|
||||
@NotNull // Non null
|
||||
@NotBlank // Non vide (String)
|
||||
@Size(min, max) // Taille min/max
|
||||
@Min(value) // Valeur minimale (nombres)
|
||||
@Max(value) // Valeur maximale (nombres)
|
||||
@Email // Format email
|
||||
@Pattern(regex) // Regex custom
|
||||
@Positive // > 0
|
||||
@PositiveOrZero // >= 0
|
||||
```
|
||||
|
||||
#### Annotations custom UnionFlow
|
||||
|
||||
```java
|
||||
@ValidEmail // Email avec domaines autorisés
|
||||
@ValidPhoneNumber // Téléphone international (+225, +33, etc.)
|
||||
@ValidAmount // Montant positif, max 2 décimales
|
||||
@ValidNumeroMembre // Format: ORG-YYYY-NNNN
|
||||
@ValidPeriodeCotisation // Format: YYYY-MM
|
||||
```
|
||||
|
||||
**Exemple d'utilisation** :
|
||||
|
||||
```java
|
||||
public class PaiementRequest {
|
||||
|
||||
@ValidAmount(min = 100.0, max = 10_000_000.0)
|
||||
private BigDecimal montant;
|
||||
|
||||
@ValidPhoneNumber
|
||||
private String telephonePaiement;
|
||||
|
||||
@NotNull
|
||||
@Pattern(regexp = "^\\d{4}-\\d{2}$")
|
||||
private String periode; // Ex: "2026-03"
|
||||
}
|
||||
```
|
||||
|
||||
#### Validators custom - Implémentation
|
||||
|
||||
**Annotation** :
|
||||
|
||||
```java
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = AmountValidator.class)
|
||||
public @interface ValidAmount {
|
||||
String message() default "Montant invalide";
|
||||
double min() default 0.0;
|
||||
double max() default Double.MAX_VALUE;
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
```
|
||||
|
||||
**Validator** :
|
||||
|
||||
```java
|
||||
public class AmountValidator implements ConstraintValidator<ValidAmount, BigDecimal> {
|
||||
|
||||
private double min;
|
||||
private double max;
|
||||
|
||||
@Override
|
||||
public void initialize(ValidAmount annotation) {
|
||||
this.min = annotation.min();
|
||||
this.max = annotation.max();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(BigDecimal value, ConstraintValidatorContext context) {
|
||||
if (value == null) return true; // Use @NotNull separately
|
||||
|
||||
double amount = value.doubleValue();
|
||||
|
||||
// Check positive
|
||||
if (amount <= 0) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate("Le montant doit être positif")
|
||||
.addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check range
|
||||
if (amount < min || amount > max) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
String.format("Le montant doit être entre %.2f et %.2f", min, max)
|
||||
).addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check max 2 decimals
|
||||
if (value.scale() > 2) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate("Maximum 2 décimales autorisées")
|
||||
.addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Enums
|
||||
|
||||
#### Exemple : StatutApprobation
|
||||
|
||||
```java
|
||||
public enum StatutApprobation {
|
||||
PENDING("En attente"),
|
||||
APPROVED("Approuvée"),
|
||||
REJECTED("Rejetée"),
|
||||
CANCELLED("Annulée");
|
||||
|
||||
private final String libelle;
|
||||
|
||||
StatutApprobation(String libelle) {
|
||||
this.libelle = libelle;
|
||||
}
|
||||
|
||||
public String getLibelle() {
|
||||
return libelle;
|
||||
}
|
||||
|
||||
public static StatutApprobation fromString(String str) {
|
||||
return Arrays.stream(values())
|
||||
.filter(s -> s.name().equalsIgnoreCase(str))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Statut invalide: " + str));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage** :
|
||||
|
||||
```java
|
||||
StatutApprobation statut = StatutApprobation.APPROVED;
|
||||
System.out.println(statut.getLibelle()); // "Approuvée"
|
||||
|
||||
StatutApprobation parsed = StatutApprobation.fromString("PENDING");
|
||||
```
|
||||
|
||||
### 4. BaseResponse - Héritage commun
|
||||
|
||||
Tous les Response DTOs étendent `BaseResponse` :
|
||||
|
||||
```java
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public abstract class BaseResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Audit fields (si nécessaire côté client)
|
||||
private LocalDateTime dateCreation;
|
||||
private LocalDateTime dateModification;
|
||||
private Boolean actif;
|
||||
}
|
||||
```
|
||||
|
||||
**Avantages** :
|
||||
- Champs audit automatiques
|
||||
- Serializable pour cache/sessions
|
||||
- Type-safe avec génériques
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
### Tests de validation
|
||||
|
||||
**Fichier** : `src/test/java/dev/lions/unionflow/server/api/validation/AmountValidatorTest.java`
|
||||
|
||||
```java
|
||||
@Test
|
||||
void shouldRejectNegativeAmount() {
|
||||
CreatePaiementRequest request = new CreatePaiementRequest();
|
||||
request.setMontant(BigDecimal.valueOf(-100));
|
||||
|
||||
Set<ConstraintViolation<CreatePaiementRequest>> violations = validator.validate(request);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream()
|
||||
.anyMatch(v -> v.getMessage().contains("positif")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectTooManyDecimals() {
|
||||
CreatePaiementRequest request = new CreatePaiementRequest();
|
||||
request.setMontant(BigDecimal.valueOf(100.123));
|
||||
|
||||
Set<ConstraintViolation<CreatePaiementRequest>> violations = validator.validate(request);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream()
|
||||
.anyMatch(v -> v.getMessage().contains("2 décimales")));
|
||||
}
|
||||
```
|
||||
|
||||
### Lancer les tests
|
||||
|
||||
```bash
|
||||
mvn test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 DTOs par Feature
|
||||
|
||||
### Dashboard
|
||||
|
||||
- `DashboardStatsResponse` - Stats organisation (membres, cotisations, events)
|
||||
- `MembreDashboardSyntheseResponse` - Synthèse membre (solde, cotisations)
|
||||
- `UpcomingEventResponse` - Événements à venir
|
||||
|
||||
### Finance Workflow
|
||||
|
||||
- `TransactionApprovalResponse` - Approbation de transaction
|
||||
- `BudgetResponse` - Budget avec lignes budgétaires
|
||||
- `AdhesionResponse` - Adhésion membre
|
||||
|
||||
### Membres
|
||||
|
||||
- `MembreResponse` - Détails membre complets
|
||||
- `MembreSummaryResponse` - Résumé membre (liste)
|
||||
- `CreateMembreRequest` - Création membre
|
||||
- `UpdateMembreRequest` - Modification membre
|
||||
|
||||
### Cotisations
|
||||
|
||||
- `CotisationResponse` - Cotisation avec détails
|
||||
- `CreateCotisationRequest` - Enregistrement cotisation
|
||||
- `CotisationStatisticsResponse` - Statistiques cotisations
|
||||
|
||||
### Notifications
|
||||
|
||||
- `NotificationResponse` - Notification utilisateur
|
||||
- `MarkAsReadRequest` - Marquer comme lue
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Publication Maven (Développeurs seulement)
|
||||
|
||||
### Publier une nouvelle version
|
||||
|
||||
```bash
|
||||
# 1. Mettre à jour la version dans pom.xml
|
||||
<version>2.1.0</version>
|
||||
|
||||
# 2. Compiler et publier
|
||||
mvn clean deploy
|
||||
|
||||
# Les artifacts sont publiés sur:
|
||||
# https://git.lions.dev/api/packages/lionsdev/maven
|
||||
```
|
||||
|
||||
### Versioning Semantic
|
||||
|
||||
- **Major** (2.0.0) : Breaking changes
|
||||
- **Minor** (2.1.0) : Nouvelles features (backward compatible)
|
||||
- **Patch** (2.0.1) : Bugfixes
|
||||
|
||||
---
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
### v2.0.0 (2026-03-14)
|
||||
|
||||
✅ **Nouveau** :
|
||||
- DTOs Finance Workflow complets
|
||||
- Validation `@ValidAmount` avec min/max
|
||||
- Enums `BudgetPeriod`, `BudgetCategory`
|
||||
- `TransactionApprovalResponse` avec tous les champs
|
||||
|
||||
✅ **Améliorations** :
|
||||
- BaseResponse avec audit fields
|
||||
- ValidationConstants centralisées
|
||||
- Javadoc complète pour tous les DTOs
|
||||
|
||||
### v1.0.0 (2026-01-04)
|
||||
|
||||
- Version initiale
|
||||
- 20+ DTOs principaux
|
||||
- 10+ validators custom
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
### Javadoc
|
||||
|
||||
```bash
|
||||
# Générer Javadoc
|
||||
mvn javadoc:javadoc
|
||||
|
||||
# Ouvrir
|
||||
open target/site/apidocs/index.html
|
||||
```
|
||||
|
||||
### Ressources
|
||||
|
||||
- **Jakarta Bean Validation**: https://jakarta.ee/specifications/bean-validation/
|
||||
- **Maven Repository**: https://git.lions.dev/lionsdev/unionflow-server-api
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contribution
|
||||
|
||||
1. Créer une branche feature
|
||||
2. Ajouter DTOs/Validators avec tests
|
||||
3. Documenter avec Javadoc
|
||||
4. Pull Request avec description
|
||||
|
||||
---
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
Propriétaire - © 2026 Lions Club Côte d'Ivoire
|
||||
|
||||
---
|
||||
|
||||
**Version** : 2.0.0
|
||||
**Dernière mise à jour** : 2026-03-14
|
||||
**Auteur** : Équipe UnionFlow
|
||||
359
checkstyle-unionflow.xml
Normal file
359
checkstyle-unionflow.xml
Normal file
@@ -0,0 +1,359 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
Configuration Checkstyle pour UnionFlow
|
||||
Basée sur Google Java Style Guide avec adaptations pour UnionFlow
|
||||
Objectif : 100% de conformité (zéro violation)
|
||||
|
||||
@author UnionFlow Team
|
||||
@version 1.0
|
||||
@since 2025-01-10
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
<property name="charset" value="UTF-8"/>
|
||||
<property name="severity" value="error"/>
|
||||
<property name="fileExtensions" value="java, properties, xml"/>
|
||||
|
||||
<!-- Suppressions pour les fichiers générés -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
|
||||
default="checkstyle-suppressions.xml" />
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- Vérifications au niveau des fichiers -->
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="LineLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="max" value="120"/>
|
||||
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
|
||||
<!-- Vérifications au niveau des arbres syntaxiques -->
|
||||
<module name="TreeWalker">
|
||||
|
||||
<!-- Annotations -->
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationMostCases"/>
|
||||
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationVariables"/>
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||
</module>
|
||||
<module name="AnnotationUseStyle"/>
|
||||
<module name="MissingOverride"/>
|
||||
|
||||
<!-- Blocs -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<module name="EmptyBlock">
|
||||
<property name="option" value="TEXT"/>
|
||||
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||
</module>
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="expected"/>
|
||||
</module>
|
||||
<module name="LeftCurly"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_DO"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="option" value="alone"/>
|
||||
<property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT, INSTANCE_INIT"/>
|
||||
</module>
|
||||
|
||||
<!-- Conception de classe -->
|
||||
<module name="FinalClass"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
<module name="InterfaceIsType"/>
|
||||
<module name="OneTopLevelClass"/>
|
||||
<module name="VisibilityModifier">
|
||||
<property name="protectedAllowed" value="true"/>
|
||||
<property name="packageAllowed" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- Codage -->
|
||||
<module name="ArrayTrailingComma"/>
|
||||
<module name="AvoidEscapedUnicodeCharacters">
|
||||
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||
<property name="allowByTailComment" value="true"/>
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
</module>
|
||||
<module name="CovariantEquals"/>
|
||||
<module name="DeclarationOrder"/>
|
||||
<module name="DefaultComesLast"/>
|
||||
<module name="EmptyStatement"/>
|
||||
<module name="EqualsAvoidNull"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="ExplicitInitialization"/>
|
||||
<module name="FallThrough"/>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="IllegalToken"/>
|
||||
<module name="IllegalTokenText">
|
||||
<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="message" value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
</module>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="MagicNumber">
|
||||
<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="ignoreAnnotation" value="true"/>
|
||||
<property name="ignoreFieldDeclaration" value="true"/>
|
||||
</module>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<module name="ModifiedControlVariable"/>
|
||||
<module name="MultipleStringLiterals">
|
||||
<property name="allowedDuplicates" value="3"/>
|
||||
</module>
|
||||
<module name="MultipleVariableDeclarations"/>
|
||||
<module name="NoClone"/>
|
||||
<module name="NoFinalizer"/>
|
||||
<module name="OneStatementPerLine"/>
|
||||
<module name="OverloadMethodsDeclarationOrder"/>
|
||||
<module name="PackageDeclaration"/>
|
||||
<module name="ParameterAssignment"/>
|
||||
<module name="RequireThis">
|
||||
<property name="checkFields" value="false"/>
|
||||
<property name="checkMethods" value="false"/>
|
||||
</module>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
<module name="StringLiteralEquality"/>
|
||||
<module name="UnnecessaryParentheses"/>
|
||||
<module name="VariableDeclarationUsageDistance"/>
|
||||
|
||||
<!-- Imports -->
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="AvoidStaticImport">
|
||||
<property name="excludes" value="org.assertj.core.api.Assertions.*,org.junit.jupiter.api.Assertions.*,org.mockito.Mockito.*"/>
|
||||
</module>
|
||||
<module name="CustomImportOrder">
|
||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||
<property name="separateLineBetweenGroups" value="true"/>
|
||||
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/>
|
||||
</module>
|
||||
<module name="IllegalImport"/>
|
||||
<module name="RedundantImport"/>
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
<!-- Javadoc -->
|
||||
<module name="AtclauseOrder">
|
||||
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||
</module>
|
||||
<module name="InvalidJavadocPosition"/>
|
||||
<module name="JavadocMethod">
|
||||
<property name="allowMissingParamTags" value="false"/>
|
||||
<property name="allowMissingReturnTag" value="false"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
|
||||
</module>
|
||||
<module name="JavadocParagraph"/>
|
||||
<module name="JavadocStyle"/>
|
||||
<module name="JavadocTagContinuationIndentation"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="MissingJavadocMethod">
|
||||
<property name="minLineCount" value="2"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
|
||||
</module>
|
||||
<module name="MissingJavadocType"/>
|
||||
<module name="NonEmptyAtclauseDescription"/>
|
||||
<module name="SingleLineJavadoc">
|
||||
<property name="ignoreInlineTags" value="false"/>
|
||||
</module>
|
||||
<module name="SummaryJavadoc">
|
||||
<property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||
</module>
|
||||
|
||||
<!-- Métriques -->
|
||||
<module name="BooleanExpressionComplexity">
|
||||
<property name="max" value="7"/>
|
||||
</module>
|
||||
<module name="ClassDataAbstractionCoupling">
|
||||
<property name="max" value="15"/>
|
||||
</module>
|
||||
<module name="ClassFanOutComplexity">
|
||||
<property name="max" value="25"/>
|
||||
</module>
|
||||
<module name="CyclomaticComplexity">
|
||||
<property name="max" value="15"/>
|
||||
</module>
|
||||
<module name="JavaNCSS">
|
||||
<property name="methodMaximum" value="80"/>
|
||||
<property name="classMaximum" value="2000"/>
|
||||
</module>
|
||||
<module name="NPathComplexity">
|
||||
<property name="max" value="200"/>
|
||||
</module>
|
||||
|
||||
<!-- Divers -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="CommentsIndentation"/>
|
||||
<module name="Indentation">
|
||||
<property name="basicOffset" value="4"/>
|
||||
<property name="braceAdjustment" value="0"/>
|
||||
<property name="caseIndent" value="4"/>
|
||||
<property name="throwsIndent" value="8"/>
|
||||
<property name="lineWrappingIndentation" value="8"/>
|
||||
<property name="arrayInitIndent" value="4"/>
|
||||
</module>
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="TodoComment">
|
||||
<property name="format" value="(TODO)|(FIXME)"/>
|
||||
</module>
|
||||
<module name="TrailingComment"/>
|
||||
<module name="UncommentedMain">
|
||||
<property name="excludedClasses" value="\.Main$"/>
|
||||
</module>
|
||||
<module name="UpperEll"/>
|
||||
|
||||
<!-- Modificateurs -->
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="RedundantModifier"/>
|
||||
|
||||
<!-- Conventions de nommage -->
|
||||
<module name="AbbreviationAsWordInName">
|
||||
<property name="ignoreFinal" value="false"/>
|
||||
<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"/>
|
||||
</module>
|
||||
<module name="ClassTypeParameterName">
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="ConstantName"/>
|
||||
<module name="InterfaceTypeParameterName">
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName">
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="MethodTypeParameterName">
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||
<message key="name.invalidPattern" value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ParameterName">
|
||||
<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}''."/>
|
||||
</module>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName">
|
||||
<message key="name.invalidPattern" value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
|
||||
<!-- Taille -->
|
||||
<module name="AnonInnerLength">
|
||||
<property name="max" value="30"/>
|
||||
</module>
|
||||
<module name="ExecutableStatementCount">
|
||||
<property name="max" value="50"/>
|
||||
</module>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="120"/>
|
||||
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||
</module>
|
||||
<module name="MethodCount">
|
||||
<property name="maxTotal" value="50"/>
|
||||
<property name="maxPrivate" value="30"/>
|
||||
<property name="maxPackage" value="30"/>
|
||||
<property name="maxProtected" value="30"/>
|
||||
<property name="maxPublic" value="30"/>
|
||||
</module>
|
||||
<module name="MethodLength">
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
|
||||
<property name="max" value="100"/>
|
||||
</module>
|
||||
<module name="OuterTypeNumber"/>
|
||||
<module name="ParameterNumber">
|
||||
<property name="max" value="8"/>
|
||||
<property name="ignoreOverriddenMethods" value="true"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
|
||||
</module>
|
||||
|
||||
<!-- Espaces blancs -->
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
</module>
|
||||
<module name="GenericWhitespace">
|
||||
<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.illegalFollow" value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||
<message key="ws.notPreceded" value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoLineWrap"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="OperatorWrap">
|
||||
<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 "/>
|
||||
</module>
|
||||
<module name="ParenPad"/>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapDot"/>
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapComma"/>
|
||||
<property name="tokens" value="COMMA"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapEllipsis"/>
|
||||
<property name="tokens" value="ELLIPSIS"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapArrayDeclarator"/>
|
||||
<property name="tokens" value="ARRAY_DECLARATOR"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapMethodRef"/>
|
||||
<property name="tokens" value="METHOD_REF"/>
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyTypes" 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.notPreceded" value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
</module>
|
||||
2
lombok.config
Normal file
2
lombok.config
Normal file
@@ -0,0 +1,2 @@
|
||||
config.stopBubbling = true
|
||||
lombok.addLombokGeneratedAnnotation = true
|
||||
96
parent-pom.xml
Normal file
96
parent-pom.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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>
|
||||
|
||||
<groupId>dev.lions.unionflow</groupId>
|
||||
<artifactId>unionflow-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>UnionFlow - Parent</name>
|
||||
<description>Plateforme complète de gestion d'union — POM parent partagé</description>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitea-lionsdev</id>
|
||||
<url>https://git.lions.dev/api/packages/lionsdev/maven</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>gitea-lionsdev</id>
|
||||
<url>https://git.lions.dev/api/packages/lionsdev/maven</url>
|
||||
</snapshotRepository>
|
||||
</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>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.version>3.15.1</quarkus.platform.version>
|
||||
<lombok.version>1.18.34</lombok.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.lions.unionflow</groupId>
|
||||
<artifactId>unionflow-server-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<parameters>true</parameters>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
241
pom.xml
Normal file
241
pom.xml
Normal file
@@ -0,0 +1,241 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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>
|
||||
|
||||
<parent>
|
||||
<groupId>dev.lions.unionflow</groupId>
|
||||
<artifactId>unionflow-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>parent-pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>unionflow-server-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>UnionFlow Server API</name>
|
||||
<description>API définitions pour le serveur UnionFlow</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<quarkus.platform.version>3.15.1</quarkus.platform.version>
|
||||
<jackson.version>2.17.0</jackson.version>
|
||||
<validation-api.version>3.0.2</validation-api.version>
|
||||
<microprofile-openapi.version>3.1.1</microprofile-openapi.version>
|
||||
|
||||
<!-- Versions des plugins de qualité -->
|
||||
<jacoco.version>0.8.11</jacoco.version>
|
||||
<checkstyle.version>10.12.4</checkstyle.version>
|
||||
<maven-checkstyle-plugin.version>3.3.1</maven-checkstyle-plugin.version>
|
||||
<junit.version>5.10.1</junit.version>
|
||||
<mockito.version>5.7.0</mockito.version>
|
||||
<assertj.version>3.24.2</assertj.version>
|
||||
|
||||
<!-- Seuils de couverture Jacoco - 100% obligatoire -->
|
||||
<jacoco.line.coverage.minimum>1.00</jacoco.line.coverage.minimum>
|
||||
<jacoco.branch.coverage.minimum>1.00</jacoco.branch.coverage.minimum>
|
||||
<jacoco.instruction.coverage.minimum>1.00</jacoco.instruction.coverage.minimum>
|
||||
<jacoco.method.coverage.minimum>1.00</jacoco.method.coverage.minimum>
|
||||
<jacoco.class.coverage.minimum>1.00</jacoco.class.coverage.minimum>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Jackson pour la sérialisation JSON -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Bean Validation -->
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<version>${validation-api.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MicroProfile OpenAPI pour la documentation -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.microprofile.openapi</groupId>
|
||||
<artifactId>microprofile-openapi-api</artifactId>
|
||||
<version>${microprofile-openapi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- Dépendances de test -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.1.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>jakarta.el</artifactId>
|
||||
<version>4.0.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok pour génération automatique des getters/setters -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Plugin Jacoco pour la couverture de code -->
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>check</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>LINE</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.line.coverage.minimum}</minimum>
|
||||
</limit>
|
||||
<limit>
|
||||
<counter>BRANCH</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.branch.coverage.minimum}</minimum>
|
||||
</limit>
|
||||
<limit>
|
||||
<counter>INSTRUCTION</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.instruction.coverage.minimum}</minimum>
|
||||
</limit>
|
||||
<limit>
|
||||
<counter>METHOD</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.method.coverage.minimum}</minimum>
|
||||
</limit>
|
||||
<limit>
|
||||
<counter>CLASS</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco.class.coverage.minimum}</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Plugin Checkstyle pour la qualité du code -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>${maven-checkstyle-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<configLocation>google_checks.xml</configLocation>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<failsOnError>true</failsOnError>
|
||||
<violationSeverity>warning</violationSeverity>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
<excludes>**/target/**/*</excludes>
|
||||
</configuration>
|
||||
<!-- Executions désactivées temporairement pour les tests
|
||||
<executions>
|
||||
<execution>
|
||||
<id>validate</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
-->
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
30
script/publish-api.bat
Normal file
30
script/publish-api.bat
Normal file
@@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
REM Publie le parent pom + server-api sur le Gitea Package Registry
|
||||
REM Usage : script\publish-api.bat
|
||||
REM Depuis : n'importe où dans le repo server-api
|
||||
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_ID=gitea-lionsdev
|
||||
|
||||
cd /d "%~dp0\.."
|
||||
|
||||
echo.
|
||||
echo [1/2] Publication du parent pom...
|
||||
call mvn deploy:deploy-file ^
|
||||
-DgroupId=dev.lions.unionflow ^
|
||||
-DartifactId=unionflow-parent ^
|
||||
-Dversion=1.0.0 ^
|
||||
-Dpackaging=pom ^
|
||||
-Dfile=parent-pom.xml ^
|
||||
-DrepositoryId=%REGISTRY_ID% ^
|
||||
-Durl=%REGISTRY_URL%
|
||||
if errorlevel 409 echo [WARN] Parent pom deja publie pour cette version, on continue.
|
||||
|
||||
echo.
|
||||
echo [2/2] Publication du server-api...
|
||||
call mvn deploy -DskipTests
|
||||
if errorlevel 409 echo [WARN] Server-api deja publie - incrementer la version pour republier.
|
||||
|
||||
echo.
|
||||
echo Done -- https://git.lions.dev/lionsdev/-/packages
|
||||
32
script/publish-api.sh
Normal file
32
script/publish-api.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# Publie le parent pom + server-api sur le Gitea Package Registry
|
||||
# Usage : ./script/publish-api.sh
|
||||
# Depuis : n'importe où dans le repo server-api
|
||||
# Prérequis: credentials dans ~/.m2/settings.xml (server id: gitea-lionsdev)
|
||||
|
||||
set -e
|
||||
|
||||
REGISTRY_URL="https://git.lions.dev/api/packages/lionsdev/maven"
|
||||
REGISTRY_ID="gitea-lionsdev"
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
echo ""
|
||||
echo "[1/2] Publication du parent pom..."
|
||||
mvn deploy:deploy-file \
|
||||
-DgroupId=dev.lions.unionflow \
|
||||
-DartifactId=unionflow-parent \
|
||||
-Dversion=1.0.0 \
|
||||
-Dpackaging=pom \
|
||||
-Dfile=parent-pom.xml \
|
||||
-DrepositoryId="${REGISTRY_ID}" \
|
||||
-Durl="${REGISTRY_URL}" \
|
||||
|| echo "[WARN] Parent pom déjà publié pour cette version (409), on continue."
|
||||
|
||||
echo ""
|
||||
echo "[2/2] Publication du server-api..."
|
||||
mvn deploy -DskipTests \
|
||||
|| echo "[WARN] Server-api déjà publié pour cette version (409) - incrémenter la version pour republier."
|
||||
|
||||
echo ""
|
||||
echo "Done -- https://git.lions.dev/lionsdev/-/packages"
|
||||
@@ -0,0 +1,82 @@
|
||||
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.TypePeriodeAbonnement;
|
||||
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Future;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un abonnement.
|
||||
*/
|
||||
@Builder
|
||||
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,
|
||||
|
||||
@NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId,
|
||||
|
||||
String nomOrganisation,
|
||||
|
||||
@NotNull(message = "L'identifiant de la formule est obligatoire") UUID formulaireId,
|
||||
|
||||
String codeFormule,
|
||||
String nomFormule,
|
||||
TypeFormule typeFormule,
|
||||
|
||||
@NotNull(message = "Le statut est obligatoire") StatutAbonnement statut,
|
||||
|
||||
@NotNull(message = "Le type d'abonnement est obligatoire") TypePeriodeAbonnement typeAbonnement,
|
||||
|
||||
@NotNull(message = "La date de début est obligatoire") LocalDate dateDebut,
|
||||
|
||||
@Future(message = "La date de fin doit être dans le futur") LocalDate dateFin,
|
||||
|
||||
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,
|
||||
|
||||
@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 = "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 periodeEssaiUtilisee,
|
||||
LocalDate dateFinEssai,
|
||||
Integer maxMembres,
|
||||
Integer nombreMembresActuels,
|
||||
BigDecimal espaceStockageGB,
|
||||
BigDecimal espaceStockageUtilise,
|
||||
Boolean supportTechnique,
|
||||
String niveauSupport,
|
||||
Boolean fonctionnalitesAvancees,
|
||||
Boolean apiAccess,
|
||||
Boolean rapportsPersonnalises,
|
||||
Boolean integrationsTierces,
|
||||
UUID responsableId,
|
||||
String nomResponsable,
|
||||
String emailResponsable,
|
||||
String telephoneResponsable,
|
||||
|
||||
@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,
|
||||
|
||||
@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,
|
||||
|
||||
Boolean alertesActivees,
|
||||
Boolean notificationsEmail,
|
||||
Boolean notificationsSMS) {
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
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.TypePeriodeAbonnement;
|
||||
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Future;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'un abonnement.
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateAbonnementRequest(
|
||||
@Pattern(regexp = "^ABO-\\d{4}-[A-Z0-9]{8}$", message = "Format de référence invalide (ABO-YYYY-XXXXXXXX)") String numeroReference,
|
||||
|
||||
UUID organisationId,
|
||||
String nomOrganisation,
|
||||
UUID formulaireId,
|
||||
|
||||
String codeFormule,
|
||||
String nomFormule,
|
||||
TypeFormule typeFormule,
|
||||
|
||||
StatutAbonnement statut,
|
||||
TypePeriodeAbonnement typeAbonnement,
|
||||
|
||||
LocalDate dateDebut,
|
||||
|
||||
@Future(message = "La date de fin doit être dans le futur") LocalDate dateFin,
|
||||
|
||||
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,
|
||||
|
||||
@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 = "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 periodeEssaiUtilisee,
|
||||
LocalDate dateFinEssai,
|
||||
Integer maxMembres,
|
||||
Integer nombreMembresActuels,
|
||||
BigDecimal espaceStockageGB,
|
||||
BigDecimal espaceStockageUtilise,
|
||||
Boolean supportTechnique,
|
||||
String niveauSupport,
|
||||
Boolean fonctionnalitesAvancees,
|
||||
Boolean apiAccess,
|
||||
Boolean rapportsPersonnalises,
|
||||
Boolean integrationsTierces,
|
||||
UUID responsableId,
|
||||
String nomResponsable,
|
||||
String emailResponsable,
|
||||
String telephoneResponsable,
|
||||
|
||||
@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,
|
||||
|
||||
@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,
|
||||
|
||||
Boolean alertesActivees,
|
||||
Boolean notificationsEmail,
|
||||
Boolean notificationsSMS) {
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package dev.lions.unionflow.server.api.dto.abonnement.response;
|
||||
|
||||
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.TypePeriodeAbonnement;
|
||||
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée pour un abonnement.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AbonnementResponse extends BaseResponse {
|
||||
|
||||
private String numeroReference;
|
||||
private UUID organisationId;
|
||||
private String nomOrganisation;
|
||||
private UUID formulaireId;
|
||||
private String codeFormule;
|
||||
private String nomFormule;
|
||||
private TypeFormule typeFormule;
|
||||
private StatutAbonnement statut;
|
||||
private TypePeriodeAbonnement typeAbonnement;
|
||||
private LocalDate dateDebut;
|
||||
private LocalDate dateFin;
|
||||
private LocalDate dateProchainePeriode;
|
||||
private BigDecimal montant;
|
||||
private String devise;
|
||||
private BigDecimal remise;
|
||||
private BigDecimal montantFinal;
|
||||
private Boolean renouvellementAutomatique;
|
||||
private Boolean periodeEssaiUtilisee;
|
||||
private LocalDate dateFinEssai;
|
||||
private Integer maxMembres;
|
||||
private Integer nombreMembresActuels;
|
||||
private BigDecimal espaceStockageGB;
|
||||
private BigDecimal espaceStockageUtilise;
|
||||
private Boolean supportTechnique;
|
||||
private String niveauSupport;
|
||||
private Boolean fonctionnalitesAvancees;
|
||||
private Boolean apiAccess;
|
||||
private Boolean rapportsPersonnalises;
|
||||
private Boolean integrationsTierces;
|
||||
private LocalDateTime dateDerniereUtilisation;
|
||||
private Integer connexionsCeMois;
|
||||
private UUID responsableId;
|
||||
private String nomResponsable;
|
||||
private String emailResponsable;
|
||||
private String telephoneResponsable;
|
||||
|
||||
private String modePaiementPrefere;
|
||||
private String numeroPaiementMobile;
|
||||
private String historiquePaiements;
|
||||
private String notes;
|
||||
|
||||
private Boolean alertesActivees;
|
||||
private Boolean notificationsEmail;
|
||||
private Boolean notificationsSMS;
|
||||
|
||||
private LocalDateTime dateSuspension;
|
||||
|
||||
private String raisonSuspension;
|
||||
|
||||
private LocalDateTime dateAnnulation;
|
||||
|
||||
private String raisonAnnulation;
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
|
||||
public boolean isActive() {
|
||||
return StatutAbonnement.ACTIF.equals(statut);
|
||||
}
|
||||
|
||||
public boolean isExpire() {
|
||||
return StatutAbonnement.EXPIRE.equals(statut) ||
|
||||
(dateFin != null && dateFin.isBefore(LocalDate.now()));
|
||||
}
|
||||
|
||||
public boolean isSuspendu() {
|
||||
return StatutAbonnement.SUSPENDU.equals(statut);
|
||||
}
|
||||
|
||||
public int getMembresRestants() {
|
||||
if (maxMembres == null) return 0;
|
||||
int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0;
|
||||
return Math.max(0, maxMembres - actuels);
|
||||
}
|
||||
|
||||
public boolean isQuotaAtteint() {
|
||||
if (maxMembres == null) return false;
|
||||
int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0;
|
||||
return actuels >= maxMembres;
|
||||
}
|
||||
|
||||
public int getPourcentageUtilisation() {
|
||||
if (maxMembres == null || maxMembres == 0) return 0;
|
||||
int actuels = nombreMembresActuels != null ? nombreMembresActuels : 0;
|
||||
return (actuels * 100) / maxMembres;
|
||||
}
|
||||
|
||||
public long getJoursRestants() {
|
||||
if (dateFin == null) return -1;
|
||||
LocalDate maintenant = LocalDate.now();
|
||||
if (maintenant.isAfter(dateFin)) return 0;
|
||||
return java.time.temporal.ChronoUnit.DAYS.between(maintenant, dateFin);
|
||||
}
|
||||
|
||||
public boolean isExpirationProche() {
|
||||
long joursRestants = getJoursRestants();
|
||||
return joursRestants >= 0 && joursRestants <= 30;
|
||||
}
|
||||
|
||||
public boolean peutEtreRenouvele() {
|
||||
return Boolean.TRUE.equals(renouvellementAutomatique) && !isExpire();
|
||||
}
|
||||
|
||||
public String getStatutLibelle() {
|
||||
return statut != null ? statut.name() : "INCONNU";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package dev.lions.unionflow.server.api.dto.admin.request;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un log d'audit.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateAuditLogRequest(
|
||||
String typeAction,
|
||||
String severite,
|
||||
String utilisateur,
|
||||
String role,
|
||||
String module,
|
||||
String description,
|
||||
String details,
|
||||
String ipAddress,
|
||||
String userAgent,
|
||||
String sessionId,
|
||||
LocalDateTime dateHeure,
|
||||
String donneesAvant,
|
||||
String donneesApres,
|
||||
String entiteId,
|
||||
String entiteType) {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.admin.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse pour les logs d'audit.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AuditLogResponse extends BaseResponse {
|
||||
|
||||
private String typeAction;
|
||||
private String severite;
|
||||
private String utilisateur;
|
||||
private String role;
|
||||
private String module;
|
||||
private String description;
|
||||
private String details;
|
||||
private String ipAddress;
|
||||
private String userAgent;
|
||||
private String sessionId;
|
||||
private LocalDateTime dateHeure;
|
||||
private String donneesAvant;
|
||||
private String donneesApres;
|
||||
private String entiteId;
|
||||
private String entiteType;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package dev.lions.unionflow.server.api.dto.adresse.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Requete de création d'une adresse.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
*/
|
||||
public record CreateAdresseRequest(
|
||||
@NotBlank(message = "Le type d'adresse est obligatoire") String typeAdresse, // Code depuis types_reference
|
||||
|
||||
@NotBlank(message = "L'adresse est obligatoire") String adresse,
|
||||
|
||||
String complementAdresse,
|
||||
String codePostal,
|
||||
|
||||
@NotBlank(message = "La ville est obligatoire") String ville,
|
||||
|
||||
String region,
|
||||
|
||||
@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 = "-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,
|
||||
|
||||
String libelle,
|
||||
String notes,
|
||||
|
||||
UUID organisationId, // Exclusive: soit organisationId, soit membreId, soit evenementId
|
||||
UUID membreId,
|
||||
UUID evenementId) {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.lions.unionflow.server.api.dto.adresse.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Requete de mise à jour d'une adresse.
|
||||
* Tous les champs sont optionnels pour permettre des mises à jour partielles.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
*/
|
||||
public record UpdateAdresseRequest(
|
||||
String typeAdresse, // Code depuis types_reference
|
||||
String adresse,
|
||||
String complementAdresse,
|
||||
String codePostal,
|
||||
String ville,
|
||||
String region,
|
||||
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 = "-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,
|
||||
String libelle,
|
||||
String notes,
|
||||
|
||||
UUID organisationId,
|
||||
UUID membreId,
|
||||
UUID evenementId) {
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package dev.lions.unionflow.server.api.dto.adresse.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* DTO de réponse détaillée pour une adresse.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AdresseResponse extends BaseResponse {
|
||||
|
||||
private String typeAdresse; // Code
|
||||
private String typeAdresseLibelle; // Depuis types_reference
|
||||
private String typeAdresseIcone;
|
||||
|
||||
private String adresse;
|
||||
private String complementAdresse;
|
||||
private String codePostal;
|
||||
private String ville;
|
||||
private String region;
|
||||
private String pays;
|
||||
|
||||
private BigDecimal latitude;
|
||||
private BigDecimal longitude;
|
||||
|
||||
private Boolean principale;
|
||||
private String libelle;
|
||||
private String notes;
|
||||
|
||||
private UUID organisationId;
|
||||
private UUID membreId;
|
||||
private UUID evenementId;
|
||||
|
||||
private String adresseComplete;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package dev.lions.unionflow.server.api.dto.agricole;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||
import dev.lions.unionflow.server.api.enums.agricole.StatutCampagneAgricole;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class CampagneAgricoleDTO extends BaseDTO {
|
||||
|
||||
private String organisationCoopId;
|
||||
|
||||
// Exemple : "Campagne d'Arachide 2025/2026"
|
||||
private String designation;
|
||||
|
||||
private String typeCulturePrincipale;
|
||||
|
||||
// Nombre d'hectares au total couvert par les membres de la coop
|
||||
private BigDecimal surfaceTotaleEstimeeHectares;
|
||||
|
||||
// Tonnes récoltées attendues vs réelles
|
||||
private BigDecimal volumePrevisionnelTonnes;
|
||||
private BigDecimal volumeReelTonnes;
|
||||
|
||||
private StatutCampagneAgricole statut;
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package dev.lions.unionflow.server.api.dto.analytics;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.TypeMetrique;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* DTO pour les données analytics UnionFlow
|
||||
*
|
||||
* <p>
|
||||
* Représente une donnée analytique avec sa valeur, sa métrique associée, sa
|
||||
* période d'analyse et
|
||||
* ses métadonnées.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-16
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AnalyticsDataResponse extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Type de métrique analysée */
|
||||
@NotNull(message = "Le type de métrique est obligatoire")
|
||||
private TypeMetrique typeMetrique;
|
||||
|
||||
/** Période d'analyse */
|
||||
@NotNull(message = "La période d'analyse est obligatoire")
|
||||
private PeriodeAnalyse periodeAnalyse;
|
||||
|
||||
/** Valeur numérique de la métrique */
|
||||
@NotNull(message = "La valeur est obligatoire")
|
||||
@DecimalMin(value = "0.0", message = "La valeur doit être positive ou nulle")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de valeur invalide")
|
||||
private BigDecimal valeur;
|
||||
|
||||
/** Valeur précédente pour comparaison */
|
||||
@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")
|
||||
private BigDecimal valeurPrecedente;
|
||||
|
||||
/** Pourcentage d'évolution par rapport à la période précédente */
|
||||
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
|
||||
private BigDecimal pourcentageEvolution;
|
||||
|
||||
/** Date de début de la période analysée */
|
||||
@NotNull(message = "La date de début est obligatoire")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDebut;
|
||||
|
||||
/** Date de fin de la période analysée */
|
||||
@NotNull(message = "La date de fin est obligatoire")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateFin;
|
||||
|
||||
/** Date de calcul de la métrique */
|
||||
@NotNull(message = "La date de calcul est obligatoire")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateCalcul;
|
||||
|
||||
/** Identifiant de l'organisation (optionnel pour filtrage) */
|
||||
private UUID organisationId;
|
||||
|
||||
/** Nom de l'organisation */
|
||||
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
|
||||
private String nomOrganisation;
|
||||
|
||||
/** Identifiant de l'utilisateur qui a demandé le calcul */
|
||||
private UUID utilisateurId;
|
||||
|
||||
/** 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")
|
||||
private String nomUtilisateur;
|
||||
|
||||
/** Libellé personnalisé de la métrique */
|
||||
@Size(max = 300, message = "Le libellé personnalisé ne peut pas dépasser 300 caractères")
|
||||
private String libellePersonnalise;
|
||||
|
||||
/** Description ou commentaire sur la métrique */
|
||||
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
|
||||
private String description;
|
||||
|
||||
/** 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")
|
||||
private String donneesDetaillees;
|
||||
|
||||
/** Configuration du graphique (couleurs, type, etc.) */
|
||||
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
|
||||
private String configurationGraphique;
|
||||
|
||||
/** Métadonnées additionnelles */
|
||||
private Map<String, Object> metadonnees;
|
||||
|
||||
/** Indicateur de fiabilité des données (0-100) */
|
||||
@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")
|
||||
@Digits(integer = 3, fraction = 1, message = "Format d'indicateur de fiabilité invalide")
|
||||
private BigDecimal indicateurFiabilite;
|
||||
|
||||
/** Nombre d'éléments analysés pour calculer cette métrique */
|
||||
@DecimalMin(value = "0", message = "Le nombre d'éléments doit être positif")
|
||||
private Integer nombreElementsAnalyses;
|
||||
|
||||
/** Temps de calcul en millisecondes */
|
||||
@DecimalMin(value = "0", message = "Le temps de calcul doit être positif")
|
||||
private Long tempsCalculMs;
|
||||
|
||||
/** Indicateur si la métrique est en temps réel */
|
||||
@Builder.Default
|
||||
private Boolean tempsReel = false;
|
||||
|
||||
/** Indicateur si la métrique nécessite une mise à jour */
|
||||
@Builder.Default
|
||||
private Boolean necessiteMiseAJour = false;
|
||||
|
||||
/** Niveau de priorité de la métrique (1=faible, 5=critique) */
|
||||
@DecimalMin(value = "1", message = "Le niveau de priorité minimum est 1")
|
||||
@DecimalMax(value = "5", message = "Le niveau de priorité maximum est 5")
|
||||
private Integer niveauPriorite;
|
||||
|
||||
/** Tags pour catégoriser la métrique */
|
||||
private List<String> tags;
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
|
||||
/**
|
||||
* Retourne le libellé à afficher (personnalisé ou par défaut)
|
||||
*
|
||||
* @return Le libellé à afficher
|
||||
*/
|
||||
public String getLibelleAffichage() {
|
||||
return libellePersonnalise != null && !libellePersonnalise.trim().isEmpty()
|
||||
? libellePersonnalise
|
||||
: typeMetrique.getLibelle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'unité de mesure de la métrique
|
||||
*
|
||||
* @return L'unité de mesure
|
||||
*/
|
||||
public String getUnite() {
|
||||
return typeMetrique.getUnite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône de la métrique
|
||||
*
|
||||
* @return L'icône Material Design
|
||||
*/
|
||||
public String getIcone() {
|
||||
return typeMetrique.getIcone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la couleur de la métrique
|
||||
*
|
||||
* @return Le code couleur hexadécimal
|
||||
*/
|
||||
public String getCouleur() {
|
||||
return typeMetrique.getCouleur();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la métrique a évolué positivement
|
||||
*
|
||||
* @return true si l'évolution est positive
|
||||
*/
|
||||
public boolean hasEvolutionPositive() {
|
||||
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la métrique a évolué négativement
|
||||
*
|
||||
* @return true si l'évolution est négative
|
||||
*/
|
||||
public boolean hasEvolutionNegative() {
|
||||
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la métrique est stable (pas d'évolution)
|
||||
*
|
||||
* @return true si l'évolution est nulle
|
||||
*/
|
||||
public boolean isStable() {
|
||||
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la tendance sous forme de texte
|
||||
*
|
||||
* @return "hausse", "baisse" ou "stable"
|
||||
*/
|
||||
public String getTendance() {
|
||||
if (hasEvolutionPositive())
|
||||
return "hausse";
|
||||
if (hasEvolutionNegative())
|
||||
return "baisse";
|
||||
return "stable";
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si les données sont fiables (indicateur > 80)
|
||||
*
|
||||
* @return true si les données sont considérées comme fiables
|
||||
*/
|
||||
public boolean isDonneesFiables() {
|
||||
return indicateurFiabilite != null
|
||||
&& indicateurFiabilite.compareTo(new BigDecimal("80.0")) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la métrique est critique (priorité >= 4)
|
||||
*
|
||||
* @return true si la métrique est critique
|
||||
*/
|
||||
public boolean isCritique() {
|
||||
return niveauPriorite != null && niveauPriorite >= 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructeur avec les champs essentiels
|
||||
*
|
||||
* @param typeMetrique Le type de métrique
|
||||
* @param periodeAnalyse La période d'analyse
|
||||
* @param valeur La valeur de la métrique
|
||||
*/
|
||||
public AnalyticsDataResponse(
|
||||
TypeMetrique typeMetrique, PeriodeAnalyse periodeAnalyse, BigDecimal valeur) {
|
||||
super();
|
||||
this.typeMetrique = typeMetrique;
|
||||
this.periodeAnalyse = periodeAnalyse;
|
||||
this.valeur = valeur;
|
||||
this.dateCalcul = LocalDateTime.now();
|
||||
this.dateDebut = periodeAnalyse.getDateDebut();
|
||||
this.dateFin = periodeAnalyse.getDateFin();
|
||||
this.tempsReel = false;
|
||||
this.necessiteMiseAJour = false;
|
||||
this.niveauPriorite = 3; // Priorité normale par défaut
|
||||
this.indicateurFiabilite = new BigDecimal("95.0"); // Fiabilité élevée par défaut
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
package dev.lions.unionflow.server.api.dto.analytics;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.TypeMetrique;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* position et ses données.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-16
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DashboardWidgetResponse extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Titre du widget */
|
||||
@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")
|
||||
private String titre;
|
||||
|
||||
/** Description du widget */
|
||||
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
|
||||
private String description;
|
||||
|
||||
/** Type de widget (kpi, chart, table, gauge, progress, text) */
|
||||
@NotBlank(message = "Le type de widget est obligatoire")
|
||||
@Size(max = 50, message = "Le type de widget ne peut pas dépasser 50 caractères")
|
||||
private String typeWidget;
|
||||
|
||||
/** Type de métrique affiché */
|
||||
private TypeMetrique typeMetrique;
|
||||
|
||||
/** Période d'analyse */
|
||||
private PeriodeAnalyse periodeAnalyse;
|
||||
|
||||
/** Identifiant de l'organisation (optionnel pour filtrage) */
|
||||
private UUID organisationId;
|
||||
|
||||
/** Nom de l'organisation */
|
||||
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
|
||||
private String nomOrganisation;
|
||||
|
||||
/** Identifiant de l'utilisateur propriétaire */
|
||||
@NotNull(message = "L'identifiant de l'utilisateur propriétaire est obligatoire")
|
||||
private UUID utilisateurProprietaireId;
|
||||
|
||||
/** Nom de l'utilisateur propriétaire */
|
||||
@Size(
|
||||
max = 200,
|
||||
message = "Le nom de l'utilisateur propriétaire ne peut pas dépasser 200 caractères")
|
||||
private String nomUtilisateurProprietaire;
|
||||
|
||||
/** Position X du widget sur la grille */
|
||||
@NotNull(message = "La position X est obligatoire")
|
||||
@DecimalMin(value = "0", message = "La position X doit être positive ou nulle")
|
||||
private Integer positionX;
|
||||
|
||||
/** Position Y du widget sur la grille */
|
||||
@NotNull(message = "La position Y est obligatoire")
|
||||
@DecimalMin(value = "0", message = "La position Y doit être positive ou nulle")
|
||||
private Integer positionY;
|
||||
|
||||
/** Largeur du widget (en unités de grille) */
|
||||
@NotNull(message = "La largeur est obligatoire")
|
||||
@DecimalMin(value = "1", message = "La largeur minimum est 1")
|
||||
@DecimalMax(value = "12", message = "La largeur maximum est 12")
|
||||
private Integer largeur;
|
||||
|
||||
/** Hauteur du widget (en unités de grille) */
|
||||
@NotNull(message = "La hauteur est obligatoire")
|
||||
@DecimalMin(value = "1", message = "La hauteur minimum est 1")
|
||||
@DecimalMax(value = "12", message = "La hauteur maximum est 12")
|
||||
private Integer hauteur;
|
||||
|
||||
/** Ordre d'affichage (z-index) */
|
||||
@DecimalMin(value = "0", message = "L'ordre d'affichage doit être positif ou nul")
|
||||
@Builder.Default
|
||||
private Integer ordreAffichage = 0;
|
||||
|
||||
/** Configuration visuelle du widget */
|
||||
@Size(max = 5000, message = "La configuration visuelle ne peut pas dépasser 5000 caractères")
|
||||
private String configurationVisuelle;
|
||||
|
||||
/** Couleur principale du widget */
|
||||
@Size(max = 7, message = "La couleur doit être au format #RRGGBB")
|
||||
private String couleurPrincipale;
|
||||
|
||||
/** Couleur secondaire du widget */
|
||||
@Size(max = 7, message = "La couleur secondaire doit être au format #RRGGBB")
|
||||
private String couleurSecondaire;
|
||||
|
||||
/** Icône du widget */
|
||||
@Size(max = 50, message = "L'icône ne peut pas dépasser 50 caractères")
|
||||
private String icone;
|
||||
|
||||
/** Indicateur si le widget est visible */
|
||||
@Builder.Default private Boolean visible = true;
|
||||
|
||||
/** Indicateur si le widget est redimensionnable */
|
||||
@Builder.Default private Boolean redimensionnable = true;
|
||||
|
||||
/** Indicateur si le widget est déplaçable */
|
||||
@Builder.Default private Boolean deplacable = true;
|
||||
|
||||
/** Indicateur si le widget peut être supprimé */
|
||||
@Builder.Default private Boolean supprimable = true;
|
||||
|
||||
/** Indicateur si le widget se met à jour automatiquement */
|
||||
@Builder.Default private Boolean miseAJourAutomatique = true;
|
||||
|
||||
/** Fréquence de mise à jour en secondes */
|
||||
@DecimalMin(value = "30", message = "La fréquence minimum est 30 secondes")
|
||||
@Builder.Default
|
||||
private Integer frequenceMiseAJourSecondes = 300; // 5 minutes par défaut
|
||||
|
||||
/** Date de dernière mise à jour des données */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDerniereMiseAJour;
|
||||
|
||||
/** Prochaine mise à jour programmée */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime prochaineMiseAJour;
|
||||
|
||||
/** Données du widget (format JSON) */
|
||||
@Size(max = 50000, message = "Les données du widget ne peuvent pas dépasser 50000 caractères")
|
||||
private String donneesWidget;
|
||||
|
||||
/** Configuration des filtres */
|
||||
private Map<String, Object> configurationFiltres;
|
||||
|
||||
/** Configuration des alertes */
|
||||
private Map<String, Object> configurationAlertes;
|
||||
|
||||
/** Seuil d'alerte bas */
|
||||
private Double seuilAlerteBas;
|
||||
|
||||
/** Seuil d'alerte haut */
|
||||
private Double seuilAlerteHaut;
|
||||
|
||||
/** Indicateur si une alerte est active */
|
||||
@Builder.Default private Boolean alerteActive = false;
|
||||
|
||||
/** Message d'alerte actuel */
|
||||
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
|
||||
private String messageAlerte;
|
||||
|
||||
/** Type d'alerte (info, warning, error, success) */
|
||||
@Size(max = 20, message = "Le type d'alerte ne peut pas dépasser 20 caractères")
|
||||
private String typeAlerte;
|
||||
|
||||
/** Permissions d'accès au widget */
|
||||
@Size(max = 1000, message = "Les permissions ne peuvent pas dépasser 1000 caractères")
|
||||
private String permissions;
|
||||
|
||||
/** Rôles autorisés à voir le widget */
|
||||
@Size(max = 500, message = "Les rôles autorisés ne peuvent pas dépasser 500 caractères")
|
||||
private String rolesAutorises;
|
||||
|
||||
/** Template personnalisé du widget */
|
||||
@Size(max = 10000, message = "Le template personnalisé ne peut pas dépasser 10000 caractères")
|
||||
private String templatePersonnalise;
|
||||
|
||||
/** CSS personnalisé du widget */
|
||||
@Size(max = 5000, message = "Le CSS personnalisé ne peut pas dépasser 5000 caractères")
|
||||
private String cssPersonnalise;
|
||||
|
||||
/** JavaScript personnalisé du widget */
|
||||
@Size(max = 10000, message = "Le JavaScript personnalisé ne peut pas dépasser 10000 caractères")
|
||||
private String javascriptPersonnalise;
|
||||
|
||||
/** Métadonnées additionnelles */
|
||||
private Map<String, Object> metadonnees;
|
||||
|
||||
/** Nombre de vues du widget */
|
||||
@DecimalMin(value = "0", message = "Le nombre de vues doit être positif")
|
||||
@Builder.Default
|
||||
private Long nombreVues = 0L;
|
||||
|
||||
/** Nombre d'interactions avec le widget */
|
||||
@DecimalMin(value = "0", message = "Le nombre d'interactions doit être positif")
|
||||
@Builder.Default
|
||||
private Long nombreInteractions = 0L;
|
||||
|
||||
/** Temps moyen passé sur le widget (en secondes) */
|
||||
@DecimalMin(value = "0", message = "Le temps moyen doit être positif")
|
||||
private Integer tempsMoyenSecondes;
|
||||
|
||||
/** Taux d'erreur du widget (en pourcentage) */
|
||||
@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%")
|
||||
@Builder.Default
|
||||
private Double tauxErreur = 0.0;
|
||||
|
||||
/** Date de dernière erreur */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDerniereErreur;
|
||||
|
||||
/** Message de dernière erreur */
|
||||
@Size(max = 1000, message = "Le message d'erreur ne peut pas dépasser 1000 caractères")
|
||||
private String messageDerniereErreur;
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
|
||||
/**
|
||||
* Retourne le libellé de la métrique si définie
|
||||
*
|
||||
* @return Le libellé de la métrique ou null
|
||||
*/
|
||||
public String getLibelleMetrique() {
|
||||
return typeMetrique != null ? typeMetrique.getLibelle() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'unité de mesure si métrique définie
|
||||
*
|
||||
* @return L'unité de mesure ou chaîne vide
|
||||
*/
|
||||
public String getUnite() {
|
||||
return typeMetrique != null ? typeMetrique.getUnite() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône de la métrique ou l'icône personnalisée
|
||||
*
|
||||
* @return L'icône à afficher
|
||||
*/
|
||||
public String getIconeAffichage() {
|
||||
if (icone != null && !icone.trim().isEmpty()) {
|
||||
return icone;
|
||||
}
|
||||
return typeMetrique != null ? typeMetrique.getIcone() : "dashboard";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la couleur de la métrique ou la couleur personnalisée
|
||||
*
|
||||
* @return La couleur à utiliser
|
||||
*/
|
||||
public String getCouleurAffichage() {
|
||||
if (couleurPrincipale != null && !couleurPrincipale.trim().isEmpty()) {
|
||||
return couleurPrincipale;
|
||||
}
|
||||
return typeMetrique != null ? typeMetrique.getCouleur() : "#757575";
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le widget nécessite une mise à jour
|
||||
*
|
||||
* @return true si une mise à jour est nécessaire
|
||||
*/
|
||||
public boolean necessiteMiseAJour() {
|
||||
return miseAJourAutomatique
|
||||
&& prochaineMiseAJour != null
|
||||
&& prochaineMiseAJour.isBefore(LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le widget est interactif
|
||||
*
|
||||
* @return true si le widget permet des interactions
|
||||
*/
|
||||
public boolean isInteractif() {
|
||||
return "chart".equals(typeWidget) || "table".equals(typeWidget) || "gauge".equals(typeWidget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le widget affiche des données 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). */
|
||||
private boolean isFrequenceTempsReel() {
|
||||
if (frequenceMiseAJourSecondes == null) return false;
|
||||
return frequenceMiseAJourSecondes <= 60;
|
||||
}
|
||||
|
||||
public boolean isTempsReel() {
|
||||
return isFrequenceTempsReel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la taille du widget (surface occupée)
|
||||
*
|
||||
* @return La surface en unités de grille
|
||||
*/
|
||||
public int getTailleWidget() {
|
||||
return largeur * hauteur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le widget est grand (surface > 6)
|
||||
*
|
||||
* @return true si le widget est considéré comme grand
|
||||
*/
|
||||
public boolean isWidgetGrand() {
|
||||
return getTailleWidget() > 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le widget a des erreurs récentes (< 24h)
|
||||
*
|
||||
* @return true si des erreurs récentes sont détectées
|
||||
*/
|
||||
public boolean hasErreursRecentes() {
|
||||
return dateDerniereErreur != null
|
||||
&& dateDerniereErreur.isAfter(LocalDateTime.now().minusHours(24));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le statut du widget
|
||||
*
|
||||
* @return "actif", "erreur", "inactif" ou "maintenance"
|
||||
*/
|
||||
/** Indique si le taux d'erreur déclenche le statut maintenance (pour couverture branches). */
|
||||
private boolean isTauxErreurMaintenance() {
|
||||
if (tauxErreur == null) return false;
|
||||
return tauxErreur > 10.0;
|
||||
}
|
||||
|
||||
public String getStatutWidget() {
|
||||
if (hasErreursRecentes()) return "erreur";
|
||||
if (!visible) return "inactif";
|
||||
if (isTauxErreurMaintenance()) return "maintenance";
|
||||
return "actif";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package dev.lions.unionflow.server.api.dto.analytics;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.TypeMetrique;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* générer des graphiques de tendance.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-16
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class KPITrendResponse extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Type de métrique pour cette tendance */
|
||||
@NotNull(message = "Le type de métrique est obligatoire")
|
||||
private TypeMetrique typeMetrique;
|
||||
|
||||
/** Période d'analyse globale */
|
||||
@NotNull(message = "La période d'analyse est obligatoire")
|
||||
private PeriodeAnalyse periodeAnalyse;
|
||||
|
||||
/** Identifiant de l'organisation (optionnel) */
|
||||
private UUID organisationId;
|
||||
|
||||
/** Nom de l'organisation */
|
||||
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
|
||||
private String nomOrganisation;
|
||||
|
||||
/** Date de début de la période analysée */
|
||||
@NotNull(message = "La date de début est obligatoire")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDebut;
|
||||
|
||||
/** Date de fin de la période analysée */
|
||||
@NotNull(message = "La date de fin est obligatoire")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateFin;
|
||||
|
||||
/** Points de données pour la tendance */
|
||||
@NotNull(message = "Les points de données sont obligatoires")
|
||||
private List<PointDonneeDTO> pointsDonnees;
|
||||
|
||||
/** Valeur actuelle du KPI */
|
||||
@NotNull(message = "La valeur actuelle est obligatoire")
|
||||
@DecimalMin(value = "0.0", message = "La valeur actuelle doit être positive ou nulle")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de valeur actuelle invalide")
|
||||
private BigDecimal valeurActuelle;
|
||||
|
||||
/** Valeur minimale sur la période */
|
||||
@DecimalMin(value = "0.0", message = "La valeur minimale doit être positive ou nulle")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de valeur minimale invalide")
|
||||
private BigDecimal valeurMinimale;
|
||||
|
||||
/** Valeur maximale sur la période */
|
||||
@DecimalMin(value = "0.0", message = "La valeur maximale doit être positive ou nulle")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de valeur maximale invalide")
|
||||
private BigDecimal valeurMaximale;
|
||||
|
||||
/** Valeur moyenne sur la période */
|
||||
@DecimalMin(value = "0.0", message = "La valeur moyenne doit être positive ou nulle")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de valeur moyenne invalide")
|
||||
private BigDecimal valeurMoyenne;
|
||||
|
||||
/** Écart-type des valeurs */
|
||||
@DecimalMin(value = "0.0", message = "L'écart-type doit être positif ou nul")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format d'écart-type invalide")
|
||||
private BigDecimal ecartType;
|
||||
|
||||
/** Coefficient de variation (écart-type / moyenne) */
|
||||
@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")
|
||||
private BigDecimal coefficientVariation;
|
||||
|
||||
/** Tendance générale (pente de la régression linéaire) */
|
||||
@Digits(integer = 10, fraction = 6, message = "Format de tendance invalide")
|
||||
private BigDecimal tendanceGenerale;
|
||||
|
||||
/** Coefficient de corrélation R² */
|
||||
@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")
|
||||
@Digits(integer = 1, fraction = 6, message = "Format de coefficient de corrélation invalide")
|
||||
private BigDecimal coefficientCorrelation;
|
||||
|
||||
/** Pourcentage d'évolution depuis le début de la période */
|
||||
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
|
||||
private BigDecimal pourcentageEvolutionGlobale;
|
||||
|
||||
/** Prédiction pour la prochaine période */
|
||||
@DecimalMin(value = "0.0", message = "La prédiction doit être positive ou nulle")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de prédiction invalide")
|
||||
private BigDecimal predictionProchainePeriode;
|
||||
|
||||
/** Marge d'erreur de la prédiction (en pourcentage) */
|
||||
@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%")
|
||||
@Digits(integer = 3, fraction = 2, message = "Format de marge d'erreur invalide")
|
||||
private BigDecimal margeErreurPrediction;
|
||||
|
||||
/** Seuil d'alerte bas */
|
||||
@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")
|
||||
private BigDecimal seuilAlerteBas;
|
||||
|
||||
/** Seuil d'alerte haut */
|
||||
@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")
|
||||
private BigDecimal seuilAlerteHaut;
|
||||
|
||||
/** Indicateur si une alerte est active */
|
||||
@Builder.Default private Boolean alerteActive = false;
|
||||
|
||||
/** Type d'alerte (bas, haut, anomalie) */
|
||||
@Size(max = 50, message = "Le type d'alerte ne peut pas dépasser 50 caractères")
|
||||
private String typeAlerte;
|
||||
|
||||
/** Message d'alerte */
|
||||
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
|
||||
private String messageAlerte;
|
||||
|
||||
/** Configuration du graphique (couleurs, style, etc.) */
|
||||
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
|
||||
private String configurationGraphique;
|
||||
|
||||
/** Intervalle de regroupement des données */
|
||||
@Size(max = 20, message = "L'intervalle de regroupement ne peut pas dépasser 20 caractères")
|
||||
private String intervalleRegroupement;
|
||||
|
||||
/** Format d'affichage des dates */
|
||||
@Size(max = 20, message = "Le format de date ne peut pas dépasser 20 caractères")
|
||||
private String formatDate;
|
||||
|
||||
/** Date de dernière mise à jour */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDerniereMiseAJour;
|
||||
|
||||
/** Fréquence de mise à jour en minutes */
|
||||
@DecimalMin(value = "1", message = "La fréquence de mise à jour minimum est 1 minute")
|
||||
private Integer frequenceMiseAJourMinutes;
|
||||
|
||||
// === CLASSES INTERNES ===
|
||||
|
||||
/** Classe interne représentant un point de données dans la tendance */
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class PointDonneeDTO {
|
||||
|
||||
/** Date du point de données */
|
||||
@NotNull(message = "La date du point de données est obligatoire")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime date;
|
||||
|
||||
/** Valeur du point de données */
|
||||
@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")
|
||||
@Digits(integer = 15, fraction = 4, message = "Format de valeur du point invalide")
|
||||
private BigDecimal valeur;
|
||||
|
||||
/** Libellé du point (optionnel) */
|
||||
@Size(max = 100, message = "Le libellé du point ne peut pas dépasser 100 caractères")
|
||||
private String libelle;
|
||||
|
||||
/** Indicateur si le point est une anomalie */
|
||||
@Builder.Default private Boolean anomalie = false;
|
||||
|
||||
/** Indicateur si le point est une prédiction */
|
||||
@Builder.Default private Boolean prediction = false;
|
||||
|
||||
/** Métadonnées additionnelles du point */
|
||||
private String metadonnees;
|
||||
}
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
|
||||
/**
|
||||
* Retourne le libellé de la métrique
|
||||
*
|
||||
* @return Le libellé de la métrique
|
||||
*/
|
||||
public String getLibelleMetrique() {
|
||||
return typeMetrique.getLibelle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'unité de mesure
|
||||
*
|
||||
* @return L'unité de mesure
|
||||
*/
|
||||
public String getUnite() {
|
||||
return typeMetrique.getUnite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône de la métrique
|
||||
*
|
||||
* @return L'icône Material Design
|
||||
*/
|
||||
public String getIcone() {
|
||||
return typeMetrique.getIcone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la couleur de la métrique
|
||||
*
|
||||
* @return Le code couleur hexadécimal
|
||||
*/
|
||||
public String getCouleur() {
|
||||
return typeMetrique.getCouleur();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la tendance est positive
|
||||
*
|
||||
* @return true si la tendance générale est positive
|
||||
*/
|
||||
public boolean isTendancePositive() {
|
||||
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la tendance est négative
|
||||
*
|
||||
* @return true si la tendance générale est négative
|
||||
*/
|
||||
public boolean isTendanceNegative() {
|
||||
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la tendance est stable
|
||||
*
|
||||
* @return true si la tendance générale est stable
|
||||
*/
|
||||
public boolean isTendanceStable() {
|
||||
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la volatilité du KPI (basée sur le coefficient de variation)
|
||||
*
|
||||
* @return "faible", "moyenne" ou "élevée"
|
||||
*/
|
||||
public String getVolatilite() {
|
||||
if (coefficientVariation == null) return "inconnue";
|
||||
|
||||
BigDecimal cv = coefficientVariation;
|
||||
if (cv.compareTo(new BigDecimal("0.1")) <= 0) return "faible";
|
||||
if (cv.compareTo(new BigDecimal("0.3")) <= 0) return "moyenne";
|
||||
return "élevée";
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la prédiction est fiable (R² > 0.7)
|
||||
*
|
||||
* @return true si la prédiction est considérée comme fiable
|
||||
*/
|
||||
public boolean isPredictionFiable() {
|
||||
return coefficientCorrelation != null
|
||||
&& coefficientCorrelation.compareTo(new BigDecimal("0.7")) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le nombre de points de données
|
||||
*
|
||||
* @return Le nombre de points de données
|
||||
*/
|
||||
public int getNombrePointsDonnees() {
|
||||
return pointsDonnees != null ? pointsDonnees.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si des anomalies ont été détectées
|
||||
*
|
||||
* @return true si au moins un point est marqué comme anomalie
|
||||
*/
|
||||
public boolean hasAnomalies() {
|
||||
return pointsDonnees != null
|
||||
&& pointsDonnees.stream().anyMatch(point -> Boolean.TRUE.equals(point.getAnomalie()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
package dev.lions.unionflow.server.api.dto.analytics;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.PeriodeAnalyse;
|
||||
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* ses paramètres d'export.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-16
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReportConfigDTO extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Nom du rapport */
|
||||
@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")
|
||||
private String nom;
|
||||
|
||||
/** Description du rapport */
|
||||
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
|
||||
private String description;
|
||||
|
||||
/** Type de rapport (executif, analytique, technique, operationnel) */
|
||||
@NotBlank(message = "Le type de rapport est obligatoire")
|
||||
@Size(max = 50, message = "Le type de rapport ne peut pas dépasser 50 caractères")
|
||||
private String typeRapport;
|
||||
|
||||
/** Période d'analyse par défaut */
|
||||
@NotNull(message = "La période d'analyse est obligatoire")
|
||||
private PeriodeAnalyse periodeAnalyse;
|
||||
|
||||
/** Date de début personnalisée (si période personnalisée) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDebutPersonnalisee;
|
||||
|
||||
/** Date de fin personnalisée (si période personnalisée) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateFinPersonnalisee;
|
||||
|
||||
/** Identifiant de l'organisation (optionnel pour filtrage) */
|
||||
private UUID organisationId;
|
||||
|
||||
/** Nom de l'organisation */
|
||||
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
|
||||
private String nomOrganisation;
|
||||
|
||||
/** Identifiant de l'utilisateur créateur */
|
||||
@NotNull(message = "L'identifiant de l'utilisateur créateur est obligatoire")
|
||||
private UUID utilisateurCreateurId;
|
||||
|
||||
/** 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")
|
||||
private String nomUtilisateurCreateur;
|
||||
|
||||
/** Métriques incluses dans le rapport */
|
||||
@NotNull(message = "Les métriques sont obligatoires")
|
||||
@Valid
|
||||
private List<MetriqueConfigDTO> metriques;
|
||||
|
||||
/** Sections du rapport */
|
||||
@Valid private List<SectionRapportDTO> sections;
|
||||
|
||||
/** Format d'export par défaut */
|
||||
@NotNull(message = "Le format d'export est obligatoire")
|
||||
private FormatExport formatExport;
|
||||
|
||||
/** Formats d'export autorisés */
|
||||
private List<FormatExport> formatsExportAutorises;
|
||||
|
||||
/** Modèle de rapport à utiliser */
|
||||
@Size(max = 100, message = "Le modèle de rapport ne peut pas dépasser 100 caractères")
|
||||
private String modeleRapport;
|
||||
|
||||
/** Configuration de la mise en page */
|
||||
@Size(
|
||||
max = 2000,
|
||||
message = "La configuration de mise en page ne peut pas dépasser 2000 caractères")
|
||||
private String configurationMiseEnPage;
|
||||
|
||||
/** Logo personnalisé (URL ou base64) */
|
||||
@Size(max = 5000, message = "Le logo personnalisé ne peut pas dépasser 5000 caractères")
|
||||
private String logoPersonnalise;
|
||||
|
||||
/** Couleurs personnalisées du rapport */
|
||||
private Map<String, String> couleursPersonnalisees;
|
||||
|
||||
/** Indicateur si le rapport est public */
|
||||
@Builder.Default private Boolean rapportPublic = false;
|
||||
|
||||
/** Indicateur si le rapport est automatique */
|
||||
@Builder.Default private Boolean rapportAutomatique = false;
|
||||
|
||||
/** Fréquence de génération automatique (en heures) */
|
||||
@DecimalMin(value = "1", message = "La fréquence minimum est 1 heure")
|
||||
private Integer frequenceGenerationHeures;
|
||||
|
||||
/** Prochaine génération automatique */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime prochaineGeneration;
|
||||
|
||||
/** Liste des destinataires pour l'envoi automatique */
|
||||
private List<String> destinatairesEmail;
|
||||
|
||||
/** 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")
|
||||
private String objetEmail;
|
||||
|
||||
/** 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")
|
||||
private String corpsEmail;
|
||||
|
||||
/** Paramètres de filtrage avancé */
|
||||
private Map<String, Object> parametresFiltrage;
|
||||
|
||||
/** Tags pour catégoriser le rapport */
|
||||
private List<String> tags;
|
||||
|
||||
/** Niveau de confidentialité (1=public, 5=confidentiel) */
|
||||
@DecimalMin(value = "1", message = "Le niveau de confidentialité minimum est 1")
|
||||
@DecimalMax(value = "5", message = "Le niveau de confidentialité maximum est 5")
|
||||
@Builder.Default
|
||||
private Integer niveauConfidentialite = 1;
|
||||
|
||||
/** Date de dernière génération */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateDerniereGeneration;
|
||||
|
||||
/** Nombre de générations effectuées */
|
||||
@DecimalMin(value = "0", message = "Le nombre de générations doit être positif")
|
||||
@Builder.Default
|
||||
private Integer nombreGenerations = 0;
|
||||
|
||||
/** Taille moyenne des rapports générés (en KB) */
|
||||
@DecimalMin(value = "0", message = "La taille moyenne doit être positive")
|
||||
private Long tailleMoyenneKB;
|
||||
|
||||
/** Temps moyen de génération (en secondes) */
|
||||
@DecimalMin(value = "0", message = "Le temps moyen de génération doit être positif")
|
||||
private Integer tempsMoyenGenerationSecondes;
|
||||
|
||||
// === CLASSES INTERNES ===
|
||||
|
||||
/** Configuration d'une métrique dans le rapport */
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class MetriqueConfigDTO {
|
||||
|
||||
/** Type de métrique */
|
||||
@NotNull(message = "Le type de métrique est obligatoire")
|
||||
private TypeMetrique typeMetrique;
|
||||
|
||||
/** Libellé personnalisé */
|
||||
@Size(max = 200, message = "Le libellé personnalisé ne peut pas dépasser 200 caractères")
|
||||
private String libellePersonnalise;
|
||||
|
||||
/** Position dans le rapport (ordre d'affichage) */
|
||||
@DecimalMin(value = "1", message = "La position minimum est 1")
|
||||
private Integer position;
|
||||
|
||||
/** Taille d'affichage (1=petit, 2=moyen, 3=grand) */
|
||||
@DecimalMin(value = "1", message = "La taille minimum est 1")
|
||||
@DecimalMax(value = "3", message = "La taille maximum est 3")
|
||||
@Builder.Default
|
||||
private Integer tailleAffichage = 2;
|
||||
|
||||
/** Couleur personnalisée */
|
||||
@Size(max = 7, message = "La couleur doit être au format #RRGGBB")
|
||||
private String couleurPersonnalisee;
|
||||
|
||||
/** Indicateur si la métrique inclut un graphique */
|
||||
@Builder.Default private Boolean inclureGraphique = true;
|
||||
|
||||
/** Type de graphique (line, bar, pie, area) */
|
||||
@Size(max = 20, message = "Le type de graphique ne peut pas dépasser 20 caractères")
|
||||
@Builder.Default
|
||||
private String typeGraphique = "line";
|
||||
|
||||
/** Indicateur si la métrique inclut la tendance */
|
||||
@Builder.Default private Boolean inclureTendance = true;
|
||||
|
||||
/** Indicateur si la métrique inclut la comparaison */
|
||||
@Builder.Default private Boolean inclureComparaison = true;
|
||||
|
||||
/** Seuils d'alerte personnalisés */
|
||||
private Map<String, Object> seuilsAlerte;
|
||||
|
||||
/** Filtres spécifiques à cette métrique */
|
||||
private Map<String, Object> filtresSpecifiques;
|
||||
}
|
||||
|
||||
/** Configuration d'une section du rapport */
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SectionRapportDTO {
|
||||
|
||||
/** Nom de la section */
|
||||
@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")
|
||||
private String nom;
|
||||
|
||||
/** Description de la section */
|
||||
@Size(max = 500, message = "La description de la section ne peut pas dépasser 500 caractères")
|
||||
private String description;
|
||||
|
||||
/** Position de la section dans le rapport */
|
||||
@DecimalMin(value = "1", message = "La position minimum est 1")
|
||||
private Integer position;
|
||||
|
||||
/** Type de section (resume, metriques, graphiques, tableaux, analyse) */
|
||||
@NotBlank(message = "Le type de section est obligatoire")
|
||||
@Size(max = 50, message = "Le type de section ne peut pas dépasser 50 caractères")
|
||||
private String typeSection;
|
||||
|
||||
/** Métriques incluses dans cette section */
|
||||
private List<TypeMetrique> metriquesIncluses;
|
||||
|
||||
/** Configuration spécifique de la section */
|
||||
private Map<String, Object> configurationSection;
|
||||
|
||||
/** Indicateur si la section est visible */
|
||||
@Builder.Default private Boolean visible = true;
|
||||
|
||||
/** Indicateur si la section peut être réduite */
|
||||
@Builder.Default private Boolean pliable = false;
|
||||
}
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
|
||||
/**
|
||||
* Retourne le nombre de métriques configurées
|
||||
*
|
||||
* @return Le nombre de métriques
|
||||
*/
|
||||
public int getNombreMetriques() {
|
||||
return metriques != null ? metriques.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le nombre de sections configurées
|
||||
*
|
||||
* @return Le nombre de sections
|
||||
*/
|
||||
public int getNombreSections() {
|
||||
return sections != null ? sections.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le rapport utilise une période personnalisée
|
||||
*
|
||||
* @return true si la période est personnalisée
|
||||
*/
|
||||
public boolean isPeriodePersonnalisee() {
|
||||
return periodeAnalyse == PeriodeAnalyse.PERIODE_PERSONNALISEE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le rapport est confidentiel (niveau >= 4)
|
||||
*
|
||||
* @return true si le rapport est confidentiel
|
||||
*/
|
||||
/** Indique si le niveau de confidentialité est élevé (pour couverture branches). */
|
||||
private boolean isNiveauConfidentiel() {
|
||||
if (niveauConfidentialite == null) return false;
|
||||
return niveauConfidentialite >= 4;
|
||||
}
|
||||
|
||||
public boolean isConfidentiel() {
|
||||
return isNiveauConfidentiel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le rapport nécessite une génération
|
||||
*
|
||||
* @return true si la prochaine génération est due
|
||||
*/
|
||||
public boolean necessiteGeneration() {
|
||||
return rapportAutomatique
|
||||
&& prochaineGeneration != null
|
||||
&& prochaineGeneration.isBefore(LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la fréquence de génération en texte
|
||||
*
|
||||
* @return La fréquence sous forme de texte
|
||||
*/
|
||||
public String getFrequenceTexte() {
|
||||
if (frequenceGenerationHeures == null) return "Manuelle";
|
||||
|
||||
return switch (frequenceGenerationHeures) {
|
||||
case 1 -> "Toutes les heures";
|
||||
case 24 -> "Quotidienne";
|
||||
case 168 -> "Hebdomadaire"; // 24 * 7
|
||||
case 720 -> "Mensuelle"; // 24 * 30
|
||||
default -> "Toutes les " + frequenceGenerationHeures + " heures";
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package dev.lions.unionflow.server.api.dto.auth.request;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête d'authentification utilisateur.
|
||||
*
|
||||
* @param username Email ou nom d'utilisateur
|
||||
* @param password Mot de passe
|
||||
* @param typeCompte Type de compte (MEMBRE, ADMIN, etc.)
|
||||
* @param rememberMe Se souvenir de moi
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
* @since 2026-02-28
|
||||
*/
|
||||
@Builder
|
||||
public record LoginRequest(
|
||||
@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")
|
||||
String username,
|
||||
|
||||
@NotBlank(message = "Le mot de passe est requis")
|
||||
@Size(min = 6, message = "Le mot de passe doit contenir au moins 6 caractères")
|
||||
String password,
|
||||
|
||||
@NotBlank(message = "Le type de compte est requis")
|
||||
String typeCompte,
|
||||
|
||||
Boolean rememberMe) {
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package dev.lions.unionflow.server.api.dto.auth.response;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse d'authentification contenant le token JWT et les informations utilisateur.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
* @since 2026-02-28
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginResponse {
|
||||
|
||||
private String accessToken;
|
||||
private String refreshToken;
|
||||
@Builder.Default
|
||||
private String tokenType = "Bearer";
|
||||
private Long expiresIn;
|
||||
private LocalDateTime expirationDate;
|
||||
private UserInfo user;
|
||||
|
||||
/**
|
||||
* Vérifie si le token est expiré.
|
||||
*
|
||||
* @return true si le token est expiré
|
||||
*/
|
||||
public boolean isExpired() {
|
||||
return expirationDate != null && LocalDateTime.now().isAfter(expirationDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Informations de l'utilisateur connecté.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class UserInfo {
|
||||
private UUID id;
|
||||
private String nom;
|
||||
private String prenom;
|
||||
private String email;
|
||||
private String username;
|
||||
private String typeCompte;
|
||||
private List<String> roles;
|
||||
private List<String> permissions;
|
||||
private EntiteInfo entite;
|
||||
|
||||
/**
|
||||
* Retourne le nom complet de l'utilisateur.
|
||||
*
|
||||
* @return Prénom + Nom ou nom d'utilisateur si absent
|
||||
*/
|
||||
public String getNomComplet() {
|
||||
if (prenom != null && nom != null) {
|
||||
return prenom + " " + nom;
|
||||
}
|
||||
return nom != null ? nom : username;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informations sur l'entité (organisation/membre) de l'utilisateur.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class EntiteInfo {
|
||||
private UUID id;
|
||||
private String nom;
|
||||
private String type;
|
||||
private String pays;
|
||||
private String ville;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package dev.lions.unionflow.server.api.dto.ayantdroit;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Past;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AyantDroitRequest {
|
||||
|
||||
@NotBlank(message = "L'Id du membre principal rattaché est obligatoire")
|
||||
private String membrePrincipalId;
|
||||
|
||||
@NotBlank(message = "Le prénom est obligatoire")
|
||||
private String prenom;
|
||||
|
||||
@NotBlank(message = "Le nom est obligatoire")
|
||||
private String nom;
|
||||
|
||||
@NotNull(message = "La date de naissance est obligatoire pour l'âge limite")
|
||||
@Past(message = "La date de naissance doit être dans le passé")
|
||||
private LocalDate dateNaissance;
|
||||
|
||||
private String sexe;
|
||||
|
||||
private String pieceIdentite;
|
||||
|
||||
@NotNull(message = "Le lien de parenté / bénéfice est requis")
|
||||
private LienParente lienParente;
|
||||
|
||||
// Id document du livret de famille ou certificat médical / scolaire
|
||||
private String justificatifLienId;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package dev.lions.unionflow.server.api.dto.ayantdroit;
|
||||
|
||||
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.StatutAyantDroit;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AyantDroitResponse extends BaseDTO {
|
||||
|
||||
private String membrePrincipalId;
|
||||
|
||||
private String numeroCarteBeneficiaire;
|
||||
|
||||
private String prenom;
|
||||
private String nom;
|
||||
|
||||
private LocalDate dateNaissance;
|
||||
private Integer ageActuel;
|
||||
private String sexe;
|
||||
private String pieceIdentite;
|
||||
|
||||
private LienParente lienParente;
|
||||
|
||||
// Prise en charge (%) par rapport à la couverture du Membre Principal
|
||||
private BigDecimal pourcentageCouvertureSante;
|
||||
|
||||
private StatutAyantDroit statut;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package dev.lions.unionflow.server.api.dto.backup.request;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Request pour créer une sauvegarde
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateBackupRequest {
|
||||
|
||||
@NotBlank(message = "Le nom de la sauvegarde est requis")
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
private String type; // AUTO, MANUAL, RESTORE_POINT
|
||||
|
||||
private Boolean includeDatabase;
|
||||
private Boolean includeFiles;
|
||||
private Boolean includeConfiguration;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package dev.lions.unionflow.server.api.dto.backup.request;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Request pour restaurer une sauvegarde
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RestoreBackupRequest {
|
||||
|
||||
@NotNull(message = "L'ID de la sauvegarde est requis")
|
||||
private UUID backupId;
|
||||
|
||||
private Boolean restoreDatabase;
|
||||
private Boolean restoreFiles;
|
||||
private Boolean restoreConfiguration;
|
||||
|
||||
private Boolean createRestorePoint; // Créer un point de restauration avant
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.lions.unionflow.server.api.dto.backup.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Request pour mettre à jour la configuration des sauvegardes automatiques
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateBackupConfigRequest {
|
||||
|
||||
private Boolean autoBackupEnabled;
|
||||
private String frequency; // HOURLY, DAILY, WEEKLY
|
||||
private String retention; // "7 jours", "30 jours", "90 jours", "1 an"
|
||||
private Integer retentionDays;
|
||||
private String backupTime; // Format HH:mm pour sauvegarde quotidienne
|
||||
private Boolean includeDatabase;
|
||||
private Boolean includeFiles;
|
||||
private Boolean includeConfiguration;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.backup.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Response contenant la configuration des sauvegardes automatiques
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BackupConfigResponse {
|
||||
|
||||
private Boolean autoBackupEnabled;
|
||||
private String frequency; // HOURLY, DAILY, WEEKLY
|
||||
private String retention; // "7 jours", "30 jours", etc.
|
||||
private Integer retentionDays;
|
||||
private String backupTime; // HH:mm
|
||||
private Boolean includeDatabase;
|
||||
private Boolean includeFiles;
|
||||
private Boolean includeConfiguration;
|
||||
|
||||
private LocalDateTime lastBackup;
|
||||
private LocalDateTime nextScheduledBackup;
|
||||
private Integer totalBackups;
|
||||
private Long totalSizeBytes;
|
||||
private String totalSizeFormatted;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package dev.lions.unionflow.server.api.dto.backup.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Response représentant une sauvegarde
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BackupResponse {
|
||||
|
||||
private UUID id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String type; // AUTO, MANUAL, RESTORE_POINT
|
||||
private Long sizeBytes;
|
||||
private String sizeFormatted; // ex: "2.3 GB"
|
||||
private String status; // PENDING, IN_PROGRESS, COMPLETED, FAILED
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime completedAt;
|
||||
private String createdBy;
|
||||
|
||||
private Boolean includesDatabase;
|
||||
private Boolean includesFiles;
|
||||
private Boolean includesConfiguration;
|
||||
|
||||
private String filePath;
|
||||
private String errorMessage; // Si status = FAILED
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package dev.lions.unionflow.server.api.dto.base;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Classe de base pour tous les DTOs UnionFlow Fournit les propriétés communes
|
||||
* d'audit et de gestion
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-10
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class BaseDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Identifiant unique UUID */
|
||||
private UUID id;
|
||||
|
||||
/** Date de création de l'enregistrement */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
public LocalDateTime dateCreation;
|
||||
|
||||
/** Date de dernière modification */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
public LocalDateTime dateModification;
|
||||
|
||||
/** Utilisateur qui a créé l'enregistrement */
|
||||
private String creePar;
|
||||
|
||||
/** Utilisateur qui a modifié l'enregistrement en dernier */
|
||||
private String modifiePar;
|
||||
|
||||
/** Version pour gestion de la concurrence optimiste */
|
||||
private Long version;
|
||||
|
||||
/** Indicateur si l'enregistrement est actif */
|
||||
private Boolean actif;
|
||||
|
||||
// Constructeur par défaut
|
||||
public BaseDTO() {
|
||||
this.dateCreation = LocalDateTime.now();
|
||||
this.actif = true;
|
||||
this.version = 0L;
|
||||
}
|
||||
|
||||
// Getters et Setters générés automatiquement par Lombok @Getter/@Setter
|
||||
|
||||
// Méthodes utilitaires
|
||||
|
||||
/**
|
||||
* Marque l'entité comme nouvellement créée
|
||||
*
|
||||
* @param utilisateur L'utilisateur qui crée l'entité
|
||||
*/
|
||||
public void marquerCommeNouveau(String utilisateur) {
|
||||
LocalDateTime maintenant = LocalDateTime.now();
|
||||
this.dateCreation = maintenant;
|
||||
this.dateModification = maintenant;
|
||||
this.creePar = utilisateur;
|
||||
this.modifiePar = utilisateur;
|
||||
this.version = 0L;
|
||||
this.actif = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marque l'entité comme modifiée
|
||||
*
|
||||
* @param utilisateur L'utilisateur qui modifie l'entité
|
||||
*/
|
||||
public void marquerCommeModifie(String utilisateur) {
|
||||
this.dateModification = LocalDateTime.now();
|
||||
this.modifiePar = utilisateur;
|
||||
if (this.version != null) {
|
||||
this.version++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Désactive l'entité (soft delete)
|
||||
*
|
||||
* @param utilisateur L'utilisateur qui désactive l'entité
|
||||
*/
|
||||
public void desactiver(String utilisateur) {
|
||||
this.actif = false;
|
||||
marquerCommeModifie(utilisateur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Réactive l'entité
|
||||
*
|
||||
* @param utilisateur L'utilisateur qui réactive l'entité
|
||||
*/
|
||||
public void reactiver(String utilisateur) {
|
||||
this.actif = true;
|
||||
marquerCommeModifie(utilisateur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'entité est nouvelle (pas encore persistée)
|
||||
*
|
||||
* @return true si l'entité est nouvelle
|
||||
*/
|
||||
public boolean isNouveau() {
|
||||
return id == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'entité est active
|
||||
*
|
||||
* @return true si l'entité est active
|
||||
*/
|
||||
public boolean isActif() {
|
||||
return Boolean.TRUE.equals(actif);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
|
||||
BaseDTO baseDTO = (BaseDTO) obj;
|
||||
return id != null && id.equals(baseDTO.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()
|
||||
+ "{"
|
||||
+ "id="
|
||||
+ id
|
||||
+ ", dateCreation="
|
||||
+ dateCreation
|
||||
+ ", dateModification="
|
||||
+ dateModification
|
||||
+ ", creePar='"
|
||||
+ creePar
|
||||
+ '\''
|
||||
+ ", modifiePar='"
|
||||
+ modifiePar
|
||||
+ '\''
|
||||
+ ", version="
|
||||
+ version
|
||||
+ ", actif="
|
||||
+ actif
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package dev.lions.unionflow.server.api.dto.base;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Classe de base pour les DTOs de réponse.
|
||||
*
|
||||
* <p>
|
||||
* Contient les champs d'audit communs à toutes
|
||||
* les réponses : identifiant, dates de
|
||||
* création/modification, créateur, et version.
|
||||
*
|
||||
* <p>
|
||||
* Les DTOs de type Request ne doivent
|
||||
* <b>pas</b> hériter de cette classe (utiliser
|
||||
* des {@code record} sans héritage).
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
* @since 2026-02-21
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class BaseResponse {
|
||||
|
||||
/** Identifiant unique de l'entité. */
|
||||
private UUID id;
|
||||
|
||||
/** Date de création de l'entité. */
|
||||
private LocalDateTime dateCreation;
|
||||
|
||||
/** Date de dernière modification. */
|
||||
private LocalDateTime dateModification;
|
||||
|
||||
/** Email du créateur. */
|
||||
private String creePar;
|
||||
|
||||
/** Email du dernier modificateur. */
|
||||
private String modifiePar;
|
||||
|
||||
/** Version pour l'optimistic locking. */
|
||||
private Long version;
|
||||
|
||||
/** État actif/inactif (soft-delete). */
|
||||
private Boolean actif;
|
||||
|
||||
/**
|
||||
* Comparaison basée sur l'ID.
|
||||
* Deux BaseResponse sont égaux si leurs IDs sont égaux et non null.
|
||||
*
|
||||
* @param obj Objet à comparer
|
||||
* @return true si les objets ont le même ID
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseResponse that = (BaseResponse) obj;
|
||||
return id != null && id.equals(that.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code basé sur l'ID.
|
||||
*
|
||||
* @return Hash code de l'ID, ou 0 si ID null
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package dev.lions.unionflow.server.api.dto.base;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Réponse paginée générique.
|
||||
*
|
||||
* <p>
|
||||
* Encapsule une liste d'éléments avec les
|
||||
* métadonnées de pagination (page, taille,
|
||||
* total). Utilisable pour tout type de réponse
|
||||
* paginée.
|
||||
*
|
||||
* @param <T> type des éléments de la page
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
* @since 2026-02-21
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class PageResponse<T> {
|
||||
|
||||
/** Éléments de la page courante. */
|
||||
private final List<T> contenu;
|
||||
|
||||
/** Numéro de page courant (0-indexed). */
|
||||
private final int page;
|
||||
|
||||
/** Taille de la page demandée. */
|
||||
private final int taille;
|
||||
|
||||
/** Nombre total d'éléments. */
|
||||
private final long totalElements;
|
||||
|
||||
/** Nombre total de pages. */
|
||||
private final int totalPages;
|
||||
|
||||
/**
|
||||
* Indique s'il existe une page suivante.
|
||||
*
|
||||
* @return {@code true} si une page suivante
|
||||
* existe
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return page < totalPages - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indique s'il existe une page précédente.
|
||||
*
|
||||
* @return {@code true} si une page précédente
|
||||
* existe
|
||||
*/
|
||||
public boolean hasPrevious() {
|
||||
return page > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package dev.lions.unionflow.server.api.dto.collectefonds;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||
import dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Campagne de levée de fonds (Crowdfunding / ONG)")
|
||||
public class CampagneCollecteResponse extends BaseDTO {
|
||||
|
||||
private String organisationId;
|
||||
|
||||
private String titre;
|
||||
private String courteDescription;
|
||||
private String htmlDescriptionComplete;
|
||||
private String imageBanniereUrl;
|
||||
|
||||
@Schema(description = "Objectif monétaire escompté")
|
||||
private BigDecimal objectifFinancier;
|
||||
|
||||
@Schema(description = "Somme totale déjà récoltée sur cette campagne")
|
||||
private BigDecimal montantCollecteActuel;
|
||||
|
||||
private Integer nombreDonateurs;
|
||||
|
||||
private StatutCampagneCollecte statut;
|
||||
|
||||
private LocalDateTime dateOuverture;
|
||||
private LocalDateTime dateCloturePrevue;
|
||||
|
||||
// Si la page est visible pour les non-membres (donateurs externes)
|
||||
private Boolean estPublique;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package dev.lions.unionflow.server.api.dto.collectefonds;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||
import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Don transactionnel reçu pour une campagne de collecte")
|
||||
public class ContributionCollecteDTO extends BaseDTO {
|
||||
|
||||
private String campagneId;
|
||||
|
||||
@Schema(description = "Id du membre (Null si le don est public/externe)")
|
||||
private String membreDonateurId;
|
||||
|
||||
@Schema(description = "Nom affiché si don public ou pour le mur de contributeurs")
|
||||
private String aliasDonateur;
|
||||
|
||||
private Boolean estAnonyme;
|
||||
|
||||
private BigDecimal montantSoutien;
|
||||
|
||||
private String messageSoutien;
|
||||
|
||||
private LocalDateTime dateContribution;
|
||||
|
||||
// Lien avec la passerelle de paiement
|
||||
private String transactionPaiementId;
|
||||
private StatutTransactionWave statutPaiement;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package dev.lions.unionflow.server.api.dto.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param <T> Type des éléments dans la liste
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
*/
|
||||
public class PagedResponse<T> {
|
||||
|
||||
@JsonProperty("data")
|
||||
private List<T> data;
|
||||
|
||||
@JsonProperty("total")
|
||||
private Long total;
|
||||
|
||||
@JsonProperty("page")
|
||||
private Integer page;
|
||||
|
||||
@JsonProperty("size")
|
||||
private Integer size;
|
||||
|
||||
@JsonProperty("totalPages")
|
||||
private Integer totalPages;
|
||||
|
||||
// Constructeurs
|
||||
public PagedResponse() {
|
||||
}
|
||||
|
||||
public PagedResponse(List<T> data, Long total, Integer page, Integer size) {
|
||||
this.data = data;
|
||||
this.total = total;
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
this.totalPages = calculateTotalPages(total, size);
|
||||
}
|
||||
|
||||
public PagedResponse(List<T> data, Long total, Integer page, Integer size, Integer totalPages) {
|
||||
this.data = data;
|
||||
this.total = total;
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
this.totalPages = totalPages;
|
||||
}
|
||||
|
||||
// Méthode utilitaire pour calculer le nombre de pages
|
||||
private Integer calculateTotalPages(Long total, Integer size) {
|
||||
if (size == null || size == 0 || total == null) {
|
||||
return 0;
|
||||
}
|
||||
return (int) Math.ceil((double) total / size);
|
||||
}
|
||||
|
||||
// Getters et setters
|
||||
public List<T> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<T> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(Long total) {
|
||||
this.total = total;
|
||||
this.totalPages = calculateTotalPages(total, this.size);
|
||||
}
|
||||
|
||||
public Integer getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(Integer page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Integer size) {
|
||||
this.size = size;
|
||||
this.totalPages = calculateTotalPages(this.total, size);
|
||||
}
|
||||
|
||||
public Integer getTotalPages() {
|
||||
return totalPages;
|
||||
}
|
||||
|
||||
public void setTotalPages(Integer totalPages) {
|
||||
this.totalPages = totalPages;
|
||||
}
|
||||
|
||||
// Méthodes utilitaires
|
||||
public boolean hasNext() {
|
||||
return page != null && totalPages != null && page < totalPages - 1;
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return page != null && page > 0;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return data == null || data.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PagedResponse{" +
|
||||
"total=" + total +
|
||||
", page=" + page +
|
||||
", size=" + size +
|
||||
", totalPages=" + totalPages +
|
||||
", itemsCount=" + (data != null ? data.size() : 0) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un compte comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateCompteComptableRequest(
|
||||
@NotBlank(message = "Le numéro de compte est obligatoire") String numeroCompte,
|
||||
@NotBlank(message = "Le libellé est obligatoire") String libelle,
|
||||
@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,
|
||||
BigDecimal soldeInitial,
|
||||
BigDecimal soldeActuel,
|
||||
Boolean compteCollectif,
|
||||
Boolean compteAnalytique,
|
||||
String description) {
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une écriture comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateEcritureComptableRequest(
|
||||
@NotBlank(message = "Le numéro de pièce est obligatoire") String numeroPiece,
|
||||
|
||||
@NotNull(message = "La date de l'écriture est obligatoire") LocalDate dateEcriture,
|
||||
|
||||
@NotBlank(message = "Le libellé est obligatoire") String libelle,
|
||||
|
||||
String reference,
|
||||
String lettrage,
|
||||
Boolean pointe,
|
||||
|
||||
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit,
|
||||
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
|
||||
|
||||
String commentaire,
|
||||
|
||||
@NotNull(message = "Le journal est obligatoire") UUID journalId,
|
||||
UUID organisationId,
|
||||
UUID paiementId,
|
||||
|
||||
List<CreateLigneEcritureRequest> lignes) {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un journal comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateJournalComptableRequest(
|
||||
@NotBlank(message = "Le code du journal est obligatoire") String code,
|
||||
@NotBlank(message = "Le libellé est obligatoire") String libelle,
|
||||
@NotNull(message = "Le type de journal est obligatoire") TypeJournalComptable typeJournal,
|
||||
LocalDate dateDebut,
|
||||
LocalDate dateFin,
|
||||
String statut,
|
||||
String description) {
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une ligne d'écriture comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
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,
|
||||
|
||||
@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,
|
||||
|
||||
String libelle,
|
||||
String reference,
|
||||
|
||||
@NotNull(message = "L'écriture est obligatoire") UUID ecritureId,
|
||||
@NotNull(message = "Le compte comptable est obligatoire") UUID compteComptableId) {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'un compte comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateCompteComptableRequest(
|
||||
String numeroCompte,
|
||||
String libelle,
|
||||
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,
|
||||
BigDecimal soldeInitial,
|
||||
BigDecimal soldeActuel,
|
||||
Boolean compteCollectif,
|
||||
Boolean compteAnalytique,
|
||||
String description) {
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une écriture comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateEcritureComptableRequest(
|
||||
String numeroPiece,
|
||||
LocalDate dateEcriture,
|
||||
String libelle,
|
||||
String reference,
|
||||
String lettrage,
|
||||
Boolean pointe,
|
||||
|
||||
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantDebit,
|
||||
@DecimalMin(value = "0.0") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
|
||||
|
||||
String commentaire,
|
||||
UUID journalId,
|
||||
UUID paiementId,
|
||||
|
||||
List<UpdateLigneEcritureRequest> lignes) {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'un journal comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateJournalComptableRequest(
|
||||
String libelle,
|
||||
TypeJournalComptable typeJournal,
|
||||
LocalDate dateDebut,
|
||||
LocalDate dateFin,
|
||||
String statut,
|
||||
String description) {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une ligne d'écriture comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateLigneEcritureRequest(
|
||||
@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 crédit doit être positif ou nul") @Digits(integer = 12, fraction = 2) BigDecimal montantCredit,
|
||||
String libelle,
|
||||
String reference,
|
||||
UUID compteComptableId) {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée d'un compte comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CompteComptableResponse extends BaseResponse {
|
||||
|
||||
private String numeroCompte;
|
||||
private String libelle;
|
||||
private TypeCompteComptable typeCompte;
|
||||
private Integer classeComptable;
|
||||
private BigDecimal soldeInitial;
|
||||
private BigDecimal soldeActuel;
|
||||
private Boolean compteCollectif;
|
||||
private Boolean compteAnalytique;
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée d'une écriture comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EcritureComptableResponse extends BaseResponse {
|
||||
|
||||
private String numeroPiece;
|
||||
private LocalDate dateEcriture;
|
||||
private String libelle;
|
||||
private String reference;
|
||||
private String lettrage;
|
||||
private Boolean pointe;
|
||||
private BigDecimal montantDebit;
|
||||
private BigDecimal montantCredit;
|
||||
private String commentaire;
|
||||
private UUID journalId;
|
||||
private UUID organisationId;
|
||||
private UUID paiementId;
|
||||
private List<LigneEcritureResponse> lignes;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
|
||||
import java.time.LocalDate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée d'un journal comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class JournalComptableResponse extends BaseResponse {
|
||||
|
||||
private String code;
|
||||
private String libelle;
|
||||
private TypeJournalComptable typeJournal;
|
||||
private LocalDate dateDebut;
|
||||
private LocalDate dateFin;
|
||||
private String statut;
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.comptabilite.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée d'une ligne d'écriture comptable.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LigneEcritureResponse extends BaseResponse {
|
||||
|
||||
private Integer numeroLigne;
|
||||
private BigDecimal montantDebit;
|
||||
private BigDecimal montantCredit;
|
||||
private String libelle;
|
||||
private String reference;
|
||||
private UUID ecritureId;
|
||||
private UUID compteComptableId;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.lions.unionflow.server.api.dto.config.request;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une configuration.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateConfigurationRequest(
|
||||
String cle,
|
||||
String valeur,
|
||||
String type,
|
||||
String categorie,
|
||||
String description,
|
||||
Boolean modifiable,
|
||||
Boolean visible,
|
||||
Map<String, Object> metadonnees) {
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package dev.lions.unionflow.server.api.dto.config.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
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).
|
||||
* Définit les seuils au-dessus desquels les justifications d'origine des fonds sont obligatoires.
|
||||
*
|
||||
* @author lions dev Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Paramètres LCB-FT (seuils de vigilance)")
|
||||
public class ParametresLcbFtRequest {
|
||||
|
||||
@Schema(description = "ID de l'organisation (null pour paramètres plateforme)")
|
||||
private String organisationId;
|
||||
|
||||
@NotNull(message = "Le montant seuil de justification est obligatoire")
|
||||
@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")
|
||||
private BigDecimal montantSeuilJustification;
|
||||
|
||||
@NotNull(message = "Le montant seuil de validation manuelle est obligatoire")
|
||||
@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")
|
||||
private BigDecimal montantSeuilValidationManuelle;
|
||||
|
||||
@NotBlank(message = "Le code devise est obligatoire")
|
||||
@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")
|
||||
private String codeDevise;
|
||||
|
||||
@Schema(description = "Notes ou commentaires sur la configuration")
|
||||
private String notes;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.lions.unionflow.server.api.dto.config.request;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une configuration.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateConfigurationRequest(
|
||||
String cle,
|
||||
String valeur,
|
||||
String type,
|
||||
String categorie,
|
||||
String description,
|
||||
Boolean modifiable,
|
||||
Boolean visible,
|
||||
Map<String, Object> metadonnees) {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.config.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse contenant les données d'une configuration.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ConfigurationResponse extends BaseResponse {
|
||||
|
||||
private String cle;
|
||||
private String valeur;
|
||||
private String type;
|
||||
private String categorie;
|
||||
private String description;
|
||||
private Boolean modifiable;
|
||||
private Boolean visible;
|
||||
private Map<String, Object> metadonnees;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package dev.lions.unionflow.server.api.dto.config.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author lions dev Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Paramètres LCB-FT avec seuils de vigilance")
|
||||
public class ParametresLcbFtResponse extends BaseResponse {
|
||||
|
||||
@Schema(description = "ID de l'organisation (null si paramètres plateforme)")
|
||||
private String organisationId;
|
||||
|
||||
@Schema(description = "Nom de l'organisation (null si paramètres plateforme)")
|
||||
private String organisationNom;
|
||||
|
||||
@Schema(description = "Montant au-dessus duquel l'origine des fonds est obligatoire", example = "500000")
|
||||
private BigDecimal montantSeuilJustification;
|
||||
|
||||
@Schema(description = "Montant au-dessus duquel une validation manuelle est requise", example = "1000000")
|
||||
private BigDecimal montantSeuilValidationManuelle;
|
||||
|
||||
@Schema(description = "Code devise ISO 4217", example = "XOF")
|
||||
private String codeDevise;
|
||||
|
||||
@Schema(description = "Notes ou commentaires sur la configuration")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "Indique si ces paramètres s'appliquent à toute la plateforme")
|
||||
private Boolean estParametrePlateforme;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package dev.lions.unionflow.server.api.dto.cotisation.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une nouvelle cotisation.
|
||||
*
|
||||
* @param membreId Identifiant du membre concerné.
|
||||
* @param typeCotisation Type de cotisation (MENSUELLE, etc.).
|
||||
* @param libelle Libellé de la cotisation.
|
||||
* @param description Description détaillée.
|
||||
* @param montantDu Montant total à payer.
|
||||
* @param codeDevise Code ISO de la devise (par défaut XOF).
|
||||
* @param dateEcheance Date limite de paiement.
|
||||
* @param periode Période concernée (ex: Janvier 2025).
|
||||
* @param annee Année de référence.
|
||||
* @param mois Mois de référence (1-12, optionnel).
|
||||
* @param recurrente Indique si la cotisation est récurrente.
|
||||
* @param observations Commentaires libres.
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-02-22
|
||||
*/
|
||||
@Builder
|
||||
public record CreateCotisationRequest(
|
||||
@NotNull(message = "L'identifiant du membre est obligatoire") UUID membreId,
|
||||
|
||||
@NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId,
|
||||
|
||||
@NotBlank(message = "Le type de cotisation est obligatoire") String typeCotisation,
|
||||
|
||||
@NotBlank(message = "Le libellé est obligatoire") @Size(max = 100) String libelle,
|
||||
|
||||
@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,
|
||||
|
||||
@Size(min = 3, max = 3) String codeDevise,
|
||||
|
||||
@NotNull(message = "La date d'échéance est obligatoire") LocalDate dateEcheance,
|
||||
|
||||
@Size(max = 50) String periode,
|
||||
|
||||
@Min(2020) @Max(2100) Integer annee,
|
||||
|
||||
@Min(1) @Max(12) Integer mois,
|
||||
|
||||
Boolean recurrente,
|
||||
|
||||
@Size(max = 1000) String observations) {
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package dev.lions.unionflow.server.api.dto.cotisation.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une cotisation existante.
|
||||
*
|
||||
* @param libelle Nouveau libellé.
|
||||
* @param description Nouvelle description.
|
||||
* @param montantDu Nouveau montant dû (si non payé).
|
||||
* @param dateEcheance Nouvelle date d'échéance.
|
||||
* @param observations Nouvelles observations.
|
||||
* @param statut Nouveau statut (validation métier requise).
|
||||
* @param annee Année de référence.
|
||||
* @param mois Mois de référence.
|
||||
* @param recurrente État de récurrence.
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-02-22
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateCotisationRequest(
|
||||
@Size(max = 100) String libelle,
|
||||
|
||||
@Size(max = 500) String description,
|
||||
|
||||
@DecimalMin(value = "0.0", inclusive = false) @Digits(integer = 10, fraction = 2) BigDecimal montantDu,
|
||||
|
||||
LocalDate dateEcheance,
|
||||
|
||||
@Size(max = 1000) String observations,
|
||||
|
||||
String statut,
|
||||
|
||||
@Min(2020) @Max(2100) Integer annee,
|
||||
|
||||
@Min(1) @Max(12) Integer mois,
|
||||
|
||||
Boolean recurrente) {
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package dev.lions.unionflow.server.api.dto.cotisation.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée pour une cotisation.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-02-22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CotisationResponse extends BaseResponse {
|
||||
|
||||
private String numeroReference;
|
||||
private UUID membreId;
|
||||
private String nomMembre;
|
||||
/** Nom complet (prénom + nom) pour affichage */
|
||||
private String nomCompletMembre;
|
||||
private String numeroMembre;
|
||||
/** Initiales du membre (ex: JD pour Jean Dupont) */
|
||||
private String initialesMembre;
|
||||
/** Type / statut du membre (ex: Actif, En attente) */
|
||||
private String typeMembre;
|
||||
private UUID organisationId;
|
||||
private String nomOrganisation;
|
||||
/** Région de l'organisation (affichage liste) */
|
||||
private String regionOrganisation;
|
||||
/** Classe CSS icône PrimeFaces pour l'organisation (ex: pi-building) */
|
||||
private String iconeOrganisation;
|
||||
private String typeCotisation;
|
||||
/** Alias pour tri/filtre (type de cotisation) */
|
||||
private String type;
|
||||
private String typeCotisationLibelle;
|
||||
/** Libellé du type pour affichage (alias typeCotisationLibelle) */
|
||||
private String typeLibelle;
|
||||
/** Sévérité PrimeFaces pour le tag type (info, success, warn, error, secondary) */
|
||||
private String typeSeverity;
|
||||
/** Classe icône PrimeFaces pour le type (ex: pi-calendar) */
|
||||
private String typeIcon;
|
||||
private String libelle;
|
||||
private String description;
|
||||
private BigDecimal montantDu;
|
||||
/** Alias pour tri/filtre (montant du) */
|
||||
private BigDecimal montant;
|
||||
/** Montant formaté pour affichage (ex: "5 000") */
|
||||
private String montantFormatte;
|
||||
private BigDecimal montantPaye;
|
||||
private BigDecimal montantRestant;
|
||||
private String codeDevise;
|
||||
private String statut;
|
||||
private String statutLibelle;
|
||||
/** Sévérité PrimeFaces pour le tag statut */
|
||||
private String statutSeverity;
|
||||
/** Classe icône PrimeFaces pour le statut (ex: pi-check) */
|
||||
private String statutIcon;
|
||||
private LocalDate dateEcheance;
|
||||
/** Date d'échéance formatée pour affichage */
|
||||
private String dateEcheanceFormattee;
|
||||
/** Classe CSS couleur pour le retard (ex: text-red-500) */
|
||||
private String retardCouleur;
|
||||
/** Texte affiché pour le retard (ex: "X jours de retard") */
|
||||
private String retardTexte;
|
||||
/** Date de paiement formatée pour affichage */
|
||||
private String datePaiementFormattee;
|
||||
/** Icône PrimeFaces pour le mode de paiement */
|
||||
private String modePaiementIcon;
|
||||
/** Libellé du mode de paiement */
|
||||
private String modePaiementLibelle;
|
||||
private LocalDateTime datePaiement;
|
||||
private String periode;
|
||||
private Integer annee;
|
||||
private Integer mois;
|
||||
private String observations;
|
||||
private Boolean recurrente;
|
||||
private Integer nombreRappels;
|
||||
private LocalDateTime dateDernierRappel;
|
||||
private UUID valideParId;
|
||||
private String nomValidateur;
|
||||
private LocalDateTime dateValidation;
|
||||
private Integer pourcentagePaiement;
|
||||
private Long joursRetard;
|
||||
private Boolean enRetard;
|
||||
|
||||
// Informations de paiement
|
||||
private String methodePaiement; // WAVE_MONEY, VIREMENT, ESPECES, CARTE, MOBILE_MONEY
|
||||
private String referencePaiement; // Référence externe du paiement
|
||||
private String waveSessionId; // ID de session Wave Money pour prélèvements
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package dev.lions.unionflow.server.api.dto.cotisation.response;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Réponse simplifiée pour les listes de cotisations.
|
||||
*
|
||||
* @param id Identifiant unique.
|
||||
* @param numeroReference Référence unique.
|
||||
* @param nomMembre Nom du membre.
|
||||
* @param montantDu Montant total dû.
|
||||
* @param montantPaye Montant déjà réglé.
|
||||
* @param statut Statut actuel (code).
|
||||
* @param statutLibelle Libellé du statut pour l'UI.
|
||||
* @param dateEcheance Date limite.
|
||||
* @param annee Année concernée.
|
||||
* @param actif Indique si l'entité est active.
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-02-22
|
||||
*/
|
||||
public record CotisationSummaryResponse(
|
||||
UUID id,
|
||||
String numeroReference,
|
||||
String nomMembre,
|
||||
BigDecimal montantDu,
|
||||
BigDecimal montantPaye,
|
||||
String statut,
|
||||
String statutLibelle,
|
||||
LocalDate dateEcheance,
|
||||
Integer annee,
|
||||
Boolean actif) {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.culte;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||
import dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DonReligieuxDTO extends BaseDTO {
|
||||
|
||||
private String institutionId; // Mosquée, Église, Paroisse...
|
||||
|
||||
// Si relié spécifiquement à un fidèle enregistré
|
||||
private String fideleId;
|
||||
|
||||
private TypeDonReligieux typeDon;
|
||||
|
||||
private BigDecimal montant;
|
||||
private LocalDateTime dateEncaissement;
|
||||
|
||||
// Utile pour la zakat (Nissab de l'année concernée) ou la dîme périodique
|
||||
private String periodeOuNatureAssociee;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package dev.lions.unionflow.server.api.dto.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DTO principal pour toutes les données du dashboard
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DashboardDataResponse {
|
||||
|
||||
@JsonProperty("stats")
|
||||
private DashboardStatsResponse stats;
|
||||
|
||||
@JsonProperty("recentActivities")
|
||||
private List<RecentActivityResponse> recentActivities;
|
||||
|
||||
@JsonProperty("upcomingEvents")
|
||||
private List<UpcomingEventResponse> upcomingEvents;
|
||||
|
||||
@JsonProperty("userPreferences")
|
||||
private Map<String, Object> userPreferences;
|
||||
|
||||
@JsonProperty("organizationId")
|
||||
private String organizationId;
|
||||
|
||||
@JsonProperty("userId")
|
||||
private String userId;
|
||||
|
||||
// Méthodes utilitaires
|
||||
public Integer getTodayEventsCount() {
|
||||
if (upcomingEvents == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) upcomingEvents.stream()
|
||||
.filter(event -> event.getIsToday() != null && event.getIsToday())
|
||||
.count();
|
||||
}
|
||||
|
||||
public Integer getTomorrowEventsCount() {
|
||||
if (upcomingEvents == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) upcomingEvents.stream()
|
||||
.filter(event -> event.getIsTomorrow() != null && event.getIsTomorrow())
|
||||
.count();
|
||||
}
|
||||
|
||||
public Integer getRecentActivitiesCount() {
|
||||
if (recentActivities == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) recentActivities.stream()
|
||||
.filter(activity -> activity.getIsRecent() != null && activity.getIsRecent())
|
||||
.count();
|
||||
}
|
||||
|
||||
public Integer getTodayActivitiesCount() {
|
||||
if (recentActivities == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) recentActivities.stream()
|
||||
.filter(activity -> activity.getIsToday() != null && activity.getIsToday())
|
||||
.count();
|
||||
}
|
||||
|
||||
public Boolean getHasUpcomingEvents() {
|
||||
return upcomingEvents != null && !upcomingEvents.isEmpty();
|
||||
}
|
||||
|
||||
public Boolean getHasRecentActivities() {
|
||||
return recentActivities != null && !recentActivities.isEmpty();
|
||||
}
|
||||
|
||||
public String getThemePreference() {
|
||||
if (userPreferences == null) {
|
||||
return "royal_teal";
|
||||
}
|
||||
return (String) userPreferences.getOrDefault("theme", "royal_teal");
|
||||
}
|
||||
|
||||
public String getLanguagePreference() {
|
||||
if (userPreferences == null) {
|
||||
return "fr";
|
||||
}
|
||||
return (String) userPreferences.getOrDefault("language", "fr");
|
||||
}
|
||||
|
||||
public Boolean getNotificationsEnabled() {
|
||||
if (userPreferences == null) {
|
||||
return true;
|
||||
}
|
||||
return (Boolean) userPreferences.getOrDefault("notifications", true);
|
||||
}
|
||||
|
||||
public Boolean getAutoRefreshEnabled() {
|
||||
if (userPreferences == null) {
|
||||
return true;
|
||||
}
|
||||
return (Boolean) userPreferences.getOrDefault("autoRefresh", true);
|
||||
}
|
||||
|
||||
public Integer getRefreshInterval() {
|
||||
if (userPreferences == null) {
|
||||
return 300; // 5 minutes par défaut
|
||||
}
|
||||
return (Integer) userPreferences.getOrDefault("refreshInterval", 300);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package dev.lions.unionflow.server.api.dto.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DTO pour les statistiques du dashboard
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DashboardStatsResponse {
|
||||
|
||||
@JsonProperty("totalMembers")
|
||||
private Integer totalMembers;
|
||||
|
||||
@JsonProperty("activeMembers")
|
||||
private Integer activeMembers;
|
||||
|
||||
@JsonProperty("totalEvents")
|
||||
private Integer totalEvents;
|
||||
|
||||
@JsonProperty("upcomingEvents")
|
||||
private Integer upcomingEvents;
|
||||
|
||||
@JsonProperty("totalContributions")
|
||||
private Integer totalContributions;
|
||||
|
||||
@JsonProperty("totalContributionAmount")
|
||||
private Double totalContributionAmount;
|
||||
|
||||
@JsonProperty("pendingRequests")
|
||||
private Integer pendingRequests;
|
||||
|
||||
@JsonProperty("completedProjects")
|
||||
private Integer completedProjects;
|
||||
|
||||
@JsonProperty("monthlyGrowth")
|
||||
private Double monthlyGrowth;
|
||||
|
||||
@JsonProperty("engagementRate")
|
||||
private Double engagementRate;
|
||||
|
||||
@JsonProperty("lastUpdated")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime lastUpdated;
|
||||
|
||||
/**
|
||||
* Nombre total d'organisations dans le système (SuperAdmin uniquement)
|
||||
*/
|
||||
@JsonProperty("totalOrganizations")
|
||||
private Integer totalOrganizations;
|
||||
|
||||
/**
|
||||
* Répartition des organisations par type
|
||||
* Exemple: {"Mutuelle": 15, "Coopérative": 8, "Tontine": 5, "Autre": 3}
|
||||
*/
|
||||
@JsonProperty("organizationTypeDistribution")
|
||||
private Map<String, Integer> organizationTypeDistribution;
|
||||
|
||||
/**
|
||||
* Données historiques mensuelles pour les graphiques (12 derniers mois)
|
||||
*/
|
||||
@JsonProperty("monthlyHistoricalData")
|
||||
private List<MonthlyStatDTO> monthlyHistoricalData;
|
||||
|
||||
// Méthodes utilitaires
|
||||
public String getFormattedContributionAmount() {
|
||||
if (totalContributionAmount == null) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
if (totalContributionAmount >= 1_000_000) {
|
||||
return String.format("%.1fM", totalContributionAmount / 1_000_000);
|
||||
} else if (totalContributionAmount >= 1_000) {
|
||||
return String.format("%.0fK", totalContributionAmount / 1_000);
|
||||
} else {
|
||||
return String.format("%.0f", totalContributionAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getHasGrowth() {
|
||||
return monthlyGrowth != null && monthlyGrowth > 0;
|
||||
}
|
||||
|
||||
public Boolean getIsHighEngagement() {
|
||||
return engagementRate != null && engagementRate > 0.7;
|
||||
}
|
||||
|
||||
public Double getInactiveMembers() {
|
||||
if (totalMembers == null || activeMembers == null) {
|
||||
return 0.0;
|
||||
}
|
||||
return (double) (totalMembers - activeMembers);
|
||||
}
|
||||
|
||||
public Double getActiveMemberPercentage() {
|
||||
if (totalMembers == null || activeMembers == null || totalMembers == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return (double) activeMembers / totalMembers * 100;
|
||||
}
|
||||
|
||||
public Double getEngagementPercentage() {
|
||||
if (engagementRate == null) {
|
||||
return 0.0;
|
||||
}
|
||||
return engagementRate * 100;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package dev.lions.unionflow.server.api.dto.dashboard;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* DTO de synthèse dashboard membre (cotisations, épargne, événements, aides).
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
public record MembreDashboardSyntheseResponse(
|
||||
String prenom,
|
||||
String nom,
|
||||
LocalDate dateInscription,
|
||||
|
||||
// Cotisations
|
||||
BigDecimal mesCotisationsPaiement,
|
||||
/** Total des cotisations payées sur l'année en cours (pour affichage dashboard). */
|
||||
BigDecimal totalCotisationsPayeesAnnee,
|
||||
/** Total des cotisations payées tout temps (pour la carte « Contribution Totale »). */
|
||||
BigDecimal totalCotisationsPayeesToutTemps,
|
||||
/** Nombre de cotisations PAYÉES (pour la carte « Cotisations »). */
|
||||
Integer nombreCotisationsPayees,
|
||||
String statutCotisations,
|
||||
/** Taux de cotisation en % (0-100). Calculé sur l'année courante ou toutes années si pas de cotisation 2026. */
|
||||
Integer tauxCotisationsPerso,
|
||||
/** Nombre TOTAL de cotisations (toutes années, tous statuts) — pour calcul du taux d'engagement. */
|
||||
Integer nombreCotisationsTotal,
|
||||
|
||||
// Epargne
|
||||
BigDecimal monSoldeEpargne,
|
||||
BigDecimal evolutionEpargneNombre,
|
||||
String evolutionEpargne,
|
||||
Integer objectifEpargne,
|
||||
|
||||
// Evenements
|
||||
Integer mesEvenementsInscrits,
|
||||
Integer evenementsAVenir,
|
||||
Integer tauxParticipationPerso,
|
||||
|
||||
// Aides
|
||||
Integer mesDemandesAide,
|
||||
Integer aidesEnCours,
|
||||
Integer tauxAidesApprouvees) implements Serializable {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package dev.lions.unionflow.server.api.dto.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO pour les statistiques mensuelles historiques
|
||||
* Utilisé pour générer des graphiques de croissance sur 12 mois
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
* @since 2026-03-07
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MonthlyStatDTO {
|
||||
|
||||
/**
|
||||
* Mois au format "2026-01", "2026-02", etc.
|
||||
*/
|
||||
@JsonProperty("month")
|
||||
private String month;
|
||||
|
||||
/**
|
||||
* Nombre de membres ce mois-là
|
||||
*/
|
||||
@JsonProperty("totalMembers")
|
||||
private Integer totalMembers;
|
||||
|
||||
/**
|
||||
* Nombre de membres actifs ce mois-là
|
||||
*/
|
||||
@JsonProperty("activeMembers")
|
||||
private Integer activeMembers;
|
||||
|
||||
/**
|
||||
* Montant total des contributions ce mois-là
|
||||
*/
|
||||
@JsonProperty("contributionAmount")
|
||||
private Double contributionAmount;
|
||||
|
||||
/**
|
||||
* Nombre d'événements organisés ce mois-là
|
||||
*/
|
||||
@JsonProperty("eventsCount")
|
||||
private Integer eventsCount;
|
||||
|
||||
/**
|
||||
* Taux d'engagement ce mois-là
|
||||
*/
|
||||
@JsonProperty("engagementRate")
|
||||
private Double engagementRate;
|
||||
|
||||
/**
|
||||
* Nombre de nouveaux membres ce mois-là
|
||||
*/
|
||||
@JsonProperty("newMembers")
|
||||
private Integer newMembers;
|
||||
|
||||
/**
|
||||
* Nombre de cotisations payées ce mois-là
|
||||
*/
|
||||
@JsonProperty("contributionsCount")
|
||||
private Integer contributionsCount;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package dev.lions.unionflow.server.api.dto.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
/**
|
||||
* DTO pour les activités récentes du dashboard
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RecentActivityResponse {
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@JsonProperty("userName")
|
||||
private String userName;
|
||||
|
||||
@JsonProperty("timestamp")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime timestamp;
|
||||
|
||||
@JsonProperty("userAvatar")
|
||||
private String userAvatar;
|
||||
|
||||
@JsonProperty("actionUrl")
|
||||
private String actionUrl;
|
||||
|
||||
// Méthodes utilitaires
|
||||
public String getTimeAgo() {
|
||||
if (timestamp == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
long minutes = ChronoUnit.MINUTES.between(timestamp, now);
|
||||
long hours = ChronoUnit.HOURS.between(timestamp, now);
|
||||
long days = ChronoUnit.DAYS.between(timestamp, now);
|
||||
|
||||
if (minutes < 60) {
|
||||
return minutes + "min";
|
||||
} else if (hours < 24) {
|
||||
return hours + "h";
|
||||
} else if (days < 7) {
|
||||
return days + "j";
|
||||
} else {
|
||||
long weeks = days / 7;
|
||||
return weeks + "sem";
|
||||
}
|
||||
}
|
||||
|
||||
public String getActivityIcon() {
|
||||
if (type == null) {
|
||||
return "help_outline";
|
||||
}
|
||||
|
||||
switch (type.toLowerCase()) {
|
||||
case "member":
|
||||
return "person";
|
||||
case "event":
|
||||
return "event";
|
||||
case "contribution":
|
||||
return "payment";
|
||||
case "organization":
|
||||
return "business";
|
||||
case "system":
|
||||
return "settings";
|
||||
default:
|
||||
return "info";
|
||||
}
|
||||
}
|
||||
|
||||
public String getActivityColor() {
|
||||
if (type == null) {
|
||||
return "#6B7280"; // grey
|
||||
}
|
||||
|
||||
switch (type.toLowerCase()) {
|
||||
case "member":
|
||||
return "#10B981"; // success
|
||||
case "event":
|
||||
return "#3B82F6"; // info
|
||||
case "contribution":
|
||||
return "#008B8B"; // teal blue
|
||||
case "organization":
|
||||
return "#4169E1"; // royal blue
|
||||
case "system":
|
||||
return "#6B7280"; // grey
|
||||
default:
|
||||
return "#6B7280"; // grey
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getIsRecent() {
|
||||
if (timestamp == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
long hours = ChronoUnit.HOURS.between(timestamp, now);
|
||||
return hours < 24;
|
||||
}
|
||||
|
||||
public Boolean getIsToday() {
|
||||
if (timestamp == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return timestamp.toLocalDate().equals(now.toLocalDate());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package dev.lions.unionflow.server.api.dto.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DTO pour les événements à venir du dashboard
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpcomingEventResponse {
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@JsonProperty("startDate")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime startDate;
|
||||
|
||||
@JsonProperty("endDate")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime endDate;
|
||||
|
||||
@JsonProperty("location")
|
||||
private String location;
|
||||
|
||||
@JsonProperty("maxParticipants")
|
||||
private Integer maxParticipants;
|
||||
|
||||
@JsonProperty("currentParticipants")
|
||||
private Integer currentParticipants;
|
||||
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
@JsonProperty("imageUrl")
|
||||
private String imageUrl;
|
||||
|
||||
@JsonProperty("tags")
|
||||
private List<String> tags;
|
||||
|
||||
// Méthodes utilitaires
|
||||
public String getDaysUntilEvent() {
|
||||
return getDaysUntilEvent(LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Version testable avec une date de référence fixe (même package).
|
||||
*/
|
||||
String getDaysUntilEvent(LocalDateTime now) {
|
||||
if (startDate == null) {
|
||||
return "";
|
||||
}
|
||||
long days = ChronoUnit.DAYS.between(now.toLocalDate(), startDate.toLocalDate());
|
||||
long hours = ChronoUnit.HOURS.between(now, startDate);
|
||||
|
||||
if (days < 0) {
|
||||
return "En cours";
|
||||
}
|
||||
if (days == 0) {
|
||||
// Vérifier si l'événement est déjà passé (même si moins d'1h)
|
||||
if (startDate.isBefore(now)) {
|
||||
return "En cours";
|
||||
} else if (hours < 2) {
|
||||
return "Bientôt";
|
||||
} else {
|
||||
return "Aujourd'hui";
|
||||
}
|
||||
} else if (days == 1) {
|
||||
return "Demain";
|
||||
} else if (days < 7) {
|
||||
return "Dans " + days + " jours";
|
||||
} else {
|
||||
long weeks = days / 7;
|
||||
return "Dans " + weeks + " semaine" + (weeks > 1 ? "s" : "");
|
||||
}
|
||||
}
|
||||
|
||||
public Double getFillPercentage() {
|
||||
if (maxParticipants == null || currentParticipants == null || maxParticipants == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return (double) currentParticipants / maxParticipants * 100;
|
||||
}
|
||||
|
||||
public Boolean getIsFull() {
|
||||
if (maxParticipants == null || currentParticipants == null) {
|
||||
return false;
|
||||
}
|
||||
return currentParticipants >= maxParticipants;
|
||||
}
|
||||
|
||||
public Boolean getIsAlmostFull() {
|
||||
Double fillPercentage = getFillPercentage();
|
||||
return fillPercentage >= 80.0 && fillPercentage < 100.0;
|
||||
}
|
||||
|
||||
public Boolean getIsToday() {
|
||||
if (startDate == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return startDate.toLocalDate().equals(now.toLocalDate());
|
||||
}
|
||||
|
||||
public Boolean getIsTomorrow() {
|
||||
if (startDate == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return startDate.toLocalDate().equals(now.toLocalDate().plusDays(1));
|
||||
}
|
||||
|
||||
public String getStatusColor() {
|
||||
if (status == null) {
|
||||
return "#6B7280"; // grey
|
||||
}
|
||||
|
||||
switch (status.toLowerCase()) {
|
||||
case "confirmed":
|
||||
return "#10B981"; // success
|
||||
case "open":
|
||||
return "#3B82F6"; // info
|
||||
case "cancelled":
|
||||
return "#EF4444"; // error
|
||||
case "postponed":
|
||||
return "#F59E0B"; // warning
|
||||
default:
|
||||
return "#6B7280"; // grey
|
||||
}
|
||||
}
|
||||
|
||||
public String getStatusLabel() {
|
||||
if (status == null) {
|
||||
return "Inconnu";
|
||||
}
|
||||
|
||||
switch (status.toLowerCase()) {
|
||||
case "confirmed":
|
||||
return "Confirmé";
|
||||
case "open":
|
||||
return "Ouvert";
|
||||
case "cancelled":
|
||||
return "Annulé";
|
||||
case "postponed":
|
||||
return "Reporté";
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getAvailableSpots() {
|
||||
if (maxParticipants == null || currentParticipants == null) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(0, maxParticipants - currentParticipants);
|
||||
}
|
||||
|
||||
public String getParticipationSummary() {
|
||||
if (maxParticipants == null || currentParticipants == null) {
|
||||
return "0/0 participants";
|
||||
}
|
||||
return currentParticipants + "/" + maxParticipants + " participants";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.lions.unionflow.server.api.dto.document.request;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.document.TypeDocument;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un document.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateDocumentRequest(
|
||||
@NotBlank(message = "Le nom du fichier est obligatoire") String nomFichier,
|
||||
String nomOriginal,
|
||||
@NotBlank(message = "Le chemin de stockage est obligatoire") String cheminStockage,
|
||||
String typeMime,
|
||||
@NotNull(message = "La taille est obligatoire") @Min(value = 0, message = "La taille doit être positive") Long tailleOctets,
|
||||
TypeDocument typeDocument,
|
||||
String hashMd5,
|
||||
String hashSha256,
|
||||
String description) {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.lions.unionflow.server.api.dto.document.request;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une pièce jointe.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreatePieceJointeRequest(
|
||||
@NotNull(message = "L'ordre est obligatoire") @Min(value = 1, message = "L'ordre doit être positif") Integer ordre,
|
||||
String libelle,
|
||||
String commentaire,
|
||||
@NotNull(message = "Le document est obligatoire") UUID documentId,
|
||||
@NotNull(message = "Le type entité est obligatoire") String typeEntiteRattachee,
|
||||
@NotNull(message = "L'ID entité est obligatoire") UUID entiteRattacheeId) {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package dev.lions.unionflow.server.api.dto.document.request;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.document.TypeDocument;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'un document.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateDocumentRequest(
|
||||
String nomFichier,
|
||||
String nomOriginal,
|
||||
TypeDocument typeDocument,
|
||||
String description) {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.lions.unionflow.server.api.dto.document.request;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une pièce jointe.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record UpdatePieceJointeRequest(
|
||||
@Min(value = 1, message = "L'ordre doit être positif") Integer ordre,
|
||||
String libelle,
|
||||
String commentaire) {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.lions.unionflow.server.api.dto.document.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import dev.lions.unionflow.server.api.enums.document.TypeDocument;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée d'un document.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DocumentResponse extends BaseResponse {
|
||||
|
||||
private String nomFichier;
|
||||
private String nomOriginal;
|
||||
private String cheminStockage;
|
||||
private String typeMime;
|
||||
private Long tailleOctets;
|
||||
private TypeDocument typeDocument;
|
||||
private String hashMd5;
|
||||
private String hashSha256;
|
||||
private String description;
|
||||
private Integer nombreTelechargements;
|
||||
private String tailleFormatee;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.lions.unionflow.server.api.dto.document.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse contenant les données d'une pièce jointe.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PieceJointeResponse extends BaseResponse {
|
||||
|
||||
private Integer ordre;
|
||||
private String libelle;
|
||||
private String commentaire;
|
||||
private UUID documentId;
|
||||
private String typeEntiteRattachee;
|
||||
private UUID entiteRattacheeId;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
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.StatutEvenement;
|
||||
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
|
||||
import dev.lions.unionflow.server.api.validation.ValidationConstants;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.FutureOrPresent;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un événement.
|
||||
*/
|
||||
@Builder
|
||||
public record CreateEvenementRequest(
|
||||
@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,
|
||||
|
||||
@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 statut est obligatoire") StatutEvenement statut,
|
||||
|
||||
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,
|
||||
LocalDate dateFin,
|
||||
LocalTime heureDebut,
|
||||
LocalTime heureFin,
|
||||
@NotBlank(message = "Le lieu est obligatoire") @Size(max = 100) String lieu,
|
||||
@Size(max = 200) String adresse,
|
||||
@Size(max = 50) String ville,
|
||||
@Size(max = 50) String region,
|
||||
@DecimalMin(value = "-90.0") @DecimalMax(value = "90.0") BigDecimal latitude,
|
||||
@DecimalMin(value = "-180.0") @DecimalMax(value = "180.0") BigDecimal longitude,
|
||||
@NotNull(message = "L'association organisatrice est obligatoire") UUID associationId,
|
||||
@Size(max = 100) String organisateur,
|
||||
@Email(message = "Format d'email invalide") @Size(max = 100) String emailOrganisateur,
|
||||
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$") String telephoneOrganisateur,
|
||||
@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 coutReel,
|
||||
|
||||
@Pattern(regexp = ValidationConstants.DEVISE_PATTERN, message = ValidationConstants.DEVISE_MESSAGE) String codeDevise,
|
||||
Boolean inscriptionObligatoire,
|
||||
LocalDate dateLimiteInscription,
|
||||
Boolean evenementPublic,
|
||||
Boolean recurrent,
|
||||
String frequenceRecurrence,
|
||||
@Size(max = 500) String instructions,
|
||||
@Size(max = 500) String materielNecessaire,
|
||||
@Size(max = 100) String conditionsMeteo,
|
||||
@Size(max = 255) String imageUrl,
|
||||
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$") String couleurTheme) {
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
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.StatutEvenement;
|
||||
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
|
||||
import dev.lions.unionflow.server.api.validation.ValidationConstants;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'un événement.
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateEvenementRequest(
|
||||
@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,
|
||||
|
||||
TypeEvenementMetier typeEvenement,
|
||||
StatutEvenement statut,
|
||||
PrioriteEvenement priorite,
|
||||
|
||||
LocalDate dateDebut,
|
||||
LocalDate dateFin,
|
||||
LocalTime heureDebut,
|
||||
LocalTime heureFin,
|
||||
@NotBlank(message = "Le lieu est obligatoire") @Size(max = 100) String lieu,
|
||||
@Size(max = 200) String adresse,
|
||||
@Size(max = 50) String ville,
|
||||
@Size(max = 50) String region,
|
||||
@DecimalMin(value = "-90.0") @DecimalMax(value = "90.0") BigDecimal latitude,
|
||||
@DecimalMin(value = "-180.0") @DecimalMax(value = "180.0") BigDecimal longitude,
|
||||
@Size(max = 100) String organisateur,
|
||||
@Email(message = "Format d'email invalide") @Size(max = 100) String emailOrganisateur,
|
||||
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$") String telephoneOrganisateur,
|
||||
@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 coutReel,
|
||||
|
||||
@Pattern(regexp = ValidationConstants.DEVISE_PATTERN, message = ValidationConstants.DEVISE_MESSAGE) String codeDevise,
|
||||
Boolean inscriptionObligatoire,
|
||||
LocalDate dateLimiteInscription,
|
||||
Boolean evenementPublic,
|
||||
Boolean recurrent,
|
||||
String frequenceRecurrence,
|
||||
@Size(max = 500) String instructions,
|
||||
@Size(max = 500) String materielNecessaire,
|
||||
@Size(max = 100) String conditionsMeteo,
|
||||
@Size(max = 255) String imageUrl,
|
||||
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$") String couleurTheme) {
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package dev.lions.unionflow.server.api.dto.evenement.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
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.TypeEvenementMetier;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée pour un événement.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EvenementResponse extends BaseResponse {
|
||||
|
||||
private String titre;
|
||||
private String description;
|
||||
private TypeEvenementMetier typeEvenement;
|
||||
private StatutEvenement statut;
|
||||
private PrioriteEvenement priorite;
|
||||
|
||||
// Décommenter si l'on a besoin du @JsonFormat, sinon on garde le standard
|
||||
// @JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate dateDebut;
|
||||
|
||||
// @JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate dateFin;
|
||||
|
||||
// @JsonFormat(pattern = "HH:mm")
|
||||
private LocalTime heureDebut;
|
||||
|
||||
// @JsonFormat(pattern = "HH:mm")
|
||||
private LocalTime heureFin;
|
||||
private String lieu;
|
||||
private String adresse;
|
||||
private String ville;
|
||||
private String region;
|
||||
private BigDecimal latitude;
|
||||
private BigDecimal longitude;
|
||||
private UUID associationId;
|
||||
private String nomAssociation;
|
||||
private String organisateur;
|
||||
private String emailOrganisateur;
|
||||
private String telephoneOrganisateur;
|
||||
private Integer capaciteMax;
|
||||
private Integer participantsInscrits;
|
||||
private Integer participantsPresents;
|
||||
private BigDecimal budget;
|
||||
private BigDecimal coutReel;
|
||||
private String codeDevise;
|
||||
private Boolean inscriptionObligatoire;
|
||||
|
||||
// @JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate dateLimiteInscription;
|
||||
|
||||
private Boolean evenementPublic;
|
||||
private Boolean recurrent;
|
||||
private String frequenceRecurrence;
|
||||
private String instructions;
|
||||
private String materielNecessaire;
|
||||
private String conditionsMeteo;
|
||||
private String imageUrl;
|
||||
private String couleurTheme;
|
||||
|
||||
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateAnnulation;
|
||||
private String raisonAnnulation;
|
||||
private String nomAnnulateur;
|
||||
private Long annulePar;
|
||||
|
||||
// === METHODES UTILITAIRES ===
|
||||
|
||||
public boolean estEnCours() {
|
||||
return StatutEvenement.EN_COURS.equals(statut);
|
||||
}
|
||||
|
||||
public boolean estTermine() {
|
||||
return StatutEvenement.TERMINE.equals(statut);
|
||||
}
|
||||
|
||||
public boolean estAnnule() {
|
||||
return StatutEvenement.ANNULE.equals(statut);
|
||||
}
|
||||
|
||||
public boolean estComplet() {
|
||||
return capaciteMax != null
|
||||
&& participantsInscrits != null
|
||||
&& participantsInscrits >= capaciteMax;
|
||||
}
|
||||
|
||||
public int getPlacesDisponibles() {
|
||||
if (capaciteMax == null || participantsInscrits == null) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(0, capaciteMax - participantsInscrits);
|
||||
}
|
||||
|
||||
public int getTauxRemplissage() {
|
||||
if (capaciteMax == null || capaciteMax == 0 || participantsInscrits == null) {
|
||||
return 0;
|
||||
}
|
||||
return (participantsInscrits * 100) / capaciteMax;
|
||||
}
|
||||
|
||||
public int getTauxPresence() {
|
||||
if (participantsInscrits == null || participantsInscrits == 0 || participantsPresents == null) {
|
||||
return 0;
|
||||
}
|
||||
return (participantsPresents * 100) / participantsInscrits;
|
||||
}
|
||||
|
||||
public boolean sontInscriptionsOuvertes() {
|
||||
if (estAnnule() || estTermine()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dateLimiteInscription != null && LocalDate.now().isAfter(dateLimiteInscription)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !estComplet();
|
||||
}
|
||||
|
||||
public long getDureeEnHeures() {
|
||||
if (heureDebut == null || heureFin == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return heureDebut.until(heureFin, java.time.temporal.ChronoUnit.HOURS);
|
||||
}
|
||||
|
||||
public boolean estEvenementMultiJours() {
|
||||
return dateFin != null && !dateDebut.equals(dateFin);
|
||||
}
|
||||
|
||||
public String getTypeEvenementLibelle() {
|
||||
return typeEvenement != null ? typeEvenement.getLibelle() : "Non défini";
|
||||
}
|
||||
|
||||
public String getStatutLibelle() {
|
||||
return statut != null ? statut.getLibelle() : "Non défini";
|
||||
}
|
||||
|
||||
public String getPrioriteLibelle() {
|
||||
return priorite != null ? priorite.getLibelle() : "Normale";
|
||||
}
|
||||
|
||||
public String getAdresseComplete() {
|
||||
StringBuilder adresseComplete = new StringBuilder();
|
||||
|
||||
if (lieu != null && !lieu.trim().isEmpty()) {
|
||||
adresseComplete.append(lieu);
|
||||
}
|
||||
|
||||
if (adresse != null && !adresse.trim().isEmpty()) {
|
||||
if (adresseComplete.length() > 0)
|
||||
adresseComplete.append(", ");
|
||||
adresseComplete.append(adresse);
|
||||
}
|
||||
|
||||
if (ville != null && !ville.trim().isEmpty()) {
|
||||
if (adresseComplete.length() > 0)
|
||||
adresseComplete.append(", ");
|
||||
adresseComplete.append(ville);
|
||||
}
|
||||
|
||||
if (region != null && !region.trim().isEmpty()) {
|
||||
if (adresseComplete.length() > 0)
|
||||
adresseComplete.append(", ");
|
||||
adresseComplete.append(region);
|
||||
}
|
||||
|
||||
return adresseComplete.toString();
|
||||
}
|
||||
|
||||
public boolean hasCoordonnees() {
|
||||
return latitude != null && longitude != null;
|
||||
}
|
||||
|
||||
public BigDecimal getEcartBudgetaire() {
|
||||
if (budget == null || coutReel == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return budget.subtract(coutReel);
|
||||
}
|
||||
|
||||
public boolean estBudgetDepasse() {
|
||||
return getEcartBudgetaire().compareTo(BigDecimal.ZERO) < 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.lions.unionflow.server.api.dto.favoris.request;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un favori.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
public record CreateFavoriRequest(
|
||||
UUID utilisateurId,
|
||||
String typeFavori,
|
||||
String titre,
|
||||
String description,
|
||||
String url,
|
||||
String icon,
|
||||
String couleur,
|
||||
String categorie,
|
||||
Integer ordre,
|
||||
Integer nbVisites,
|
||||
String derniereVisite,
|
||||
Boolean estPlusUtilise) {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package dev.lions.unionflow.server.api.dto.favoris.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.Builder;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Réponse pour un favori utilisateur.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class FavoriResponse extends BaseResponse {
|
||||
|
||||
private UUID utilisateurId;
|
||||
private String typeFavori;
|
||||
private String titre;
|
||||
private String description;
|
||||
private String url;
|
||||
private String icon;
|
||||
private String couleur;
|
||||
private String categorie;
|
||||
private Integer ordre;
|
||||
private Integer nbVisites;
|
||||
private String derniereVisite;
|
||||
private Boolean estPlusUtilise;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une adhésion.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
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,
|
||||
|
||||
@NotNull(message = "L'identifiant du membre est obligatoire") UUID membreId,
|
||||
@NotNull(message = "L'identifiant de l'organisation est obligatoire") UUID organisationId,
|
||||
@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,
|
||||
|
||||
@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) {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance.request;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une adhésion.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Builder
|
||||
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,
|
||||
|
||||
@Pattern(regexp = "^(EN_ATTENTE|APPROUVEE|REJETEE|ANNULEE|EN_PAIEMENT|PAYEE)$", message = "Statut invalide") String statut,
|
||||
|
||||
LocalDate dateApprobation,
|
||||
LocalDateTime datePaiement,
|
||||
|
||||
@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 = 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 = 255, message = "Le nom de l'approbateur ne peut pas dépasser 255 caractères") String approuvePar,
|
||||
|
||||
LocalDate dateValidation) {
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse contenant les données d'une adhésion.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AdhesionResponse extends BaseResponse {
|
||||
|
||||
private String numeroReference;
|
||||
private UUID membreId;
|
||||
private String numeroMembre;
|
||||
private String nomMembre;
|
||||
private String emailMembre;
|
||||
private UUID organisationId;
|
||||
private String nomOrganisation;
|
||||
private LocalDate dateDemande;
|
||||
private BigDecimal fraisAdhesion;
|
||||
private BigDecimal montantPaye;
|
||||
private String codeDevise;
|
||||
private String statut;
|
||||
private LocalDate dateApprobation;
|
||||
private LocalDateTime datePaiement;
|
||||
private String methodePaiement;
|
||||
private String referencePaiement;
|
||||
private String motifRejet;
|
||||
private String observations;
|
||||
private String approuvePar;
|
||||
private LocalDate dateValidation;
|
||||
|
||||
// Méthodes utilitaires héritées de l'ancien DTO
|
||||
public boolean isPayeeIntegralement() {
|
||||
return montantPaye != null && fraisAdhesion != null && montantPaye.compareTo(fraisAdhesion) >= 0;
|
||||
}
|
||||
|
||||
public boolean isEnAttentePaiement() {
|
||||
return "APPROUVEE".equals(statut) && !isPayeeIntegralement();
|
||||
}
|
||||
|
||||
public BigDecimal getMontantRestant() {
|
||||
if (fraisAdhesion == null)
|
||||
return BigDecimal.ZERO;
|
||||
if (montantPaye == null)
|
||||
return fraisAdhesion;
|
||||
BigDecimal restant = fraisAdhesion.subtract(montantPaye);
|
||||
return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public int getPourcentagePaiement() {
|
||||
if (fraisAdhesion == null || fraisAdhesion.compareTo(BigDecimal.ZERO) == 0)
|
||||
return 0;
|
||||
if (montantPaye == null)
|
||||
return 0;
|
||||
return montantPaye.multiply(BigDecimal.valueOf(100)).divide(fraisAdhesion, 0, java.math.RoundingMode.HALF_UP)
|
||||
.intValue();
|
||||
}
|
||||
|
||||
public long getJoursDepuisDemande() {
|
||||
if (dateDemande == null)
|
||||
return 0;
|
||||
return ChronoUnit.DAYS.between(dateDemande, LocalDate.now());
|
||||
}
|
||||
|
||||
public String getStatutLibelle() {
|
||||
if (statut == null)
|
||||
return "Non défini";
|
||||
return switch (statut) {
|
||||
case "EN_ATTENTE" -> "En attente";
|
||||
case "APPROUVEE" -> "Approuvée";
|
||||
case "REJETEE" -> "Rejetée";
|
||||
case "ANNULEE" -> "Annulée";
|
||||
case "EN_PAIEMENT" -> "En paiement";
|
||||
case "PAYEE" -> "Payée";
|
||||
default -> statut;
|
||||
};
|
||||
}
|
||||
|
||||
public String getStatutSeverity() {
|
||||
if (statut == null)
|
||||
return "secondary";
|
||||
return switch (statut) {
|
||||
case "APPROUVEE", "PAYEE" -> "success";
|
||||
case "EN_ATTENTE", "EN_PAIEMENT" -> "warning";
|
||||
case "REJETEE" -> "danger";
|
||||
case "ANNULEE" -> "secondary";
|
||||
default -> "secondary";
|
||||
};
|
||||
}
|
||||
|
||||
public String getStatutIcon() {
|
||||
if (statut == null)
|
||||
return "pi-circle";
|
||||
return switch (statut) {
|
||||
case "APPROUVEE", "PAYEE" -> "pi-check";
|
||||
case "EN_ATTENTE" -> "pi-clock";
|
||||
case "EN_PAIEMENT" -> "pi-credit-card";
|
||||
case "REJETEE" -> "pi-times";
|
||||
case "ANNULEE" -> "pi-ban";
|
||||
default -> "pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
public String getMethodePaiementLibelle() {
|
||||
if (methodePaiement == null)
|
||||
return "Non défini";
|
||||
return switch (methodePaiement) {
|
||||
case "ESPECES" -> "Espèces";
|
||||
case "VIREMENT" -> "Virement bancaire";
|
||||
case "CHEQUE" -> "Chèque";
|
||||
case "WAVE_MONEY" -> "Wave Money";
|
||||
case "ORANGE_MONEY" -> "Orange Money";
|
||||
case "FREE_MONEY" -> "Free Money";
|
||||
case "CARTE_BANCAIRE" -> "Carte bancaire";
|
||||
default -> methodePaiement;
|
||||
};
|
||||
}
|
||||
|
||||
public String getDateDemandeFormatee() {
|
||||
if (dateDemande == null)
|
||||
return "";
|
||||
return dateDemande.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
public String getDateApprobationFormatee() {
|
||||
if (dateApprobation == null)
|
||||
return "";
|
||||
return dateApprobation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
public String getDatePaiementFormatee() {
|
||||
if (datePaiement == null)
|
||||
return "";
|
||||
return datePaiement.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
|
||||
}
|
||||
|
||||
public String getFraisAdhesionFormatte() {
|
||||
if (fraisAdhesion == null)
|
||||
return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", fraisAdhesion.doubleValue());
|
||||
}
|
||||
|
||||
public String getMontantPayeFormatte() {
|
||||
if (montantPaye == null)
|
||||
return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", montantPaye.doubleValue());
|
||||
}
|
||||
|
||||
public String getMontantRestantFormatte() {
|
||||
return String.format("%,.0f FCFA", getMontantRestant().doubleValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.request;
|
||||
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de requête pour approuver une transaction
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class ApproveTransactionRequest {
|
||||
|
||||
@Size(max = 1000, message = "Le commentaire ne peut pas dépasser 1000 caractères")
|
||||
private String comment;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.request;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de requête pour créer une ligne budgétaire
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class CreateBudgetLineRequest {
|
||||
|
||||
@NotBlank(message = "La catégorie est requise")
|
||||
@Pattern(regexp = "^(CONTRIBUTIONS|SAVINGS|SOLIDARITY|EVENTS|OPERATIONAL|INVESTMENTS|OTHER)$",
|
||||
message = "Catégorie invalide")
|
||||
private String category;
|
||||
|
||||
@NotBlank(message = "Le nom est requis")
|
||||
@Size(max = 200, message = "Le nom ne peut pas dépasser 200 caractères")
|
||||
private String name;
|
||||
|
||||
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
|
||||
private String description;
|
||||
|
||||
@NotNull(message = "Le montant prévu est requis")
|
||||
@DecimalMin(value = "0.0", message = "Le montant prévu doit être positif")
|
||||
@Digits(integer = 14, fraction = 2, message = "Format du montant invalide")
|
||||
private BigDecimal amountPlanned;
|
||||
|
||||
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères")
|
||||
private String notes;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.request;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de requête pour créer un budget
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class CreateBudgetRequest {
|
||||
|
||||
@NotBlank(message = "Le nom est requis")
|
||||
@Size(max = 200, message = "Le nom ne peut pas dépasser 200 caractères")
|
||||
private String name;
|
||||
|
||||
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
|
||||
private String description;
|
||||
|
||||
@NotNull(message = "L'ID de l'organisation est requis")
|
||||
private UUID organizationId;
|
||||
|
||||
@NotBlank(message = "La période est requise")
|
||||
@Pattern(regexp = "^(MONTHLY|QUARTERLY|SEMIANNUAL|ANNUAL)$",
|
||||
message = "Période invalide")
|
||||
private String period;
|
||||
|
||||
@NotNull(message = "L'année est requise")
|
||||
@Min(value = 2020, message = "L'année doit être >= 2020")
|
||||
@Max(value = 2100, message = "L'année doit être <= 2100")
|
||||
private Integer year;
|
||||
|
||||
@Min(value = 1, message = "Le mois doit être entre 1 et 12")
|
||||
@Max(value = 12, message = "Le mois doit être entre 1 et 12")
|
||||
private Integer month;
|
||||
|
||||
@NotNull(message = "Au moins une ligne budgétaire est requise")
|
||||
@Size(min = 1, message = "Au moins une ligne budgétaire est requise")
|
||||
@Valid
|
||||
@Builder.Default
|
||||
private List<CreateBudgetLineRequest> lines = new ArrayList<>();
|
||||
|
||||
@Pattern(regexp = "^[A-Z]{3}$", message = "Code devise invalide (doit être ISO 3 lettres)")
|
||||
private String currency; // Optionnel, défaut XOF
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.request;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de requête pour rejeter une transaction
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class RejectTransactionRequest {
|
||||
|
||||
@NotBlank(message = "La raison du rejet est requise")
|
||||
@Size(min = 10, max = 1000, message = "La raison doit contenir entre 10 et 1000 caractères")
|
||||
private String reason;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de réponse pour une action d'approbateur
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class ApproverActionResponse {
|
||||
|
||||
private UUID id;
|
||||
|
||||
@NotNull
|
||||
private UUID approverId;
|
||||
|
||||
@NotBlank
|
||||
private String approverName;
|
||||
|
||||
@NotBlank
|
||||
private String approverRole;
|
||||
|
||||
@NotBlank
|
||||
private String decision; // PENDING, APPROVED, REJECTED
|
||||
|
||||
private String comment;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime decidedAt;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.response;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de réponse pour une ligne budgétaire
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class BudgetLineResponse {
|
||||
|
||||
private UUID id;
|
||||
|
||||
@NotBlank
|
||||
private String category; // CONTRIBUTIONS, SAVINGS, SOLIDARITY, etc.
|
||||
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal amountPlanned;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal amountRealized;
|
||||
|
||||
private String notes;
|
||||
|
||||
// Champs calculés
|
||||
private Double realizationRate;
|
||||
private BigDecimal variance;
|
||||
private Boolean isOverBudget;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de réponse pour un budget
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class BudgetResponse {
|
||||
|
||||
private UUID id;
|
||||
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
@NotNull
|
||||
private UUID organizationId;
|
||||
|
||||
@NotBlank
|
||||
private String period; // MONTHLY, QUARTERLY, SEMIANNUAL, ANNUAL
|
||||
|
||||
@NotNull
|
||||
private Integer year;
|
||||
|
||||
private Integer month;
|
||||
|
||||
@NotBlank
|
||||
private String status; // DRAFT, ACTIVE, CLOSED, CANCELLED
|
||||
|
||||
@Builder.Default
|
||||
private List<BudgetLineResponse> lines = new ArrayList<>();
|
||||
|
||||
@NotNull
|
||||
private BigDecimal totalPlanned;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal totalRealized;
|
||||
|
||||
@NotBlank
|
||||
private String currency;
|
||||
|
||||
@NotNull
|
||||
private UUID createdById;
|
||||
|
||||
@NotNull
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime approvedAt;
|
||||
|
||||
private UUID approvedById;
|
||||
|
||||
@NotNull
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate startDate;
|
||||
|
||||
@NotNull
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate endDate;
|
||||
|
||||
private String metadata;
|
||||
|
||||
// Champs calculés
|
||||
private Double realizationRate;
|
||||
private BigDecimal variance;
|
||||
private Double varianceRate;
|
||||
private Boolean isOverBudget;
|
||||
private Boolean isActive;
|
||||
private Boolean isCurrentPeriod;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package dev.lions.unionflow.server.api.dto.finance_workflow.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* DTO de réponse pour une approbation de transaction
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-13
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TransactionApprovalResponse {
|
||||
|
||||
private UUID id;
|
||||
|
||||
@NotNull
|
||||
private UUID transactionId;
|
||||
|
||||
@NotBlank
|
||||
private String transactionType; // CONTRIBUTION, DEPOSIT, WITHDRAWAL, etc.
|
||||
|
||||
@NotNull
|
||||
private BigDecimal amount;
|
||||
|
||||
@NotBlank
|
||||
private String currency;
|
||||
|
||||
@NotNull
|
||||
private UUID requesterId;
|
||||
|
||||
@NotBlank
|
||||
private String requesterName;
|
||||
|
||||
private UUID organizationId;
|
||||
|
||||
@NotBlank
|
||||
private String requiredLevel; // NONE, LEVEL1, LEVEL2, LEVEL3
|
||||
|
||||
@NotBlank
|
||||
private String status; // PENDING, APPROVED, VALIDATED, REJECTED, EXPIRED, CANCELLED
|
||||
|
||||
@Builder.Default
|
||||
private List<ApproverActionResponse> approvers = new ArrayList<>();
|
||||
|
||||
private String rejectionReason;
|
||||
|
||||
@NotNull
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime expiresAt;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
private LocalDateTime completedAt;
|
||||
|
||||
private String metadata;
|
||||
|
||||
// Champs calculés
|
||||
private Integer approvalCount;
|
||||
private Integer requiredApprovals;
|
||||
private Boolean hasAllApprovals;
|
||||
private Boolean isExpired;
|
||||
private Boolean isPending;
|
||||
private Boolean isCompleted;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
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.TypeFormule;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'une formule d'abonnement.
|
||||
*/
|
||||
@Builder
|
||||
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 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,
|
||||
@NotNull(message = "Le type de formule est obligatoire") TypeFormule type,
|
||||
@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,
|
||||
@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,
|
||||
@NotNull(message = "Le nombre maximum de membres est obligatoire") Integer maxMembres,
|
||||
@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 = "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,
|
||||
Boolean fonctionnalitesAvancees,
|
||||
Boolean apiAccess,
|
||||
Boolean rapportsPersonnalises,
|
||||
Boolean integrationsTierces,
|
||||
Boolean sauvegardeAutomatique,
|
||||
Boolean multiLangues,
|
||||
Boolean personnalisationInterface,
|
||||
Boolean formationIncluse,
|
||||
Integer heuresFormation,
|
||||
Boolean populaire,
|
||||
Boolean recommandee,
|
||||
Integer periodeEssaiJours,
|
||||
LocalDate dateDebutValidite,
|
||||
LocalDate dateFinValidite,
|
||||
Integer ordreAffichage,
|
||||
@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 = 500, message = "Les notes ne peuvent pas dépasser 500 caractères") String notes) {
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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.TypeFormule;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de mise à jour d'une formule d'abonnement.
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateFormuleAbonnementRequest(
|
||||
@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,
|
||||
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères") String description,
|
||||
TypeFormule type,
|
||||
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 annuel doit être positif") @Digits(integer = 10, fraction = 2) BigDecimal prixAnnuel,
|
||||
@Pattern(regexp = "^[A-Z]{3}$") String devise,
|
||||
Integer maxMembres,
|
||||
Integer maxAdministrateurs,
|
||||
@DecimalMin(value = "0.1", message = "L'espace de stockage doit être d'au moins 0.1 GB") BigDecimal espaceStockageGB,
|
||||
Boolean supportTechnique,
|
||||
@Pattern(regexp = "^(EMAIL|CHAT|TELEPHONE|PREMIUM)$", message = "Le niveau de support doit être EMAIL, CHAT, TELEPHONE ou PREMIUM") String niveauSupport,
|
||||
Boolean fonctionnalitesAvancees,
|
||||
Boolean apiAccess,
|
||||
Boolean rapportsPersonnalises,
|
||||
Boolean integrationsTierces,
|
||||
Boolean sauvegardeAutomatique,
|
||||
Boolean multiLangues,
|
||||
Boolean personnalisationInterface,
|
||||
Boolean formationIncluse,
|
||||
Integer heuresFormation,
|
||||
Boolean populaire,
|
||||
Boolean recommandee,
|
||||
Integer periodeEssaiJours,
|
||||
LocalDate dateDebutValidite,
|
||||
LocalDate dateFinValidite,
|
||||
Integer ordreAffichage,
|
||||
@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 = 500, message = "Les notes ne peuvent pas dépasser 500 caractères") String notes) {
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package dev.lions.unionflow.server.api.dto.formuleabonnement.response;
|
||||
|
||||
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.TypeFormule;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse détaillée pour une formule d'abonnement.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class FormuleAbonnementResponse extends BaseResponse {
|
||||
|
||||
private String nom;
|
||||
private String code;
|
||||
private String description;
|
||||
private TypeFormule type;
|
||||
private StatutFormule statut;
|
||||
private BigDecimal prixMensuel;
|
||||
private BigDecimal prixAnnuel;
|
||||
@Builder.Default
|
||||
private String devise = "XOF";
|
||||
private Integer maxMembres;
|
||||
private Integer maxAdministrateurs;
|
||||
private BigDecimal espaceStockageGB;
|
||||
private Boolean supportTechnique;
|
||||
private String niveauSupport;
|
||||
private Boolean fonctionnalitesAvancees;
|
||||
private Boolean apiAccess;
|
||||
private Boolean rapportsPersonnalises;
|
||||
private Boolean integrationsTierces;
|
||||
private Boolean sauvegardeAutomatique;
|
||||
private Boolean multiLangues;
|
||||
private Boolean personnalisationInterface;
|
||||
private Boolean formationIncluse;
|
||||
private Integer heuresFormation;
|
||||
private Boolean populaire;
|
||||
private Boolean recommandee;
|
||||
private Integer periodeEssaiJours;
|
||||
private LocalDate dateDebutValidite;
|
||||
private LocalDate dateFinValidite;
|
||||
private Integer ordreAffichage;
|
||||
private String couleur;
|
||||
private String icone;
|
||||
private String notes;
|
||||
|
||||
public boolean isActive() {
|
||||
return StatutFormule.ACTIVE.equals(statut);
|
||||
}
|
||||
|
||||
public boolean isInactive() {
|
||||
return StatutFormule.INACTIVE.equals(statut);
|
||||
}
|
||||
|
||||
public boolean isArchivee() {
|
||||
return StatutFormule.ARCHIVEE.equals(statut);
|
||||
}
|
||||
|
||||
public boolean isValide() {
|
||||
if (!isActive())
|
||||
return false;
|
||||
|
||||
LocalDate aujourd = LocalDate.now();
|
||||
if (dateDebutValidite != null && aujourd.isBefore(dateDebutValidite))
|
||||
return false;
|
||||
if (dateFinValidite != null && aujourd.isAfter(dateFinValidite))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public BigDecimal getEconomieAnnuelle() {
|
||||
if (prixMensuel == null || prixAnnuel == null)
|
||||
return BigDecimal.ZERO;
|
||||
BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12));
|
||||
return coutMensuelAnnuel.subtract(prixAnnuel);
|
||||
}
|
||||
|
||||
public int getPourcentageEconomieAnnuelle() {
|
||||
if (prixMensuel == null || prixAnnuel == null)
|
||||
return 0;
|
||||
BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12));
|
||||
if (coutMensuelAnnuel.compareTo(BigDecimal.ZERO) > 0) {
|
||||
return getEconomieAnnuelle()
|
||||
.multiply(BigDecimal.valueOf(100))
|
||||
.divide(coutMensuelAnnuel, 0, java.math.RoundingMode.HALF_UP)
|
||||
.intValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean hasPeriodeEssai() {
|
||||
return periodeEssaiJours != null && periodeEssaiJours > 0;
|
||||
}
|
||||
|
||||
public boolean hasFormation() {
|
||||
return Boolean.TRUE.equals(formationIncluse) && heuresFormation != null && heuresFormation > 0;
|
||||
}
|
||||
|
||||
public boolean isMiseEnAvant() {
|
||||
return Boolean.TRUE.equals(populaire) || Boolean.TRUE.equals(recommandee);
|
||||
}
|
||||
|
||||
public String getBadge() {
|
||||
if (Boolean.TRUE.equals(populaire))
|
||||
return "POPULAIRE";
|
||||
if (Boolean.TRUE.equals(recommandee))
|
||||
return "RECOMMANDÉE";
|
||||
if (hasPeriodeEssai())
|
||||
return "ESSAI GRATUIT";
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getScoreFonctionnalites() {
|
||||
if (supportTechnique == null && sauvegardeAutomatique == null && fonctionnalitesAvancees == null
|
||||
&& apiAccess == null && rapportsPersonnalises == null && integrationsTierces == null
|
||||
&& multiLangues == null && personnalisationInterface == null) {
|
||||
return 0;
|
||||
}
|
||||
int score = 0;
|
||||
int total = 0;
|
||||
if (Boolean.TRUE.equals(supportTechnique)) score += 10;
|
||||
total += 10;
|
||||
if (Boolean.TRUE.equals(sauvegardeAutomatique)) score += 10;
|
||||
total += 10;
|
||||
if (Boolean.TRUE.equals(fonctionnalitesAvancees)) score += 15;
|
||||
total += 15;
|
||||
if (Boolean.TRUE.equals(apiAccess)) score += 15;
|
||||
total += 15;
|
||||
if (Boolean.TRUE.equals(rapportsPersonnalises)) score += 15;
|
||||
total += 15;
|
||||
if (Boolean.TRUE.equals(integrationsTierces)) score += 15;
|
||||
total += 15;
|
||||
if (Boolean.TRUE.equals(multiLangues)) score += 10;
|
||||
total += 10;
|
||||
if (Boolean.TRUE.equals(personnalisationInterface)) score += 10;
|
||||
total += 10;
|
||||
return (score * 100) / total;
|
||||
}
|
||||
|
||||
public String getCssClass() {
|
||||
if (type == null)
|
||||
return "formule-default";
|
||||
return switch (type) {
|
||||
case BASIC -> "formule-basic";
|
||||
case STANDARD -> "formule-standard";
|
||||
case PREMIUM -> "formule-premium";
|
||||
case ENTERPRISE -> "formule-enterprise";
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package dev.lions.unionflow.server.api.dto.gouvernance;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||
import dev.lions.unionflow.server.api.enums.gouvernance.NiveauEchelon;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class EchelonOrganigrammeDTO extends BaseDTO {
|
||||
|
||||
// L'Id physique de l'organisation dans le système (une organisation == un
|
||||
// échelon)
|
||||
private String organisationId;
|
||||
|
||||
// L'organisation mère / chapeau de cet échelon
|
||||
private String echelonParentId;
|
||||
|
||||
private NiveauEchelon niveau;
|
||||
|
||||
private String designation;
|
||||
private String zoneGeographiqueOuDelegation;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* DTO représentant le "compte adhérent" d'un membre de mutuelle/association.
|
||||
*
|
||||
* <p>Ce compte est une vue agrégée (non persistée en tant que telle) qui regroupe
|
||||
* toutes les informations financières du membre :
|
||||
* <ul>
|
||||
* <li>Numéro de membre (identifiant lisible, ex : MUF-2026-001)</li>
|
||||
* <li>Solde cotisations (total payé toutes années)</li>
|
||||
* <li>Solde épargne (somme des comptes d'épargne actifs)</li>
|
||||
* <li>Solde total disponible = cotisations + épargne</li>
|
||||
* <li>Encours crédit (prêts en cours, 0 si pas encore implémenté)</li>
|
||||
* <li>Capacité d'emprunt estimée (3× l'épargne — règle mutuelle classique)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param numeroMembre Numéro unique du membre sur la plateforme (ex: MUF-2026-001)
|
||||
* @param nomComplet Nom et prénom du membre
|
||||
* @param organisationNom Nom de l'organisation principale (ou null si aucune)
|
||||
* @param dateAdhesion Date d'inscription sur la plateforme
|
||||
* @param statutCompte Statut actuel du compte (ACTIF, SUSPENDU, etc.)
|
||||
*
|
||||
* @param soldeCotisations Total des cotisations payées (toutes années confondues)
|
||||
* @param soldeEpargne Solde disponible sur l'ensemble des comptes épargne actifs
|
||||
* @param soldeBloque Montant bloqué (garantie de prêt)
|
||||
* @param soldeTotalDisponible soldeCotisations + soldeEpargne - soldeBloque
|
||||
* @param encoursCreditTotal Montant total des prêts en cours (0 si fonctionnalité non encore activée)
|
||||
* @param capaciteEmprunt Capacité d'emprunt estimée (3 × soldeEpargne selon règle mutuelle standard)
|
||||
*
|
||||
* @param nombreCotisationsPayees Nombre de cotisations payées (historique complet)
|
||||
* @param nombreCotisationsTotal Nombre total de cotisations (payées + en attente + retard)
|
||||
* @param nombreCotisationsEnRetard Nombre de cotisations en retard
|
||||
* @param tauxEngagement Taux de paiement global en % (0-100)
|
||||
*
|
||||
* @param nombreComptesEpargne Nombre de comptes épargne actifs
|
||||
* @param dateCalcul Date/heure du calcul (pour information client)
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
public record CompteAdherentResponse(
|
||||
|
||||
// ── Identité ──────────────────────────────────────────────────────────
|
||||
String numeroMembre,
|
||||
String nomComplet,
|
||||
String organisationNom,
|
||||
LocalDate dateAdhesion,
|
||||
String statutCompte,
|
||||
|
||||
// ── Soldes ────────────────────────────────────────────────────────────
|
||||
BigDecimal soldeCotisations,
|
||||
BigDecimal soldeEpargne,
|
||||
BigDecimal soldeBloque,
|
||||
BigDecimal soldeTotalDisponible,
|
||||
BigDecimal encoursCreditTotal,
|
||||
BigDecimal capaciteEmprunt,
|
||||
|
||||
// ── Cotisations ───────────────────────────────────────────────────────
|
||||
Integer nombreCotisationsPayees,
|
||||
Integer nombreCotisationsTotal,
|
||||
Integer nombreCotisationsEnRetard,
|
||||
Integer tauxEngagement,
|
||||
|
||||
// ── Épargne ───────────────────────────────────────────────────────────
|
||||
Integer nombreComptesEpargne,
|
||||
|
||||
// ── Méta ──────────────────────────────────────────────────────────────
|
||||
LocalDate dateCalcul
|
||||
|
||||
) implements Serializable {}
|
||||
@@ -0,0 +1,226 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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
|
||||
* multiples critères
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-19
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Critères de recherche avancée pour les membres")
|
||||
public class MembreSearchCriteria {
|
||||
|
||||
/** 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")
|
||||
@Size(max = 100, message = "Le terme de recherche ne peut pas dépasser 100 caractères")
|
||||
private String query;
|
||||
|
||||
/** Recherche par nom exact ou partiel */
|
||||
@Schema(description = "Filtre par nom (recherche partielle)", example = "Dupont")
|
||||
@Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères")
|
||||
private String nom;
|
||||
|
||||
/** Recherche par prénom exact ou partiel */
|
||||
@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")
|
||||
private String prenom;
|
||||
|
||||
/** Recherche par email exact ou partiel */
|
||||
@Schema(description = "Filtre par email (recherche partielle)", example = "@unionflow.com")
|
||||
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
|
||||
private String email;
|
||||
|
||||
/** Filtre par numéro de téléphone */
|
||||
@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")
|
||||
private String telephone;
|
||||
|
||||
/** Liste des IDs d'organisations */
|
||||
@Schema(description = "Liste des IDs d'organisations à inclure")
|
||||
private List<UUID> organisationIds;
|
||||
|
||||
/** Liste des rôles à rechercher */
|
||||
@Schema(description = "Liste des rôles à rechercher", example = "[\"PRESIDENT\", \"SECRETAIRE\"]")
|
||||
private List<String> roles;
|
||||
|
||||
/** Filtre par statut d'activité */
|
||||
@Schema(description = "Filtre par statut d'activité", example = "ACTIF")
|
||||
@Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
|
||||
private String statut;
|
||||
|
||||
/** Date d'adhésion minimum */
|
||||
@Schema(description = "Date d'adhésion minimum", example = "2020-01-01")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate dateAdhesionMin;
|
||||
|
||||
/** Date d'adhésion maximum */
|
||||
@Schema(description = "Date d'adhésion maximum", example = "2025-12-31")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate dateAdhesionMax;
|
||||
|
||||
/** Âge minimum */
|
||||
@Schema(description = "Âge minimum", example = "18")
|
||||
@Min(value = 0, message = "L'âge minimum doit être positif")
|
||||
@Max(value = 120, message = "L'âge minimum ne peut pas dépasser 120 ans")
|
||||
private Integer ageMin;
|
||||
|
||||
/** Âge maximum */
|
||||
@Schema(description = "Âge maximum", example = "65")
|
||||
@Min(value = 0, message = "L'âge maximum doit être positif")
|
||||
@Max(value = 120, message = "L'âge maximum ne peut pas dépasser 120 ans")
|
||||
private Integer ageMax;
|
||||
|
||||
/** Filtre par région */
|
||||
@Schema(description = "Filtre par région", example = "Dakar")
|
||||
@Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
|
||||
private String region;
|
||||
|
||||
/** Filtre par ville */
|
||||
@Schema(description = "Filtre par ville", example = "Dakar")
|
||||
@Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
|
||||
private String ville;
|
||||
|
||||
/** Filtre par profession */
|
||||
@Schema(description = "Filtre par profession", example = "Ingénieur")
|
||||
@Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
|
||||
private String profession;
|
||||
|
||||
/** Filtre par nationalité */
|
||||
@Schema(description = "Filtre par nationalité", example = "Sénégalaise")
|
||||
@Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
|
||||
private String nationalite;
|
||||
|
||||
/** Filtre membres du bureau uniquement */
|
||||
@Schema(description = "Filtre pour les membres du bureau uniquement")
|
||||
private Boolean membreBureau;
|
||||
|
||||
/** Filtre responsables uniquement */
|
||||
@Schema(description = "Filtre pour les responsables uniquement")
|
||||
private Boolean responsable;
|
||||
|
||||
/** Inclure les membres inactifs dans la recherche */
|
||||
@Schema(description = "Inclure les membres inactifs", defaultValue = "false")
|
||||
@Builder.Default
|
||||
private Boolean includeInactifs = false;
|
||||
|
||||
/**
|
||||
* Vérifie si au moins un critère de recherche est défini
|
||||
*
|
||||
* @return true si au moins un critère est défini
|
||||
*/
|
||||
public boolean hasAnyCriteria() {
|
||||
return query != null && !query.trim().isEmpty()
|
||||
|| nom != null && !nom.trim().isEmpty()
|
||||
|| prenom != null && !prenom.trim().isEmpty()
|
||||
|| email != null && !email.trim().isEmpty()
|
||||
|| telephone != null && !telephone.trim().isEmpty()
|
||||
|| organisationIds != null && !organisationIds.isEmpty()
|
||||
|| roles != null && !roles.isEmpty()
|
||||
|| statut != null && !statut.trim().isEmpty()
|
||||
|| dateAdhesionMin != null
|
||||
|| dateAdhesionMax != null
|
||||
|| ageMin != null
|
||||
|| ageMax != null
|
||||
|| region != null && !region.trim().isEmpty()
|
||||
|| ville != null && !ville.trim().isEmpty()
|
||||
|| profession != null && !profession.trim().isEmpty()
|
||||
|| nationalite != null && !nationalite.trim().isEmpty()
|
||||
|| membreBureau != null
|
||||
|| responsable != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide la cohérence des critères de recherche
|
||||
*
|
||||
* @return true si les critères sont cohérents
|
||||
*/
|
||||
public boolean isValid() {
|
||||
// Validation des dates
|
||||
if (dateAdhesionMin != null && dateAdhesionMax != null) {
|
||||
if (dateAdhesionMin.isAfter(dateAdhesionMax)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validation des âges
|
||||
if (ageMin != null && ageMax != null) {
|
||||
if (ageMin > ageMax) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Nettoie les chaînes de caractères (trim et null si vide) */
|
||||
public void sanitize() {
|
||||
query = sanitizeString(query);
|
||||
nom = sanitizeString(nom);
|
||||
prenom = sanitizeString(prenom);
|
||||
email = sanitizeString(email);
|
||||
telephone = sanitizeString(telephone);
|
||||
statut = sanitizeString(statut);
|
||||
region = sanitizeString(region);
|
||||
ville = sanitizeString(ville);
|
||||
profession = sanitizeString(profession);
|
||||
nationalite = sanitizeString(nationalite);
|
||||
}
|
||||
|
||||
private String sanitizeString(String str) {
|
||||
if (str == null) return null;
|
||||
str = str.trim();
|
||||
return str.isEmpty() ? null : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne une description textuelle des critères actifs
|
||||
*
|
||||
* @return Description des critères
|
||||
*/
|
||||
public String getDescription() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (query != null) sb.append("Recherche: '").append(query).append("' ");
|
||||
if (nom != null) sb.append("Nom: '").append(nom).append("' ");
|
||||
if (prenom != null) sb.append("Prénom: '").append(prenom).append("' ");
|
||||
if (email != null) sb.append("Email: '").append(email).append("' ");
|
||||
if (statut != null) sb.append("Statut: ").append(statut).append(" ");
|
||||
if (organisationIds != null && !organisationIds.isEmpty()) {
|
||||
sb.append("Organisations: ").append(organisationIds.size()).append(" ");
|
||||
}
|
||||
if (roles != null && !roles.isEmpty()) {
|
||||
sb.append("Rôles: ").append(String.join(", ", roles)).append(" ");
|
||||
}
|
||||
if (dateAdhesionMin != null) sb.append("Adhésion >= ").append(dateAdhesionMin).append(" ");
|
||||
if (dateAdhesionMax != null) sb.append("Adhésion <= ").append(dateAdhesionMax).append(" ");
|
||||
if (ageMin != null) sb.append("Âge >= ").append(ageMin).append(" ");
|
||||
if (ageMax != null) sb.append("Âge <= ").append(ageMax).append(" ");
|
||||
if (region != null) sb.append("Région: '").append(region).append("' ");
|
||||
if (ville != null) sb.append("Ville: '").append(ville).append("' ");
|
||||
if (profession != null) sb.append("Profession: '").append(profession).append("' ");
|
||||
if (nationalite != null) sb.append("Nationalité: '").append(nationalite).append("' ");
|
||||
if (Boolean.TRUE.equals(membreBureau)) sb.append("Membre bureau ");
|
||||
if (Boolean.TRUE.equals(responsable)) sb.append("Responsable ");
|
||||
|
||||
return sb.toString().trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* DTO pour les résultats de recherche avancée des membres Contient les
|
||||
* résultats paginés et les
|
||||
* métadonnées de recherche
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-19
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Résultats de recherche avancée des membres avec pagination")
|
||||
public class MembreSearchResultDTO {
|
||||
|
||||
/** Liste des membres trouvés */
|
||||
@Schema(description = "Liste des membres correspondant aux critères")
|
||||
private List<MembreSummaryResponse> membres;
|
||||
|
||||
/** Nombre total de résultats (toutes pages confondues) */
|
||||
@Schema(description = "Nombre total de résultats trouvés", example = "247")
|
||||
private long totalElements;
|
||||
|
||||
/** Nombre total de pages */
|
||||
@Schema(description = "Nombre total de pages", example = "13")
|
||||
private int totalPages;
|
||||
|
||||
/** Numéro de la page actuelle (0-based) */
|
||||
@Schema(description = "Numéro de la page actuelle", example = "0")
|
||||
private int currentPage;
|
||||
|
||||
/** Taille de la page */
|
||||
@Schema(description = "Nombre d'éléments par page", example = "20")
|
||||
private int pageSize;
|
||||
|
||||
/** Nombre d'éléments sur la page actuelle */
|
||||
@Schema(description = "Nombre d'éléments sur cette page", example = "20")
|
||||
private int numberOfElements;
|
||||
|
||||
/** Indique s'il y a une page suivante */
|
||||
@Schema(description = "Indique s'il y a une page suivante")
|
||||
private boolean hasNext;
|
||||
|
||||
/** 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;
|
||||
|
||||
/** Indique si c'est la première page */
|
||||
@Schema(description = "Indique si c'est la première page")
|
||||
@JsonProperty("isFirst")
|
||||
private boolean isFirst;
|
||||
|
||||
/** Indique si c'est la dernière page */
|
||||
@Schema(description = "Indique si c'est la dernière page")
|
||||
@JsonProperty("isLast")
|
||||
private boolean isLast;
|
||||
|
||||
/** Critères de recherche utilisés */
|
||||
@Schema(description = "Critères de recherche qui ont été appliqués")
|
||||
private MembreSearchCriteria criteria;
|
||||
|
||||
/** Temps d'exécution de la recherche en millisecondes */
|
||||
@Schema(description = "Temps d'exécution de la recherche en ms", example = "45")
|
||||
private long executionTimeMs;
|
||||
|
||||
/** Statistiques de recherche */
|
||||
@Schema(description = "Statistiques sur les résultats de recherche")
|
||||
private SearchStatistics statistics;
|
||||
|
||||
/** Statistiques sur les résultats de recherche */
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Statistiques sur les résultats de recherche")
|
||||
public static class SearchStatistics {
|
||||
|
||||
/** Répartition par statut */
|
||||
@Schema(description = "Nombre de membres actifs dans les résultats")
|
||||
private long membresActifs;
|
||||
|
||||
@Schema(description = "Nombre de membres inactifs dans les résultats")
|
||||
private long membresInactifs;
|
||||
|
||||
/** Répartition par âge */
|
||||
@Schema(description = "Âge moyen des membres trouvés")
|
||||
private double ageMoyen;
|
||||
|
||||
@Schema(description = "Âge minimum des membres trouvés")
|
||||
private int ageMin;
|
||||
|
||||
@Schema(description = "Âge maximum des membres trouvés")
|
||||
private int ageMax;
|
||||
|
||||
/** Répartition par organisation */
|
||||
@Schema(description = "Nombre d'organisations représentées")
|
||||
private long nombreOrganisations;
|
||||
|
||||
/** Répartition par région */
|
||||
@Schema(description = "Nombre de régions représentées")
|
||||
private long nombreRegions;
|
||||
|
||||
/** Ancienneté moyenne */
|
||||
@Schema(description = "Ancienneté moyenne en années")
|
||||
private double ancienneteMoyenne;
|
||||
}
|
||||
|
||||
/** Calcule et met à jour les indicateurs de pagination */
|
||||
public void calculatePaginationFlags() {
|
||||
this.isFirst = currentPage == 0;
|
||||
this.isLast = currentPage >= totalPages - 1;
|
||||
this.hasPrevious = currentPage > 0;
|
||||
this.hasNext = currentPage < totalPages - 1;
|
||||
this.numberOfElements = membres != null ? membres.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si les résultats sont vides
|
||||
*
|
||||
* @return true si aucun résultat
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return membres == null || membres.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public int getNextPageNumber() {
|
||||
return hasNext ? currentPage + 2 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public int getPreviousPageNumber() {
|
||||
return hasPrevious ? currentPage : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne une description textuelle des résultats
|
||||
*
|
||||
* @return Description des résultats
|
||||
*/
|
||||
public String getResultDescription() {
|
||||
if (isEmpty()) {
|
||||
return "Aucun membre trouvé";
|
||||
}
|
||||
|
||||
if (totalElements == 1) {
|
||||
return "1 membre trouvé";
|
||||
}
|
||||
|
||||
if (totalPages == 1) {
|
||||
return String.format("%d membres trouvés", totalElements);
|
||||
}
|
||||
|
||||
int startElement = currentPage * pageSize + 1;
|
||||
int endElement = Math.min(startElement + numberOfElements - 1, (int) totalElements);
|
||||
|
||||
return String.format(
|
||||
"Membres %d-%d sur %d (page %d/%d)",
|
||||
startElement, endElement, totalElements, currentPage + 1, totalPages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method pour créer un résultat vide
|
||||
*
|
||||
* @param criteria Critères de recherche
|
||||
* @return Résultat vide
|
||||
*/
|
||||
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria) {
|
||||
return empty(criteria, 20, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method pour créer un résultat vide avec pageSize spécifique
|
||||
*
|
||||
* @param criteria Critères de recherche
|
||||
* @param pageSize Taille de la page
|
||||
* @param currentPage Page actuelle
|
||||
* @return Résultat vide
|
||||
*/
|
||||
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria, int pageSize, int currentPage) {
|
||||
MembreSearchResultDTO result = new MembreSearchResultDTO();
|
||||
result.setMembres(List.of());
|
||||
result.setTotalElements(0L);
|
||||
result.setTotalPages(0);
|
||||
result.setCurrentPage(currentPage);
|
||||
result.setPageSize(pageSize);
|
||||
result.setNumberOfElements(0);
|
||||
result.setHasNext(false);
|
||||
result.setHasPrevious(false);
|
||||
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.setCriteria(criteria);
|
||||
result.setExecutionTimeMs(0L);
|
||||
// Initialiser statistics avec des valeurs vides
|
||||
result.setStatistics(SearchStatistics.builder()
|
||||
.membresActifs(0)
|
||||
.membresInactifs(0)
|
||||
.ageMoyen(0.0)
|
||||
.ageMin(0)
|
||||
.ageMax(0)
|
||||
.nombreOrganisations(0)
|
||||
.nombreRegions(0)
|
||||
.ancienneteMoyenne(0.0)
|
||||
.build());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre.request;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête de création d'un membre.
|
||||
*
|
||||
* <p>
|
||||
* Immutable via {@code record}. Exclut l'ID,
|
||||
* les champs d'audit, et le numéroMembre
|
||||
* (généré côté serveur).
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
* @since 2026-02-21
|
||||
* @param prenom prénom
|
||||
* @param nom nom de famille
|
||||
* @param email email
|
||||
* @param telephone téléphone
|
||||
* @param telephoneWave numéro Wave
|
||||
* @param dateNaissance date de naissance
|
||||
* @param profession profession
|
||||
* @param photoUrl URL de la photo
|
||||
* @param statutMatrimonial statut matrimonial
|
||||
* @param nationalite nationalité
|
||||
* @param typeIdentite type pièce d'identité
|
||||
* @param numeroIdentite numéro d'identité
|
||||
*/
|
||||
@Builder
|
||||
public record CreateMembreRequest(
|
||||
@NotBlank @Size(max = 100) String prenom,
|
||||
@NotBlank @Size(max = 100) String nom,
|
||||
@NotBlank @Email @Size(max = 255) String email,
|
||||
@Size(max = 20) String telephone,
|
||||
@Size(max = 13) String telephoneWave,
|
||||
@NotNull LocalDate dateNaissance,
|
||||
@Size(max = 100) String profession,
|
||||
@Size(max = 500) String photoUrl,
|
||||
@Size(max = 50) String statutMatrimonial,
|
||||
@Size(max = 100) String nationalite,
|
||||
@Size(max = 50) String typeIdentite,
|
||||
@Size(max = 100) String numeroIdentite) {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre.request;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* Requête pour mettre à jour un membre existant.
|
||||
*/
|
||||
@Builder
|
||||
public record UpdateMembreRequest(
|
||||
@NotBlank @Size(max = 100) String prenom,
|
||||
@NotBlank @Size(max = 100) String nom,
|
||||
@NotBlank @Email @Size(max = 255) String email,
|
||||
@Size(max = 20) String telephone,
|
||||
@Size(max = 13) String telephoneWave,
|
||||
@NotNull LocalDate dateNaissance,
|
||||
@Size(max = 100) String profession,
|
||||
@Size(max = 500) String photoUrl,
|
||||
@Size(max = 50) String statutMatrimonial,
|
||||
@Size(max = 100) String nationalite,
|
||||
@Size(max = 50) String typeIdentite,
|
||||
@Size(max = 100) String numeroIdentite,
|
||||
Boolean actif) {
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre.response;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseResponse;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Réponse contenant les données d'un membre.
|
||||
*
|
||||
* <p>
|
||||
* Classe Lombok (getters/setters) pour la
|
||||
* compatibilité avec les frameworks d'affichage
|
||||
* (PrimeFaces, etc.).
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
* @since 2026-02-21
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MembreResponse extends BaseResponse {
|
||||
|
||||
// ── Identité ───────────────────────────────
|
||||
private String numeroMembre;
|
||||
private UUID keycloakId;
|
||||
private String prenom;
|
||||
private String nom;
|
||||
private String nomComplet;
|
||||
private String email;
|
||||
private String telephone;
|
||||
private String telephoneWave;
|
||||
private LocalDate dateNaissance;
|
||||
private int age;
|
||||
|
||||
// ── Personnel ──────────────────────────────
|
||||
private String profession;
|
||||
private String photoUrl;
|
||||
private String statutMatrimonial;
|
||||
private String statutMatrimonialLibelle;
|
||||
private String nationalite;
|
||||
private String typeIdentite;
|
||||
private String typeIdentiteLibelle;
|
||||
private String numeroIdentite;
|
||||
|
||||
// ── KYC / LCB-FT ───────────────────────────
|
||||
private String niveauVigilanceKyc;
|
||||
private String statutKyc;
|
||||
private LocalDate dateVerificationIdentite;
|
||||
|
||||
// ── Statut ─────────────────────────────────
|
||||
private String statutCompte;
|
||||
private String statutCompteLibelle;
|
||||
private String statutCompteSeverity;
|
||||
private List<String> roles;
|
||||
|
||||
// ── Adhésion (contexte organisation) ───────
|
||||
private UUID organisationId;
|
||||
private String associationNom;
|
||||
private LocalDate dateAdhesion;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.lions.unionflow.server.api.dto.membre.response;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DTO de réponse résumé pour Membre (listes et optimisations).
|
||||
*/
|
||||
public record MembreSummaryResponse(
|
||||
UUID id,
|
||||
String numeroMembre,
|
||||
String prenom,
|
||||
String nom,
|
||||
String email,
|
||||
String telephone,
|
||||
String profession,
|
||||
String statutCompte,
|
||||
String statutCompteLibelle,
|
||||
String statutCompteSeverity,
|
||||
Boolean actif,
|
||||
List<String> roles,
|
||||
UUID organisationId,
|
||||
String associationNom) {
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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.TypeGarantie;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Requête initiale pour une demande de financement (Crédit)")
|
||||
public class DemandeCreditRequest {
|
||||
|
||||
@NotBlank(message = "L'ID du demandeur est obligatoire")
|
||||
private String membreId;
|
||||
|
||||
@NotNull(message = "Le type de crédit est obligatoire")
|
||||
private TypeCredit typeCredit;
|
||||
|
||||
@NotNull(message = "Le montant demandé est obligatoire")
|
||||
@DecimalMin(value = "1.0", message = "Le montant demandé doit être positif")
|
||||
private BigDecimal montantDemande;
|
||||
|
||||
@Min(value = 1, message = "La durée (en mois) doit être au moins de 1 mois")
|
||||
private Integer dureeMois;
|
||||
|
||||
@Schema(description = "Compte épargne adossé (si remboursement automatique ou nantissement)")
|
||||
private String compteLieId;
|
||||
|
||||
@NotBlank(message = "Le motif détaillé du financement est requis (Plan d'affaires, usage...)")
|
||||
private String justificationDetaillee;
|
||||
|
||||
@Schema(description = "Liste des IDs de documents justificatifs attachés au dossier")
|
||||
private List<String> documentIds;
|
||||
|
||||
@Schema(description = "Liste des garanties proposées avec la demande")
|
||||
private List<GarantieDemandeDTO> garantiesProposees;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package dev.lions.unionflow.server.api.dto.mutuelle.credit;
|
||||
|
||||
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.TypeCredit;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Réponse avec le tableau de bord résumé d'un dossier de crédit")
|
||||
public class DemandeCreditResponse extends BaseDTO {
|
||||
|
||||
private String numeroDossier;
|
||||
private String membreId;
|
||||
private TypeCredit typeCredit;
|
||||
private String compteLieId;
|
||||
|
||||
private BigDecimal montantDemande;
|
||||
private Integer dureeMoisDemande;
|
||||
|
||||
// Conditions actées par le comité de crédit (peuvent différer de la demande)
|
||||
private BigDecimal montantApprouve;
|
||||
private Integer dureeMoisApprouvee;
|
||||
private BigDecimal tauxInteretAnnuel; // Pourcentage
|
||||
private BigDecimal coutTotalCredit; // Total Intérêts
|
||||
|
||||
private StatutDemandeCredit statut;
|
||||
private String notesComite;
|
||||
|
||||
private LocalDate dateSoumission;
|
||||
private LocalDate dateValidation;
|
||||
private LocalDate datePremierEcheance;
|
||||
|
||||
@Schema(description = "Aperçu des échéances générées pour le tableau d'amortissement")
|
||||
private List<EcheanceCreditDTO> echeancier;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package dev.lions.unionflow.server.api.dto.mutuelle.credit;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||
import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutEcheanceCredit;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "Représente une ligne unique du tableau d'amortissement d'un crédit")
|
||||
public class EcheanceCreditDTO extends BaseDTO {
|
||||
|
||||
private String demandeCreditId;
|
||||
|
||||
@Schema(description = "Indice de l'échéance (ex: mois 1, 2, 3...)")
|
||||
private Integer ordre;
|
||||
|
||||
private LocalDate dateEcheancePrevue;
|
||||
private LocalDate datePaiementEffectif;
|
||||
|
||||
private BigDecimal capitalAmorti;
|
||||
private BigDecimal interetsDeLaPeriode;
|
||||
private BigDecimal montantTotalExigible;
|
||||
|
||||
private BigDecimal capitalRestantDu;
|
||||
|
||||
// Pénalités éventuelles additionnelles liées au retard
|
||||
private BigDecimal penalitesRetard;
|
||||
|
||||
// Somme physiquement encaissée pour cette traite à l'instant T
|
||||
private BigDecimal montantRegle;
|
||||
|
||||
private StatutEcheanceCredit statut;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user