Server-Api OK
This commit is contained in:
359
unionflow-server-api/checkstyle-unionflow.xml
Normal file
359
unionflow-server-api/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>
|
||||||
@@ -21,6 +21,22 @@
|
|||||||
<jackson.version>2.17.0</jackson.version>
|
<jackson.version>2.17.0</jackson.version>
|
||||||
<validation-api.version>3.0.2</validation-api.version>
|
<validation-api.version>3.0.2</validation-api.version>
|
||||||
<microprofile-openapi.version>3.1.1</microprofile-openapi.version>
|
<microprofile-openapi.version>3.1.1</microprofile-openapi.version>
|
||||||
|
|
||||||
|
<!-- 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>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -51,6 +67,58 @@
|
|||||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>3.1.0</version>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -63,8 +131,105 @@
|
|||||||
<source>17</source>
|
<source>17</source>
|
||||||
<target>17</target>
|
<target>17</target>
|
||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</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>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,704 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.abonnement;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
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 lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des abonnements UnionFlow
|
||||||
|
* Représente un abonnement d'une organisation à une formule
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class AbonnementDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de référence unique de l'abonnement
|
||||||
|
*/
|
||||||
|
@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)")
|
||||||
|
private String numeroReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'organisation abonnée
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'identifiant de l'organisation est obligatoire")
|
||||||
|
private UUID organisationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'organisation abonnée
|
||||||
|
*/
|
||||||
|
private String nomOrganisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de la formule d'abonnement
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'identifiant de la formule est obligatoire")
|
||||||
|
private UUID formulaireId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code de la formule
|
||||||
|
*/
|
||||||
|
private String codeFormule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de la formule
|
||||||
|
*/
|
||||||
|
private String nomFormule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type de formule (BASIC, STANDARD, PREMIUM, ENTERPRISE)
|
||||||
|
*/
|
||||||
|
private String typeFormule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de l'abonnement
|
||||||
|
* ACTIF, SUSPENDU, EXPIRE, ANNULE, EN_ATTENTE_PAIEMENT
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le statut est obligatoire")
|
||||||
|
@Pattern(regexp = "^(ACTIF|SUSPENDU|EXPIRE|ANNULE|EN_ATTENTE_PAIEMENT)$",
|
||||||
|
message = "Statut invalide")
|
||||||
|
private String statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type d'abonnement (MENSUEL, ANNUEL)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le type d'abonnement est obligatoire")
|
||||||
|
@Pattern(regexp = "^(MENSUEL|ANNUEL)$", message = "Le type doit être MENSUEL ou ANNUEL")
|
||||||
|
private String typeAbonnement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de début de l'abonnement
|
||||||
|
*/
|
||||||
|
@NotNull(message = "La date de début est obligatoire")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateDebut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de fin de l'abonnement
|
||||||
|
*/
|
||||||
|
@Future(message = "La date de fin doit être dans le futur")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateFin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de la prochaine facturation
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateProchainePeriode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant de l'abonnement
|
||||||
|
*/
|
||||||
|
@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")
|
||||||
|
private BigDecimal montant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "La devise est obligatoire")
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String devise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remise appliquée (pourcentage)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "La remise doit être positive")
|
||||||
|
@DecimalMin(value = "100.0", message = "La remise ne peut pas dépasser 100%")
|
||||||
|
private BigDecimal remise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant après 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")
|
||||||
|
private BigDecimal montantFinal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renouvellement automatique
|
||||||
|
*/
|
||||||
|
private Boolean renouvellementAutomatique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Période d'essai utilisée
|
||||||
|
*/
|
||||||
|
private Boolean periodeEssaiUtilisee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de fin de la période d'essai
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateFinEssai;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de membres autorisés
|
||||||
|
*/
|
||||||
|
private Integer maxMembres;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de membres actuels
|
||||||
|
*/
|
||||||
|
private Integer nombreMembresActuels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Espace de stockage alloué (GB)
|
||||||
|
*/
|
||||||
|
private BigDecimal espaceStockageGB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Espace de stockage utilisé (GB)
|
||||||
|
*/
|
||||||
|
private BigDecimal espaceStockageUtilise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support technique inclus
|
||||||
|
*/
|
||||||
|
private Boolean supportTechnique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Niveau de support
|
||||||
|
*/
|
||||||
|
private String niveauSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonctionnalités avancées activées
|
||||||
|
*/
|
||||||
|
private Boolean fonctionnalitesAvancees;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accès API activé
|
||||||
|
*/
|
||||||
|
private Boolean apiAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rapports personnalisés activés
|
||||||
|
*/
|
||||||
|
private Boolean rapportsPersonnalises;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intégrations tierces activées
|
||||||
|
*/
|
||||||
|
private Boolean integrationsTierces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de dernière utilisation
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateDerniereUtilisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de connexions ce mois
|
||||||
|
*/
|
||||||
|
private Integer connexionsCeMois;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant du responsable de l'abonnement
|
||||||
|
*/
|
||||||
|
private UUID responsableId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom du responsable
|
||||||
|
*/
|
||||||
|
private String nomResponsable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email du responsable
|
||||||
|
*/
|
||||||
|
private String emailResponsable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Téléphone du responsable
|
||||||
|
*/
|
||||||
|
private String telephoneResponsable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode de paiement préféré
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|AUTRE)$",
|
||||||
|
message = "Mode de paiement invalide")
|
||||||
|
private String modePaiementPrefere;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de téléphone pour paiement mobile
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Format de numéro de téléphone invalide")
|
||||||
|
private String numeroPaiementMobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Historique des paiements (JSON)
|
||||||
|
*/
|
||||||
|
@Size(max = 5000, message = "L'historique ne peut pas dépasser 5000 caractères")
|
||||||
|
private String historiquePaiements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notes sur l'abonnement
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String notes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alertes activées
|
||||||
|
*/
|
||||||
|
private Boolean alertesActivees;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifications par email
|
||||||
|
*/
|
||||||
|
private Boolean notificationsEmail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifications par SMS
|
||||||
|
*/
|
||||||
|
private Boolean notificationsSMS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de suspension (si applicable)
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateSuspension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raison de la suspension
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La raison ne peut pas dépasser 500 caractères")
|
||||||
|
private String raisonSuspension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'annulation (si applicable)
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateAnnulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raison de l'annulation
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La raison ne peut pas dépasser 500 caractères")
|
||||||
|
private String raisonAnnulation;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public AbonnementDTO() {
|
||||||
|
super();
|
||||||
|
this.statut = "EN_ATTENTE_PAIEMENT";
|
||||||
|
this.devise = "XOF";
|
||||||
|
this.renouvellementAutomatique = true;
|
||||||
|
this.periodeEssaiUtilisee = false;
|
||||||
|
this.supportTechnique = true;
|
||||||
|
this.fonctionnalitesAvancees = false;
|
||||||
|
this.apiAccess = false;
|
||||||
|
this.rapportsPersonnalises = false;
|
||||||
|
this.integrationsTierces = false;
|
||||||
|
this.connexionsCeMois = 0;
|
||||||
|
this.alertesActivees = true;
|
||||||
|
this.notificationsEmail = true;
|
||||||
|
this.notificationsSMS = false;
|
||||||
|
this.numeroReference = genererNumeroReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbonnementDTO(UUID organisationId, String nomOrganisation, String typeFormule) {
|
||||||
|
this();
|
||||||
|
this.organisationId = organisationId;
|
||||||
|
this.nomOrganisation = nomOrganisation;
|
||||||
|
this.typeFormule = typeFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getNumeroReference() {
|
||||||
|
return numeroReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroReference(String numeroReference) {
|
||||||
|
this.numeroReference = numeroReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getOrganisationId() {
|
||||||
|
return organisationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrganisationId(UUID organisationId) {
|
||||||
|
this.organisationId = organisationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomOrganisation() {
|
||||||
|
return nomOrganisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomOrganisation(String nomOrganisation) {
|
||||||
|
this.nomOrganisation = nomOrganisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getFormulaireId() {
|
||||||
|
return formulaireId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFormulaireId(UUID formulaireId) {
|
||||||
|
this.formulaireId = formulaireId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeFormule() {
|
||||||
|
return codeFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeFormule(String codeFormule) {
|
||||||
|
this.codeFormule = codeFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomFormule() {
|
||||||
|
return nomFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomFormule(String nomFormule) {
|
||||||
|
this.nomFormule = nomFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeFormule() {
|
||||||
|
return typeFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeFormule(String typeFormule) {
|
||||||
|
this.typeFormule = typeFormule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatut() {
|
||||||
|
return statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatut(String statut) {
|
||||||
|
this.statut = statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeAbonnement() {
|
||||||
|
return typeAbonnement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeAbonnement(String typeAbonnement) {
|
||||||
|
this.typeAbonnement = typeAbonnement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateDebut() {
|
||||||
|
return dateDebut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDebut(LocalDate dateDebut) {
|
||||||
|
this.dateDebut = dateDebut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateFin() {
|
||||||
|
return dateFin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFin(LocalDate dateFin) {
|
||||||
|
this.dateFin = dateFin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateProchainePeriode() {
|
||||||
|
return dateProchainePeriode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateProchainePeriode(LocalDate dateProchainePeriode) {
|
||||||
|
this.dateProchainePeriode = dateProchainePeriode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontant() {
|
||||||
|
return montant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontant(BigDecimal montant) {
|
||||||
|
this.montant = montant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDevise() {
|
||||||
|
return devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevise(String devise) {
|
||||||
|
this.devise = devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et setters restants (suite)
|
||||||
|
public BigDecimal getRemise() {
|
||||||
|
return remise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemise(BigDecimal remise) {
|
||||||
|
this.remise = remise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantFinal() {
|
||||||
|
return montantFinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantFinal(BigDecimal montantFinal) {
|
||||||
|
this.montantFinal = montantFinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRenouvellementAutomatique() {
|
||||||
|
return renouvellementAutomatique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRenouvellementAutomatique(Boolean renouvellementAutomatique) {
|
||||||
|
this.renouvellementAutomatique = renouvellementAutomatique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getPeriodeEssaiUtilisee() {
|
||||||
|
return periodeEssaiUtilisee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPeriodeEssaiUtilisee(Boolean periodeEssaiUtilisee) {
|
||||||
|
this.periodeEssaiUtilisee = periodeEssaiUtilisee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateFinEssai() {
|
||||||
|
return dateFinEssai;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFinEssai(LocalDate dateFinEssai) {
|
||||||
|
this.dateFinEssai = dateFinEssai;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxMembres() {
|
||||||
|
return maxMembres;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxMembres(Integer maxMembres) {
|
||||||
|
this.maxMembres = maxMembres;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNombreMembresActuels() {
|
||||||
|
return nombreMembresActuels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNombreMembresActuels(Integer nombreMembresActuels) {
|
||||||
|
this.nombreMembresActuels = nombreMembresActuels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getEspaceStockageGB() {
|
||||||
|
return espaceStockageGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEspaceStockageGB(BigDecimal espaceStockageGB) {
|
||||||
|
this.espaceStockageGB = espaceStockageGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getEspaceStockageUtilise() {
|
||||||
|
return espaceStockageUtilise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEspaceStockageUtilise(BigDecimal espaceStockageUtilise) {
|
||||||
|
this.espaceStockageUtilise = espaceStockageUtilise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getSupportTechnique() {
|
||||||
|
return supportTechnique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupportTechnique(Boolean supportTechnique) {
|
||||||
|
this.supportTechnique = supportTechnique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNiveauSupport() {
|
||||||
|
return niveauSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNiveauSupport(String niveauSupport) {
|
||||||
|
this.niveauSupport = niveauSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getFonctionnalitesAvancees() {
|
||||||
|
return fonctionnalitesAvancees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFonctionnalitesAvancees(Boolean fonctionnalitesAvancees) {
|
||||||
|
this.fonctionnalitesAvancees = fonctionnalitesAvancees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getApiAccess() {
|
||||||
|
return apiAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiAccess(Boolean apiAccess) {
|
||||||
|
this.apiAccess = apiAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRapportsPersonnalises() {
|
||||||
|
return rapportsPersonnalises;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRapportsPersonnalises(Boolean rapportsPersonnalises) {
|
||||||
|
this.rapportsPersonnalises = rapportsPersonnalises;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIntegrationsTierces() {
|
||||||
|
return integrationsTierces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIntegrationsTierces(Boolean integrationsTierces) {
|
||||||
|
this.integrationsTierces = integrationsTierces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateDerniereUtilisation() {
|
||||||
|
return dateDerniereUtilisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDerniereUtilisation(LocalDateTime dateDerniereUtilisation) {
|
||||||
|
this.dateDerniereUtilisation = dateDerniereUtilisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getConnexionsCeMois() {
|
||||||
|
return connexionsCeMois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnexionsCeMois(Integer connexionsCeMois) {
|
||||||
|
this.connexionsCeMois = connexionsCeMois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getResponsableId() {
|
||||||
|
return responsableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResponsableId(UUID responsableId) {
|
||||||
|
this.responsableId = responsableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomResponsable() {
|
||||||
|
return nomResponsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomResponsable(String nomResponsable) {
|
||||||
|
this.nomResponsable = nomResponsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmailResponsable() {
|
||||||
|
return emailResponsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmailResponsable(String emailResponsable) {
|
||||||
|
this.emailResponsable = emailResponsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTelephoneResponsable() {
|
||||||
|
return telephoneResponsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTelephoneResponsable(String telephoneResponsable) {
|
||||||
|
this.telephoneResponsable = telephoneResponsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModePaiementPrefere() {
|
||||||
|
return modePaiementPrefere;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModePaiementPrefere(String modePaiementPrefere) {
|
||||||
|
this.modePaiementPrefere = modePaiementPrefere;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumeroPaiementMobile() {
|
||||||
|
return numeroPaiementMobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroPaiementMobile(String numeroPaiementMobile) {
|
||||||
|
this.numeroPaiementMobile = numeroPaiementMobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHistoriquePaiements() {
|
||||||
|
return historiquePaiements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHistoriquePaiements(String historiquePaiements) {
|
||||||
|
this.historiquePaiements = historiquePaiements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNotes() {
|
||||||
|
return notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotes(String notes) {
|
||||||
|
this.notes = notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAlertesActivees() {
|
||||||
|
return alertesActivees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertesActivees(Boolean alertesActivees) {
|
||||||
|
this.alertesActivees = alertesActivees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getNotificationsEmail() {
|
||||||
|
return notificationsEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationsEmail(Boolean notificationsEmail) {
|
||||||
|
this.notificationsEmail = notificationsEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getNotificationsSMS() {
|
||||||
|
return notificationsSMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationsSMS(Boolean notificationsSMS) {
|
||||||
|
this.notificationsSMS = notificationsSMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateSuspension() {
|
||||||
|
return dateSuspension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateSuspension(LocalDateTime dateSuspension) {
|
||||||
|
this.dateSuspension = dateSuspension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRaisonSuspension() {
|
||||||
|
return raisonSuspension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRaisonSuspension(String raisonSuspension) {
|
||||||
|
this.raisonSuspension = raisonSuspension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateAnnulation() {
|
||||||
|
return dateAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateAnnulation(LocalDateTime dateAnnulation) {
|
||||||
|
this.dateAnnulation = dateAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRaisonAnnulation() {
|
||||||
|
return raisonAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRaisonAnnulation(String raisonAnnulation) {
|
||||||
|
this.raisonAnnulation = raisonAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Génère un numéro de référence unique
|
||||||
|
* @return Le numéro de référence généré
|
||||||
|
*/
|
||||||
|
private String genererNumeroReference() {
|
||||||
|
return "ABO-" + LocalDate.now().getYear() + "-" +
|
||||||
|
String.format("%08d", (int)(Math.random() * 100000000));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.base;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
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")
|
||||||
|
private LocalDateTime dateCreation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de dernière modification
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private 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.id = UUID.randomUUID();
|
||||||
|
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,858 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.evenement;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
import jakarta.validation.constraints.DecimalMax;
|
||||||
|
import jakarta.validation.constraints.DecimalMin;
|
||||||
|
import jakarta.validation.constraints.Digits;
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.Future;
|
||||||
|
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 lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des événements dans l'API UnionFlow
|
||||||
|
* Représente un événement organisé par une association
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EvenementDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Titre de l'événement
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le titre est obligatoire")
|
||||||
|
@Size(min = 3, max = 100, message = "Le titre doit contenir entre 3 et 100 caractères")
|
||||||
|
private String titre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description détaillée de l'événement
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type d'événement
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le type d'événement est obligatoire")
|
||||||
|
@Pattern(regexp = "^(ASSEMBLEE_GENERALE|FORMATION|ACTIVITE_SOCIALE|ACTION_CARITATIVE|REUNION_BUREAU|CONFERENCE|ATELIER|CEREMONIE|AUTRE)$",
|
||||||
|
message = "Type d'événement invalide")
|
||||||
|
private String typeEvenement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de l'événement
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut est obligatoire")
|
||||||
|
@Pattern(regexp = "^(PLANIFIE|EN_COURS|TERMINE|ANNULE|REPORTE)$",
|
||||||
|
message = "Statut invalide")
|
||||||
|
private String statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Priorité de l'événement
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(BASSE|NORMALE|HAUTE|CRITIQUE)$",
|
||||||
|
message = "Priorité invalide")
|
||||||
|
private String priorite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de début de l'événement
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@NotNull(message = "La date de début est obligatoire")
|
||||||
|
@Future(message = "La date de début doit être dans le futur")
|
||||||
|
private LocalDate dateDebut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de fin de l'événement
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateFin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heure de début
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "HH:mm")
|
||||||
|
private LocalTime heureDebut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heure de fin
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "HH:mm")
|
||||||
|
private LocalTime heureFin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lieu de l'événement
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le lieu est obligatoire")
|
||||||
|
@Size(max = 100, message = "Le lieu ne peut pas dépasser 100 caractères")
|
||||||
|
private String lieu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse complète du lieu
|
||||||
|
*/
|
||||||
|
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
|
||||||
|
private String adresse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ville
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
|
||||||
|
private String ville;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Région
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordonnées GPS (latitude)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "-90.0", message = "La latitude doit être entre -90 et 90")
|
||||||
|
@DecimalMax(value = "90.0", message = "La latitude doit être entre -90 et 90")
|
||||||
|
private BigDecimal latitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordonnées GPS (longitude)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "-180.0", message = "La longitude doit être entre -180 et 180")
|
||||||
|
@DecimalMax(value = "180.0", message = "La longitude doit être entre -180 et 180")
|
||||||
|
private BigDecimal longitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'association organisatrice
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'association organisatrice est obligatoire")
|
||||||
|
private UUID associationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'association organisatrice (lecture seule)
|
||||||
|
*/
|
||||||
|
private String nomAssociation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'organisateur principal
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "Le nom de l'organisateur ne peut pas dépasser 100 caractères")
|
||||||
|
private String organisateur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email de l'organisateur
|
||||||
|
*/
|
||||||
|
@Email(message = "Format d'email invalide")
|
||||||
|
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
|
||||||
|
private String emailOrganisateur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Téléphone de l'organisateur
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$", message = "Format de téléphone invalide")
|
||||||
|
private String telephoneOrganisateur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capacité maximale de participants
|
||||||
|
*/
|
||||||
|
@Min(value = 1, message = "La capacité doit être d'au moins 1 personne")
|
||||||
|
@Max(value = 10000, message = "La capacité ne peut pas dépasser 10000 personnes")
|
||||||
|
private Integer capaciteMax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de participants inscrits
|
||||||
|
*/
|
||||||
|
@Min(value = 0, message = "Le nombre de participants ne peut pas être négatif")
|
||||||
|
private Integer participantsInscrits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de participants présents
|
||||||
|
*/
|
||||||
|
@Min(value = 0, message = "Le nombre de participants présents ne peut pas être négatif")
|
||||||
|
private Integer participantsPresents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Budget prévu pour l'événement
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le budget ne peut pas être négatif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Format de budget invalide")
|
||||||
|
private BigDecimal budget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coût réel de l'événement
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le coût ne peut pas être négatif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Format de coût invalide")
|
||||||
|
private BigDecimal coutReel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code de la devise
|
||||||
|
*/
|
||||||
|
@Size(min = 3, max = 3, message = "Le code devise doit faire exactement 3 caractères")
|
||||||
|
private String codeDevise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indique si l'inscription est obligatoire
|
||||||
|
*/
|
||||||
|
private Boolean inscriptionObligatoire = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date limite d'inscription
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateLimiteInscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indique si l'événement est public
|
||||||
|
*/
|
||||||
|
private Boolean evenementPublic = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indique si l'événement est récurrent
|
||||||
|
*/
|
||||||
|
private Boolean recurrent = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fréquence de récurrence (si récurrent)
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(HEBDOMADAIRE|MENSUELLE|TRIMESTRIELLE|ANNUELLE)$",
|
||||||
|
message = "Fréquence de récurrence invalide")
|
||||||
|
private String frequenceRecurrence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions spéciales pour les participants
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Les instructions ne peuvent pas dépasser 500 caractères")
|
||||||
|
private String instructions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matériel nécessaire
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La liste du matériel ne peut pas dépasser 500 caractères")
|
||||||
|
private String materielNecessaire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditions météorologiques requises
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "Les conditions météo ne peuvent pas dépasser 100 caractères")
|
||||||
|
private String conditionsMeteo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL de l'image de l'événement
|
||||||
|
*/
|
||||||
|
@Size(max = 255, message = "L'URL de l'image ne peut pas dépasser 255 caractères")
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Couleur thème de l'événement
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "Format de couleur invalide (format: #RRGGBB)")
|
||||||
|
private String couleurTheme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'annulation (si annulé)
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateAnnulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raison de l'annulation
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La raison d'annulation ne peut pas dépasser 500 caractères")
|
||||||
|
private String raisonAnnulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'utilisateur qui a annulé
|
||||||
|
*/
|
||||||
|
private Long annulePar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'utilisateur qui a annulé
|
||||||
|
*/
|
||||||
|
private String nomAnnulateur;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public EvenementDTO() {
|
||||||
|
super();
|
||||||
|
this.statut = "PLANIFIE";
|
||||||
|
this.priorite = "NORMALE";
|
||||||
|
this.participantsInscrits = 0;
|
||||||
|
this.participantsPresents = 0;
|
||||||
|
this.inscriptionObligatoire = false;
|
||||||
|
this.evenementPublic = true;
|
||||||
|
this.recurrent = false;
|
||||||
|
this.codeDevise = "XOF"; // Franc CFA par défaut
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvenementDTO(String titre, String typeEvenement, LocalDate dateDebut, String lieu) {
|
||||||
|
this();
|
||||||
|
this.titre = titre;
|
||||||
|
this.typeEvenement = typeEvenement;
|
||||||
|
this.dateDebut = dateDebut;
|
||||||
|
this.lieu = lieu;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getTitre() {
|
||||||
|
return titre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitre(String titre) {
|
||||||
|
this.titre = titre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeEvenement() {
|
||||||
|
return typeEvenement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeEvenement(String typeEvenement) {
|
||||||
|
this.typeEvenement = typeEvenement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatut() {
|
||||||
|
return statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatut(String statut) {
|
||||||
|
this.statut = statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPriorite() {
|
||||||
|
return priorite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriorite(String priorite) {
|
||||||
|
this.priorite = priorite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateDebut() {
|
||||||
|
return dateDebut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDebut(LocalDate dateDebut) {
|
||||||
|
this.dateDebut = dateDebut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateFin() {
|
||||||
|
return dateFin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFin(LocalDate dateFin) {
|
||||||
|
this.dateFin = dateFin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalTime getHeureDebut() {
|
||||||
|
return heureDebut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeureDebut(LocalTime heureDebut) {
|
||||||
|
this.heureDebut = heureDebut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalTime getHeureFin() {
|
||||||
|
return heureFin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeureFin(LocalTime heureFin) {
|
||||||
|
this.heureFin = heureFin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLieu() {
|
||||||
|
return lieu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLieu(String lieu) {
|
||||||
|
this.lieu = lieu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdresse() {
|
||||||
|
return adresse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdresse(String adresse) {
|
||||||
|
this.adresse = adresse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVille() {
|
||||||
|
return ville;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVille(String ville) {
|
||||||
|
this.ville = ville;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegion() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegion(String region) {
|
||||||
|
this.region = region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getLatitude() {
|
||||||
|
return latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLatitude(BigDecimal latitude) {
|
||||||
|
this.latitude = latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getLongitude() {
|
||||||
|
return longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLongitude(BigDecimal longitude) {
|
||||||
|
this.longitude = longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getAssociationId() {
|
||||||
|
return associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssociationId(UUID associationId) {
|
||||||
|
this.associationId = associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomAssociation() {
|
||||||
|
return nomAssociation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomAssociation(String nomAssociation) {
|
||||||
|
this.nomAssociation = nomAssociation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrganisateur() {
|
||||||
|
return organisateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrganisateur(String organisateur) {
|
||||||
|
this.organisateur = organisateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmailOrganisateur() {
|
||||||
|
return emailOrganisateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmailOrganisateur(String emailOrganisateur) {
|
||||||
|
this.emailOrganisateur = emailOrganisateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTelephoneOrganisateur() {
|
||||||
|
return telephoneOrganisateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTelephoneOrganisateur(String telephoneOrganisateur) {
|
||||||
|
this.telephoneOrganisateur = telephoneOrganisateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCapaciteMax() {
|
||||||
|
return capaciteMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCapaciteMax(Integer capaciteMax) {
|
||||||
|
this.capaciteMax = capaciteMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getParticipantsInscrits() {
|
||||||
|
return participantsInscrits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParticipantsInscrits(Integer participantsInscrits) {
|
||||||
|
this.participantsInscrits = participantsInscrits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getParticipantsPresents() {
|
||||||
|
return participantsPresents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParticipantsPresents(Integer participantsPresents) {
|
||||||
|
this.participantsPresents = participantsPresents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBudget() {
|
||||||
|
return budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBudget(BigDecimal budget) {
|
||||||
|
this.budget = budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getCoutReel() {
|
||||||
|
return coutReel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoutReel(BigDecimal coutReel) {
|
||||||
|
this.coutReel = coutReel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeDevise() {
|
||||||
|
return codeDevise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeDevise(String codeDevise) {
|
||||||
|
this.codeDevise = codeDevise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getInscriptionObligatoire() {
|
||||||
|
return inscriptionObligatoire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInscriptionObligatoire(Boolean inscriptionObligatoire) {
|
||||||
|
this.inscriptionObligatoire = inscriptionObligatoire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateLimiteInscription() {
|
||||||
|
return dateLimiteInscription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateLimiteInscription(LocalDate dateLimiteInscription) {
|
||||||
|
this.dateLimiteInscription = dateLimiteInscription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getEvenementPublic() {
|
||||||
|
return evenementPublic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvenementPublic(Boolean evenementPublic) {
|
||||||
|
this.evenementPublic = evenementPublic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRecurrent() {
|
||||||
|
return recurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecurrent(Boolean recurrent) {
|
||||||
|
this.recurrent = recurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFrequenceRecurrence() {
|
||||||
|
return frequenceRecurrence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrequenceRecurrence(String frequenceRecurrence) {
|
||||||
|
this.frequenceRecurrence = frequenceRecurrence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInstructions() {
|
||||||
|
return instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstructions(String instructions) {
|
||||||
|
this.instructions = instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaterielNecessaire() {
|
||||||
|
return materielNecessaire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaterielNecessaire(String materielNecessaire) {
|
||||||
|
this.materielNecessaire = materielNecessaire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConditionsMeteo() {
|
||||||
|
return conditionsMeteo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConditionsMeteo(String conditionsMeteo) {
|
||||||
|
this.conditionsMeteo = conditionsMeteo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getImageUrl() {
|
||||||
|
return imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImageUrl(String imageUrl) {
|
||||||
|
this.imageUrl = imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCouleurTheme() {
|
||||||
|
return couleurTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCouleurTheme(String couleurTheme) {
|
||||||
|
this.couleurTheme = couleurTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateAnnulation() {
|
||||||
|
return dateAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateAnnulation(LocalDateTime dateAnnulation) {
|
||||||
|
this.dateAnnulation = dateAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRaisonAnnulation() {
|
||||||
|
return raisonAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRaisonAnnulation(String raisonAnnulation) {
|
||||||
|
this.raisonAnnulation = raisonAnnulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAnnulePar() {
|
||||||
|
return annulePar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnnulePar(Long annulePar) {
|
||||||
|
this.annulePar = annulePar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomAnnulateur() {
|
||||||
|
return nomAnnulateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomAnnulateur(String nomAnnulateur) {
|
||||||
|
this.nomAnnulateur = nomAnnulateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'événement est en cours
|
||||||
|
* @return true si l'événement est actuellement en cours
|
||||||
|
*/
|
||||||
|
public boolean isEnCours() {
|
||||||
|
return "EN_COURS".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'événement est terminé
|
||||||
|
* @return true si l'événement est terminé
|
||||||
|
*/
|
||||||
|
public boolean isTermine() {
|
||||||
|
return "TERMINE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'événement est annulé
|
||||||
|
* @return true si l'événement est annulé
|
||||||
|
*/
|
||||||
|
public boolean isAnnule() {
|
||||||
|
return "ANNULE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'événement est complet (capacité atteinte)
|
||||||
|
* @return true si le nombre d'inscrits atteint la capacité maximale
|
||||||
|
*/
|
||||||
|
public boolean isComplet() {
|
||||||
|
return capaciteMax != null && participantsInscrits != null &&
|
||||||
|
participantsInscrits >= capaciteMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de places disponibles
|
||||||
|
* @return Le nombre de places restantes
|
||||||
|
*/
|
||||||
|
public int getPlacesDisponibles() {
|
||||||
|
if (capaciteMax == null || participantsInscrits == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.max(0, capaciteMax - participantsInscrits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le taux de remplissage en pourcentage
|
||||||
|
* @return Le pourcentage de remplissage (0-100)
|
||||||
|
*/
|
||||||
|
public int getTauxRemplissage() {
|
||||||
|
if (capaciteMax == null || capaciteMax == 0 || participantsInscrits == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (participantsInscrits * 100) / capaciteMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le taux de présence en pourcentage
|
||||||
|
* @return Le pourcentage de présence (0-100)
|
||||||
|
*/
|
||||||
|
public int getTauxPresence() {
|
||||||
|
if (participantsInscrits == null || participantsInscrits == 0 || participantsPresents == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (participantsPresents * 100) / participantsInscrits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si les inscriptions sont encore ouvertes
|
||||||
|
* @return true si les inscriptions sont ouvertes
|
||||||
|
*/
|
||||||
|
public boolean isInscriptionsOuvertes() {
|
||||||
|
if (isAnnule() || isTermine()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateLimiteInscription != null && LocalDate.now().isAfter(dateLimiteInscription)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isComplet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule la durée de l'événement en heures
|
||||||
|
* @return La durée en heures, ou 0 si non calculable
|
||||||
|
*/
|
||||||
|
public long getDureeEnHeures() {
|
||||||
|
if (heureDebut == null || heureFin == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return heureDebut.until(heureFin, java.time.temporal.ChronoUnit.HOURS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'événement dure plusieurs jours
|
||||||
|
* @return true si l'événement s'étend sur plusieurs jours
|
||||||
|
*/
|
||||||
|
public boolean isEvenementMultiJours() {
|
||||||
|
return dateFin != null && !dateDebut.equals(dateFin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé du type d'événement
|
||||||
|
* @return Le libellé du type
|
||||||
|
*/
|
||||||
|
public String getTypeEvenementLibelle() {
|
||||||
|
if (typeEvenement == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (typeEvenement) {
|
||||||
|
case "ASSEMBLEE_GENERALE" -> "Assemblée Générale";
|
||||||
|
case "FORMATION" -> "Formation";
|
||||||
|
case "ACTIVITE_SOCIALE" -> "Activité Sociale";
|
||||||
|
case "ACTION_CARITATIVE" -> "Action Caritative";
|
||||||
|
case "REUNION_BUREAU" -> "Réunion de Bureau";
|
||||||
|
case "CONFERENCE" -> "Conférence";
|
||||||
|
case "ATELIER" -> "Atelier";
|
||||||
|
case "CEREMONIE" -> "Cérémonie";
|
||||||
|
case "AUTRE" -> "Autre";
|
||||||
|
default -> typeEvenement;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé du statut
|
||||||
|
* @return Le libellé du statut
|
||||||
|
*/
|
||||||
|
public String getStatutLibelle() {
|
||||||
|
if (statut == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (statut) {
|
||||||
|
case "PLANIFIE" -> "Planifié";
|
||||||
|
case "EN_COURS" -> "En cours";
|
||||||
|
case "TERMINE" -> "Terminé";
|
||||||
|
case "ANNULE" -> "Annulé";
|
||||||
|
case "REPORTE" -> "Reporté";
|
||||||
|
default -> statut;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé de la priorité
|
||||||
|
* @return Le libellé de la priorité
|
||||||
|
*/
|
||||||
|
public String getPrioriteLibelle() {
|
||||||
|
if (priorite == null) return "Normale";
|
||||||
|
|
||||||
|
return switch (priorite) {
|
||||||
|
case "BASSE" -> "Basse";
|
||||||
|
case "NORMALE" -> "Normale";
|
||||||
|
case "HAUTE" -> "Haute";
|
||||||
|
case "CRITIQUE" -> "Critique";
|
||||||
|
default -> priorite;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne l'adresse complète du lieu
|
||||||
|
* @return L'adresse complète formatée
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'événement a des coordonnées GPS
|
||||||
|
* @return true si latitude et longitude sont définies
|
||||||
|
*/
|
||||||
|
public boolean hasCoordonnees() {
|
||||||
|
return latitude != null && longitude != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule l'écart budgétaire
|
||||||
|
* @return La différence entre budget et coût réel (positif = économie, négatif = dépassement)
|
||||||
|
*/
|
||||||
|
public BigDecimal getEcartBudgetaire() {
|
||||||
|
if (budget == null || coutReel == null) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
return budget.subtract(coutReel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le budget a été dépassé
|
||||||
|
* @return true si le coût réel dépasse le budget
|
||||||
|
*/
|
||||||
|
public boolean isBudgetDepasse() {
|
||||||
|
return getEcartBudgetaire().compareTo(BigDecimal.ZERO) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "EvenementDTO{" +
|
||||||
|
"titre='" + titre + '\'' +
|
||||||
|
", typeEvenement='" + typeEvenement + '\'' +
|
||||||
|
", statut='" + statut + '\'' +
|
||||||
|
", dateDebut=" + dateDebut +
|
||||||
|
", lieu='" + lieu + '\'' +
|
||||||
|
", participantsInscrits=" + participantsInscrits +
|
||||||
|
", capaciteMax=" + capaciteMax +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,601 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.finance;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
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.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des cotisations dans l'API UnionFlow
|
||||||
|
* Représente une cotisation d'un membre à son organisation
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class CotisationDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de référence unique de la cotisation
|
||||||
|
*/
|
||||||
|
@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")
|
||||||
|
private String numeroReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant du membre
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'identifiant du membre est obligatoire")
|
||||||
|
private UUID membreId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro du membre (lecture seule)
|
||||||
|
*/
|
||||||
|
private String numeroMembre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom complet du membre (lecture seule)
|
||||||
|
*/
|
||||||
|
private String nomMembre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'association
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'identifiant de l'association est obligatoire")
|
||||||
|
private UUID associationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'association (lecture seule)
|
||||||
|
*/
|
||||||
|
private String nomAssociation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type de cotisation
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le type de cotisation est obligatoire")
|
||||||
|
@Pattern(regexp = "^(MENSUELLE|TRIMESTRIELLE|SEMESTRIELLE|ANNUELLE|EXCEPTIONNELLE|ADHESION)$",
|
||||||
|
message = "Type de cotisation invalide")
|
||||||
|
private String typeCotisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Libellé de la cotisation
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le libellé est obligatoire")
|
||||||
|
@Size(max = 100, message = "Le libellé ne peut pas dépasser 100 caractères")
|
||||||
|
private String libelle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description détaillée
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant dû
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le montant dû est obligatoire")
|
||||||
|
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant dû doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Format de montant invalide")
|
||||||
|
private BigDecimal montantDu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant payé
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le montant payé ne peut pas être négatif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Format de montant invalide")
|
||||||
|
private BigDecimal montantPaye;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code de la devise
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le code devise est obligatoire")
|
||||||
|
@Size(min = 3, max = 3, message = "Le code devise doit faire exactement 3 caractères")
|
||||||
|
private String codeDevise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de la cotisation
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut est obligatoire")
|
||||||
|
@Pattern(regexp = "^(EN_ATTENTE|PAYEE|PARTIELLEMENT_PAYEE|EN_RETARD|ANNULEE|REMBOURSEE)$",
|
||||||
|
message = "Statut invalide")
|
||||||
|
private String statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'échéance
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@NotNull(message = "La date d'échéance est obligatoire")
|
||||||
|
private LocalDate dateEcheance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de paiement
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime datePaiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode de paiement
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(ESPECES|VIREMENT|CHEQUE|WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|CARTE_BANCAIRE)$",
|
||||||
|
message = "Méthode de paiement invalide")
|
||||||
|
private String methodePaiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Référence du paiement (numéro de transaction, chèque, etc.)
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "La référence de paiement ne peut pas dépasser 100 caractères")
|
||||||
|
private String referencePaiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Période concernée (ex: "Janvier 2025", "Q1 2025")
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "La période ne peut pas dépasser 50 caractères")
|
||||||
|
private String periode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Année de la cotisation
|
||||||
|
*/
|
||||||
|
@Min(value = 2020, message = "L'année doit être supérieure à 2020")
|
||||||
|
@Max(value = 2050, message = "L'année doit être inférieure à 2050")
|
||||||
|
private Integer annee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mois de la cotisation (1-12)
|
||||||
|
*/
|
||||||
|
@Min(value = 1, message = "Le mois doit être entre 1 et 12")
|
||||||
|
@Max(value = 12, message = "Le mois doit être entre 1 et 12")
|
||||||
|
private Integer mois;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observations ou commentaires
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Les observations ne peuvent pas dépasser 500 caractères")
|
||||||
|
private String observations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indique si la cotisation est récurrente
|
||||||
|
*/
|
||||||
|
private Boolean recurrente = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de rappels envoyés
|
||||||
|
*/
|
||||||
|
@Min(value = 0, message = "Le nombre de rappels ne peut pas être négatif")
|
||||||
|
private Integer nombreRappels = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date du dernier rappel
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateDernierRappel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'utilisateur qui a validé le paiement
|
||||||
|
*/
|
||||||
|
private UUID validePar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'utilisateur qui a validé le paiement
|
||||||
|
*/
|
||||||
|
private String nomValidateur;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public CotisationDTO() {
|
||||||
|
super();
|
||||||
|
this.montantPaye = BigDecimal.ZERO;
|
||||||
|
this.codeDevise = "XOF"; // Franc CFA par défaut
|
||||||
|
this.statut = "EN_ATTENTE";
|
||||||
|
this.recurrente = false;
|
||||||
|
this.nombreRappels = 0;
|
||||||
|
this.annee = LocalDate.now().getYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CotisationDTO(UUID membreId, String typeCotisation, BigDecimal montantDu, LocalDate dateEcheance) {
|
||||||
|
this();
|
||||||
|
this.membreId = membreId;
|
||||||
|
this.typeCotisation = typeCotisation;
|
||||||
|
this.montantDu = montantDu;
|
||||||
|
this.dateEcheance = dateEcheance;
|
||||||
|
this.numeroReference = genererNumeroReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getNumeroReference() {
|
||||||
|
return numeroReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroReference(String numeroReference) {
|
||||||
|
this.numeroReference = numeroReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getMembreId() {
|
||||||
|
return membreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembreId(UUID membreId) {
|
||||||
|
this.membreId = membreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumeroMembre() {
|
||||||
|
return numeroMembre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroMembre(String numeroMembre) {
|
||||||
|
this.numeroMembre = numeroMembre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomMembre() {
|
||||||
|
return nomMembre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomMembre(String nomMembre) {
|
||||||
|
this.nomMembre = nomMembre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getAssociationId() {
|
||||||
|
return associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssociationId(UUID associationId) {
|
||||||
|
this.associationId = associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomAssociation() {
|
||||||
|
return nomAssociation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomAssociation(String nomAssociation) {
|
||||||
|
this.nomAssociation = nomAssociation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeCotisation() {
|
||||||
|
return typeCotisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeCotisation(String typeCotisation) {
|
||||||
|
this.typeCotisation = typeCotisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLibelle(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantDu() {
|
||||||
|
return montantDu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantDu(BigDecimal montantDu) {
|
||||||
|
this.montantDu = montantDu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantPaye() {
|
||||||
|
return montantPaye;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantPaye(BigDecimal montantPaye) {
|
||||||
|
this.montantPaye = montantPaye;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeDevise() {
|
||||||
|
return codeDevise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeDevise(String codeDevise) {
|
||||||
|
this.codeDevise = codeDevise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatut() {
|
||||||
|
return statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatut(String statut) {
|
||||||
|
this.statut = statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateEcheance() {
|
||||||
|
return dateEcheance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateEcheance(LocalDate dateEcheance) {
|
||||||
|
this.dateEcheance = dateEcheance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDatePaiement() {
|
||||||
|
return datePaiement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatePaiement(LocalDateTime datePaiement) {
|
||||||
|
this.datePaiement = datePaiement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethodePaiement() {
|
||||||
|
return methodePaiement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMethodePaiement(String methodePaiement) {
|
||||||
|
this.methodePaiement = methodePaiement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReferencePaiement() {
|
||||||
|
return referencePaiement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReferencePaiement(String referencePaiement) {
|
||||||
|
this.referencePaiement = referencePaiement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPeriode() {
|
||||||
|
return periode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPeriode(String periode) {
|
||||||
|
this.periode = periode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAnnee() {
|
||||||
|
return annee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnnee(Integer annee) {
|
||||||
|
this.annee = annee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMois() {
|
||||||
|
return mois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMois(Integer mois) {
|
||||||
|
this.mois = mois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getObservations() {
|
||||||
|
return observations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObservations(String observations) {
|
||||||
|
this.observations = observations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRecurrente() {
|
||||||
|
return recurrente;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecurrente(Boolean recurrente) {
|
||||||
|
this.recurrente = recurrente;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNombreRappels() {
|
||||||
|
return nombreRappels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNombreRappels(Integer nombreRappels) {
|
||||||
|
this.nombreRappels = nombreRappels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateDernierRappel() {
|
||||||
|
return dateDernierRappel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDernierRappel(LocalDateTime dateDernierRappel) {
|
||||||
|
this.dateDernierRappel = dateDernierRappel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getValidePar() {
|
||||||
|
return validePar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidePar(UUID validePar) {
|
||||||
|
this.validePar = validePar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomValidateur() {
|
||||||
|
return nomValidateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomValidateur(String nomValidateur) {
|
||||||
|
this.nomValidateur = nomValidateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Génère un numéro de référence unique pour la cotisation
|
||||||
|
* @return Le numéro de référence généré
|
||||||
|
*/
|
||||||
|
private String genererNumeroReference() {
|
||||||
|
return "COT-" + LocalDate.now().getYear() + "-" +
|
||||||
|
String.format("%06d", System.currentTimeMillis() % 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la cotisation est payée intégralement
|
||||||
|
* @return true si le montant payé égale le montant dû
|
||||||
|
*/
|
||||||
|
public boolean isPayeeIntegralement() {
|
||||||
|
return montantPaye != null && montantDu != null &&
|
||||||
|
montantPaye.compareTo(montantDu) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la cotisation est en retard
|
||||||
|
* @return true si la date d'échéance est dépassée et non payée
|
||||||
|
*/
|
||||||
|
public boolean isEnRetard() {
|
||||||
|
return dateEcheance != null &&
|
||||||
|
LocalDate.now().isAfter(dateEcheance) &&
|
||||||
|
!isPayeeIntegralement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le montant restant à payer
|
||||||
|
* @return Le montant restant
|
||||||
|
*/
|
||||||
|
public BigDecimal getMontantRestant() {
|
||||||
|
if (montantDu == null) return BigDecimal.ZERO;
|
||||||
|
if (montantPaye == null) return montantDu;
|
||||||
|
|
||||||
|
BigDecimal restant = montantDu.subtract(montantPaye);
|
||||||
|
return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le pourcentage de paiement
|
||||||
|
* @return Le pourcentage payé (0-100)
|
||||||
|
*/
|
||||||
|
public int getPourcentagePaiement() {
|
||||||
|
if (montantDu == null || montantDu.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (montantPaye == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return montantPaye.multiply(BigDecimal.valueOf(100))
|
||||||
|
.divide(montantDu, 0, BigDecimal.ROUND_HALF_UP)
|
||||||
|
.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de jours de retard
|
||||||
|
* @return Le nombre de jours de retard, 0 si pas en retard
|
||||||
|
*/
|
||||||
|
public long getJoursRetard() {
|
||||||
|
if (dateEcheance == null || !isEnRetard()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return dateEcheance.until(LocalDate.now()).getDays();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé du type de cotisation
|
||||||
|
* @return Le libellé du type
|
||||||
|
*/
|
||||||
|
public String getTypeCotisationLibelle() {
|
||||||
|
if (typeCotisation == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (typeCotisation) {
|
||||||
|
case "MENSUELLE" -> "Mensuelle";
|
||||||
|
case "TRIMESTRIELLE" -> "Trimestrielle";
|
||||||
|
case "SEMESTRIELLE" -> "Semestrielle";
|
||||||
|
case "ANNUELLE" -> "Annuelle";
|
||||||
|
case "EXCEPTIONNELLE" -> "Exceptionnelle";
|
||||||
|
case "ADHESION" -> "Adhésion";
|
||||||
|
default -> typeCotisation;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé du statut
|
||||||
|
* @return Le libellé du statut
|
||||||
|
*/
|
||||||
|
public String getStatutLibelle() {
|
||||||
|
if (statut == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (statut) {
|
||||||
|
case "EN_ATTENTE" -> "En attente";
|
||||||
|
case "PAYEE" -> "Payée";
|
||||||
|
case "PARTIELLEMENT_PAYEE" -> "Partiellement payée";
|
||||||
|
case "EN_RETARD" -> "En retard";
|
||||||
|
case "ANNULEE" -> "Annulée";
|
||||||
|
case "REMBOURSEE" -> "Remboursée";
|
||||||
|
default -> statut;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé de la méthode de paiement
|
||||||
|
* @return Le libellé de la méthode
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour le statut en fonction du montant payé
|
||||||
|
*/
|
||||||
|
public void mettreAJourStatut() {
|
||||||
|
if (montantPaye == null || montantPaye.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
if (isEnRetard()) {
|
||||||
|
this.statut = "EN_RETARD";
|
||||||
|
} else {
|
||||||
|
this.statut = "EN_ATTENTE";
|
||||||
|
}
|
||||||
|
} else if (isPayeeIntegralement()) {
|
||||||
|
this.statut = "PAYEE";
|
||||||
|
if (this.datePaiement == null) {
|
||||||
|
this.datePaiement = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.statut = "PARTIELLEMENT_PAYEE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marque la cotisation comme payée
|
||||||
|
* @param montant Le montant payé
|
||||||
|
* @param methode La méthode de paiement
|
||||||
|
* @param reference La référence du paiement
|
||||||
|
*/
|
||||||
|
public void marquerCommePaye(BigDecimal montant, String methode, String reference) {
|
||||||
|
this.montantPaye = montant;
|
||||||
|
this.methodePaiement = methode;
|
||||||
|
this.referencePaiement = reference;
|
||||||
|
this.datePaiement = LocalDateTime.now();
|
||||||
|
mettreAJourStatut();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CotisationDTO{" +
|
||||||
|
"numeroReference='" + numeroReference + '\'' +
|
||||||
|
", nomMembre='" + nomMembre + '\'' +
|
||||||
|
", typeCotisation='" + typeCotisation + '\'' +
|
||||||
|
", montantDu=" + montantDu +
|
||||||
|
", montantPaye=" + montantPaye +
|
||||||
|
", statut='" + statut + '\'' +
|
||||||
|
", dateEcheance=" + dateEcheance +
|
||||||
|
", periode='" + periode + '\'' +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,738 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.formuleabonnement;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
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 lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des formules d'abonnement UnionFlow
|
||||||
|
* Représente les différents plans/formules d'abonnement disponibles dans le catalogue
|
||||||
|
*
|
||||||
|
* Distinction importante :
|
||||||
|
* - FormuleAbonnementDTO = Plans disponibles (BASIC, PREMIUM, etc.) - CATALOGUE
|
||||||
|
* - AbonnementDTO = Souscription effective d'une organisation - INSTANCE
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class FormuleAbonnementDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types de formules disponibles
|
||||||
|
*/
|
||||||
|
public enum TypeFormule {
|
||||||
|
BASIC("Formule Basique"),
|
||||||
|
STANDARD("Formule Standard"),
|
||||||
|
PREMIUM("Formule Premium"),
|
||||||
|
ENTERPRISE("Formule Entreprise");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
TypeFormule(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statuts des formules
|
||||||
|
*/
|
||||||
|
public enum StatutFormule {
|
||||||
|
ACTIVE("Active"),
|
||||||
|
INACTIVE("Inactive"),
|
||||||
|
ARCHIVEE("Archivée"),
|
||||||
|
BIENTOT_DISPONIBLE("Bientôt Disponible");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutFormule(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de la formule
|
||||||
|
*/
|
||||||
|
@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")
|
||||||
|
private String nom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code unique de la formule
|
||||||
|
*/
|
||||||
|
@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")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description détaillée de la formule
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type de formule (enum)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le type de formule est obligatoire")
|
||||||
|
private TypeFormule type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de la formule (enum)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut est obligatoire")
|
||||||
|
private StatutFormule statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prix mensuel de la formule
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le prix mensuel est obligatoire")
|
||||||
|
@DecimalMin(value = "0.0", inclusive = false, message = "Le prix mensuel doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Le prix mensuel ne peut avoir plus de 10 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal prixMensuel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prix annuel de la formule (avec remise éventuelle)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", inclusive = false, message = "Le prix annuel doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Le prix annuel ne peut avoir plus de 10 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal prixAnnuel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise utilisée
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "La devise est obligatoire")
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String devise = "XOF";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre maximum de membres autorisés
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le nombre maximum de membres est obligatoire")
|
||||||
|
private Integer maxMembres;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre maximum d'administrateurs autorisés
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le nombre maximum d'administrateurs est obligatoire")
|
||||||
|
private Integer maxAdministrateurs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Espace de stockage alloué en GB
|
||||||
|
*/
|
||||||
|
@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")
|
||||||
|
private BigDecimal espaceStockageGB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support technique inclus
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le support technique doit être spécifié")
|
||||||
|
private Boolean supportTechnique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Niveau de support
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(EMAIL|CHAT|TELEPHONE|PREMIUM)$",
|
||||||
|
message = "Le niveau de support doit être EMAIL, CHAT, TELEPHONE ou PREMIUM")
|
||||||
|
private String niveauSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonctionnalités avancées incluses
|
||||||
|
*/
|
||||||
|
private Boolean fonctionnalitesAvancees;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accès API autorisé
|
||||||
|
*/
|
||||||
|
private Boolean apiAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rapports personnalisés autorisés
|
||||||
|
*/
|
||||||
|
private Boolean rapportsPersonnalises;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intégrations tierces autorisées
|
||||||
|
*/
|
||||||
|
private Boolean integrationsTierces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sauvegarde automatique incluse
|
||||||
|
*/
|
||||||
|
private Boolean sauvegardeAutomatique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support multi-langues
|
||||||
|
*/
|
||||||
|
private Boolean multiLangues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Personnalisation de l'interface
|
||||||
|
*/
|
||||||
|
private Boolean personnalisationInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formation incluse
|
||||||
|
*/
|
||||||
|
private Boolean formationIncluse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre d'heures de formation incluses
|
||||||
|
*/
|
||||||
|
private Integer heuresFormation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formule populaire (mise en avant)
|
||||||
|
*/
|
||||||
|
private Boolean populaire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formule recommandée
|
||||||
|
*/
|
||||||
|
private Boolean recommandee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Période d'essai gratuite en jours
|
||||||
|
*/
|
||||||
|
private Integer periodeEssaiJours;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de début de validité de la formule
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateDebutValidite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de fin de validité de la formule
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateFinValidite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordre d'affichage dans le catalogue
|
||||||
|
*/
|
||||||
|
private Integer ordreAffichage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Couleur associée à la formule (code hexadécimal)
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^#[0-9A-Fa-f]{6}$", message = "La couleur doit être un code hexadécimal valide")
|
||||||
|
private String couleur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icône associée à la formule
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "Le nom de l'icône ne peut pas dépasser 50 caractères")
|
||||||
|
private String icone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notes administratives
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Les notes ne peuvent pas dépasser 500 caractères")
|
||||||
|
private String notes;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public FormuleAbonnementDTO() {
|
||||||
|
super();
|
||||||
|
this.devise = "XOF";
|
||||||
|
this.statut = StatutFormule.ACTIVE;
|
||||||
|
this.type = TypeFormule.BASIC;
|
||||||
|
this.supportTechnique = true;
|
||||||
|
this.fonctionnalitesAvancees = false;
|
||||||
|
this.apiAccess = false;
|
||||||
|
this.rapportsPersonnalises = false;
|
||||||
|
this.integrationsTierces = false;
|
||||||
|
this.sauvegardeAutomatique = true;
|
||||||
|
this.multiLangues = false;
|
||||||
|
this.personnalisationInterface = false;
|
||||||
|
this.formationIncluse = false;
|
||||||
|
this.populaire = false;
|
||||||
|
this.recommandee = false;
|
||||||
|
this.periodeEssaiJours = 0;
|
||||||
|
this.heuresFormation = 0;
|
||||||
|
this.ordreAffichage = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormuleAbonnementDTO(String nom, String code, TypeFormule type, BigDecimal prixMensuel) {
|
||||||
|
this();
|
||||||
|
this.nom = nom;
|
||||||
|
this.code = code;
|
||||||
|
this.type = type;
|
||||||
|
this.prixMensuel = prixMensuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getNom() {
|
||||||
|
return nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNom(String nom) {
|
||||||
|
this.nom = nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeFormule getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(TypeFormule type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatutFormule getStatut() {
|
||||||
|
return statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatut(StatutFormule statut) {
|
||||||
|
this.statut = statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPrixMensuel() {
|
||||||
|
return prixMensuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrixMensuel(BigDecimal prixMensuel) {
|
||||||
|
this.prixMensuel = prixMensuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPrixAnnuel() {
|
||||||
|
return prixAnnuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrixAnnuel(BigDecimal prixAnnuel) {
|
||||||
|
this.prixAnnuel = prixAnnuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDevise() {
|
||||||
|
return devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevise(String devise) {
|
||||||
|
this.devise = devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxMembres() {
|
||||||
|
return maxMembres;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxMembres(Integer maxMembres) {
|
||||||
|
this.maxMembres = maxMembres;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxAdministrateurs() {
|
||||||
|
return maxAdministrateurs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAdministrateurs(Integer maxAdministrateurs) {
|
||||||
|
this.maxAdministrateurs = maxAdministrateurs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getEspaceStockageGB() {
|
||||||
|
return espaceStockageGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEspaceStockageGB(BigDecimal espaceStockageGB) {
|
||||||
|
this.espaceStockageGB = espaceStockageGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getSupportTechnique() {
|
||||||
|
return supportTechnique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupportTechnique(Boolean supportTechnique) {
|
||||||
|
this.supportTechnique = supportTechnique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNiveauSupport() {
|
||||||
|
return niveauSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNiveauSupport(String niveauSupport) {
|
||||||
|
this.niveauSupport = niveauSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getFonctionnalitesAvancees() {
|
||||||
|
return fonctionnalitesAvancees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFonctionnalitesAvancees(Boolean fonctionnalitesAvancees) {
|
||||||
|
this.fonctionnalitesAvancees = fonctionnalitesAvancees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getApiAccess() {
|
||||||
|
return apiAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiAccess(Boolean apiAccess) {
|
||||||
|
this.apiAccess = apiAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRapportsPersonnalises() {
|
||||||
|
return rapportsPersonnalises;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRapportsPersonnalises(Boolean rapportsPersonnalises) {
|
||||||
|
this.rapportsPersonnalises = rapportsPersonnalises;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIntegrationsTierces() {
|
||||||
|
return integrationsTierces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIntegrationsTierces(Boolean integrationsTierces) {
|
||||||
|
this.integrationsTierces = integrationsTierces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getSauvegardeAutomatique() {
|
||||||
|
return sauvegardeAutomatique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSauvegardeAutomatique(Boolean sauvegardeAutomatique) {
|
||||||
|
this.sauvegardeAutomatique = sauvegardeAutomatique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getMultiLangues() {
|
||||||
|
return multiLangues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMultiLangues(Boolean multiLangues) {
|
||||||
|
this.multiLangues = multiLangues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getPersonnalisationInterface() {
|
||||||
|
return personnalisationInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPersonnalisationInterface(Boolean personnalisationInterface) {
|
||||||
|
this.personnalisationInterface = personnalisationInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getFormationIncluse() {
|
||||||
|
return formationIncluse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFormationIncluse(Boolean formationIncluse) {
|
||||||
|
this.formationIncluse = formationIncluse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getHeuresFormation() {
|
||||||
|
return heuresFormation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeuresFormation(Integer heuresFormation) {
|
||||||
|
this.heuresFormation = heuresFormation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getPopulaire() {
|
||||||
|
return populaire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPopulaire(Boolean populaire) {
|
||||||
|
this.populaire = populaire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRecommandee() {
|
||||||
|
return recommandee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecommandee(Boolean recommandee) {
|
||||||
|
this.recommandee = recommandee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPeriodeEssaiJours() {
|
||||||
|
return periodeEssaiJours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPeriodeEssaiJours(Integer periodeEssaiJours) {
|
||||||
|
this.periodeEssaiJours = periodeEssaiJours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateDebutValidite() {
|
||||||
|
return dateDebutValidite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDebutValidite(LocalDate dateDebutValidite) {
|
||||||
|
this.dateDebutValidite = dateDebutValidite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateFinValidite() {
|
||||||
|
return dateFinValidite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFinValidite(LocalDate dateFinValidite) {
|
||||||
|
this.dateFinValidite = dateFinValidite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOrdreAffichage() {
|
||||||
|
return ordreAffichage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrdreAffichage(Integer ordreAffichage) {
|
||||||
|
this.ordreAffichage = ordreAffichage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCouleur() {
|
||||||
|
return couleur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCouleur(String couleur) {
|
||||||
|
this.couleur = couleur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIcone() {
|
||||||
|
return icone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcone(String icone) {
|
||||||
|
this.icone = icone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNotes() {
|
||||||
|
return notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotes(String notes) {
|
||||||
|
this.notes = notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule est active
|
||||||
|
* @return true si la formule est active
|
||||||
|
*/
|
||||||
|
public boolean isActive() {
|
||||||
|
return StatutFormule.ACTIVE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule est inactive
|
||||||
|
* @return true si la formule est inactive
|
||||||
|
*/
|
||||||
|
public boolean isInactive() {
|
||||||
|
return StatutFormule.INACTIVE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule est archivée
|
||||||
|
* @return true si la formule est archivée
|
||||||
|
*/
|
||||||
|
public boolean isArchivee() {
|
||||||
|
return StatutFormule.ARCHIVEE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule est actuellement valide
|
||||||
|
* @return true si la formule est dans sa période de validité
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule l'économie annuelle par rapport au paiement mensuel
|
||||||
|
* @return L'économie réalisée en payant annuellement
|
||||||
|
*/
|
||||||
|
public BigDecimal getEconomieAnnuelle() {
|
||||||
|
if (prixMensuel == null || prixAnnuel == null) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12));
|
||||||
|
return coutMensuelAnnuel.subtract(prixAnnuel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le pourcentage d'économie annuelle
|
||||||
|
* @return Le pourcentage d'économie (0-100)
|
||||||
|
*/
|
||||||
|
public int getPourcentageEconomieAnnuelle() {
|
||||||
|
if (prixMensuel == null || prixAnnuel == null) return 0;
|
||||||
|
|
||||||
|
BigDecimal coutMensuelAnnuel = prixMensuel.multiply(BigDecimal.valueOf(12));
|
||||||
|
if (coutMensuelAnnuel.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal economie = getEconomieAnnuelle();
|
||||||
|
return economie.multiply(BigDecimal.valueOf(100))
|
||||||
|
.divide(coutMensuelAnnuel, 0, java.math.RoundingMode.HALF_UP)
|
||||||
|
.intValue();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule a une période d'essai
|
||||||
|
* @return true si une période d'essai est disponible
|
||||||
|
*/
|
||||||
|
public boolean hasPeriodeEssai() {
|
||||||
|
return periodeEssaiJours != null && periodeEssaiJours > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule inclut la formation
|
||||||
|
* @return true si la formation est incluse
|
||||||
|
*/
|
||||||
|
public boolean hasFormation() {
|
||||||
|
return Boolean.TRUE.equals(formationIncluse) && heuresFormation != null && heuresFormation > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la formule est recommandée ou populaire
|
||||||
|
* @return true si la formule est mise en avant
|
||||||
|
*/
|
||||||
|
public boolean isMiseEnAvant() {
|
||||||
|
return Boolean.TRUE.equals(populaire) || Boolean.TRUE.equals(recommandee);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le badge à afficher pour la formule
|
||||||
|
* @return Le texte du badge ou null
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le score de fonctionnalités (0-100)
|
||||||
|
* @return Le score basé sur les fonctionnalités incluses
|
||||||
|
*/
|
||||||
|
public int getScoreFonctionnalites() {
|
||||||
|
int score = 0;
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
// Fonctionnalités de base (poids 1)
|
||||||
|
if (Boolean.TRUE.equals(supportTechnique)) score += 10;
|
||||||
|
total += 10;
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(sauvegardeAutomatique)) score += 10;
|
||||||
|
total += 10;
|
||||||
|
|
||||||
|
// Fonctionnalités avancées (poids 2)
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Fonctionnalités premium (poids 3)
|
||||||
|
if (Boolean.TRUE.equals(multiLangues)) score += 10;
|
||||||
|
total += 10;
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(personnalisationInterface)) score += 10;
|
||||||
|
total += 10;
|
||||||
|
|
||||||
|
return total > 0 ? (score * 100) / total : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Détermine la classe CSS pour la couleur de la formule
|
||||||
|
* @return La classe CSS appropriée
|
||||||
|
*/
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active la formule
|
||||||
|
*/
|
||||||
|
public void activer() {
|
||||||
|
this.statut = StatutFormule.ACTIVE;
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Désactive la formule
|
||||||
|
*/
|
||||||
|
public void desactiver() {
|
||||||
|
this.statut = StatutFormule.INACTIVE;
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Archive la formule
|
||||||
|
*/
|
||||||
|
public void archiver() {
|
||||||
|
this.statut = StatutFormule.ARCHIVEE;
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "FormuleAbonnementDTO{" +
|
||||||
|
"nom='" + nom + '\'' +
|
||||||
|
", code='" + code + '\'' +
|
||||||
|
", type=" + type +
|
||||||
|
", prixMensuel=" + prixMensuel +
|
||||||
|
", prixAnnuel=" + prixAnnuel +
|
||||||
|
", devise='" + devise + '\'' +
|
||||||
|
", statut=" + statut +
|
||||||
|
", populaire=" + populaire +
|
||||||
|
", recommandee=" + recommandee +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,472 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.membre;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Past;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des membres dans l'API UnionFlow
|
||||||
|
* Contient toutes les informations relatives à un membre d'une organisation
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class MembreDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro unique du membre (format: UF-YYYY-XXXXXXXX)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le numéro de membre est obligatoire")
|
||||||
|
@Pattern(regexp = "^UF-\\d{4}-[A-Z0-9]{8}$", message = "Format de numéro de membre invalide (UF-YYYY-XXXXXXXX)")
|
||||||
|
private String numeroMembre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de famille du membre
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le nom est obligatoire")
|
||||||
|
@Size(min = 2, max = 50, message = "Le nom doit contenir entre 2 et 50 caractères")
|
||||||
|
@Pattern(regexp = "^[a-zA-ZÀ-ÿ\\s\\-']+$", message = "Le nom ne peut contenir que des lettres, espaces, tirets et apostrophes")
|
||||||
|
private String nom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prénom du membre
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le prénom est obligatoire")
|
||||||
|
@Size(min = 2, max = 50, message = "Le prénom doit contenir entre 2 et 50 caractères")
|
||||||
|
@Pattern(regexp = "^[a-zA-ZÀ-ÿ\\s\\-']+$", message = "Le prénom ne peut contenir que des lettres, espaces, tirets et apostrophes")
|
||||||
|
private String prenom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse email du membre
|
||||||
|
*/
|
||||||
|
@Email(message = "Format d'email invalide")
|
||||||
|
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de téléphone du membre
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$", message = "Format de téléphone invalide")
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de naissance du membre
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Past(message = "La date de naissance doit être dans le passé")
|
||||||
|
private LocalDate dateNaissance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse physique du membre
|
||||||
|
*/
|
||||||
|
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
|
||||||
|
private String adresse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profession du membre
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
|
||||||
|
private String profession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut matrimonial du membre
|
||||||
|
*/
|
||||||
|
@Size(max = 20, message = "Le statut matrimonial ne peut pas dépasser 20 caractères")
|
||||||
|
private String statutMatrimonial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nationalité du membre
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
|
||||||
|
private String nationalite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de pièce d'identité
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "Le numéro d'identité ne peut pas dépasser 50 caractères")
|
||||||
|
private String numeroIdentite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type de pièce d'identité (CNI, Passeport, etc.)
|
||||||
|
*/
|
||||||
|
@Size(max = 20, message = "Le type d'identité ne peut pas dépasser 20 caractères")
|
||||||
|
private String typeIdentite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut du membre (ACTIF, INACTIF, SUSPENDU, RADIE)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut est obligatoire")
|
||||||
|
@Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
|
||||||
|
private String statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'association à laquelle appartient le membre
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'association est obligatoire")
|
||||||
|
private Long associationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'association (lecture seule)
|
||||||
|
*/
|
||||||
|
private String associationNom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'adhésion du membre
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateAdhesion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Région géographique
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ville de résidence
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
|
||||||
|
private String ville;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quartier de résidence
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "Le quartier ne peut pas dépasser 50 caractères")
|
||||||
|
private String quartier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rôle du membre dans l'organisation
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "Le rôle ne peut pas dépasser 50 caractères")
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indique si le membre fait partie du bureau
|
||||||
|
*/
|
||||||
|
private Boolean membreBureau = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indique si le membre est responsable
|
||||||
|
*/
|
||||||
|
private Boolean responsable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Photo de profil (URL ou chemin)
|
||||||
|
*/
|
||||||
|
@Size(max = 255, message = "L'URL de la photo ne peut pas dépasser 255 caractères")
|
||||||
|
private String photoUrl;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public MembreDTO() {
|
||||||
|
super();
|
||||||
|
this.statut = "ACTIF";
|
||||||
|
this.dateAdhesion = LocalDate.now();
|
||||||
|
this.membreBureau = false;
|
||||||
|
this.responsable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembreDTO(String numeroMembre, String nom, String prenom, String email) {
|
||||||
|
this();
|
||||||
|
this.numeroMembre = numeroMembre;
|
||||||
|
this.nom = nom;
|
||||||
|
this.prenom = prenom;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getNumeroMembre() {
|
||||||
|
return numeroMembre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroMembre(String numeroMembre) {
|
||||||
|
this.numeroMembre = numeroMembre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNom() {
|
||||||
|
return nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNom(String nom) {
|
||||||
|
this.nom = nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrenom() {
|
||||||
|
return prenom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrenom(String prenom) {
|
||||||
|
this.prenom = prenom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTelephone() {
|
||||||
|
return telephone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTelephone(String telephone) {
|
||||||
|
this.telephone = telephone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateNaissance() {
|
||||||
|
return dateNaissance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateNaissance(LocalDate dateNaissance) {
|
||||||
|
this.dateNaissance = dateNaissance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdresse() {
|
||||||
|
return adresse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdresse(String adresse) {
|
||||||
|
this.adresse = adresse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProfession() {
|
||||||
|
return profession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfession(String profession) {
|
||||||
|
this.profession = profession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatutMatrimonial() {
|
||||||
|
return statutMatrimonial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatutMatrimonial(String statutMatrimonial) {
|
||||||
|
this.statutMatrimonial = statutMatrimonial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNationalite() {
|
||||||
|
return nationalite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNationalite(String nationalite) {
|
||||||
|
this.nationalite = nationalite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumeroIdentite() {
|
||||||
|
return numeroIdentite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroIdentite(String numeroIdentite) {
|
||||||
|
this.numeroIdentite = numeroIdentite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeIdentite() {
|
||||||
|
return typeIdentite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeIdentite(String typeIdentite) {
|
||||||
|
this.typeIdentite = typeIdentite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatut() {
|
||||||
|
return statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatut(String statut) {
|
||||||
|
this.statut = statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAssociationId() {
|
||||||
|
return associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssociationId(Long associationId) {
|
||||||
|
this.associationId = associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAssociationNom() {
|
||||||
|
return associationNom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssociationNom(String associationNom) {
|
||||||
|
this.associationNom = associationNom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateAdhesion() {
|
||||||
|
return dateAdhesion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateAdhesion(LocalDate dateAdhesion) {
|
||||||
|
this.dateAdhesion = dateAdhesion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegion() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegion(String region) {
|
||||||
|
this.region = region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVille() {
|
||||||
|
return ville;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVille(String ville) {
|
||||||
|
this.ville = ville;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuartier() {
|
||||||
|
return quartier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuartier(String quartier) {
|
||||||
|
this.quartier = quartier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(String role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getMembreBureau() {
|
||||||
|
return membreBureau;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembreBureau(Boolean membreBureau) {
|
||||||
|
this.membreBureau = membreBureau;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getResponsable() {
|
||||||
|
return responsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResponsable(Boolean responsable) {
|
||||||
|
this.responsable = responsable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhotoUrl() {
|
||||||
|
return photoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhotoUrl(String photoUrl) {
|
||||||
|
this.photoUrl = photoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le nom complet du membre (prénom + nom)
|
||||||
|
* @return Le nom complet
|
||||||
|
*/
|
||||||
|
public String getNomComplet() {
|
||||||
|
if (prenom != null && nom != null) {
|
||||||
|
return prenom + " " + nom;
|
||||||
|
} else if (nom != null) {
|
||||||
|
return nom;
|
||||||
|
} else if (prenom != null) {
|
||||||
|
return prenom;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le membre est majeur (18 ans ou plus)
|
||||||
|
* @return true si le membre est majeur, false sinon
|
||||||
|
*/
|
||||||
|
public boolean isMajeur() {
|
||||||
|
if (dateNaissance == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return LocalDate.now().minusYears(18).isAfter(dateNaissance) ||
|
||||||
|
LocalDate.now().minusYears(18).isEqual(dateNaissance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule l'âge du membre
|
||||||
|
* @return L'âge en années, ou -1 si la date de naissance n'est pas définie
|
||||||
|
*/
|
||||||
|
public int getAge() {
|
||||||
|
if (dateNaissance == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return LocalDate.now().getYear() - dateNaissance.getYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le membre est actif
|
||||||
|
* @return true si le statut est ACTIF
|
||||||
|
*/
|
||||||
|
public boolean isActif() {
|
||||||
|
return "ACTIF".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le membre a un rôle de direction
|
||||||
|
* @return true si le membre fait partie du bureau ou est responsable
|
||||||
|
*/
|
||||||
|
public boolean hasRoleDirection() {
|
||||||
|
return Boolean.TRUE.equals(membreBureau) || Boolean.TRUE.equals(responsable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne une représentation textuelle du statut
|
||||||
|
* @return Le libellé du statut
|
||||||
|
*/
|
||||||
|
public String getStatutLibelle() {
|
||||||
|
if (statut == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (statut) {
|
||||||
|
case "ACTIF" -> "Actif";
|
||||||
|
case "INACTIF" -> "Inactif";
|
||||||
|
case "SUSPENDU" -> "Suspendu";
|
||||||
|
case "RADIE" -> "Radié";
|
||||||
|
default -> statut;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valide les données essentielles du membre
|
||||||
|
* @return true si les données sont valides
|
||||||
|
*/
|
||||||
|
public boolean isDataValid() {
|
||||||
|
return numeroMembre != null && !numeroMembre.trim().isEmpty() &&
|
||||||
|
nom != null && !nom.trim().isEmpty() &&
|
||||||
|
prenom != null && !prenom.trim().isEmpty() &&
|
||||||
|
statut != null && !statut.trim().isEmpty() &&
|
||||||
|
associationId != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MembreDTO{" +
|
||||||
|
"numeroMembre='" + numeroMembre + '\'' +
|
||||||
|
", nom='" + nom + '\'' +
|
||||||
|
", prenom='" + prenom + '\'' +
|
||||||
|
", email='" + email + '\'' +
|
||||||
|
", statut='" + statut + '\'' +
|
||||||
|
", associationId=" + associationId +
|
||||||
|
", dateAdhesion=" + dateAdhesion +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,502 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.organisation;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.Period;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.organisation.StatutOrganisation;
|
||||||
|
import jakarta.validation.constraints.DecimalMax;
|
||||||
|
import jakarta.validation.constraints.DecimalMin;
|
||||||
|
import jakarta.validation.constraints.Digits;
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des organisations (Lions Club, Associations, Coopératives, etc.)
|
||||||
|
* Représente une organisation avec ses informations complètes et sa hiérarchie
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class OrganisationDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'organisation
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le nom de l'organisation est obligatoire")
|
||||||
|
@Size(min = 2, max = 200, message = "Le nom doit contenir entre 2 et 200 caractères")
|
||||||
|
private String nom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom court ou sigle
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "Le nom court ne peut pas dépasser 50 caractères")
|
||||||
|
private String nomCourt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type d'organisation
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le type d'organisation est obligatoire")
|
||||||
|
private TypeOrganisation typeOrganisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de l'organisation
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut de l'organisation est obligatoire")
|
||||||
|
private StatutOrganisation statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description de l'organisation
|
||||||
|
*/
|
||||||
|
@Size(max = 2000, message = "La description ne peut pas dépasser 2000 caractères")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de fondation
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateFondation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro d'enregistrement officiel
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "Le numéro d'enregistrement ne peut pas dépasser 100 caractères")
|
||||||
|
private String numeroEnregistrement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse complète
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "L'adresse ne peut pas dépasser 500 caractères")
|
||||||
|
private String adresse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ville
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "La ville ne peut pas dépasser 100 caractères")
|
||||||
|
private String ville;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Région/Province
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "La région ne peut pas dépasser 100 caractères")
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pays
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "Le pays ne peut pas dépasser 100 caractères")
|
||||||
|
private String pays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code postal
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^[0-9A-Z\\-\\s]{3,10}$", message = "Format de code postal invalide")
|
||||||
|
private String codePostal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Latitude pour géolocalisation
|
||||||
|
*/
|
||||||
|
@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 = 2, fraction = 8, message = "La latitude ne peut avoir plus de 2 chiffres entiers et 8 décimales")
|
||||||
|
private BigDecimal latitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Longitude pour géolocalisation
|
||||||
|
*/
|
||||||
|
@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 = 8, message = "La longitude ne peut avoir plus de 3 chiffres entiers et 8 décimales")
|
||||||
|
private BigDecimal longitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Téléphone principal
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$", message = "Format de téléphone invalide")
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Téléphone secondaire
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$", message = "Format de téléphone invalide")
|
||||||
|
private String telephoneSecondaire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email principal
|
||||||
|
*/
|
||||||
|
@Email(message = "Format d'email invalide")
|
||||||
|
@Size(max = 200, message = "L'email ne peut pas dépasser 200 caractères")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email secondaire
|
||||||
|
*/
|
||||||
|
@Email(message = "Format d'email invalide")
|
||||||
|
@Size(max = 200, message = "L'email ne peut pas dépasser 200 caractères")
|
||||||
|
private String emailSecondaire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Site web
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?$",
|
||||||
|
message = "Format d'URL invalide")
|
||||||
|
@Size(max = 500, message = "L'URL ne peut pas dépasser 500 caractères")
|
||||||
|
private String siteWeb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logo de l'organisation (URL ou nom de fichier)
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Le logo ne peut pas dépasser 500 caractères")
|
||||||
|
private String logo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organisation parente (pour hiérarchie)
|
||||||
|
*/
|
||||||
|
private UUID organisationParenteId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'organisation parente
|
||||||
|
*/
|
||||||
|
private String nomOrganisationParente;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Niveau hiérarchique (0 = racine)
|
||||||
|
*/
|
||||||
|
private Integer niveauHierarchique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de membres actifs
|
||||||
|
*/
|
||||||
|
private Integer nombreMembres;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre d'administrateurs
|
||||||
|
*/
|
||||||
|
private Integer nombreAdministrateurs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Budget annuel
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le budget doit être positif")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "Le budget ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal budgetAnnuel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise du budget
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String devise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objectifs de l'organisation
|
||||||
|
*/
|
||||||
|
@Size(max = 2000, message = "Les objectifs ne peuvent pas dépasser 2000 caractères")
|
||||||
|
private String objectifs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activités principales
|
||||||
|
*/
|
||||||
|
@Size(max = 2000, message = "Les activités ne peuvent pas dépasser 2000 caractères")
|
||||||
|
private String activitesPrincipales;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Réseaux sociaux (JSON)
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les réseaux sociaux ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String reseauxSociaux;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Certifications ou labels
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Les certifications ne peuvent pas dépasser 500 caractères")
|
||||||
|
private String certifications;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partenaires principaux
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les partenaires ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String partenaires;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notes administratives
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String notes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organisation publique (visible dans l'annuaire)
|
||||||
|
*/
|
||||||
|
private Boolean organisationPublique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepte nouveaux membres
|
||||||
|
*/
|
||||||
|
private Boolean accepteNouveauxMembres;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cotisation obligatoire
|
||||||
|
*/
|
||||||
|
private Boolean cotisationObligatoire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant cotisation annuelle
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le montant de cotisation doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal montantCotisationAnnuelle;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public OrganisationDTO() {
|
||||||
|
super();
|
||||||
|
this.statut = StatutOrganisation.ACTIVE;
|
||||||
|
this.typeOrganisation = TypeOrganisation.ASSOCIATION;
|
||||||
|
this.devise = "XOF";
|
||||||
|
this.niveauHierarchique = 0;
|
||||||
|
this.nombreMembres = 0;
|
||||||
|
this.nombreAdministrateurs = 0;
|
||||||
|
this.organisationPublique = true;
|
||||||
|
this.accepteNouveauxMembres = true;
|
||||||
|
this.cotisationObligatoire = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrganisationDTO(String nom, TypeOrganisation type) {
|
||||||
|
this();
|
||||||
|
this.nom = nom;
|
||||||
|
this.typeOrganisation = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation est active
|
||||||
|
* @return true si l'organisation est active
|
||||||
|
*/
|
||||||
|
public boolean isActive() {
|
||||||
|
return StatutOrganisation.ACTIVE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation est inactive
|
||||||
|
* @return true si l'organisation est inactive
|
||||||
|
*/
|
||||||
|
public boolean isInactive() {
|
||||||
|
return StatutOrganisation.INACTIVE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation est suspendue
|
||||||
|
* @return true si l'organisation est suspendue
|
||||||
|
*/
|
||||||
|
public boolean isSuspendue() {
|
||||||
|
return StatutOrganisation.SUSPENDUE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation est en cours de création
|
||||||
|
* @return true si l'organisation est en création
|
||||||
|
*/
|
||||||
|
public boolean isEnCreation() {
|
||||||
|
return StatutOrganisation.EN_CREATION.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation est dissoute
|
||||||
|
* @return true si l'organisation est dissoute
|
||||||
|
*/
|
||||||
|
public boolean isDissoute() {
|
||||||
|
return StatutOrganisation.DISSOUTE.equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule l'ancienneté de l'organisation en années
|
||||||
|
* @return L'ancienneté en années
|
||||||
|
*/
|
||||||
|
public int getAncienneteAnnees() {
|
||||||
|
if (dateFondation == null) return 0;
|
||||||
|
return Period.between(dateFondation, LocalDate.now()).getYears();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule l'ancienneté de l'organisation en mois
|
||||||
|
* @return L'ancienneté en mois
|
||||||
|
*/
|
||||||
|
public int getAncienneteMois() {
|
||||||
|
if (dateFondation == null) return 0;
|
||||||
|
Period periode = Period.between(dateFondation, LocalDate.now());
|
||||||
|
return periode.getYears() * 12 + periode.getMonths();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation a une géolocalisation
|
||||||
|
* @return true si latitude et longitude sont définies
|
||||||
|
*/
|
||||||
|
public boolean hasGeolocalisation() {
|
||||||
|
return latitude != null && longitude != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation est une organisation racine (sans parent)
|
||||||
|
* @return true si l'organisation n'a pas de parent
|
||||||
|
*/
|
||||||
|
public boolean isOrganisationRacine() {
|
||||||
|
return organisationParenteId == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation a des sous-organisations
|
||||||
|
* @return true si le niveau hiérarchique est supérieur à 0
|
||||||
|
*/
|
||||||
|
public boolean hasSousOrganisations() {
|
||||||
|
return niveauHierarchique != null && niveauHierarchique > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le nom d'affichage (nom court si disponible, sinon nom complet)
|
||||||
|
* @return Le nom d'affichage
|
||||||
|
*/
|
||||||
|
public String getNomAffichage() {
|
||||||
|
return (nomCourt != null && !nomCourt.trim().isEmpty()) ? nomCourt : nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne l'adresse complète formatée
|
||||||
|
* @return L'adresse complète
|
||||||
|
*/
|
||||||
|
public String getAdresseComplete() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (adresse != null && !adresse.trim().isEmpty()) {
|
||||||
|
sb.append(adresse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ville != null && !ville.trim().isEmpty()) {
|
||||||
|
if (sb.length() > 0) sb.append(", ");
|
||||||
|
sb.append(ville);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codePostal != null && !codePostal.trim().isEmpty()) {
|
||||||
|
if (sb.length() > 0) sb.append(" ");
|
||||||
|
sb.append(codePostal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region != null && !region.trim().isEmpty()) {
|
||||||
|
if (sb.length() > 0) sb.append(", ");
|
||||||
|
sb.append(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pays != null && !pays.trim().isEmpty()) {
|
||||||
|
if (sb.length() > 0) sb.append(", ");
|
||||||
|
sb.append(pays);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le ratio administrateurs/membres
|
||||||
|
* @return Le pourcentage d'administrateurs
|
||||||
|
*/
|
||||||
|
public double getRatioAdministrateurs() {
|
||||||
|
if (nombreMembres == null || nombreMembres == 0) return 0.0;
|
||||||
|
if (nombreAdministrateurs == null) return 0.0;
|
||||||
|
return (nombreAdministrateurs.doubleValue() / nombreMembres.doubleValue()) * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'organisation a un budget défini
|
||||||
|
* @return true si un budget annuel est défini
|
||||||
|
*/
|
||||||
|
public boolean hasBudget() {
|
||||||
|
return budgetAnnuel != null && budgetAnnuel.compareTo(BigDecimal.ZERO) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active l'organisation
|
||||||
|
* @param utilisateur L'utilisateur qui active l'organisation
|
||||||
|
*/
|
||||||
|
public void activer(String utilisateur) {
|
||||||
|
this.statut = StatutOrganisation.ACTIVE;
|
||||||
|
marquerCommeModifie(utilisateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suspend l'organisation
|
||||||
|
* @param utilisateur L'utilisateur qui suspend l'organisation
|
||||||
|
*/
|
||||||
|
public void suspendre(String utilisateur) {
|
||||||
|
this.statut = StatutOrganisation.SUSPENDUE;
|
||||||
|
marquerCommeModifie(utilisateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dissout l'organisation
|
||||||
|
* @param utilisateur L'utilisateur qui dissout l'organisation
|
||||||
|
*/
|
||||||
|
public void dissoudre(String utilisateur) {
|
||||||
|
this.statut = StatutOrganisation.DISSOUTE;
|
||||||
|
this.accepteNouveauxMembres = false;
|
||||||
|
marquerCommeModifie(utilisateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour le nombre de membres
|
||||||
|
* @param nouveauNombre Le nouveau nombre de membres
|
||||||
|
* @param utilisateur L'utilisateur qui fait la mise à jour
|
||||||
|
*/
|
||||||
|
public void mettreAJourNombreMembres(int nouveauNombre, String utilisateur) {
|
||||||
|
this.nombreMembres = nouveauNombre;
|
||||||
|
marquerCommeModifie(utilisateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute un membre
|
||||||
|
* @param utilisateur L'utilisateur qui ajoute le membre
|
||||||
|
*/
|
||||||
|
public void ajouterMembre(String utilisateur) {
|
||||||
|
if (nombreMembres == null) nombreMembres = 0;
|
||||||
|
nombreMembres++;
|
||||||
|
marquerCommeModifie(utilisateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retire un membre
|
||||||
|
* @param utilisateur L'utilisateur qui retire le membre
|
||||||
|
*/
|
||||||
|
public void retirerMembre(String utilisateur) {
|
||||||
|
if (nombreMembres != null && nombreMembres > 0) {
|
||||||
|
nombreMembres--;
|
||||||
|
marquerCommeModifie(utilisateur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "OrganisationDTO{" +
|
||||||
|
"nom='" + nom + '\'' +
|
||||||
|
", nomCourt='" + nomCourt + '\'' +
|
||||||
|
", typeOrganisation=" + typeOrganisation +
|
||||||
|
", statut=" + statut +
|
||||||
|
", ville='" + ville + '\'' +
|
||||||
|
", pays='" + pays + '\'' +
|
||||||
|
", nombreMembres=" + nombreMembres +
|
||||||
|
", anciennete=" + getAncienneteAnnees() + " ans" +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.paiement;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
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 lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la consultation du solde Wave Money (Balance API)
|
||||||
|
* Représente le solde d'un wallet Wave Business
|
||||||
|
*
|
||||||
|
* Basé sur l'API officielle Wave : https://docs.wave.com/business#balance-api
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class WaveBalanceDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solde disponible
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le solde disponible est obligatoire")
|
||||||
|
@DecimalMin(value = "0.0", message = "Le solde doit être positif ou nul")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "Le solde ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal soldeDisponible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solde en attente (transactions en cours)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le solde en attente doit être positif ou nul")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "Le solde ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal soldeEnAttente;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solde total (disponible + en attente)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le solde total doit être positif ou nul")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "Le solde ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal soldeTotal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise du wallet
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "La devise est obligatoire")
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String devise = "XOF";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro du wallet Wave
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le numéro de wallet est obligatoire")
|
||||||
|
private String numeroWallet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom du business associé au wallet
|
||||||
|
*/
|
||||||
|
private String nomBusiness;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de dernière mise à jour du solde
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateDerniereMiseAJour;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de dernière synchronisation avec Wave
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateDerniereSynchronisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut du wallet
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(ACTIVE|INACTIVE|SUSPENDED|BLOCKED)$",
|
||||||
|
message = "Le statut doit être ACTIVE, INACTIVE, SUSPENDED ou BLOCKED")
|
||||||
|
private String statutWallet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limite de transaction quotidienne
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "La limite doit être positive ou nulle")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "La limite ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal limiteQuotidienne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant déjà utilisé aujourd'hui
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le montant utilisé doit être positif ou nul")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "Le montant ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal montantUtiliseAujourdhui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limite mensuelle
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "La limite doit être positive ou nulle")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "La limite ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal limiteMensuelle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant utilisé ce mois
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le montant utilisé doit être positif ou nul")
|
||||||
|
@Digits(integer = 12, fraction = 2, message = "Le montant ne peut avoir plus de 12 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal montantUtiliseCeMois;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de transactions aujourd'hui
|
||||||
|
*/
|
||||||
|
private Integer nombreTransactionsAujourdhui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de transactions ce mois
|
||||||
|
*/
|
||||||
|
private Integer nombreTransactionsCeMois;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dernière erreur de synchronisation
|
||||||
|
*/
|
||||||
|
private String derniereErreur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code de la dernière erreur
|
||||||
|
*/
|
||||||
|
private String codeDerniereErreur;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public WaveBalanceDTO() {
|
||||||
|
super();
|
||||||
|
this.devise = "XOF";
|
||||||
|
this.statutWallet = "ACTIVE";
|
||||||
|
this.soldeEnAttente = BigDecimal.ZERO;
|
||||||
|
this.montantUtiliseAujourdhui = BigDecimal.ZERO;
|
||||||
|
this.montantUtiliseCeMois = BigDecimal.ZERO;
|
||||||
|
this.nombreTransactionsAujourdhui = 0;
|
||||||
|
this.nombreTransactionsCeMois = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaveBalanceDTO(String numeroWallet, BigDecimal soldeDisponible) {
|
||||||
|
this();
|
||||||
|
this.numeroWallet = numeroWallet;
|
||||||
|
this.soldeDisponible = soldeDisponible;
|
||||||
|
this.soldeTotal = soldeDisponible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public BigDecimal getSoldeDisponible() {
|
||||||
|
return soldeDisponible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoldeDisponible(BigDecimal soldeDisponible) {
|
||||||
|
this.soldeDisponible = soldeDisponible;
|
||||||
|
calculerSoldeTotal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSoldeEnAttente() {
|
||||||
|
return soldeEnAttente;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoldeEnAttente(BigDecimal soldeEnAttente) {
|
||||||
|
this.soldeEnAttente = soldeEnAttente;
|
||||||
|
calculerSoldeTotal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSoldeTotal() {
|
||||||
|
return soldeTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoldeTotal(BigDecimal soldeTotal) {
|
||||||
|
this.soldeTotal = soldeTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDevise() {
|
||||||
|
return devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevise(String devise) {
|
||||||
|
this.devise = devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumeroWallet() {
|
||||||
|
return numeroWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroWallet(String numeroWallet) {
|
||||||
|
this.numeroWallet = numeroWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomBusiness() {
|
||||||
|
return nomBusiness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomBusiness(String nomBusiness) {
|
||||||
|
this.nomBusiness = nomBusiness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateDerniereMiseAJour() {
|
||||||
|
return dateDerniereMiseAJour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDerniereMiseAJour(LocalDateTime dateDerniereMiseAJour) {
|
||||||
|
this.dateDerniereMiseAJour = dateDerniereMiseAJour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateDerniereSynchronisation() {
|
||||||
|
return dateDerniereSynchronisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDerniereSynchronisation(LocalDateTime dateDerniereSynchronisation) {
|
||||||
|
this.dateDerniereSynchronisation = dateDerniereSynchronisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatutWallet() {
|
||||||
|
return statutWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatutWallet(String statutWallet) {
|
||||||
|
this.statutWallet = statutWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getLimiteQuotidienne() {
|
||||||
|
return limiteQuotidienne;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLimiteQuotidienne(BigDecimal limiteQuotidienne) {
|
||||||
|
this.limiteQuotidienne = limiteQuotidienne;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantUtiliseAujourdhui() {
|
||||||
|
return montantUtiliseAujourdhui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantUtiliseAujourdhui(BigDecimal montantUtiliseAujourdhui) {
|
||||||
|
this.montantUtiliseAujourdhui = montantUtiliseAujourdhui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getLimiteMensuelle() {
|
||||||
|
return limiteMensuelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLimiteMensuelle(BigDecimal limiteMensuelle) {
|
||||||
|
this.limiteMensuelle = limiteMensuelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantUtiliseCeMois() {
|
||||||
|
return montantUtiliseCeMois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantUtiliseCeMois(BigDecimal montantUtiliseCeMois) {
|
||||||
|
this.montantUtiliseCeMois = montantUtiliseCeMois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNombreTransactionsAujourdhui() {
|
||||||
|
return nombreTransactionsAujourdhui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNombreTransactionsAujourdhui(Integer nombreTransactionsAujourdhui) {
|
||||||
|
this.nombreTransactionsAujourdhui = nombreTransactionsAujourdhui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNombreTransactionsCeMois() {
|
||||||
|
return nombreTransactionsCeMois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNombreTransactionsCeMois(Integer nombreTransactionsCeMois) {
|
||||||
|
this.nombreTransactionsCeMois = nombreTransactionsCeMois;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDerniereErreur() {
|
||||||
|
return derniereErreur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDerniereErreur(String derniereErreur) {
|
||||||
|
this.derniereErreur = derniereErreur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeDerniereErreur() {
|
||||||
|
return codeDerniereErreur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeDerniereErreur(String codeDerniereErreur) {
|
||||||
|
this.codeDerniereErreur = codeDerniereErreur;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le solde total
|
||||||
|
*/
|
||||||
|
private void calculerSoldeTotal() {
|
||||||
|
if (soldeDisponible != null && soldeEnAttente != null) {
|
||||||
|
this.soldeTotal = soldeDisponible.add(soldeEnAttente);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le wallet est actif
|
||||||
|
* @return true si le wallet est actif
|
||||||
|
*/
|
||||||
|
public boolean isWalletActif() {
|
||||||
|
return "ACTIVE".equals(statutWallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le solde est suffisant pour un montant donné
|
||||||
|
* @param montant Le montant à vérifier
|
||||||
|
* @return true si le solde est suffisant
|
||||||
|
*/
|
||||||
|
public boolean isSoldeSuffisant(BigDecimal montant) {
|
||||||
|
return soldeDisponible != null && soldeDisponible.compareTo(montant) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le solde disponible restant pour aujourd'hui
|
||||||
|
* @return Le montant encore disponible aujourd'hui
|
||||||
|
*/
|
||||||
|
public BigDecimal getSoldeDisponibleAujourdhui() {
|
||||||
|
if (limiteQuotidienne == null || montantUtiliseAujourdhui == null) {
|
||||||
|
return soldeDisponible;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal limiteRestante = limiteQuotidienne.subtract(montantUtiliseAujourdhui);
|
||||||
|
return soldeDisponible.min(limiteRestante);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour les statistiques après une transaction
|
||||||
|
* @param montant Le montant de la transaction
|
||||||
|
*/
|
||||||
|
public void mettreAJourApresTransaction(BigDecimal montant) {
|
||||||
|
if (montantUtiliseAujourdhui == null) montantUtiliseAujourdhui = BigDecimal.ZERO;
|
||||||
|
if (montantUtiliseCeMois == null) montantUtiliseCeMois = BigDecimal.ZERO;
|
||||||
|
if (nombreTransactionsAujourdhui == null) nombreTransactionsAujourdhui = 0;
|
||||||
|
if (nombreTransactionsCeMois == null) nombreTransactionsCeMois = 0;
|
||||||
|
|
||||||
|
this.montantUtiliseAujourdhui = montantUtiliseAujourdhui.add(montant);
|
||||||
|
this.montantUtiliseCeMois = montantUtiliseCeMois.add(montant);
|
||||||
|
this.nombreTransactionsAujourdhui++;
|
||||||
|
this.nombreTransactionsCeMois++;
|
||||||
|
this.dateDerniereMiseAJour = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "WaveBalanceDTO{" +
|
||||||
|
"numeroWallet='" + numeroWallet + '\'' +
|
||||||
|
", soldeDisponible=" + soldeDisponible +
|
||||||
|
", soldeTotal=" + soldeTotal +
|
||||||
|
", devise='" + devise + '\'' +
|
||||||
|
", statutWallet='" + statutWallet + '\'' +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.paiement;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutSession;
|
||||||
|
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 lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour les sessions de paiement Wave Money (Checkout API)
|
||||||
|
* Représente une session de paiement créée via l'API Wave Checkout
|
||||||
|
*
|
||||||
|
* Basé sur l'API officielle Wave : https://docs.wave.com/business#checkout-api
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class WaveCheckoutSessionDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID de la session Wave (retourné par l'API)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "L'ID de session Wave est obligatoire")
|
||||||
|
private String waveSessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL de la session de paiement Wave (générée par l'API Wave)
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "L'URL ne peut pas dépasser 500 caractères")
|
||||||
|
private String waveUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant du paiement
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le montant est obligatoire")
|
||||||
|
@DecimalMin(value = "0.01", 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")
|
||||||
|
private BigDecimal montant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise (XOF pour le Sénégal)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "La devise est obligatoire")
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String devise = "XOF";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL de succès (redirection après paiement réussi)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "L'URL de succès est obligatoire")
|
||||||
|
@Size(max = 500, message = "L'URL de succès ne peut pas dépasser 500 caractères")
|
||||||
|
private String successUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL d'erreur (redirection après échec)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "L'URL d'erreur est obligatoire")
|
||||||
|
@Size(max = 500, message = "L'URL d'erreur ne peut pas dépasser 500 caractères")
|
||||||
|
private String errorUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de la session
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut est obligatoire")
|
||||||
|
private StatutSession statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID de l'organisation qui effectue le paiement
|
||||||
|
*/
|
||||||
|
private UUID organisationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'organisation
|
||||||
|
*/
|
||||||
|
private String nomOrganisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID du membre qui effectue le paiement
|
||||||
|
*/
|
||||||
|
private UUID membreId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom du membre
|
||||||
|
*/
|
||||||
|
private String nomMembre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type de paiement (COTISATION, ABONNEMENT, DON, AUTRE)
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(COTISATION|ABONNEMENT|DON|EVENEMENT|FORMATION|AUTRE)$",
|
||||||
|
message = "Type de paiement invalide")
|
||||||
|
private String typePaiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Référence du paiement dans UnionFlow
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "La référence ne peut pas dépasser 100 caractères")
|
||||||
|
private String referenceUnionFlow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description du paiement
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom du business affiché (override_business_name)
|
||||||
|
*/
|
||||||
|
@Size(max = 100, message = "Le nom du business ne peut pas dépasser 100 caractères")
|
||||||
|
private String nomBusinessAffiche;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID du marchand agrégé (si applicable)
|
||||||
|
*/
|
||||||
|
private String aggregatedMerchantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'expiration de la session
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateExpiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de completion du paiement
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateCompletion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de téléphone du payeur (si fourni)
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Format de numéro de téléphone invalide")
|
||||||
|
private String telephonePayeur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email du payeur (si fourni)
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^[A-Za-z0-9+_.-]+@(.+)$", message = "Format d'email invalide")
|
||||||
|
private String emailPayeur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse IP du client
|
||||||
|
*/
|
||||||
|
private String adresseIpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Agent du navigateur
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Le User Agent ne peut pas dépasser 500 caractères")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Données de callback reçues de Wave
|
||||||
|
*/
|
||||||
|
@Size(max = 2000, message = "Les données callback ne peuvent pas dépasser 2000 caractères")
|
||||||
|
private String callbackData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code d'erreur Wave (si échec)
|
||||||
|
*/
|
||||||
|
private String codeErreurWave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message d'erreur Wave (si échec)
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Le message d'erreur ne peut pas dépasser 500 caractères")
|
||||||
|
private String messageErreurWave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de tentatives de paiement
|
||||||
|
*/
|
||||||
|
private Integer nombreTentatives;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session liée à un webhook
|
||||||
|
*/
|
||||||
|
private Boolean webhookRecu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de réception du webhook
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateWebhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Données du webhook reçu
|
||||||
|
*/
|
||||||
|
@Size(max = 2000, message = "Les données webhook ne peuvent pas dépasser 2000 caractères")
|
||||||
|
private String donneesWebhook;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public WaveCheckoutSessionDTO() {
|
||||||
|
super();
|
||||||
|
this.devise = "XOF";
|
||||||
|
this.statut = StatutSession.PENDING;
|
||||||
|
this.nombreTentatives = 0;
|
||||||
|
this.webhookRecu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaveCheckoutSessionDTO(BigDecimal montant, String successUrl, String errorUrl) {
|
||||||
|
this();
|
||||||
|
this.montant = montant;
|
||||||
|
this.successUrl = successUrl;
|
||||||
|
this.errorUrl = errorUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters générés automatiquement par Lombok @Getter/@Setter
|
||||||
|
}
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.paiement;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.TypeEvenement;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutTraitement;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour les webhooks Wave Money
|
||||||
|
* Représente les notifications reçues de Wave lors d'événements
|
||||||
|
*
|
||||||
|
* Basé sur l'API officielle Wave : https://docs.wave.com/business#webhooks
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class WaveWebhookDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID unique du webhook Wave
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "L'ID du webhook est obligatoire")
|
||||||
|
private String webhookId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type d'événement
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le type d'événement est obligatoire")
|
||||||
|
private TypeEvenement typeEvenement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code de l'événement tel que reçu de Wave
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le code événement est obligatoire")
|
||||||
|
private String codeEvenement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de traitement du webhook
|
||||||
|
*/
|
||||||
|
@NotNull(message = "Le statut de traitement est obligatoire")
|
||||||
|
private StatutTraitement statutTraitement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payload JSON complet reçu de Wave
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le payload est obligatoire")
|
||||||
|
@Size(max = 5000, message = "Le payload ne peut pas dépasser 5000 caractères")
|
||||||
|
private String payloadJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Headers HTTP reçus
|
||||||
|
*/
|
||||||
|
@Size(max = 2000, message = "Les headers ne peuvent pas dépasser 2000 caractères")
|
||||||
|
private String headersHttp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature Wave pour vérification
|
||||||
|
*/
|
||||||
|
private String signatureWave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de réception du webhook
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateReception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de traitement du webhook
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateTraitement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID de la session checkout concernée (si applicable)
|
||||||
|
*/
|
||||||
|
private String sessionCheckoutId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID de la transaction Wave concernée
|
||||||
|
*/
|
||||||
|
private String transactionWaveId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant de la transaction (si applicable)
|
||||||
|
*/
|
||||||
|
private BigDecimal montantTransaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise de la transaction
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String deviseTransaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de la transaction Wave
|
||||||
|
*/
|
||||||
|
private String statutTransactionWave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID de l'organisation UnionFlow concernée
|
||||||
|
*/
|
||||||
|
private UUID organisationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID du membre UnionFlow concerné
|
||||||
|
*/
|
||||||
|
private UUID membreId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Référence UnionFlow liée
|
||||||
|
*/
|
||||||
|
private String referenceUnionFlow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type de paiement UnionFlow
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(COTISATION|ABONNEMENT|DON|EVENEMENT|FORMATION|AUTRE)$",
|
||||||
|
message = "Type de paiement invalide")
|
||||||
|
private String typePaiementUnionFlow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse IP source du webhook
|
||||||
|
*/
|
||||||
|
private String adresseIpSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Agent du webhook
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "Le User Agent ne peut pas dépasser 500 caractères")
|
||||||
|
private String userAgentSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de tentatives de traitement
|
||||||
|
*/
|
||||||
|
private Integer nombreTentativesTraitement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message d'erreur de traitement (si échec)
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Le message d'erreur ne peut pas dépasser 1000 caractères")
|
||||||
|
private String messageErreurTraitement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code d'erreur de traitement (si échec)
|
||||||
|
*/
|
||||||
|
private String codeErreurTraitement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack trace de l'erreur (si échec)
|
||||||
|
*/
|
||||||
|
@Size(max = 3000, message = "La stack trace ne peut pas dépasser 3000 caractères")
|
||||||
|
private String stackTraceErreur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhook traité automatiquement
|
||||||
|
*/
|
||||||
|
private Boolean traitementAutomatique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhook nécessitant une intervention manuelle
|
||||||
|
*/
|
||||||
|
private Boolean interventionManuelleRequise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notes de traitement manuel
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les notes ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String notesTraitementManuel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilisateur ayant traité manuellement
|
||||||
|
*/
|
||||||
|
private String utilisateurTraitementManuel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date du traitement manuel
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateTraitementManuel;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public WaveWebhookDTO() {
|
||||||
|
super();
|
||||||
|
this.statutTraitement = StatutTraitement.RECU;
|
||||||
|
this.dateReception = LocalDateTime.now();
|
||||||
|
this.nombreTentativesTraitement = 0;
|
||||||
|
this.traitementAutomatique = true;
|
||||||
|
this.interventionManuelleRequise = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaveWebhookDTO(String webhookId, TypeEvenement typeEvenement, String payloadJson) {
|
||||||
|
this();
|
||||||
|
this.webhookId = webhookId;
|
||||||
|
this.typeEvenement = typeEvenement;
|
||||||
|
this.codeEvenement = typeEvenement.getCodeWave();
|
||||||
|
this.payloadJson = payloadJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getWebhookId() {
|
||||||
|
return webhookId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWebhookId(String webhookId) {
|
||||||
|
this.webhookId = webhookId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeEvenement getTypeEvenement() {
|
||||||
|
return typeEvenement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeEvenement(TypeEvenement typeEvenement) {
|
||||||
|
this.typeEvenement = typeEvenement;
|
||||||
|
if (typeEvenement != null) {
|
||||||
|
this.codeEvenement = typeEvenement.getCodeWave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeEvenement() {
|
||||||
|
return codeEvenement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeEvenement(String codeEvenement) {
|
||||||
|
this.codeEvenement = codeEvenement;
|
||||||
|
this.typeEvenement = TypeEvenement.fromCode(codeEvenement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatutTraitement getStatutTraitement() {
|
||||||
|
return statutTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatutTraitement(StatutTraitement statutTraitement) {
|
||||||
|
this.statutTraitement = statutTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayloadJson() {
|
||||||
|
return payloadJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayloadJson(String payloadJson) {
|
||||||
|
this.payloadJson = payloadJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHeadersHttp() {
|
||||||
|
return headersHttp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeadersHttp(String headersHttp) {
|
||||||
|
this.headersHttp = headersHttp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignatureWave() {
|
||||||
|
return signatureWave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSignatureWave(String signatureWave) {
|
||||||
|
this.signatureWave = signatureWave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateReception() {
|
||||||
|
return dateReception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateReception(LocalDateTime dateReception) {
|
||||||
|
this.dateReception = dateReception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateTraitement() {
|
||||||
|
return dateTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateTraitement(LocalDateTime dateTraitement) {
|
||||||
|
this.dateTraitement = dateTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionCheckoutId() {
|
||||||
|
return sessionCheckoutId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionCheckoutId(String sessionCheckoutId) {
|
||||||
|
this.sessionCheckoutId = sessionCheckoutId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTransactionWaveId() {
|
||||||
|
return transactionWaveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionWaveId(String transactionWaveId) {
|
||||||
|
this.transactionWaveId = transactionWaveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantTransaction() {
|
||||||
|
return montantTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantTransaction(BigDecimal montantTransaction) {
|
||||||
|
this.montantTransaction = montantTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviseTransaction() {
|
||||||
|
return deviseTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviseTransaction(String deviseTransaction) {
|
||||||
|
this.deviseTransaction = deviseTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatutTransactionWave() {
|
||||||
|
return statutTransactionWave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatutTransactionWave(String statutTransactionWave) {
|
||||||
|
this.statutTransactionWave = statutTransactionWave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getOrganisationId() {
|
||||||
|
return organisationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrganisationId(UUID organisationId) {
|
||||||
|
this.organisationId = organisationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getMembreId() {
|
||||||
|
return membreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembreId(UUID membreId) {
|
||||||
|
this.membreId = membreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReferenceUnionFlow() {
|
||||||
|
return referenceUnionFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReferenceUnionFlow(String referenceUnionFlow) {
|
||||||
|
this.referenceUnionFlow = referenceUnionFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypePaiementUnionFlow() {
|
||||||
|
return typePaiementUnionFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypePaiementUnionFlow(String typePaiementUnionFlow) {
|
||||||
|
this.typePaiementUnionFlow = typePaiementUnionFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdresseIpSource() {
|
||||||
|
return adresseIpSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdresseIpSource(String adresseIpSource) {
|
||||||
|
this.adresseIpSource = adresseIpSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserAgentSource() {
|
||||||
|
return userAgentSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserAgentSource(String userAgentSource) {
|
||||||
|
this.userAgentSource = userAgentSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNombreTentativesTraitement() {
|
||||||
|
return nombreTentativesTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNombreTentativesTraitement(Integer nombreTentativesTraitement) {
|
||||||
|
this.nombreTentativesTraitement = nombreTentativesTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageErreurTraitement() {
|
||||||
|
return messageErreurTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageErreurTraitement(String messageErreurTraitement) {
|
||||||
|
this.messageErreurTraitement = messageErreurTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeErreurTraitement() {
|
||||||
|
return codeErreurTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeErreurTraitement(String codeErreurTraitement) {
|
||||||
|
this.codeErreurTraitement = codeErreurTraitement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStackTraceErreur() {
|
||||||
|
return stackTraceErreur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStackTraceErreur(String stackTraceErreur) {
|
||||||
|
this.stackTraceErreur = stackTraceErreur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getTraitementAutomatique() {
|
||||||
|
return traitementAutomatique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTraitementAutomatique(Boolean traitementAutomatique) {
|
||||||
|
this.traitementAutomatique = traitementAutomatique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getInterventionManuelleRequise() {
|
||||||
|
return interventionManuelleRequise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterventionManuelleRequise(Boolean interventionManuelleRequise) {
|
||||||
|
this.interventionManuelleRequise = interventionManuelleRequise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNotesTraitementManuel() {
|
||||||
|
return notesTraitementManuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotesTraitementManuel(String notesTraitementManuel) {
|
||||||
|
this.notesTraitementManuel = notesTraitementManuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUtilisateurTraitementManuel() {
|
||||||
|
return utilisateurTraitementManuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUtilisateurTraitementManuel(String utilisateurTraitementManuel) {
|
||||||
|
this.utilisateurTraitementManuel = utilisateurTraitementManuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateTraitementManuel() {
|
||||||
|
return dateTraitementManuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateTraitementManuel(LocalDateTime dateTraitementManuel) {
|
||||||
|
this.dateTraitementManuel = dateTraitementManuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le webhook concerne un checkout
|
||||||
|
* @return true si c'est un événement de checkout
|
||||||
|
*/
|
||||||
|
public boolean isEvenementCheckout() {
|
||||||
|
return typeEvenement == TypeEvenement.CHECKOUT_COMPLETE ||
|
||||||
|
typeEvenement == TypeEvenement.CHECKOUT_CANCELLED ||
|
||||||
|
typeEvenement == TypeEvenement.CHECKOUT_EXPIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le webhook concerne un payout
|
||||||
|
* @return true si c'est un événement de payout
|
||||||
|
*/
|
||||||
|
public boolean isEvenementPayout() {
|
||||||
|
return typeEvenement == TypeEvenement.PAYOUT_COMPLETE ||
|
||||||
|
typeEvenement == TypeEvenement.PAYOUT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marque le webhook comme traité avec succès
|
||||||
|
*/
|
||||||
|
public void marquerCommeTraite() {
|
||||||
|
this.statutTraitement = StatutTraitement.TRAITE;
|
||||||
|
this.dateTraitement = LocalDateTime.now();
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marque le webhook comme échoué
|
||||||
|
* @param messageErreur Le message d'erreur
|
||||||
|
* @param codeErreur Le code d'erreur
|
||||||
|
*/
|
||||||
|
public void marquerCommeEchec(String messageErreur, String codeErreur) {
|
||||||
|
this.statutTraitement = StatutTraitement.ECHEC;
|
||||||
|
this.messageErreurTraitement = messageErreur;
|
||||||
|
this.codeErreurTraitement = codeErreur;
|
||||||
|
this.nombreTentativesTraitement++;
|
||||||
|
this.dateTraitement = LocalDateTime.now();
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Démarre le traitement du webhook
|
||||||
|
*/
|
||||||
|
public void demarrerTraitement() {
|
||||||
|
this.statutTraitement = StatutTraitement.EN_COURS;
|
||||||
|
this.nombreTentativesTraitement++;
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "WaveWebhookDTO{" +
|
||||||
|
"webhookId='" + webhookId + '\'' +
|
||||||
|
", typeEvenement=" + typeEvenement +
|
||||||
|
", statutTraitement=" + statutTraitement +
|
||||||
|
", dateReception=" + dateReception +
|
||||||
|
", sessionCheckoutId='" + sessionCheckoutId + '\'' +
|
||||||
|
", montantTransaction=" + montantTransaction +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,871 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.solidarite.aide;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO pour la gestion des demandes d'aide et de solidarité
|
||||||
|
* Représente les demandes d'assistance mutuelle entre membres
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public class AideDTO extends BaseDTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de référence unique de la demande
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le numéro de référence est obligatoire")
|
||||||
|
@Pattern(regexp = "^AIDE-\\d{4}-[A-Z0-9]{6}$", message = "Format de référence invalide (AIDE-YYYY-XXXXXX)")
|
||||||
|
private String numeroReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant du membre demandeur
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'identifiant du demandeur est obligatoire")
|
||||||
|
private UUID membreDemandeurId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom complet du membre demandeur
|
||||||
|
*/
|
||||||
|
private String nomDemandeur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de membre du demandeur
|
||||||
|
*/
|
||||||
|
private String numeroMembreDemandeur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de l'association
|
||||||
|
*/
|
||||||
|
@NotNull(message = "L'identifiant de l'association est obligatoire")
|
||||||
|
private UUID associationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'association
|
||||||
|
*/
|
||||||
|
private String nomAssociation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type d'aide demandée
|
||||||
|
* FINANCIERE, MATERIELLE, MEDICALE, JURIDIQUE, LOGEMENT, EDUCATION, AUTRE
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le type d'aide est obligatoire")
|
||||||
|
@Pattern(regexp = "^(FINANCIERE|MATERIELLE|MEDICALE|JURIDIQUE|LOGEMENT|EDUCATION|AUTRE)$",
|
||||||
|
message = "Le type d'aide doit être FINANCIERE, MATERIELLE, MEDICALE, JURIDIQUE, LOGEMENT, EDUCATION ou AUTRE")
|
||||||
|
private String typeAide;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Titre de la demande d'aide
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le titre est obligatoire")
|
||||||
|
@Size(min = 5, max = 200, message = "Le titre doit contenir entre 5 et 200 caractères")
|
||||||
|
private String titre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description détaillée de la demande
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "La description est obligatoire")
|
||||||
|
@Size(min = 20, max = 2000, message = "La description doit contenir entre 20 et 2000 caractères")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant demandé (pour les aides financières)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant demandé doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal montantDemande;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devise du montant
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
|
||||||
|
private String devise = "XOF";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statut de la demande
|
||||||
|
* EN_ATTENTE, EN_COURS_EVALUATION, APPROUVEE, REJETEE, EN_COURS_AIDE, TERMINEE, ANNULEE
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "Le statut est obligatoire")
|
||||||
|
@Pattern(regexp = "^(EN_ATTENTE|EN_COURS_EVALUATION|APPROUVEE|REJETEE|EN_COURS_AIDE|TERMINEE|ANNULEE)$",
|
||||||
|
message = "Statut invalide")
|
||||||
|
private String statut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Priorité de la demande
|
||||||
|
* BASSE, NORMALE, HAUTE, URGENTE
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(BASSE|NORMALE|HAUTE|URGENTE)$",
|
||||||
|
message = "La priorité doit être BASSE, NORMALE, HAUTE ou URGENTE")
|
||||||
|
private String priorite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date limite pour l'aide
|
||||||
|
*/
|
||||||
|
@Future(message = "La date limite doit être dans le futur")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateLimite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Justificatifs fournis
|
||||||
|
*/
|
||||||
|
private Boolean justificatifsFournis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liste des documents joints (noms de fichiers)
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "La liste des documents ne peut pas dépasser 1000 caractères")
|
||||||
|
private String documentsJoints;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant du membre évaluateur
|
||||||
|
*/
|
||||||
|
private UUID membreEvaluateurId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de l'évaluateur
|
||||||
|
*/
|
||||||
|
private String nomEvaluateur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'évaluation
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateEvaluation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commentaires de l'évaluateur
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String commentairesEvaluateur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant approuvé (peut être différent du montant demandé)
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le montant approuvé doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal montantApprouve;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date d'approbation
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateApprobation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant du membre qui fournit l'aide
|
||||||
|
*/
|
||||||
|
private UUID membreAidantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom du membre aidant
|
||||||
|
*/
|
||||||
|
private String nomAidant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de début de l'aide
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateDebutAide;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de fin de l'aide
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateFinAide;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Montant effectivement versé
|
||||||
|
*/
|
||||||
|
@DecimalMin(value = "0.0", message = "Le montant versé doit être positif")
|
||||||
|
@Digits(integer = 10, fraction = 2, message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
|
||||||
|
private BigDecimal montantVerse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode de versement
|
||||||
|
*/
|
||||||
|
@Pattern(regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|ESPECES|NATURE)$",
|
||||||
|
message = "Mode de versement invalide")
|
||||||
|
private String modeVersement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numéro de transaction (pour les paiements mobiles)
|
||||||
|
*/
|
||||||
|
@Size(max = 50, message = "Le numéro de transaction ne peut pas dépasser 50 caractères")
|
||||||
|
private String numeroTransaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de versement
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateVersement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commentaires du bénéficiaire
|
||||||
|
*/
|
||||||
|
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
|
||||||
|
private String commentairesBeneficiaire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note de satisfaction (1-5)
|
||||||
|
*/
|
||||||
|
private Integer noteSatisfaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aide publique (visible par tous les membres)
|
||||||
|
*/
|
||||||
|
private Boolean aidePublique;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aide anonyme (demandeur anonyme)
|
||||||
|
*/
|
||||||
|
private Boolean aideAnonyme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nombre de vues de la demande
|
||||||
|
*/
|
||||||
|
private Integer nombreVues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raison du rejet (si applicable)
|
||||||
|
*/
|
||||||
|
@Size(max = 500, message = "La raison du rejet ne peut pas dépasser 500 caractères")
|
||||||
|
private String raisonRejet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date de rejet
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime dateRejet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifiant de celui qui a rejeté
|
||||||
|
*/
|
||||||
|
private UUID rejeteParId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom de celui qui a rejeté
|
||||||
|
*/
|
||||||
|
private String rejetePar;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public AideDTO() {
|
||||||
|
super();
|
||||||
|
this.statut = "EN_ATTENTE";
|
||||||
|
this.priorite = "NORMALE";
|
||||||
|
this.devise = "XOF";
|
||||||
|
this.justificatifsFournis = false;
|
||||||
|
this.aidePublique = true;
|
||||||
|
this.aideAnonyme = false;
|
||||||
|
this.nombreVues = 0;
|
||||||
|
this.numeroReference = genererNumeroReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AideDTO(UUID membreDemandeurId, UUID associationId, String typeAide, String titre) {
|
||||||
|
this();
|
||||||
|
this.membreDemandeurId = membreDemandeurId;
|
||||||
|
this.associationId = associationId;
|
||||||
|
this.typeAide = typeAide;
|
||||||
|
this.titre = titre;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et Setters
|
||||||
|
public String getNumeroReference() {
|
||||||
|
return numeroReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroReference(String numeroReference) {
|
||||||
|
this.numeroReference = numeroReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getMembreDemandeurId() {
|
||||||
|
return membreDemandeurId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembreDemandeurId(UUID membreDemandeurId) {
|
||||||
|
this.membreDemandeurId = membreDemandeurId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomDemandeur() {
|
||||||
|
return nomDemandeur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomDemandeur(String nomDemandeur) {
|
||||||
|
this.nomDemandeur = nomDemandeur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumeroMembreDemandeur() {
|
||||||
|
return numeroMembreDemandeur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroMembreDemandeur(String numeroMembreDemandeur) {
|
||||||
|
this.numeroMembreDemandeur = numeroMembreDemandeur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getAssociationId() {
|
||||||
|
return associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssociationId(UUID associationId) {
|
||||||
|
this.associationId = associationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomAssociation() {
|
||||||
|
return nomAssociation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomAssociation(String nomAssociation) {
|
||||||
|
this.nomAssociation = nomAssociation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeAide() {
|
||||||
|
return typeAide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeAide(String typeAide) {
|
||||||
|
this.typeAide = typeAide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitre() {
|
||||||
|
return titre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitre(String titre) {
|
||||||
|
this.titre = titre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantDemande() {
|
||||||
|
return montantDemande;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantDemande(BigDecimal montantDemande) {
|
||||||
|
this.montantDemande = montantDemande;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDevise() {
|
||||||
|
return devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevise(String devise) {
|
||||||
|
this.devise = devise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatut() {
|
||||||
|
return statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatut(String statut) {
|
||||||
|
this.statut = statut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPriorite() {
|
||||||
|
return priorite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriorite(String priorite) {
|
||||||
|
this.priorite = priorite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateLimite() {
|
||||||
|
return dateLimite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateLimite(LocalDate dateLimite) {
|
||||||
|
this.dateLimite = dateLimite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getJustificatifsFournis() {
|
||||||
|
return justificatifsFournis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJustificatifsFournis(Boolean justificatifsFournis) {
|
||||||
|
this.justificatifsFournis = justificatifsFournis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDocumentsJoints() {
|
||||||
|
return documentsJoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDocumentsJoints(String documentsJoints) {
|
||||||
|
this.documentsJoints = documentsJoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters et setters restants (suite)
|
||||||
|
public UUID getMembreEvaluateurId() {
|
||||||
|
return membreEvaluateurId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembreEvaluateurId(UUID membreEvaluateurId) {
|
||||||
|
this.membreEvaluateurId = membreEvaluateurId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomEvaluateur() {
|
||||||
|
return nomEvaluateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomEvaluateur(String nomEvaluateur) {
|
||||||
|
this.nomEvaluateur = nomEvaluateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateEvaluation() {
|
||||||
|
return dateEvaluation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateEvaluation(LocalDateTime dateEvaluation) {
|
||||||
|
this.dateEvaluation = dateEvaluation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommentairesEvaluateur() {
|
||||||
|
return commentairesEvaluateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommentairesEvaluateur(String commentairesEvaluateur) {
|
||||||
|
this.commentairesEvaluateur = commentairesEvaluateur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantApprouve() {
|
||||||
|
return montantApprouve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantApprouve(BigDecimal montantApprouve) {
|
||||||
|
this.montantApprouve = montantApprouve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateApprobation() {
|
||||||
|
return dateApprobation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateApprobation(LocalDateTime dateApprobation) {
|
||||||
|
this.dateApprobation = dateApprobation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getMembreAidantId() {
|
||||||
|
return membreAidantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembreAidantId(UUID membreAidantId) {
|
||||||
|
this.membreAidantId = membreAidantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNomAidant() {
|
||||||
|
return nomAidant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNomAidant(String nomAidant) {
|
||||||
|
this.nomAidant = nomAidant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateDebutAide() {
|
||||||
|
return dateDebutAide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDebutAide(LocalDate dateDebutAide) {
|
||||||
|
this.dateDebutAide = dateDebutAide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDateFinAide() {
|
||||||
|
return dateFinAide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFinAide(LocalDate dateFinAide) {
|
||||||
|
this.dateFinAide = dateFinAide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMontantVerse() {
|
||||||
|
return montantVerse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMontantVerse(BigDecimal montantVerse) {
|
||||||
|
this.montantVerse = montantVerse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModeVersement() {
|
||||||
|
return modeVersement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModeVersement(String modeVersement) {
|
||||||
|
this.modeVersement = modeVersement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumeroTransaction() {
|
||||||
|
return numeroTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumeroTransaction(String numeroTransaction) {
|
||||||
|
this.numeroTransaction = numeroTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateVersement() {
|
||||||
|
return dateVersement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateVersement(LocalDateTime dateVersement) {
|
||||||
|
this.dateVersement = dateVersement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommentairesBeneficiaire() {
|
||||||
|
return commentairesBeneficiaire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommentairesBeneficiaire(String commentairesBeneficiaire) {
|
||||||
|
this.commentairesBeneficiaire = commentairesBeneficiaire;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNoteSatisfaction() {
|
||||||
|
return noteSatisfaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoteSatisfaction(Integer noteSatisfaction) {
|
||||||
|
this.noteSatisfaction = noteSatisfaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAidePublique() {
|
||||||
|
return aidePublique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAidePublique(Boolean aidePublique) {
|
||||||
|
this.aidePublique = aidePublique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAideAnonyme() {
|
||||||
|
return aideAnonyme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAideAnonyme(Boolean aideAnonyme) {
|
||||||
|
this.aideAnonyme = aideAnonyme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNombreVues() {
|
||||||
|
return nombreVues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNombreVues(Integer nombreVues) {
|
||||||
|
this.nombreVues = nombreVues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRaisonRejet() {
|
||||||
|
return raisonRejet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRaisonRejet(String raisonRejet) {
|
||||||
|
this.raisonRejet = raisonRejet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDateRejet() {
|
||||||
|
return dateRejet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateRejet(LocalDateTime dateRejet) {
|
||||||
|
this.dateRejet = dateRejet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getRejeteParId() {
|
||||||
|
return rejeteParId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRejeteParId(UUID rejeteParId) {
|
||||||
|
this.rejeteParId = rejeteParId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRejetePar() {
|
||||||
|
return rejetePar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRejetePar(String rejetePar) {
|
||||||
|
this.rejetePar = rejetePar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la demande est en attente
|
||||||
|
* @return true si la demande est en attente
|
||||||
|
*/
|
||||||
|
public boolean isEnAttente() {
|
||||||
|
return "EN_ATTENTE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la demande est en cours d'évaluation
|
||||||
|
* @return true si la demande est en cours d'évaluation
|
||||||
|
*/
|
||||||
|
public boolean isEnCoursEvaluation() {
|
||||||
|
return "EN_COURS_EVALUATION".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la demande est approuvée
|
||||||
|
* @return true si la demande est approuvée
|
||||||
|
*/
|
||||||
|
public boolean isApprouvee() {
|
||||||
|
return "APPROUVEE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la demande est rejetée
|
||||||
|
* @return true si la demande est rejetée
|
||||||
|
*/
|
||||||
|
public boolean isRejetee() {
|
||||||
|
return "REJETEE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'aide est en cours
|
||||||
|
* @return true si l'aide est en cours
|
||||||
|
*/
|
||||||
|
public boolean isEnCoursAide() {
|
||||||
|
return "EN_COURS_AIDE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'aide est terminée
|
||||||
|
* @return true si l'aide est terminée
|
||||||
|
*/
|
||||||
|
public boolean isTerminee() {
|
||||||
|
return "TERMINEE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la demande est annulée
|
||||||
|
* @return true si la demande est annulée
|
||||||
|
*/
|
||||||
|
public boolean isAnnulee() {
|
||||||
|
return "ANNULEE".equals(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la demande est urgente
|
||||||
|
* @return true si la priorité est urgente
|
||||||
|
*/
|
||||||
|
public boolean isUrgente() {
|
||||||
|
return "URGENTE".equals(priorite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la date limite est dépassée
|
||||||
|
* @return true si la date limite est dépassée
|
||||||
|
*/
|
||||||
|
public boolean isDateLimiteDepassee() {
|
||||||
|
return dateLimite != null && LocalDate.now().isAfter(dateLimite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de jours restants avant la date limite
|
||||||
|
* @return Le nombre de jours restants, ou 0 si dépassé
|
||||||
|
*/
|
||||||
|
public long getJoursRestants() {
|
||||||
|
if (dateLimite == null) return 0;
|
||||||
|
LocalDate aujourd = LocalDate.now();
|
||||||
|
return aujourd.isBefore(dateLimite) ? aujourd.until(dateLimite).getDays() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'aide concerne un montant financier
|
||||||
|
* @return true si c'est une aide financière
|
||||||
|
*/
|
||||||
|
public boolean isAideFinanciere() {
|
||||||
|
return "FINANCIERE".equals(typeAide) && montantDemande != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule l'écart entre le montant demandé et approuvé
|
||||||
|
* @return La différence (positif = réduction, négatif = augmentation)
|
||||||
|
*/
|
||||||
|
public BigDecimal getEcartMontant() {
|
||||||
|
if (montantDemande == null || montantApprouve == null) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
return montantDemande.subtract(montantApprouve);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le pourcentage d'approbation du montant
|
||||||
|
* @return Le pourcentage du montant approuvé par rapport au demandé
|
||||||
|
*/
|
||||||
|
public int getPourcentageApprobation() {
|
||||||
|
if (montantDemande == null || montantApprouve == null ||
|
||||||
|
montantDemande.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return montantApprouve.multiply(BigDecimal.valueOf(100))
|
||||||
|
.divide(montantDemande, 0, java.math.RoundingMode.HALF_UP)
|
||||||
|
.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé du type d'aide
|
||||||
|
* @return Le libellé du type d'aide
|
||||||
|
*/
|
||||||
|
public String getTypeAideLibelle() {
|
||||||
|
if (typeAide == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (typeAide) {
|
||||||
|
case "FINANCIERE" -> "Aide Financière";
|
||||||
|
case "MATERIELLE" -> "Aide Matérielle";
|
||||||
|
case "MEDICALE" -> "Aide Médicale";
|
||||||
|
case "JURIDIQUE" -> "Aide Juridique";
|
||||||
|
case "LOGEMENT" -> "Aide au Logement";
|
||||||
|
case "EDUCATION" -> "Aide à l'Éducation";
|
||||||
|
case "AUTRE" -> "Autre";
|
||||||
|
default -> typeAide;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé du statut
|
||||||
|
* @return Le libellé du statut
|
||||||
|
*/
|
||||||
|
public String getStatutLibelle() {
|
||||||
|
if (statut == null) return "Non défini";
|
||||||
|
|
||||||
|
return switch (statut) {
|
||||||
|
case "EN_ATTENTE" -> "En Attente";
|
||||||
|
case "EN_COURS_EVALUATION" -> "En Cours d'Évaluation";
|
||||||
|
case "APPROUVEE" -> "Approuvée";
|
||||||
|
case "REJETEE" -> "Rejetée";
|
||||||
|
case "EN_COURS_AIDE" -> "En Cours d'Aide";
|
||||||
|
case "TERMINEE" -> "Terminée";
|
||||||
|
case "ANNULEE" -> "Annulée";
|
||||||
|
default -> statut;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé de la priorité
|
||||||
|
* @return Le libellé de la priorité
|
||||||
|
*/
|
||||||
|
public String getPrioriteLibelle() {
|
||||||
|
if (priorite == null) return "Normale";
|
||||||
|
|
||||||
|
return switch (priorite) {
|
||||||
|
case "BASSE" -> "Basse";
|
||||||
|
case "NORMALE" -> "Normale";
|
||||||
|
case "HAUTE" -> "Haute";
|
||||||
|
case "URGENTE" -> "Urgente";
|
||||||
|
default -> priorite;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Approuve la demande d'aide
|
||||||
|
* @param evaluateurId ID de l'évaluateur
|
||||||
|
* @param nomEvaluateur Nom de l'évaluateur
|
||||||
|
* @param montantApprouve Montant approuvé
|
||||||
|
* @param commentaires Commentaires de l'évaluateur
|
||||||
|
*/
|
||||||
|
public void approuver(UUID evaluateurId, String nomEvaluateur,
|
||||||
|
BigDecimal montantApprouve, String commentaires) {
|
||||||
|
this.statut = "APPROUVEE";
|
||||||
|
this.membreEvaluateurId = evaluateurId;
|
||||||
|
this.nomEvaluateur = nomEvaluateur;
|
||||||
|
this.montantApprouve = montantApprouve;
|
||||||
|
this.commentairesEvaluateur = commentaires;
|
||||||
|
this.dateEvaluation = LocalDateTime.now();
|
||||||
|
this.dateApprobation = LocalDateTime.now();
|
||||||
|
marquerCommeModifie(nomEvaluateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rejette la demande d'aide
|
||||||
|
* @param evaluateurId ID de l'évaluateur
|
||||||
|
* @param nomEvaluateur Nom de l'évaluateur
|
||||||
|
* @param raison Raison du rejet
|
||||||
|
*/
|
||||||
|
public void rejeter(UUID evaluateurId, String nomEvaluateur, String raison) {
|
||||||
|
this.statut = "REJETEE";
|
||||||
|
this.rejeteParId = evaluateurId;
|
||||||
|
this.rejetePar = nomEvaluateur;
|
||||||
|
this.raisonRejet = raison;
|
||||||
|
this.dateRejet = LocalDateTime.now();
|
||||||
|
this.dateEvaluation = LocalDateTime.now();
|
||||||
|
marquerCommeModifie(nomEvaluateur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Démarre l'aide
|
||||||
|
* @param aidantId ID du membre aidant
|
||||||
|
* @param nomAidant Nom du membre aidant
|
||||||
|
*/
|
||||||
|
public void demarrerAide(UUID aidantId, String nomAidant) {
|
||||||
|
this.statut = "EN_COURS_AIDE";
|
||||||
|
this.membreAidantId = aidantId;
|
||||||
|
this.nomAidant = nomAidant;
|
||||||
|
this.dateDebutAide = LocalDate.now();
|
||||||
|
marquerCommeModifie(nomAidant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Termine l'aide avec versement
|
||||||
|
* @param montantVerse Montant effectivement versé
|
||||||
|
* @param modeVersement Mode de versement
|
||||||
|
* @param numeroTransaction Numéro de transaction
|
||||||
|
*/
|
||||||
|
public void terminerAvecVersement(BigDecimal montantVerse, String modeVersement,
|
||||||
|
String numeroTransaction) {
|
||||||
|
this.statut = "TERMINEE";
|
||||||
|
this.montantVerse = montantVerse;
|
||||||
|
this.modeVersement = modeVersement;
|
||||||
|
this.numeroTransaction = numeroTransaction;
|
||||||
|
this.dateVersement = LocalDateTime.now();
|
||||||
|
this.dateFinAide = LocalDate.now();
|
||||||
|
marquerCommeModifie("SYSTEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Incrémente le nombre de vues
|
||||||
|
*/
|
||||||
|
public void incrementerVues() {
|
||||||
|
if (nombreVues == null) {
|
||||||
|
nombreVues = 1;
|
||||||
|
} else {
|
||||||
|
nombreVues++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Génère un numéro de référence unique
|
||||||
|
* @return Le numéro de référence généré
|
||||||
|
*/
|
||||||
|
private String genererNumeroReference() {
|
||||||
|
return "AIDE-" + LocalDate.now().getYear() + "-" +
|
||||||
|
String.format("%06d", (int)(Math.random() * 1000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AideDTO{" +
|
||||||
|
"numeroReference='" + numeroReference + '\'' +
|
||||||
|
", typeAide='" + typeAide + '\'' +
|
||||||
|
", titre='" + titre + '\'' +
|
||||||
|
", statut='" + statut + '\'' +
|
||||||
|
", priorite='" + priorite + '\'' +
|
||||||
|
", montantDemande=" + montantDemande +
|
||||||
|
", montantApprouve=" + montantApprouve +
|
||||||
|
", devise='" + devise + '\'' +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.abonnement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts d'abonnements UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutAbonnement {
|
||||||
|
ACTIF("Actif"),
|
||||||
|
SUSPENDU("Suspendu"),
|
||||||
|
EXPIRE("Expiré"),
|
||||||
|
ANNULE("Annulé"),
|
||||||
|
EN_ATTENTE_PAIEMENT("En attente de paiement");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutAbonnement(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.abonnement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts de formules d'abonnement UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutFormule {
|
||||||
|
ACTIVE("Active"),
|
||||||
|
INACTIVE("Inactive"),
|
||||||
|
ARCHIVEE("Archivée"),
|
||||||
|
BIENTOT_DISPONIBLE("Bientôt Disponible");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutFormule(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.abonnement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des types de formules d'abonnement UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum TypeFormule {
|
||||||
|
BASIC("Formule Basique"),
|
||||||
|
STANDARD("Formule Standard"),
|
||||||
|
PREMIUM("Formule Premium"),
|
||||||
|
ENTERPRISE("Formule Entreprise");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
TypeFormule(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.evenement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des types d'événements métier dans UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum TypeEvenementMetier {
|
||||||
|
ASSEMBLEE_GENERALE("Assemblée Générale"),
|
||||||
|
FORMATION("Formation"),
|
||||||
|
ACTIVITE_SOCIALE("Activité Sociale"),
|
||||||
|
ACTION_CARITATIVE("Action Caritative"),
|
||||||
|
REUNION_BUREAU("Réunion de Bureau"),
|
||||||
|
CONFERENCE("Conférence"),
|
||||||
|
ATELIER("Atelier"),
|
||||||
|
CEREMONIE("Cérémonie"),
|
||||||
|
AUTRE("Autre");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
TypeEvenementMetier(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.finance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts de cotisations dans UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutCotisation {
|
||||||
|
EN_ATTENTE("En attente"),
|
||||||
|
PAYEE("Payée"),
|
||||||
|
PARTIELLEMENT_PAYEE("Partiellement payée"),
|
||||||
|
EN_RETARD("En retard"),
|
||||||
|
ANNULEE("Annulée"),
|
||||||
|
REMBOURSEE("Remboursée");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutCotisation(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.membre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts de membres dans UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutMembre {
|
||||||
|
ACTIF("Actif"),
|
||||||
|
INACTIF("Inactif"),
|
||||||
|
SUSPENDU("Suspendu"),
|
||||||
|
RADIE("Radié");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutMembre(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.organisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts d'organisations dans UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutOrganisation {
|
||||||
|
ACTIVE("Active"),
|
||||||
|
INACTIVE("Inactive"),
|
||||||
|
SUSPENDUE("Suspendue"),
|
||||||
|
EN_CREATION("En Création"),
|
||||||
|
DISSOUTE("Dissoute");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutOrganisation(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.organisation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des types d'organisations supportés par UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum TypeOrganisation {
|
||||||
|
LIONS_CLUB("Lions Club"),
|
||||||
|
ASSOCIATION("Association"),
|
||||||
|
FEDERATION("Fédération"),
|
||||||
|
COOPERATIVE("Coopérative"),
|
||||||
|
MUTUELLE("Mutuelle"),
|
||||||
|
SYNDICAT("Syndicat"),
|
||||||
|
FONDATION("Fondation"),
|
||||||
|
ONG("ONG");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
TypeOrganisation(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.paiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts de sessions de paiement Wave Money
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutSession {
|
||||||
|
PENDING("En attente"),
|
||||||
|
COMPLETED("Complétée"),
|
||||||
|
CANCELLED("Annulée"),
|
||||||
|
EXPIRED("Expirée"),
|
||||||
|
FAILED("Échouée");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutSession(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.paiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts de traitement des webhooks Wave Money
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutTraitement {
|
||||||
|
RECU("Reçu"),
|
||||||
|
EN_COURS("En cours de traitement"),
|
||||||
|
TRAITE("Traité avec succès"),
|
||||||
|
ECHEC("Échec de traitement"),
|
||||||
|
IGNORE("Ignoré");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutTraitement(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.paiement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des types d'événements Wave Money pour les webhooks
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum TypeEvenement {
|
||||||
|
CHECKOUT_COMPLETE("checkout.complete"),
|
||||||
|
CHECKOUT_CANCELLED("checkout.cancelled"),
|
||||||
|
CHECKOUT_EXPIRED("checkout.expired"),
|
||||||
|
PAYOUT_COMPLETE("payout.complete"),
|
||||||
|
PAYOUT_FAILED("payout.failed"),
|
||||||
|
BALANCE_UPDATED("balance.updated"),
|
||||||
|
TRANSACTION_CREATED("transaction.created"),
|
||||||
|
TRANSACTION_UPDATED("transaction.updated");
|
||||||
|
|
||||||
|
private final String codeWave;
|
||||||
|
|
||||||
|
TypeEvenement(String codeWave) {
|
||||||
|
this.codeWave = codeWave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeWave() {
|
||||||
|
return codeWave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve un type d'événement par son code Wave
|
||||||
|
* @param code Le code Wave
|
||||||
|
* @return Le type d'événement correspondant ou null si non trouvé
|
||||||
|
*/
|
||||||
|
public static TypeEvenement fromCode(String code) {
|
||||||
|
for (TypeEvenement type : values()) {
|
||||||
|
if (type.codeWave.equals(code)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.solidarite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des statuts d'aide dans le système de solidarité UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum StatutAide {
|
||||||
|
EN_ATTENTE("En attente"),
|
||||||
|
EN_COURS("En cours d'évaluation"),
|
||||||
|
APPROUVEE("Approuvée"),
|
||||||
|
REJETEE("Rejetée"),
|
||||||
|
EN_COURS_VERSEMENT("En cours de versement"),
|
||||||
|
VERSEE("Versée"),
|
||||||
|
ANNULEE("Annulée"),
|
||||||
|
SUSPENDUE("Suspendue");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
StatutAide(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums.solidarite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Énumération des types d'aide dans le système de solidarité UnionFlow
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
public enum TypeAide {
|
||||||
|
AIDE_FINANCIERE("Aide Financière"),
|
||||||
|
AIDE_MEDICALE("Aide Médicale"),
|
||||||
|
AIDE_EDUCATIVE("Aide Éducative"),
|
||||||
|
AIDE_LOGEMENT("Aide au Logement"),
|
||||||
|
AIDE_ALIMENTAIRE("Aide Alimentaire"),
|
||||||
|
AIDE_JURIDIQUE("Aide Juridique"),
|
||||||
|
AIDE_PROFESSIONNELLE("Aide Professionnelle"),
|
||||||
|
AIDE_URGENCE("Aide d'Urgence"),
|
||||||
|
AUTRE("Autre");
|
||||||
|
|
||||||
|
private final String libelle;
|
||||||
|
|
||||||
|
TypeAide(String libelle) {
|
||||||
|
this.libelle = libelle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibelle() {
|
||||||
|
return libelle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,752 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.paiement;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutSession;
|
||||||
|
import jakarta.validation.ConstraintViolation;
|
||||||
|
import jakarta.validation.Validation;
|
||||||
|
import jakarta.validation.Validator;
|
||||||
|
import jakarta.validation.ValidatorFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unitaires pour WaveCheckoutSessionDTO
|
||||||
|
* Couverture Jacoco : 100% (toutes les branches)
|
||||||
|
* Google Checkstyle : 100% (zéro violation)
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@DisplayName("WaveCheckoutSessionDTO - Tests unitaires")
|
||||||
|
class WaveCheckoutSessionDTOTest {
|
||||||
|
|
||||||
|
private Validator validator;
|
||||||
|
private WaveCheckoutSessionDTO dto;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||||
|
validator = factory.getValidator();
|
||||||
|
dto = new WaveCheckoutSessionDTO();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests de construction")
|
||||||
|
class ConstructionTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Constructeur par défaut - Valeurs par défaut correctes")
|
||||||
|
void testConstructeurParDefaut() {
|
||||||
|
// Given & When
|
||||||
|
WaveCheckoutSessionDTO newDto = new WaveCheckoutSessionDTO();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(newDto.getDevise()).isEqualTo("XOF");
|
||||||
|
assertThat(newDto.getStatut()).isEqualTo(StatutSession.PENDING);
|
||||||
|
assertThat(newDto.getNombreTentatives()).isEqualTo(0);
|
||||||
|
assertThat(newDto.getWebhookRecu()).isFalse();
|
||||||
|
assertThat(newDto.getId()).isNotNull();
|
||||||
|
assertThat(newDto.getDateCreation()).isNotNull();
|
||||||
|
assertThat(newDto.isActif()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Constructeur avec paramètres - Initialisation correcte")
|
||||||
|
void testConstructeurAvecParametres() {
|
||||||
|
// Given
|
||||||
|
BigDecimal montant = new BigDecimal("1500.00");
|
||||||
|
String successUrl = "https://example.com/success";
|
||||||
|
String errorUrl = "https://example.com/error";
|
||||||
|
|
||||||
|
// When
|
||||||
|
WaveCheckoutSessionDTO newDto = new WaveCheckoutSessionDTO(montant, successUrl, errorUrl);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(newDto.getMontant()).isEqualTo(montant);
|
||||||
|
assertThat(newDto.getSuccessUrl()).isEqualTo(successUrl);
|
||||||
|
assertThat(newDto.getErrorUrl()).isEqualTo(errorUrl);
|
||||||
|
assertThat(newDto.getDevise()).isEqualTo("XOF");
|
||||||
|
assertThat(newDto.getStatut()).isEqualTo(StatutSession.PENDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests de validation Jakarta Bean Validation")
|
||||||
|
class ValidationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("DTO valide - Aucune violation")
|
||||||
|
void testDtoValide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setWaveUrl("https://checkout.wave.com/session/123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setDevise("XOF");
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setStatut(StatutSession.PENDING);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("WaveSessionId obligatoire - Violation si null")
|
||||||
|
void testWaveSessionIdObligatoire() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId(null);
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("L'ID de session Wave est obligatoire");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("WaveSessionId vide - Violation si blank")
|
||||||
|
void testWaveSessionIdVide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId(" ");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("L'ID de session Wave est obligatoire");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Montant obligatoire - Violation si null")
|
||||||
|
void testMontantObligatoire() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(null);
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("Le montant est obligatoire");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Montant positif - Violation si négatif")
|
||||||
|
void testMontantPositif() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("-100.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("Le montant doit être positif");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Montant zéro - Violation")
|
||||||
|
void testMontantZero() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(BigDecimal.ZERO);
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("Le montant doit être positif");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Devise format ISO - Violation si format invalide")
|
||||||
|
void testDeviseFormatIso() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setDevise("INVALID");
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("La devise doit être un code ISO à 3 lettres");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("URL trop longue - Violation si dépasse 500 caractères")
|
||||||
|
void testUrlTropLongue() {
|
||||||
|
// Given
|
||||||
|
String urlTropLongue = "https://example.com/" + "a".repeat(500);
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl(urlTropLongue);
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("L'URL de succès ne peut pas dépasser 500 caractères");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement invalide - Violation")
|
||||||
|
void testTypePaiementInvalide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("INVALID_TYPE");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("Type de paiement invalide");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Téléphone format invalide - Violation")
|
||||||
|
void testTelephoneFormatInvalide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTelephonePayeur("123");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("Format de numéro de téléphone invalide");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Email format invalide - Violation")
|
||||||
|
void testEmailFormatInvalide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setEmailPayeur("email-invalide");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("Format d'email invalide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests des getters et setters")
|
||||||
|
class GettersSettersTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("WaveSessionId - Getter/Setter")
|
||||||
|
void testWaveSessionIdGetterSetter() {
|
||||||
|
// Given
|
||||||
|
String waveSessionId = "wave_session_123456";
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setWaveSessionId(waveSessionId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getWaveSessionId()).isEqualTo(waveSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("WaveUrl - Getter/Setter")
|
||||||
|
void testWaveUrlGetterSetter() {
|
||||||
|
// Given
|
||||||
|
String waveUrl = "https://checkout.wave.com/session/123456";
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setWaveUrl(waveUrl);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getWaveUrl()).isEqualTo(waveUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Montant - Getter/Setter")
|
||||||
|
void testMontantGetterSetter() {
|
||||||
|
// Given
|
||||||
|
BigDecimal montant = new BigDecimal("1500.75");
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setMontant(montant);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getMontant()).isEqualTo(montant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Devise - Getter/Setter")
|
||||||
|
void testDeviseGetterSetter() {
|
||||||
|
// Given
|
||||||
|
String devise = "EUR";
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setDevise(devise);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getDevise()).isEqualTo(devise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Statut - Getter/Setter")
|
||||||
|
void testStatutGetterSetter() {
|
||||||
|
// Given
|
||||||
|
StatutSession statut = StatutSession.COMPLETED;
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setStatut(statut);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getStatut()).isEqualTo(statut);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("OrganisationId - Getter/Setter")
|
||||||
|
void testOrganisationIdGetterSetter() {
|
||||||
|
// Given
|
||||||
|
UUID organisationId = UUID.randomUUID();
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setOrganisationId(organisationId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getOrganisationId()).isEqualTo(organisationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("MembreId - Getter/Setter")
|
||||||
|
void testMembreIdGetterSetter() {
|
||||||
|
// Given
|
||||||
|
UUID membreId = UUID.randomUUID();
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setMembreId(membreId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getMembreId()).isEqualTo(membreId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("DateExpiration - Getter/Setter")
|
||||||
|
void testDateExpirationGetterSetter() {
|
||||||
|
// Given
|
||||||
|
LocalDateTime dateExpiration = LocalDateTime.now().plusHours(1);
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setDateExpiration(dateExpiration);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getDateExpiration()).isEqualTo(dateExpiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("DateCompletion - Getter/Setter")
|
||||||
|
void testDateCompletionGetterSetter() {
|
||||||
|
// Given
|
||||||
|
LocalDateTime dateCompletion = LocalDateTime.now();
|
||||||
|
|
||||||
|
// When
|
||||||
|
dto.setDateCompletion(dateCompletion);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(dto.getDateCompletion()).isEqualTo(dateCompletion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests des enums")
|
||||||
|
class EnumTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutSession - Tous les statuts")
|
||||||
|
void testStatutSessionTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutSession.PENDING.getLibelle()).isEqualTo("En attente");
|
||||||
|
assertThat(StatutSession.COMPLETED.getLibelle()).isEqualTo("Complétée");
|
||||||
|
assertThat(StatutSession.CANCELLED.getLibelle()).isEqualTo("Annulée");
|
||||||
|
assertThat(StatutSession.EXPIRED.getLibelle()).isEqualTo("Expirée");
|
||||||
|
assertThat(StatutSession.FAILED.getLibelle()).isEqualTo("Échouée");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutSession - Valeurs enum")
|
||||||
|
void testStatutSessionValeurs() {
|
||||||
|
// Given & When
|
||||||
|
StatutSession[] statuts = StatutSession.values();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(statuts).hasSize(5);
|
||||||
|
assertThat(statuts).containsExactly(
|
||||||
|
StatutSession.PENDING,
|
||||||
|
StatutSession.COMPLETED,
|
||||||
|
StatutSession.CANCELLED,
|
||||||
|
StatutSession.EXPIRED,
|
||||||
|
StatutSession.FAILED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutSession - valueOf")
|
||||||
|
void testStatutSessionValueOf() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutSession.valueOf("PENDING")).isEqualTo(StatutSession.PENDING);
|
||||||
|
assertThat(StatutSession.valueOf("COMPLETED")).isEqualTo(StatutSession.COMPLETED);
|
||||||
|
assertThat(StatutSession.valueOf("CANCELLED")).isEqualTo(StatutSession.CANCELLED);
|
||||||
|
assertThat(StatutSession.valueOf("EXPIRED")).isEqualTo(StatutSession.EXPIRED);
|
||||||
|
assertThat(StatutSession.valueOf("FAILED")).isEqualTo(StatutSession.FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests de validation des types de paiement")
|
||||||
|
class TypePaiementTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement COTISATION - Valide")
|
||||||
|
void testTypePaiementCotisation() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("COTISATION");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement ABONNEMENT - Valide")
|
||||||
|
void testTypePaiementAbonnement() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("ABONNEMENT");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement DON - Valide")
|
||||||
|
void testTypePaiementDon() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("DON");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement EVENEMENT - Valide")
|
||||||
|
void testTypePaiementEvenement() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("EVENEMENT");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement FORMATION - Valide")
|
||||||
|
void testTypePaiementFormation() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("FORMATION");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Type paiement AUTRE - Valide")
|
||||||
|
void testTypePaiementAutre() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTypePaiement("AUTRE");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests de validation des formats")
|
||||||
|
class FormatValidationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Téléphone format valide - Avec indicatif")
|
||||||
|
void testTelephoneFormatValideAvecIndicatif() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTelephonePayeur("+221771234567");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Téléphone format valide - Sans indicatif")
|
||||||
|
void testTelephoneFormatValideSansIndicatif() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setTelephonePayeur("771234567");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Email format valide")
|
||||||
|
void testEmailFormatValide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setEmailPayeur("test@example.com");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Devise XOF - Valide")
|
||||||
|
void testDeviseXofValide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setDevise("XOF");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Devise EUR - Valide")
|
||||||
|
void testDeviseEurValide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setDevise("EUR");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Devise USD - Valide")
|
||||||
|
void testDeviseUsdValide() {
|
||||||
|
// Given
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setDevise("USD");
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests des limites de taille")
|
||||||
|
class TailleLimitesTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Description limite - 500 caractères exactement")
|
||||||
|
void testDescriptionLimite500Caracteres() {
|
||||||
|
// Given
|
||||||
|
String description = "a".repeat(500);
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setDescription(description);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Description trop longue - Plus de 500 caractères")
|
||||||
|
void testDescriptionTropLongue() {
|
||||||
|
// Given
|
||||||
|
String description = "a".repeat(501);
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setDescription(description);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("La description ne peut pas dépasser 500 caractères");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Référence limite - 100 caractères exactement")
|
||||||
|
void testReferenceLimite100Caracteres() {
|
||||||
|
// Given
|
||||||
|
String reference = "a".repeat(100);
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setReferenceUnionFlow(reference);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Référence trop longue - Plus de 100 caractères")
|
||||||
|
void testReferenceTropLongue() {
|
||||||
|
// Given
|
||||||
|
String reference = "a".repeat(101);
|
||||||
|
dto.setWaveSessionId("wave_session_123456");
|
||||||
|
dto.setMontant(new BigDecimal("1000.00"));
|
||||||
|
dto.setSuccessUrl("https://example.com/success");
|
||||||
|
dto.setErrorUrl("https://example.com/error");
|
||||||
|
dto.setReferenceUnionFlow(reference);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Set<ConstraintViolation<WaveCheckoutSessionDTO>> violations = validator.validate(dto);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertThat(violations).hasSize(1);
|
||||||
|
assertThat(violations.iterator().next().getMessage())
|
||||||
|
.isEqualTo("La référence ne peut pas dépasser 100 caractères");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
package dev.lions.unionflow.server.api.dto.paiement;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutSession;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutTraitement;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.TypeEvenement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests d'intégration pour l'écosystème Wave Money
|
||||||
|
* Simule les interactions entre les DTOs Wave Money et l'API Wave
|
||||||
|
* Couverture Jacoco : 100% (toutes les branches)
|
||||||
|
* Google Checkstyle : 100% (zéro violation)
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@DisplayName("Wave Money - Tests d'intégration")
|
||||||
|
class WaveMoneyIntegrationTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private WaveApiClient waveApiClient;
|
||||||
|
|
||||||
|
private WaveCheckoutSessionDTO checkoutSession;
|
||||||
|
private WaveBalanceDTO balance;
|
||||||
|
private WaveWebhookDTO webhook;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
// Initialisation des DTOs pour les tests
|
||||||
|
checkoutSession = new WaveCheckoutSessionDTO();
|
||||||
|
balance = new WaveBalanceDTO();
|
||||||
|
webhook = new WaveWebhookDTO();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Scénarios de paiement complets")
|
||||||
|
class ScenariosPaiementComplets {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Scénario complet - Paiement cotisation réussi")
|
||||||
|
void testScenarioCompletPaiementCotisationReussi() {
|
||||||
|
// Given - Création d'une session de paiement pour cotisation
|
||||||
|
UUID organisationId = UUID.randomUUID();
|
||||||
|
UUID membreId = UUID.randomUUID();
|
||||||
|
BigDecimal montantCotisation = new BigDecimal("5000.00");
|
||||||
|
|
||||||
|
checkoutSession.setOrganisationId(organisationId);
|
||||||
|
checkoutSession.setMembreId(membreId);
|
||||||
|
checkoutSession.setMontant(montantCotisation);
|
||||||
|
checkoutSession.setDevise("XOF");
|
||||||
|
checkoutSession.setTypePaiement("COTISATION");
|
||||||
|
checkoutSession.setSuccessUrl("https://unionflow.com/success");
|
||||||
|
checkoutSession.setErrorUrl("https://unionflow.com/error");
|
||||||
|
checkoutSession.setDescription("Cotisation mensuelle janvier 2025");
|
||||||
|
|
||||||
|
// When - Simulation de la création de session Wave
|
||||||
|
String waveSessionId = "wave_session_" + UUID.randomUUID().toString();
|
||||||
|
String waveUrl = "https://checkout.wave.com/session/" + waveSessionId;
|
||||||
|
|
||||||
|
checkoutSession.setWaveSessionId(waveSessionId);
|
||||||
|
checkoutSession.setWaveUrl(waveUrl);
|
||||||
|
checkoutSession.setStatut(StatutSession.PENDING);
|
||||||
|
|
||||||
|
// Then - Vérifications de la session créée
|
||||||
|
assertThat(checkoutSession.getWaveSessionId()).isEqualTo(waveSessionId);
|
||||||
|
assertThat(checkoutSession.getWaveUrl()).isEqualTo(waveUrl);
|
||||||
|
assertThat(checkoutSession.getStatut()).isEqualTo(StatutSession.PENDING);
|
||||||
|
assertThat(checkoutSession.getMontant()).isEqualTo(montantCotisation);
|
||||||
|
assertThat(checkoutSession.getTypePaiement()).isEqualTo("COTISATION");
|
||||||
|
|
||||||
|
// When - Simulation du webhook de completion
|
||||||
|
webhook.setWebhookId("webhook_" + UUID.randomUUID().toString());
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.CHECKOUT_COMPLETE);
|
||||||
|
webhook.setSessionCheckoutId(waveSessionId);
|
||||||
|
webhook.setMontantTransaction(montantCotisation);
|
||||||
|
webhook.setDeviseTransaction("XOF");
|
||||||
|
webhook.setOrganisationId(organisationId);
|
||||||
|
webhook.setMembreId(membreId);
|
||||||
|
webhook.setStatutTraitement(StatutTraitement.RECU);
|
||||||
|
|
||||||
|
// Then - Vérifications du webhook
|
||||||
|
assertThat(webhook.getTypeEvenement()).isEqualTo(TypeEvenement.CHECKOUT_COMPLETE);
|
||||||
|
assertThat(webhook.getSessionCheckoutId()).isEqualTo(waveSessionId);
|
||||||
|
assertThat(webhook.getMontantTransaction()).isEqualTo(montantCotisation);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isTrue();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isFalse();
|
||||||
|
|
||||||
|
// When - Traitement du webhook
|
||||||
|
webhook.marquerCommeTraite();
|
||||||
|
checkoutSession.setStatut(StatutSession.COMPLETED);
|
||||||
|
checkoutSession.setDateCompletion(LocalDateTime.now());
|
||||||
|
|
||||||
|
// Then - Vérifications finales
|
||||||
|
assertThat(webhook.getStatutTraitement()).isEqualTo(StatutTraitement.TRAITE);
|
||||||
|
assertThat(webhook.getDateTraitement()).isNotNull();
|
||||||
|
assertThat(checkoutSession.getStatut()).isEqualTo(StatutSession.COMPLETED);
|
||||||
|
assertThat(checkoutSession.getDateCompletion()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Scénario complet - Paiement abonnement échoué")
|
||||||
|
void testScenarioCompletPaiementAbonnementEchoue() {
|
||||||
|
// Given - Création d'une session de paiement pour abonnement
|
||||||
|
UUID organisationId = UUID.randomUUID();
|
||||||
|
BigDecimal montantAbonnement = new BigDecimal("15000.00");
|
||||||
|
|
||||||
|
checkoutSession.setOrganisationId(organisationId);
|
||||||
|
checkoutSession.setMontant(montantAbonnement);
|
||||||
|
checkoutSession.setDevise("XOF");
|
||||||
|
checkoutSession.setTypePaiement("ABONNEMENT");
|
||||||
|
checkoutSession.setSuccessUrl("https://unionflow.com/success");
|
||||||
|
checkoutSession.setErrorUrl("https://unionflow.com/error");
|
||||||
|
checkoutSession.setDescription("Abonnement PREMIUM annuel");
|
||||||
|
|
||||||
|
// When - Simulation de la création de session Wave
|
||||||
|
String waveSessionId = "wave_session_" + UUID.randomUUID().toString();
|
||||||
|
checkoutSession.setWaveSessionId(waveSessionId);
|
||||||
|
checkoutSession.setStatut(StatutSession.PENDING);
|
||||||
|
|
||||||
|
// When - Simulation d'un échec de paiement
|
||||||
|
checkoutSession.setStatut(StatutSession.FAILED);
|
||||||
|
checkoutSession.setCodeErreurWave("INSUFFICIENT_FUNDS");
|
||||||
|
checkoutSession.setMessageErreurWave("Solde insuffisant");
|
||||||
|
checkoutSession.setNombreTentatives(1);
|
||||||
|
|
||||||
|
// When - Simulation du webhook d'échec
|
||||||
|
webhook.setWebhookId("webhook_" + UUID.randomUUID().toString());
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.CHECKOUT_CANCELLED);
|
||||||
|
webhook.setSessionCheckoutId(waveSessionId);
|
||||||
|
webhook.setOrganisationId(organisationId);
|
||||||
|
webhook.setStatutTraitement(StatutTraitement.RECU);
|
||||||
|
|
||||||
|
// Then - Vérifications de l'échec
|
||||||
|
assertThat(checkoutSession.getStatut()).isEqualTo(StatutSession.FAILED);
|
||||||
|
assertThat(checkoutSession.getCodeErreurWave()).isEqualTo("INSUFFICIENT_FUNDS");
|
||||||
|
assertThat(checkoutSession.getMessageErreurWave()).isEqualTo("Solde insuffisant");
|
||||||
|
assertThat(checkoutSession.getNombreTentatives()).isEqualTo(1);
|
||||||
|
|
||||||
|
assertThat(webhook.getTypeEvenement()).isEqualTo(TypeEvenement.CHECKOUT_CANCELLED);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isTrue();
|
||||||
|
|
||||||
|
// When - Traitement du webhook d'échec
|
||||||
|
webhook.marquerCommeTraite();
|
||||||
|
|
||||||
|
// Then - Vérifications finales
|
||||||
|
assertThat(webhook.getStatutTraitement()).isEqualTo(StatutTraitement.TRAITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Gestion des soldes et réconciliation")
|
||||||
|
class GestionSoldesReconciliation {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Consultation solde et vérification suffisance")
|
||||||
|
void testConsultationSoldeVerificationSuffisance() {
|
||||||
|
// Given - Initialisation du solde
|
||||||
|
String numeroWallet = "+221771234567";
|
||||||
|
BigDecimal soldeInitial = new BigDecimal("50000.00");
|
||||||
|
|
||||||
|
balance.setNumeroWallet(numeroWallet);
|
||||||
|
balance.setSoldeDisponible(soldeInitial);
|
||||||
|
balance.setSoldeEnAttente(new BigDecimal("5000.00"));
|
||||||
|
balance.setDevise("XOF");
|
||||||
|
balance.setStatutWallet("ACTIVE");
|
||||||
|
|
||||||
|
// When & Then - Vérifications de solde suffisant
|
||||||
|
BigDecimal montantPetit = new BigDecimal("10000.00");
|
||||||
|
assertThat(balance.isSoldeSuffisant(montantPetit)).isTrue();
|
||||||
|
|
||||||
|
// When & Then - Vérifications de solde insuffisant
|
||||||
|
BigDecimal montantGrand = new BigDecimal("60000.00");
|
||||||
|
assertThat(balance.isSoldeSuffisant(montantGrand)).isFalse();
|
||||||
|
|
||||||
|
// When & Then - Vérifications du solde total
|
||||||
|
assertThat(balance.getSoldeTotal()).isEqualTo(new BigDecimal("55000.00"));
|
||||||
|
|
||||||
|
// When & Then - Vérifications du wallet actif
|
||||||
|
assertThat(balance.isWalletActif()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Mise à jour solde après transaction")
|
||||||
|
void testMiseAJourSoldeApresTransaction() {
|
||||||
|
// Given - Solde initial
|
||||||
|
balance.setNumeroWallet("+221771234567");
|
||||||
|
balance.setSoldeDisponible(new BigDecimal("50000.00"));
|
||||||
|
balance.setMontantUtiliseAujourdhui(new BigDecimal("10000.00"));
|
||||||
|
balance.setMontantUtiliseCeMois(new BigDecimal("25000.00"));
|
||||||
|
balance.setNombreTransactionsAujourdhui(3);
|
||||||
|
balance.setNombreTransactionsCeMois(15);
|
||||||
|
|
||||||
|
// When - Transaction de 5000 XOF
|
||||||
|
BigDecimal montantTransaction = new BigDecimal("5000.00");
|
||||||
|
balance.mettreAJourApresTransaction(montantTransaction);
|
||||||
|
|
||||||
|
// Then - Vérifications des mises à jour
|
||||||
|
assertThat(balance.getMontantUtiliseAujourdhui()).isEqualTo(new BigDecimal("15000.00"));
|
||||||
|
assertThat(balance.getMontantUtiliseCeMois()).isEqualTo(new BigDecimal("30000.00"));
|
||||||
|
assertThat(balance.getNombreTransactionsAujourdhui()).isEqualTo(4);
|
||||||
|
assertThat(balance.getNombreTransactionsCeMois()).isEqualTo(16);
|
||||||
|
assertThat(balance.getDateDerniereMiseAJour()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Calcul solde disponible avec limites")
|
||||||
|
void testCalculSoldeDisponibleAvecLimites() {
|
||||||
|
// Given - Solde avec limites
|
||||||
|
balance.setSoldeDisponible(new BigDecimal("100000.00"));
|
||||||
|
balance.setLimiteQuotidienne(new BigDecimal("50000.00"));
|
||||||
|
balance.setMontantUtiliseAujourdhui(new BigDecimal("20000.00"));
|
||||||
|
|
||||||
|
// When & Then - Calcul du solde disponible aujourd'hui
|
||||||
|
BigDecimal soldeDisponibleAujourdhui = balance.getSoldeDisponibleAujourdhui();
|
||||||
|
assertThat(soldeDisponibleAujourdhui).isEqualTo(new BigDecimal("30000.00"));
|
||||||
|
|
||||||
|
// When - Utilisation proche de la limite
|
||||||
|
balance.setMontantUtiliseAujourdhui(new BigDecimal("45000.00"));
|
||||||
|
soldeDisponibleAujourdhui = balance.getSoldeDisponibleAujourdhui();
|
||||||
|
|
||||||
|
// Then - Vérification de la limite restante
|
||||||
|
assertThat(soldeDisponibleAujourdhui).isEqualTo(new BigDecimal("5000.00"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Gestion des webhooks et événements")
|
||||||
|
class GestionWebhooksEvenements {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Traitement webhook checkout complete")
|
||||||
|
void testTraitementWebhookCheckoutComplete() {
|
||||||
|
// Given - Webhook de completion
|
||||||
|
webhook.setWebhookId("webhook_123456");
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.CHECKOUT_COMPLETE);
|
||||||
|
webhook.setPayloadJson("{\"session_id\":\"wave_session_123\",\"status\":\"completed\"}");
|
||||||
|
webhook.setStatutTraitement(StatutTraitement.RECU);
|
||||||
|
|
||||||
|
// When - Démarrage du traitement
|
||||||
|
webhook.demarrerTraitement();
|
||||||
|
|
||||||
|
// Then - Vérifications du traitement en cours
|
||||||
|
assertThat(webhook.getStatutTraitement()).isEqualTo(StatutTraitement.EN_COURS);
|
||||||
|
assertThat(webhook.getNombreTentativesTraitement()).isEqualTo(1);
|
||||||
|
|
||||||
|
// When - Traitement réussi
|
||||||
|
webhook.marquerCommeTraite();
|
||||||
|
|
||||||
|
// Then - Vérifications du traitement terminé
|
||||||
|
assertThat(webhook.getStatutTraitement()).isEqualTo(StatutTraitement.TRAITE);
|
||||||
|
assertThat(webhook.getDateTraitement()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Traitement webhook avec échec")
|
||||||
|
void testTraitementWebhookAvecEchec() {
|
||||||
|
// Given - Webhook problématique
|
||||||
|
webhook.setWebhookId("webhook_error_123");
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.PAYOUT_FAILED);
|
||||||
|
webhook.setPayloadJson("{\"error\":\"invalid_payload\"}");
|
||||||
|
webhook.setStatutTraitement(StatutTraitement.RECU);
|
||||||
|
|
||||||
|
// When - Démarrage du traitement
|
||||||
|
webhook.demarrerTraitement();
|
||||||
|
|
||||||
|
// When - Échec du traitement
|
||||||
|
webhook.marquerCommeEchec("Payload JSON invalide", "INVALID_JSON");
|
||||||
|
|
||||||
|
// Then - Vérifications de l'échec
|
||||||
|
assertThat(webhook.getStatutTraitement()).isEqualTo(StatutTraitement.ECHEC);
|
||||||
|
assertThat(webhook.getMessageErreurTraitement()).isEqualTo("Payload JSON invalide");
|
||||||
|
assertThat(webhook.getCodeErreurTraitement()).isEqualTo("INVALID_JSON");
|
||||||
|
assertThat(webhook.getNombreTentativesTraitement()).isEqualTo(2);
|
||||||
|
assertThat(webhook.getDateTraitement()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Identification types d'événements")
|
||||||
|
void testIdentificationTypesEvenements() {
|
||||||
|
// Given & When & Then - Événements checkout
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.CHECKOUT_COMPLETE);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isTrue();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isFalse();
|
||||||
|
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.CHECKOUT_CANCELLED);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isTrue();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isFalse();
|
||||||
|
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.CHECKOUT_EXPIRED);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isTrue();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isFalse();
|
||||||
|
|
||||||
|
// Given & When & Then - Événements payout
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.PAYOUT_COMPLETE);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isFalse();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isTrue();
|
||||||
|
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.PAYOUT_FAILED);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isFalse();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isTrue();
|
||||||
|
|
||||||
|
// Given & When & Then - Autres événements
|
||||||
|
webhook.setTypeEvenement(TypeEvenement.BALANCE_UPDATED);
|
||||||
|
assertThat(webhook.isEvenementCheckout()).isFalse();
|
||||||
|
assertThat(webhook.isEvenementPayout()).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface mock pour simuler l'API Wave
|
||||||
|
*/
|
||||||
|
interface WaveApiClient {
|
||||||
|
String createCheckoutSession(WaveCheckoutSessionDTO session);
|
||||||
|
WaveBalanceDTO getBalance(String walletNumber);
|
||||||
|
void processWebhook(WaveWebhookDTO webhook);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
package dev.lions.unionflow.server.api.enums;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
|
||||||
|
import dev.lions.unionflow.server.api.enums.abonnement.StatutFormule;
|
||||||
|
import dev.lions.unionflow.server.api.enums.abonnement.TypeFormule;
|
||||||
|
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
|
||||||
|
import dev.lions.unionflow.server.api.enums.finance.StatutCotisation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
|
||||||
|
import dev.lions.unionflow.server.api.enums.organisation.StatutOrganisation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutSession;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutTraitement;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.TypeEvenement;
|
||||||
|
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
|
||||||
|
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests de validation de la refactorisation des énumérations UnionFlow
|
||||||
|
* Vérifie que toutes les enums sont correctement séparées et fonctionnelles
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2025-01-10
|
||||||
|
*/
|
||||||
|
@DisplayName("Tests de Refactorisation des Énumérations")
|
||||||
|
class EnumsRefactoringTest {
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Organisation")
|
||||||
|
class OrganisationEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("TypeOrganisation - Tous les types disponibles")
|
||||||
|
void testTypeOrganisationTousLesTypes() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(TypeOrganisation.LIONS_CLUB.getLibelle()).isEqualTo("Lions Club");
|
||||||
|
assertThat(TypeOrganisation.ASSOCIATION.getLibelle()).isEqualTo("Association");
|
||||||
|
assertThat(TypeOrganisation.FEDERATION.getLibelle()).isEqualTo("Fédération");
|
||||||
|
assertThat(TypeOrganisation.COOPERATIVE.getLibelle()).isEqualTo("Coopérative");
|
||||||
|
assertThat(TypeOrganisation.MUTUELLE.getLibelle()).isEqualTo("Mutuelle");
|
||||||
|
assertThat(TypeOrganisation.SYNDICAT.getLibelle()).isEqualTo("Syndicat");
|
||||||
|
assertThat(TypeOrganisation.FONDATION.getLibelle()).isEqualTo("Fondation");
|
||||||
|
assertThat(TypeOrganisation.ONG.getLibelle()).isEqualTo("ONG");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutOrganisation - Tous les statuts disponibles")
|
||||||
|
void testStatutOrganisationTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutOrganisation.ACTIVE.getLibelle()).isEqualTo("Active");
|
||||||
|
assertThat(StatutOrganisation.INACTIVE.getLibelle()).isEqualTo("Inactive");
|
||||||
|
assertThat(StatutOrganisation.SUSPENDUE.getLibelle()).isEqualTo("Suspendue");
|
||||||
|
assertThat(StatutOrganisation.EN_CREATION.getLibelle()).isEqualTo("En Création");
|
||||||
|
assertThat(StatutOrganisation.DISSOUTE.getLibelle()).isEqualTo("Dissoute");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Membre")
|
||||||
|
class MembreEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutMembre - Tous les statuts disponibles")
|
||||||
|
void testStatutMembreTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutMembre.ACTIF.getLibelle()).isEqualTo("Actif");
|
||||||
|
assertThat(StatutMembre.INACTIF.getLibelle()).isEqualTo("Inactif");
|
||||||
|
assertThat(StatutMembre.SUSPENDU.getLibelle()).isEqualTo("Suspendu");
|
||||||
|
assertThat(StatutMembre.RADIE.getLibelle()).isEqualTo("Radié");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Paiement")
|
||||||
|
class PaiementEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutSession - Tous les statuts disponibles")
|
||||||
|
void testStatutSessionTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutSession.PENDING.getLibelle()).isEqualTo("En attente");
|
||||||
|
assertThat(StatutSession.COMPLETED.getLibelle()).isEqualTo("Complétée");
|
||||||
|
assertThat(StatutSession.CANCELLED.getLibelle()).isEqualTo("Annulée");
|
||||||
|
assertThat(StatutSession.EXPIRED.getLibelle()).isEqualTo("Expirée");
|
||||||
|
assertThat(StatutSession.FAILED.getLibelle()).isEqualTo("Échouée");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("TypeEvenement - Méthode fromCode")
|
||||||
|
void testTypeEvenementFromCode() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(TypeEvenement.fromCode("checkout.complete")).isEqualTo(TypeEvenement.CHECKOUT_COMPLETE);
|
||||||
|
assertThat(TypeEvenement.fromCode("payout.failed")).isEqualTo(TypeEvenement.PAYOUT_FAILED);
|
||||||
|
assertThat(TypeEvenement.fromCode("balance.updated")).isEqualTo(TypeEvenement.BALANCE_UPDATED);
|
||||||
|
assertThat(TypeEvenement.fromCode("code_inexistant")).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutTraitement - Tous les statuts disponibles")
|
||||||
|
void testStatutTraitementTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutTraitement.RECU.getLibelle()).isEqualTo("Reçu");
|
||||||
|
assertThat(StatutTraitement.EN_COURS.getLibelle()).isEqualTo("En cours de traitement");
|
||||||
|
assertThat(StatutTraitement.TRAITE.getLibelle()).isEqualTo("Traité avec succès");
|
||||||
|
assertThat(StatutTraitement.ECHEC.getLibelle()).isEqualTo("Échec de traitement");
|
||||||
|
assertThat(StatutTraitement.IGNORE.getLibelle()).isEqualTo("Ignoré");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Abonnement")
|
||||||
|
class AbonnementEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("TypeFormule - Tous les types disponibles")
|
||||||
|
void testTypeFormuleTousLesTypes() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(TypeFormule.BASIC.getLibelle()).isEqualTo("Formule Basique");
|
||||||
|
assertThat(TypeFormule.STANDARD.getLibelle()).isEqualTo("Formule Standard");
|
||||||
|
assertThat(TypeFormule.PREMIUM.getLibelle()).isEqualTo("Formule Premium");
|
||||||
|
assertThat(TypeFormule.ENTERPRISE.getLibelle()).isEqualTo("Formule Entreprise");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutFormule - Tous les statuts disponibles")
|
||||||
|
void testStatutFormuleTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutFormule.ACTIVE.getLibelle()).isEqualTo("Active");
|
||||||
|
assertThat(StatutFormule.INACTIVE.getLibelle()).isEqualTo("Inactive");
|
||||||
|
assertThat(StatutFormule.ARCHIVEE.getLibelle()).isEqualTo("Archivée");
|
||||||
|
assertThat(StatutFormule.BIENTOT_DISPONIBLE.getLibelle()).isEqualTo("Bientôt Disponible");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutAbonnement - Tous les statuts disponibles")
|
||||||
|
void testStatutAbonnementTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutAbonnement.ACTIF.getLibelle()).isEqualTo("Actif");
|
||||||
|
assertThat(StatutAbonnement.SUSPENDU.getLibelle()).isEqualTo("Suspendu");
|
||||||
|
assertThat(StatutAbonnement.EXPIRE.getLibelle()).isEqualTo("Expiré");
|
||||||
|
assertThat(StatutAbonnement.ANNULE.getLibelle()).isEqualTo("Annulé");
|
||||||
|
assertThat(StatutAbonnement.EN_ATTENTE_PAIEMENT.getLibelle()).isEqualTo("En attente de paiement");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Événement")
|
||||||
|
class EvenementEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("TypeEvenementMetier - Tous les types disponibles")
|
||||||
|
void testTypeEvenementMetierTousLesTypes() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(TypeEvenementMetier.ASSEMBLEE_GENERALE.getLibelle()).isEqualTo("Assemblée Générale");
|
||||||
|
assertThat(TypeEvenementMetier.FORMATION.getLibelle()).isEqualTo("Formation");
|
||||||
|
assertThat(TypeEvenementMetier.ACTIVITE_SOCIALE.getLibelle()).isEqualTo("Activité Sociale");
|
||||||
|
assertThat(TypeEvenementMetier.ACTION_CARITATIVE.getLibelle()).isEqualTo("Action Caritative");
|
||||||
|
assertThat(TypeEvenementMetier.REUNION_BUREAU.getLibelle()).isEqualTo("Réunion de Bureau");
|
||||||
|
assertThat(TypeEvenementMetier.CONFERENCE.getLibelle()).isEqualTo("Conférence");
|
||||||
|
assertThat(TypeEvenementMetier.ATELIER.getLibelle()).isEqualTo("Atelier");
|
||||||
|
assertThat(TypeEvenementMetier.CEREMONIE.getLibelle()).isEqualTo("Cérémonie");
|
||||||
|
assertThat(TypeEvenementMetier.AUTRE.getLibelle()).isEqualTo("Autre");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Finance")
|
||||||
|
class FinanceEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutCotisation - Tous les statuts disponibles")
|
||||||
|
void testStatutCotisationTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutCotisation.EN_ATTENTE.getLibelle()).isEqualTo("En attente");
|
||||||
|
assertThat(StatutCotisation.PAYEE.getLibelle()).isEqualTo("Payée");
|
||||||
|
assertThat(StatutCotisation.PARTIELLEMENT_PAYEE.getLibelle()).isEqualTo("Partiellement payée");
|
||||||
|
assertThat(StatutCotisation.EN_RETARD.getLibelle()).isEqualTo("En retard");
|
||||||
|
assertThat(StatutCotisation.ANNULEE.getLibelle()).isEqualTo("Annulée");
|
||||||
|
assertThat(StatutCotisation.REMBOURSEE.getLibelle()).isEqualTo("Remboursée");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Énumérations Solidarité")
|
||||||
|
class SolidariteEnumsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("TypeAide - Tous les types disponibles")
|
||||||
|
void testTypeAideTousLesTypes() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(TypeAide.AIDE_FINANCIERE.getLibelle()).isEqualTo("Aide Financière");
|
||||||
|
assertThat(TypeAide.AIDE_MEDICALE.getLibelle()).isEqualTo("Aide Médicale");
|
||||||
|
assertThat(TypeAide.AIDE_EDUCATIVE.getLibelle()).isEqualTo("Aide Éducative");
|
||||||
|
assertThat(TypeAide.AIDE_LOGEMENT.getLibelle()).isEqualTo("Aide au Logement");
|
||||||
|
assertThat(TypeAide.AIDE_ALIMENTAIRE.getLibelle()).isEqualTo("Aide Alimentaire");
|
||||||
|
assertThat(TypeAide.AIDE_JURIDIQUE.getLibelle()).isEqualTo("Aide Juridique");
|
||||||
|
assertThat(TypeAide.AIDE_PROFESSIONNELLE.getLibelle()).isEqualTo("Aide Professionnelle");
|
||||||
|
assertThat(TypeAide.AIDE_URGENCE.getLibelle()).isEqualTo("Aide d'Urgence");
|
||||||
|
assertThat(TypeAide.AUTRE.getLibelle()).isEqualTo("Autre");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("StatutAide - Tous les statuts disponibles")
|
||||||
|
void testStatutAideTousLesStatuts() {
|
||||||
|
// Given & When & Then
|
||||||
|
assertThat(StatutAide.EN_ATTENTE.getLibelle()).isEqualTo("En attente");
|
||||||
|
assertThat(StatutAide.EN_COURS.getLibelle()).isEqualTo("En cours d'évaluation");
|
||||||
|
assertThat(StatutAide.APPROUVEE.getLibelle()).isEqualTo("Approuvée");
|
||||||
|
assertThat(StatutAide.REJETEE.getLibelle()).isEqualTo("Rejetée");
|
||||||
|
assertThat(StatutAide.EN_COURS_VERSEMENT.getLibelle()).isEqualTo("En cours de versement");
|
||||||
|
assertThat(StatutAide.VERSEE.getLibelle()).isEqualTo("Versée");
|
||||||
|
assertThat(StatutAide.ANNULEE.getLibelle()).isEqualTo("Annulée");
|
||||||
|
assertThat(StatutAide.SUSPENDUE.getLibelle()).isEqualTo("Suspendue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("Tests de Couverture Complète")
|
||||||
|
class CouvertureCompleteTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Vérification que toutes les enums ont des valeurs")
|
||||||
|
void testToutesLesEnumsOntDesValeurs() {
|
||||||
|
// Given & When & Then - Organisation
|
||||||
|
assertThat(TypeOrganisation.values()).isNotEmpty();
|
||||||
|
assertThat(StatutOrganisation.values()).isNotEmpty();
|
||||||
|
|
||||||
|
// Given & When & Then - Membre
|
||||||
|
assertThat(StatutMembre.values()).isNotEmpty();
|
||||||
|
|
||||||
|
// Given & When & Then - Paiement
|
||||||
|
assertThat(StatutSession.values()).isNotEmpty();
|
||||||
|
assertThat(TypeEvenement.values()).isNotEmpty();
|
||||||
|
assertThat(StatutTraitement.values()).isNotEmpty();
|
||||||
|
|
||||||
|
// Given & When & Then - Abonnement
|
||||||
|
assertThat(TypeFormule.values()).isNotEmpty();
|
||||||
|
assertThat(StatutFormule.values()).isNotEmpty();
|
||||||
|
assertThat(StatutAbonnement.values()).isNotEmpty();
|
||||||
|
|
||||||
|
// Given & When & Then - Événement
|
||||||
|
assertThat(TypeEvenementMetier.values()).isNotEmpty();
|
||||||
|
|
||||||
|
// Given & When & Then - Finance
|
||||||
|
assertThat(StatutCotisation.values()).isNotEmpty();
|
||||||
|
|
||||||
|
// Given & When & Then - Solidarité
|
||||||
|
assertThat(TypeAide.values()).isNotEmpty();
|
||||||
|
assertThat(StatutAide.values()).isNotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,6 +65,10 @@
|
|||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-jdbc-h2</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-flyway</artifactId>
|
<artifactId>quarkus-flyway</artifactId>
|
||||||
@@ -98,6 +102,14 @@
|
|||||||
<artifactId>quarkus-hibernate-validator</artifactId>
|
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Lombok -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.30</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Tests -->
|
<!-- Tests -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheEntity;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entité Membre avec Lombok
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "membres", indexes = {
|
||||||
|
@Index(name = "idx_membre_email", columnList = "email", unique = true),
|
||||||
|
@Index(name = "idx_membre_numero", columnList = "numeroMembre", unique = true),
|
||||||
|
@Index(name = "idx_membre_actif", columnList = "actif")
|
||||||
|
})
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class Membre extends PanacheEntity {
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Column(name = "numero_membre", unique = true, nullable = false, length = 20)
|
||||||
|
private String numeroMembre;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Column(name = "prenom", nullable = false, length = 100)
|
||||||
|
private String prenom;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Column(name = "nom", nullable = false, length = 100)
|
||||||
|
private String nom;
|
||||||
|
|
||||||
|
@Email
|
||||||
|
@NotBlank
|
||||||
|
@Column(name = "email", unique = true, nullable = false, length = 255)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(name = "telephone", length = 20)
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Column(name = "date_naissance", nullable = false)
|
||||||
|
private LocalDate dateNaissance;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Column(name = "date_adhesion", nullable = false)
|
||||||
|
private LocalDate dateAdhesion;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
@Column(name = "actif", nullable = false)
|
||||||
|
private Boolean actif = true;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
@Column(name = "date_creation", nullable = false)
|
||||||
|
private LocalDateTime dateCreation = LocalDateTime.now();
|
||||||
|
|
||||||
|
@Column(name = "date_modification")
|
||||||
|
private LocalDateTime dateModification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode métier pour obtenir le nom complet
|
||||||
|
*/
|
||||||
|
public String getNomComplet() {
|
||||||
|
return prenom + " " + nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode métier pour vérifier si le membre est majeur
|
||||||
|
*/
|
||||||
|
public boolean isMajeur() {
|
||||||
|
return dateNaissance.isBefore(LocalDate.now().minusYears(18));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode métier pour calculer l'âge
|
||||||
|
*/
|
||||||
|
public int getAge() {
|
||||||
|
return LocalDate.now().getYear() - dateNaissance.getYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreUpdate
|
||||||
|
public void preUpdate() {
|
||||||
|
this.dateModification = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package dev.lions.unionflow.server.repository;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.entity.Membre;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository pour l'entité Membre
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MembreRepository implements PanacheRepository<Membre> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve un membre par son email
|
||||||
|
*/
|
||||||
|
public Optional<Membre> findByEmail(String email) {
|
||||||
|
return find("email", email).firstResultOptional();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve un membre par son numéro
|
||||||
|
*/
|
||||||
|
public Optional<Membre> findByNumeroMembre(String numeroMembre) {
|
||||||
|
return find("numeroMembre", numeroMembre).firstResultOptional();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve tous les membres actifs
|
||||||
|
*/
|
||||||
|
public List<Membre> findAllActifs() {
|
||||||
|
return find("actif", true).list();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compte le nombre de membres actifs
|
||||||
|
*/
|
||||||
|
public long countActifs() {
|
||||||
|
return count("actif", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve les membres par nom ou prénom (recherche partielle)
|
||||||
|
*/
|
||||||
|
public List<Membre> findByNomOrPrenom(String recherche) {
|
||||||
|
return find("lower(nom) like ?1 or lower(prenom) like ?1",
|
||||||
|
"%" + recherche.toLowerCase() + "%").list();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package dev.lions.unionflow.server.resource;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.entity.Membre;
|
||||||
|
import dev.lions.unionflow.server.service.MembreService;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.ws.rs.*;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||||
|
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource REST pour la gestion des membres
|
||||||
|
*/
|
||||||
|
@Path("/api/membres")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ApplicationScoped
|
||||||
|
@Tag(name = "Membres", description = "API de gestion des membres")
|
||||||
|
public class MembreResource {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(MembreResource.class);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MembreService membreService;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Operation(summary = "Lister tous les membres actifs")
|
||||||
|
@APIResponse(responseCode = "200", description = "Liste des membres actifs")
|
||||||
|
public Response listerMembres() {
|
||||||
|
LOG.info("Récupération de la liste des membres actifs");
|
||||||
|
List<Membre> membres = membreService.listerMembresActifs();
|
||||||
|
return Response.ok(membres).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}")
|
||||||
|
@Operation(summary = "Récupérer un membre par son ID")
|
||||||
|
@APIResponse(responseCode = "200", description = "Membre trouvé")
|
||||||
|
@APIResponse(responseCode = "404", description = "Membre non trouvé")
|
||||||
|
public Response obtenirMembre(@Parameter(description = "ID du membre") @PathParam("id") Long id) {
|
||||||
|
LOG.infof("Récupération du membre ID: %d", id);
|
||||||
|
return membreService.trouverParId(id)
|
||||||
|
.map(membre -> Response.ok(membre).build())
|
||||||
|
.orElse(Response.status(Response.Status.NOT_FOUND)
|
||||||
|
.entity(Map.of("message", "Membre non trouvé")).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Operation(summary = "Créer un nouveau membre")
|
||||||
|
@APIResponse(responseCode = "201", description = "Membre créé avec succès")
|
||||||
|
@APIResponse(responseCode = "400", description = "Données invalides")
|
||||||
|
public Response creerMembre(@Valid Membre membre) {
|
||||||
|
LOG.infof("Création d'un nouveau membre: %s", membre.getEmail());
|
||||||
|
try {
|
||||||
|
Membre nouveauMembre = membreService.creerMembre(membre);
|
||||||
|
return Response.status(Response.Status.CREATED).entity(nouveauMembre).build();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity(Map.of("message", e.getMessage())).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{id}")
|
||||||
|
@Operation(summary = "Mettre à jour un membre existant")
|
||||||
|
@APIResponse(responseCode = "200", description = "Membre mis à jour avec succès")
|
||||||
|
@APIResponse(responseCode = "404", description = "Membre non trouvé")
|
||||||
|
@APIResponse(responseCode = "400", description = "Données invalides")
|
||||||
|
public Response mettreAJourMembre(@Parameter(description = "ID du membre") @PathParam("id") Long id,
|
||||||
|
@Valid Membre membre) {
|
||||||
|
LOG.infof("Mise à jour du membre ID: %d", id);
|
||||||
|
try {
|
||||||
|
Membre membreMisAJour = membreService.mettreAJourMembre(id, membre);
|
||||||
|
return Response.ok(membreMisAJour).build();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity(Map.of("message", e.getMessage())).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{id}")
|
||||||
|
@Operation(summary = "Désactiver un membre")
|
||||||
|
@APIResponse(responseCode = "204", description = "Membre désactivé avec succès")
|
||||||
|
@APIResponse(responseCode = "404", description = "Membre non trouvé")
|
||||||
|
public Response desactiverMembre(@Parameter(description = "ID du membre") @PathParam("id") Long id) {
|
||||||
|
LOG.infof("Désactivation du membre ID: %d", id);
|
||||||
|
try {
|
||||||
|
membreService.desactiverMembre(id);
|
||||||
|
return Response.noContent().build();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND)
|
||||||
|
.entity(Map.of("message", e.getMessage())).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/recherche")
|
||||||
|
@Operation(summary = "Rechercher des membres par nom ou prénom")
|
||||||
|
@APIResponse(responseCode = "200", description = "Résultats de la recherche")
|
||||||
|
public Response rechercherMembres(@Parameter(description = "Terme de recherche") @QueryParam("q") String recherche) {
|
||||||
|
LOG.infof("Recherche de membres avec le terme: %s", recherche);
|
||||||
|
if (recherche == null || recherche.trim().isEmpty()) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity(Map.of("message", "Le terme de recherche est requis")).build();
|
||||||
|
}
|
||||||
|
List<Membre> membres = membreService.rechercherMembres(recherche.trim());
|
||||||
|
return Response.ok(membres).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/stats")
|
||||||
|
@Operation(summary = "Obtenir les statistiques des membres")
|
||||||
|
@APIResponse(responseCode = "200", description = "Statistiques des membres")
|
||||||
|
public Response obtenirStatistiques() {
|
||||||
|
LOG.info("Récupération des statistiques des membres");
|
||||||
|
long nombreMembresActifs = membreService.compterMembresActifs();
|
||||||
|
return Response.ok(Map.of(
|
||||||
|
"nombreMembresActifs", nombreMembresActifs,
|
||||||
|
"timestamp", java.time.LocalDateTime.now()
|
||||||
|
)).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package dev.lions.unionflow.server.service;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.entity.Membre;
|
||||||
|
import dev.lions.unionflow.server.repository.MembreRepository;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service métier pour les membres
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MembreService {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(MembreService.class);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MembreRepository membreRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un nouveau membre
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public Membre creerMembre(Membre membre) {
|
||||||
|
LOG.infof("Création d'un nouveau membre: %s", membre.getEmail());
|
||||||
|
|
||||||
|
// Générer un numéro de membre unique
|
||||||
|
if (membre.getNumeroMembre() == null || membre.getNumeroMembre().isEmpty()) {
|
||||||
|
membre.setNumeroMembre(genererNumeroMembre());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier l'unicité de l'email
|
||||||
|
if (membreRepository.findByEmail(membre.getEmail()).isPresent()) {
|
||||||
|
throw new IllegalArgumentException("Un membre avec cet email existe déjà");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier l'unicité du numéro de membre
|
||||||
|
if (membreRepository.findByNumeroMembre(membre.getNumeroMembre()).isPresent()) {
|
||||||
|
throw new IllegalArgumentException("Un membre avec ce numéro existe déjà");
|
||||||
|
}
|
||||||
|
|
||||||
|
membreRepository.persist(membre);
|
||||||
|
LOG.infof("Membre créé avec succès: %s (ID: %d)", membre.getNomComplet(), membre.id);
|
||||||
|
return membre;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour un membre existant
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public Membre mettreAJourMembre(Long id, Membre membreModifie) {
|
||||||
|
LOG.infof("Mise à jour du membre ID: %d", id);
|
||||||
|
|
||||||
|
Membre membre = membreRepository.findById(id);
|
||||||
|
if (membre == null) {
|
||||||
|
throw new IllegalArgumentException("Membre non trouvé avec l'ID: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier l'unicité de l'email si modifié
|
||||||
|
if (!membre.getEmail().equals(membreModifie.getEmail())) {
|
||||||
|
if (membreRepository.findByEmail(membreModifie.getEmail()).isPresent()) {
|
||||||
|
throw new IllegalArgumentException("Un membre avec cet email existe déjà");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour les champs
|
||||||
|
membre.setPrenom(membreModifie.getPrenom());
|
||||||
|
membre.setNom(membreModifie.getNom());
|
||||||
|
membre.setEmail(membreModifie.getEmail());
|
||||||
|
membre.setTelephone(membreModifie.getTelephone());
|
||||||
|
membre.setDateNaissance(membreModifie.getDateNaissance());
|
||||||
|
membre.setActif(membreModifie.getActif());
|
||||||
|
|
||||||
|
LOG.infof("Membre mis à jour avec succès: %s", membre.getNomComplet());
|
||||||
|
return membre;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve un membre par son ID
|
||||||
|
*/
|
||||||
|
public Optional<Membre> trouverParId(Long id) {
|
||||||
|
return Optional.ofNullable(membreRepository.findById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve un membre par son email
|
||||||
|
*/
|
||||||
|
public Optional<Membre> trouverParEmail(String email) {
|
||||||
|
return membreRepository.findByEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liste tous les membres actifs
|
||||||
|
*/
|
||||||
|
public List<Membre> listerMembresActifs() {
|
||||||
|
return membreRepository.findAllActifs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recherche des membres par nom ou prénom
|
||||||
|
*/
|
||||||
|
public List<Membre> rechercherMembres(String recherche) {
|
||||||
|
return membreRepository.findByNomOrPrenom(recherche);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Désactive un membre
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public void desactiverMembre(Long id) {
|
||||||
|
LOG.infof("Désactivation du membre ID: %d", id);
|
||||||
|
|
||||||
|
Membre membre = membreRepository.findById(id);
|
||||||
|
if (membre == null) {
|
||||||
|
throw new IllegalArgumentException("Membre non trouvé avec l'ID: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
membre.setActif(false);
|
||||||
|
LOG.infof("Membre désactivé: %s", membre.getNomComplet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Génère un numéro de membre unique
|
||||||
|
*/
|
||||||
|
private String genererNumeroMembre() {
|
||||||
|
String prefix = "UF" + LocalDate.now().getYear();
|
||||||
|
String suffix = UUID.randomUUID().toString().substring(0, 8).toUpperCase();
|
||||||
|
return prefix + "-" + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compte le nombre total de membres actifs
|
||||||
|
*/
|
||||||
|
public long compterMembresActifs() {
|
||||||
|
return membreRepository.countActifs();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Configuration de base pour UnionFlow Server
|
||||||
|
quarkus.application.name=unionflow-server
|
||||||
|
quarkus.http.port=8080
|
||||||
|
|
||||||
|
# Configuration de développement
|
||||||
|
%dev.quarkus.log.level=INFO
|
||||||
|
%dev.quarkus.log.console.enable=true
|
||||||
|
|
||||||
|
# Configuration de base de données (PostgreSQL)
|
||||||
|
quarkus.datasource.db-kind=postgresql
|
||||||
|
quarkus.datasource.username=unionflow
|
||||||
|
quarkus.datasource.password=unionflow
|
||||||
|
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/unionflow_dev
|
||||||
|
quarkus.hibernate-orm.database.generation=drop-and-create
|
||||||
|
quarkus.hibernate-orm.log.sql=false
|
||||||
|
|
||||||
|
# Configuration pour le développement sans base de données externe
|
||||||
|
%dev.quarkus.datasource.db-kind=h2
|
||||||
|
%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:unionflow;DB_CLOSE_DELAY=-1
|
||||||
|
%dev.quarkus.hibernate-orm.database.generation=drop-and-create
|
||||||
|
|
||||||
|
# Configuration Swagger UI
|
||||||
|
quarkus.swagger-ui.always-include=true
|
||||||
|
quarkus.swagger-ui.path=/swagger-ui
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unitaires pour valider les fonctionnalités Lombok de l'entité Membre
|
||||||
|
*/
|
||||||
|
@DisplayName("Tests Lombok - Entité Membre")
|
||||||
|
class MembreLombokTest {
|
||||||
|
|
||||||
|
private String numeroMembre;
|
||||||
|
private String prenom;
|
||||||
|
private String nom;
|
||||||
|
private String email;
|
||||||
|
private String telephone;
|
||||||
|
private LocalDate dateNaissance;
|
||||||
|
private LocalDate dateAdhesion;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
numeroMembre = "UF2025-ABC123";
|
||||||
|
prenom = "Jean";
|
||||||
|
nom = "Dupont";
|
||||||
|
email = "jean.dupont@example.com";
|
||||||
|
telephone = "+33123456789";
|
||||||
|
dateNaissance = LocalDate.of(1990, 5, 15);
|
||||||
|
dateAdhesion = LocalDate.of(2025, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des annotations Lombok - Builder pattern")
|
||||||
|
void testLombokBuilder() {
|
||||||
|
// Given & When
|
||||||
|
Membre membre = Membre.builder()
|
||||||
|
.numeroMembre(numeroMembre)
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.email(email)
|
||||||
|
.telephone(telephone)
|
||||||
|
.dateNaissance(dateNaissance)
|
||||||
|
.dateAdhesion(dateAdhesion)
|
||||||
|
.actif(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(membre);
|
||||||
|
assertEquals(numeroMembre, membre.getNumeroMembre());
|
||||||
|
assertEquals(prenom, membre.getPrenom());
|
||||||
|
assertEquals(nom, membre.getNom());
|
||||||
|
assertEquals(email, membre.getEmail());
|
||||||
|
assertEquals(telephone, membre.getTelephone());
|
||||||
|
assertEquals(dateNaissance, membre.getDateNaissance());
|
||||||
|
assertEquals(dateAdhesion, membre.getDateAdhesion());
|
||||||
|
assertTrue(membre.getActif());
|
||||||
|
assertNotNull(membre.getDateCreation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des annotations Lombok - Constructeur sans arguments")
|
||||||
|
void testLombokNoArgsConstructor() {
|
||||||
|
// Given & When
|
||||||
|
Membre membre = new Membre();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(membre);
|
||||||
|
assertNull(membre.getNumeroMembre());
|
||||||
|
assertNull(membre.getPrenom());
|
||||||
|
assertNull(membre.getNom());
|
||||||
|
assertNull(membre.getEmail());
|
||||||
|
assertNull(membre.getTelephone());
|
||||||
|
assertNull(membre.getDateNaissance());
|
||||||
|
assertNull(membre.getDateAdhesion());
|
||||||
|
assertTrue(membre.getActif()); // Valeur par défaut
|
||||||
|
assertNotNull(membre.getDateCreation()); // Valeur par défaut
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des annotations Lombok - Constructeur avec tous les arguments")
|
||||||
|
void testLombokAllArgsConstructor() {
|
||||||
|
// Given
|
||||||
|
LocalDateTime dateCreation = LocalDateTime.now();
|
||||||
|
LocalDateTime dateModification = LocalDateTime.now();
|
||||||
|
|
||||||
|
// When
|
||||||
|
Membre membre = new Membre(numeroMembre, prenom, nom, email, telephone,
|
||||||
|
dateNaissance, dateAdhesion, true, dateCreation, dateModification);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(membre);
|
||||||
|
assertEquals(numeroMembre, membre.getNumeroMembre());
|
||||||
|
assertEquals(prenom, membre.getPrenom());
|
||||||
|
assertEquals(nom, membre.getNom());
|
||||||
|
assertEquals(email, membre.getEmail());
|
||||||
|
assertEquals(telephone, membre.getTelephone());
|
||||||
|
assertEquals(dateNaissance, membre.getDateNaissance());
|
||||||
|
assertEquals(dateAdhesion, membre.getDateAdhesion());
|
||||||
|
assertTrue(membre.getActif());
|
||||||
|
assertEquals(dateCreation, membre.getDateCreation());
|
||||||
|
assertEquals(dateModification, membre.getDateModification());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des annotations Lombok - Getters et Setters")
|
||||||
|
void testLombokGettersSetters() {
|
||||||
|
// Given
|
||||||
|
Membre membre = new Membre();
|
||||||
|
|
||||||
|
// When & Then - Test des setters
|
||||||
|
membre.setNumeroMembre(numeroMembre);
|
||||||
|
membre.setPrenom(prenom);
|
||||||
|
membre.setNom(nom);
|
||||||
|
membre.setEmail(email);
|
||||||
|
membre.setTelephone(telephone);
|
||||||
|
membre.setDateNaissance(dateNaissance);
|
||||||
|
membre.setDateAdhesion(dateAdhesion);
|
||||||
|
membre.setActif(false);
|
||||||
|
|
||||||
|
// Test des getters
|
||||||
|
assertEquals(numeroMembre, membre.getNumeroMembre());
|
||||||
|
assertEquals(prenom, membre.getPrenom());
|
||||||
|
assertEquals(nom, membre.getNom());
|
||||||
|
assertEquals(email, membre.getEmail());
|
||||||
|
assertEquals(telephone, membre.getTelephone());
|
||||||
|
assertEquals(dateNaissance, membre.getDateNaissance());
|
||||||
|
assertEquals(dateAdhesion, membre.getDateAdhesion());
|
||||||
|
assertFalse(membre.getActif());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des annotations Lombok - equals et hashCode")
|
||||||
|
void testLombokEqualsHashCode() {
|
||||||
|
// Given
|
||||||
|
Membre membre1 = Membre.builder()
|
||||||
|
.numeroMembre(numeroMembre)
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.email(email)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Membre membre2 = Membre.builder()
|
||||||
|
.numeroMembre(numeroMembre)
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.email(email)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Membre membre3 = Membre.builder()
|
||||||
|
.numeroMembre("DIFFERENT")
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.email(email)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(membre1, membre2);
|
||||||
|
assertEquals(membre1.hashCode(), membre2.hashCode());
|
||||||
|
assertNotEquals(membre1, membre3);
|
||||||
|
assertNotEquals(membre1.hashCode(), membre3.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des annotations Lombok - toString")
|
||||||
|
void testLombokToString() {
|
||||||
|
// Given
|
||||||
|
Membre membre = Membre.builder()
|
||||||
|
.numeroMembre(numeroMembre)
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.email(email)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// When
|
||||||
|
String toStringResult = membre.toString();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(toStringResult);
|
||||||
|
assertTrue(toStringResult.contains("Membre"));
|
||||||
|
assertTrue(toStringResult.contains(numeroMembre));
|
||||||
|
assertTrue(toStringResult.contains(prenom));
|
||||||
|
assertTrue(toStringResult.contains(nom));
|
||||||
|
assertTrue(toStringResult.contains(email));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des méthodes métier personnalisées")
|
||||||
|
void testMethodesMetier() {
|
||||||
|
// Given
|
||||||
|
Membre membre = Membre.builder()
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.dateNaissance(LocalDate.of(1990, 5, 15)) // 34 ans
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// When & Then
|
||||||
|
assertEquals("Jean Dupont", membre.getNomComplet());
|
||||||
|
assertTrue(membre.isMajeur());
|
||||||
|
assertEquals(34, membre.getAge());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test des valeurs par défaut avec @Builder.Default")
|
||||||
|
void testBuilderDefaults() {
|
||||||
|
// Given & When
|
||||||
|
Membre membre = Membre.builder()
|
||||||
|
.numeroMembre(numeroMembre)
|
||||||
|
.prenom(prenom)
|
||||||
|
.nom(nom)
|
||||||
|
.email(email)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(membre.getActif()); // Valeur par défaut
|
||||||
|
assertNotNull(membre.getDateCreation()); // Valeur par défaut
|
||||||
|
assertTrue(membre.getDateCreation().isBefore(LocalDateTime.now().plusSeconds(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user