Compare commits
116
Commits
ff61cdf87c
...
prod/v1.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d2a2e486a | ||
|
|
b9a7dc089c | ||
|
|
1737087062 | ||
|
|
df217bc923 | ||
|
|
da0443f655 | ||
|
|
baa4d3c0cd | ||
|
|
e81be98cbe | ||
|
|
a19e49392b | ||
|
|
8ca20c9a4f | ||
|
|
92c9e80bc3 | ||
|
|
c94f89997f | ||
|
|
af31766134 | ||
|
|
3fc239683e | ||
|
|
a7c5b23198 | ||
|
|
29f9dc3bc2 | ||
|
|
5ee9be467b | ||
|
|
6dd45deb8c | ||
|
|
19cee92437 | ||
|
|
214ec08229 | ||
|
|
62209ae659 | ||
|
|
fc3373a1b4 | ||
|
|
db3eb3ab9a | ||
|
|
d1f38f11f0 | ||
|
|
acf9d6d301 | ||
|
|
3066ff0e86 | ||
|
|
64ad4be7dd | ||
|
|
d30e795325 | ||
|
|
e0388c7884 | ||
|
|
7cf29f6106 | ||
|
|
bef01e3a0e | ||
|
|
9cf1d26018 | ||
|
|
94d672c0f6 | ||
|
|
8156c8f3d0 | ||
|
|
7249b45533 | ||
|
|
7e036c1966 | ||
|
|
194986f880 | ||
|
|
d834b8d0d3 | ||
|
|
e3abe53eb0 | ||
|
|
348d6e6ccf | ||
|
|
e670e38343 | ||
|
|
fe3a1ec36c | ||
|
|
44ae524626 | ||
|
|
829a69f1a5 | ||
|
|
f8336fb407 | ||
|
|
ab1094d29a | ||
|
|
3477461fb2 | ||
|
|
bb48f919b0 | ||
|
|
5f2bf61829 | ||
|
|
2df3e792f1 | ||
|
|
8ecdc54028 | ||
|
|
e8baeab0e0 | ||
|
|
d0fde2f2e8 | ||
|
|
754a0c8dcc | ||
|
|
bbbb3978b9 | ||
|
|
5e75767f92 | ||
|
|
2f8c8f0829 | ||
|
|
bf38e01c49 | ||
|
|
6ea793de87 | ||
|
|
60257f4823 | ||
|
|
5c64184c93 | ||
|
|
2dc39521c4 | ||
|
|
c7d8aaa179 | ||
|
|
62d1158a8a | ||
|
|
48c3220013 | ||
|
|
f1bd5d9e08 | ||
|
|
5737fb6429 | ||
|
|
96eee4326a | ||
|
|
14c83be77a | ||
|
|
08dc39f61a | ||
|
|
84265660b9 | ||
|
|
da33ce934d | ||
|
|
e867acbb70 | ||
|
|
c4bb9803ed | ||
|
|
e1cd5930fd | ||
|
|
d913579c77 | ||
|
|
2adbdde121 | ||
|
|
bcf92487ab | ||
|
|
bf4c7b36bd | ||
|
|
3ed9d0454b | ||
|
|
569927c644 | ||
|
|
7d39e561f7 | ||
|
|
8dfe71ac97 | ||
|
|
87c65c6ebd | ||
|
|
bb24363500 | ||
|
|
19139124ca | ||
|
|
2e8298b3b6 | ||
|
|
bca84be16a | ||
|
|
1a4ff6fdac | ||
|
|
aba4ed0770 | ||
|
|
e39921f049 | ||
|
|
52fbd5fcf8 | ||
|
|
b6651fabb4 | ||
|
|
9531019aae | ||
|
|
499be006c0 | ||
|
|
f82021f6fc | ||
|
|
fc81b9e1ac | ||
|
|
5b0edcafef | ||
|
|
ecde6a7b68 | ||
|
|
afabea33be | ||
|
|
e895f042ff | ||
|
|
d1c8883b82 | ||
|
|
7743a220ef | ||
|
|
8a15139efb | ||
|
|
7e9504ffe0 | ||
|
|
1d259831c6 | ||
|
|
3ae296aa91 | ||
|
|
0baca4a334 | ||
|
|
a429e67133 | ||
|
|
dd31d73fed | ||
|
|
cac229486a | ||
|
|
1f803a6ecc | ||
|
|
1af0e177d5 | ||
|
|
2a116b1e02 | ||
|
|
bcd4a94973 | ||
|
|
5cd807f916 | ||
|
|
4f140775a2 |
@@ -0,0 +1,77 @@
|
||||
name: AS Talange CI/CD Pipeline - Production
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'prod/*'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Build & Run Unit Tests
|
||||
runs-on: [self-hosted, prod]
|
||||
container:
|
||||
image: maven:3.9.6-eclipse-temurin-21
|
||||
steps:
|
||||
- name: Clone repository
|
||||
run: |
|
||||
if ! command -v git &> /dev/null; then
|
||||
apt-get update && apt-get install -y git
|
||||
fi
|
||||
SERVER_URL="${{ github.server_url }}"
|
||||
SERVER_NO_PROTO="${SERVER_URL#http://}"
|
||||
SERVER_NO_PROTO="${SERVER_NO_PROTO#https://}"
|
||||
git clone "https://oauth2:${{ secrets.GITHUB_TOKEN }}@${SERVER_NO_PROTO}/${{ github.repository }}.git" .
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Run Maven Tests
|
||||
run: mvn clean test
|
||||
|
||||
|
||||
|
||||
deploy_prod:
|
||||
name: Deploy to Prod Environment
|
||||
needs: test
|
||||
if: startsWith(github.ref, 'refs/heads/prod/')
|
||||
runs-on: [self-hosted, prod]
|
||||
container:
|
||||
image: docker:latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
run: |
|
||||
apk add --no-cache git
|
||||
SERVER_URL="${{ github.server_url }}"
|
||||
SERVER_NO_PROTO="${SERVER_URL#http://}"
|
||||
SERVER_NO_PROTO="${SERVER_NO_PROTO#https://}"
|
||||
git clone "https://oauth2:${{ secrets.GITHUB_TOKEN }}@${SERVER_NO_PROTO}/${{ github.repository }}.git" .
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Deploy with Docker Compose
|
||||
env:
|
||||
PROD_DB_USER: ${{ secrets.PROD_DB_USER }}
|
||||
PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
|
||||
CAPTCHA_SECRET: ${{ secrets.CAPTCHA_SECRET }}
|
||||
CAPTCHA_SITEKEY: ${{ secrets.CAPTCHA_SITEKEY }}
|
||||
run: |
|
||||
echo "POSTGRES_USER=${PROD_DB_USER:-myuser}" > .env
|
||||
echo "POSTGRES_PASSWORD=${PROD_DB_PASSWORD:-mypassword}" >> .env
|
||||
echo "CAPTCHA_SECRET=${CAPTCHA_SECRET:-1x0000000000000000000000000000000AA}" >> .env
|
||||
echo "CAPTCHA_SITEKEY=${CAPTCHA_SITEKEY:-1x00000000000000000000AA}" >> .env
|
||||
docker compose down app || true
|
||||
docker compose up -d --build app
|
||||
|
||||
- name: Verify application startup
|
||||
run: |
|
||||
echo "Waiting for application to start..."
|
||||
COUNT=0
|
||||
while [ $COUNT -lt 30 ]; do
|
||||
if docker exec astalange_app wget -qO- http://localhost:8080/login | grep -q "Connexion"; then
|
||||
echo "Application is up and login page is accessible!"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting... ($COUNT/30)"
|
||||
sleep 5
|
||||
COUNT=$((COUNT+1))
|
||||
done
|
||||
echo "Application failed to start or login page is not accessible."
|
||||
docker logs astalange_app
|
||||
exit 1
|
||||
@@ -0,0 +1,73 @@
|
||||
name: AS Talange CI/CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Build & Run Unit Tests
|
||||
runs-on: [self-hosted, ubuntu-latest]
|
||||
container:
|
||||
image: maven:3.9.6-eclipse-temurin-21
|
||||
steps:
|
||||
- name: Clone repository
|
||||
run: |
|
||||
if ! command -v git &> /dev/null; then
|
||||
apt-get update && apt-get install -y git
|
||||
fi
|
||||
SERVER_URL="${{ github.server_url }}"
|
||||
SERVER_NO_PROTO="${SERVER_URL#http://}"
|
||||
SERVER_NO_PROTO="${SERVER_NO_PROTO#https://}"
|
||||
git clone "https://oauth2:${{ secrets.GITHUB_TOKEN }}@${SERVER_NO_PROTO}/${{ github.repository }}.git" .
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Run Maven Tests
|
||||
run: mvn clean test
|
||||
|
||||
deploy_test:
|
||||
name: Deploy to Test Environment
|
||||
needs: test
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: [self-hosted, ubuntu-latest]
|
||||
container:
|
||||
image: docker:latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
run: |
|
||||
apk add --no-cache git
|
||||
SERVER_URL="${{ github.server_url }}"
|
||||
SERVER_NO_PROTO="${SERVER_URL#http://}"
|
||||
SERVER_NO_PROTO="${SERVER_NO_PROTO#https://}"
|
||||
git clone "https://oauth2:${{ secrets.GITHUB_TOKEN }}@${SERVER_NO_PROTO}/${{ github.repository }}.git" .
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Deploy with Docker Compose
|
||||
env:
|
||||
DB_USER: ${{ secrets.DB_USER }}
|
||||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||||
run: |
|
||||
echo "POSTGRES_USER=${DB_USER:-myuser}" > .env
|
||||
echo "POSTGRES_PASSWORD=${DB_PASSWORD:-mypassword}" >> .env
|
||||
echo "CAPTCHA_SECRET=1x0000000000000000000000000000000AA" >> .env
|
||||
echo "CAPTCHA_SITEKEY=1x00000000000000000000AA" >> .env
|
||||
docker compose down app || true
|
||||
docker compose up -d --build app
|
||||
|
||||
- name: Verify application startup
|
||||
run: |
|
||||
echo "Waiting for application to start..."
|
||||
COUNT=0
|
||||
while [ $COUNT -lt 30 ]; do
|
||||
if docker exec astalange_app wget -qO- http://localhost:8080/login | grep -q "Connexion"; then
|
||||
echo "Application is up and login page is accessible!"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting... ($COUNT/30)"
|
||||
sleep 5
|
||||
COUNT=$((COUNT+1))
|
||||
done
|
||||
echo "Application failed to start or login page is not accessible."
|
||||
docker logs astalange_app
|
||||
exit 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.compile.nullAnalysis.mode": "automatic"
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>as-talange-parent</artifactId>
|
||||
<groupId>com.astalange</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>1.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# Placeholder to ensure git tracks this directory
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>as-talange-parent</artifactId>
|
||||
<groupId>com.astalange</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>1.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -61,5 +61,11 @@
|
||||
<version>1.77</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -23,22 +23,61 @@ public class Adherent {
|
||||
@org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE)
|
||||
private LocalDate dateNaissance;
|
||||
|
||||
@Column(length = 20)
|
||||
private String telephone;
|
||||
@Column(name = "lieu_naissance_ville", nullable = false, length = 100)
|
||||
private String lieuNaissanceVille;
|
||||
|
||||
@Column(length = 100)
|
||||
@Column(name = "lieu_naissance_pays", nullable = false, length = 100)
|
||||
private String lieuNaissancePays;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String nationalite;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String email;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String adresse;
|
||||
@Column(nullable = false, length = 20)
|
||||
private String telephone;
|
||||
|
||||
@Column(name = "representant_legal", length = 150)
|
||||
private String representantLegal;
|
||||
|
||||
@Column(name = "type_demande", length = 50)
|
||||
private String typeDemande;
|
||||
|
||||
@Column(name = "ancien_club", length = 150)
|
||||
private String ancienClub;
|
||||
|
||||
@Column(name = "ancienne_categorie", length = 50)
|
||||
private String ancienneCategorie;
|
||||
|
||||
@Column(name = "raison_changement_club")
|
||||
private String raisonChangementClub;
|
||||
|
||||
@Column(name = "comment_connu_club")
|
||||
private String commentConnuClub;
|
||||
|
||||
@Column(name = "taille_vetement", length = 50)
|
||||
private String tailleVetement;
|
||||
|
||||
@Column(length = 50)
|
||||
private String pointure;
|
||||
|
||||
private boolean residentTalange = true;
|
||||
|
||||
@Column(nullable = false, length = 10)
|
||||
private String sexe = "MASCULIN";
|
||||
|
||||
@Column(name = "type_maillot", nullable = false, length = 20)
|
||||
private String typeMaillot = "JOUEUR";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getSexe() { return sexe; }
|
||||
public void setSexe(String sexe) { this.sexe = sexe; }
|
||||
|
||||
public String getTypeMaillot() { return typeMaillot; }
|
||||
public void setTypeMaillot(String typeMaillot) { this.typeMaillot = typeMaillot; }
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
@@ -51,18 +90,45 @@ public class Adherent {
|
||||
public LocalDate getDateNaissance() { return dateNaissance; }
|
||||
public void setDateNaissance(LocalDate dateNaissance) { this.dateNaissance = dateNaissance; }
|
||||
|
||||
public String getTelephone() { return telephone; }
|
||||
public void setTelephone(String telephone) { this.telephone = telephone; }
|
||||
public String getLieuNaissanceVille() { return lieuNaissanceVille; }
|
||||
public void setLieuNaissanceVille(String lieuNaissanceVille) { this.lieuNaissanceVille = lieuNaissanceVille; }
|
||||
|
||||
public String getLieuNaissancePays() { return lieuNaissancePays; }
|
||||
public void setLieuNaissancePays(String lieuNaissancePays) { this.lieuNaissancePays = lieuNaissancePays; }
|
||||
|
||||
public String getNationalite() { return nationalite; }
|
||||
public void setNationalite(String nationalite) { this.nationalite = nationalite; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
|
||||
public String getAdresse() { return adresse; }
|
||||
public void setAdresse(String adresse) { this.adresse = adresse; }
|
||||
public String getTelephone() { return telephone; }
|
||||
public void setTelephone(String telephone) { this.telephone = telephone; }
|
||||
|
||||
public String getRepresentantLegal() { return representantLegal; }
|
||||
public void setRepresentantLegal(String representantLegal) { this.representantLegal = representantLegal; }
|
||||
|
||||
public String getTypeDemande() { return typeDemande; }
|
||||
public void setTypeDemande(String typeDemande) { this.typeDemande = typeDemande; }
|
||||
|
||||
public String getAncienClub() { return ancienClub; }
|
||||
public void setAncienClub(String ancienClub) { this.ancienClub = ancienClub; }
|
||||
|
||||
public String getAncienneCategorie() { return ancienneCategorie; }
|
||||
public void setAncienneCategorie(String ancienneCategorie) { this.ancienneCategorie = ancienneCategorie; }
|
||||
|
||||
public String getRaisonChangementClub() { return raisonChangementClub; }
|
||||
public void setRaisonChangementClub(String raisonChangementClub) { this.raisonChangementClub = raisonChangementClub; }
|
||||
|
||||
public String getCommentConnuClub() { return commentConnuClub; }
|
||||
public void setCommentConnuClub(String commentConnuClub) { this.commentConnuClub = commentConnuClub; }
|
||||
|
||||
public String getTailleVetement() { return tailleVetement; }
|
||||
public void setTailleVetement(String tailleVetement) { this.tailleVetement = tailleVetement; }
|
||||
|
||||
public String getPointure() { return pointure; }
|
||||
public void setPointure(String pointure) { this.pointure = pointure; }
|
||||
|
||||
public boolean isResidentTalange() { return residentTalange; }
|
||||
public void setResidentTalange(boolean residentTalange) { this.residentTalange = residentTalange; }
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ public class AppUser {
|
||||
@Column(nullable = false)
|
||||
private boolean enabled = true;
|
||||
|
||||
@Column(name = "must_change_password", nullable = false)
|
||||
private boolean mustChangePassword = false;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(
|
||||
name = "user_role",
|
||||
@@ -33,4 +36,10 @@ public class AppUser {
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id")
|
||||
)
|
||||
private Set<Role> roles = new HashSet<>();
|
||||
|
||||
@Column(name = "last_login_at")
|
||||
private java.time.LocalDateTime lastLoginAt;
|
||||
|
||||
@Column(name = "last_logout_at")
|
||||
private java.time.LocalDateTime lastLogoutAt;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "audit_log_paiement")
|
||||
public class AuditLogPaiement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String action; // CREATE, UPDATE, DELETE
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDateTime dateAction;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String utilisateur; // Username or 'Système'
|
||||
|
||||
@Column(nullable = true)
|
||||
private Long paiementId; // Can be null if the payment is completely deleted or we just want to keep track
|
||||
|
||||
@Column(nullable = false, length = 1000)
|
||||
private String details;
|
||||
|
||||
@Column(nullable = true)
|
||||
private BigDecimal montant;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String adherentNomComplet;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
this.dateAction = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public LocalDateTime getDateAction() {
|
||||
return dateAction;
|
||||
}
|
||||
|
||||
public void setDateAction(LocalDateTime dateAction) {
|
||||
this.dateAction = dateAction;
|
||||
}
|
||||
|
||||
public String getUtilisateur() {
|
||||
return utilisateur;
|
||||
}
|
||||
|
||||
public void setUtilisateur(String utilisateur) {
|
||||
this.utilisateur = utilisateur;
|
||||
}
|
||||
|
||||
public Long getPaiementId() {
|
||||
return paiementId;
|
||||
}
|
||||
|
||||
public void setPaiementId(Long paiementId) {
|
||||
this.paiementId = paiementId;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(String details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public BigDecimal getMontant() {
|
||||
return montant;
|
||||
}
|
||||
|
||||
public void setMontant(BigDecimal montant) {
|
||||
this.montant = montant;
|
||||
}
|
||||
|
||||
public String getAdherentNomComplet() {
|
||||
return adherentNomComplet;
|
||||
}
|
||||
|
||||
public void setAdherentNomComplet(String adherentNomComplet) {
|
||||
this.adherentNomComplet = adherentNomComplet;
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,25 @@ package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "categorie")
|
||||
@Table(name = "categorie", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"nom", "saison_id"})
|
||||
})
|
||||
public class Categorie {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 20)
|
||||
@Column(nullable = false, length = 20)
|
||||
private String nom;
|
||||
|
||||
@Column(nullable = false, length = 10)
|
||||
private String sexe = "MASCULIN";
|
||||
|
||||
@Column(name = "annee_min")
|
||||
private Integer anneeMin;
|
||||
|
||||
@@ -26,6 +33,13 @@ public class Categorie {
|
||||
@Column(name = "tarif_exterieur", nullable = false, precision = 10, scale = 2)
|
||||
private BigDecimal tarifExterieur;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "saison_id", nullable = false)
|
||||
private Saison saison;
|
||||
|
||||
@OneToMany(mappedBy = "categorie", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<CategorieEquipement> categorieEquipements = new ArrayList<>();
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() { return id; }
|
||||
@@ -34,6 +48,9 @@ public class Categorie {
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
|
||||
public String getSexe() { return sexe; }
|
||||
public void setSexe(String sexe) { this.sexe = sexe; }
|
||||
|
||||
public Integer getAnneeMin() { return anneeMin; }
|
||||
public void setAnneeMin(Integer anneeMin) { this.anneeMin = anneeMin; }
|
||||
|
||||
@@ -45,4 +62,61 @@ public class Categorie {
|
||||
|
||||
public BigDecimal getTarifExterieur() { return tarifExterieur; }
|
||||
public void setTarifExterieur(BigDecimal tarifExterieur) { this.tarifExterieur = tarifExterieur; }
|
||||
|
||||
public Saison getSaison() { return saison; }
|
||||
public void setSaison(Saison saison) { this.saison = saison; }
|
||||
|
||||
public List<CategorieEquipement> getCategorieEquipements() { return categorieEquipements; }
|
||||
public void setCategorieEquipements(List<CategorieEquipement> categorieEquipements) { this.categorieEquipements = categorieEquipements; }
|
||||
|
||||
@Transient
|
||||
public boolean hasEquipement(Long equipementId) {
|
||||
if (categorieEquipements == null) return false;
|
||||
return categorieEquipements.stream().anyMatch(ce -> ce.getEquipement() != null && ce.getEquipement().getId().equals(equipementId));
|
||||
}
|
||||
|
||||
@Transient
|
||||
public boolean isEquipementObligatoire(Long equipementId) {
|
||||
if (categorieEquipements == null) return false;
|
||||
return categorieEquipements.stream().anyMatch(ce -> ce.getEquipement() != null && ce.getEquipement().getId().equals(equipementId) && Boolean.TRUE.equals(ce.getObligatoire()));
|
||||
}
|
||||
|
||||
@Transient
|
||||
public BigDecimal getEquipementPrix(Long equipementId) {
|
||||
if (categorieEquipements == null) return BigDecimal.ZERO;
|
||||
return categorieEquipements.stream()
|
||||
.filter(ce -> ce.getEquipement() != null && ce.getEquipement().getId().equals(equipementId))
|
||||
.findFirst()
|
||||
.map(CategorieEquipement::getPrix)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public BigDecimal getEquipementPrixByNom(String nom) {
|
||||
if (categorieEquipements == null || nom == null) return BigDecimal.ZERO;
|
||||
return categorieEquipements.stream()
|
||||
.filter(ce -> ce.getEquipement() != null && nom.equalsIgnoreCase(ce.getEquipement().getNom()))
|
||||
.findFirst()
|
||||
.map(CategorieEquipement::getPrix)
|
||||
.map(p -> p == null ? BigDecimal.ZERO : p)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public boolean isU11OrBelow() {
|
||||
if (nom == null) return false;
|
||||
String nomCat = nom.trim().toUpperCase();
|
||||
if (nomCat.startsWith("U")) {
|
||||
java.util.regex.Matcher m = java.util.regex.Pattern.compile("^U(\\d+)").matcher(nomCat);
|
||||
if (m.find()) {
|
||||
try {
|
||||
int age = Integer.parseInt(m.group(1));
|
||||
return age <= 11;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "categorie_equipement")
|
||||
public class CategorieEquipement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "categorie_id", nullable = false)
|
||||
private Categorie categorie;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "equipement_id", nullable = false)
|
||||
private Equipement equipement;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean obligatoire = false;
|
||||
|
||||
@Column(nullable = false, precision = 10, scale = 2)
|
||||
private java.math.BigDecimal prix = java.math.BigDecimal.ZERO;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public java.math.BigDecimal getPrix() { return prix; }
|
||||
public void setPrix(java.math.BigDecimal prix) { this.prix = prix; }
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public Categorie getCategorie() { return categorie; }
|
||||
public void setCategorie(Categorie categorie) { this.categorie = categorie; }
|
||||
|
||||
public Equipement getEquipement() { return equipement; }
|
||||
public void setEquipement(Equipement equipement) { this.equipement = equipement; }
|
||||
|
||||
public Boolean getObligatoire() { return obligatoire; }
|
||||
public void setObligatoire(Boolean obligatoire) { this.obligatoire = obligatoire; }
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Table(name = "creneau_entrainement")
|
||||
public class CreneauEntrainement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "categorie_id", nullable = false)
|
||||
private Categorie categorie;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "terrain_id", nullable = false)
|
||||
private Terrain terrain;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false)
|
||||
private ZoneTerrain zone;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "jour_semaine", nullable = false)
|
||||
private JourSemaine jourSemaine;
|
||||
|
||||
@Column(name = "heure_debut", nullable = false)
|
||||
private LocalTime heureDebut;
|
||||
|
||||
@Column(name = "heure_fin", nullable = false)
|
||||
private LocalTime heureFin;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "saison_id", nullable = false)
|
||||
private Saison saison;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "equipe_id")
|
||||
private Equipe equipe;
|
||||
|
||||
@Transient
|
||||
private boolean enConflit = false;
|
||||
|
||||
@Transient
|
||||
private Set<String> categoriesEnConflit = new HashSet<>();
|
||||
|
||||
@Transient
|
||||
private String initialesEducateurs = "";
|
||||
|
||||
// Logic for Gantt diagram grid placement
|
||||
|
||||
public int getStartColumn() {
|
||||
if (heureDebut == null) return 3;
|
||||
// Clip to working hours 08:00 to 22:00
|
||||
LocalTime time = heureDebut;
|
||||
if (time.isBefore(LocalTime.of(8, 0))) {
|
||||
time = LocalTime.of(8, 0);
|
||||
}
|
||||
long minutes = Duration.between(LocalTime.of(8, 0), time).toMinutes();
|
||||
return (int) (minutes / 15) + 3; // +3 because col 1 is Field name, col 2 is Zone name
|
||||
}
|
||||
|
||||
public int getEndColumn() {
|
||||
if (heureFin == null) return 3;
|
||||
LocalTime time = heureFin;
|
||||
if (time.isAfter(LocalTime.of(22, 0))) {
|
||||
time = LocalTime.of(22, 0);
|
||||
}
|
||||
long minutes = Duration.between(LocalTime.of(8, 0), time).toMinutes();
|
||||
return (int) (minutes / 15) + 3;
|
||||
}
|
||||
|
||||
public int getStartRow(int fieldIndex) {
|
||||
int baseRow = 3 + (fieldIndex * 5); // Row index matching HTML layout (base starts at 3, 5 rows per field)
|
||||
if (zone == null) return baseRow;
|
||||
return switch (zone) {
|
||||
case COMPLET, DEMI_A, QUART_1 -> baseRow;
|
||||
case QUART_2 -> baseRow + 1;
|
||||
case DEMI_B, QUART_3 -> baseRow + 2;
|
||||
case QUART_4 -> baseRow + 3;
|
||||
};
|
||||
}
|
||||
|
||||
public int getEndRow(int fieldIndex) {
|
||||
int baseRow = 3 + (fieldIndex * 5);
|
||||
if (zone == null) return baseRow + 4;
|
||||
return switch (zone) {
|
||||
case QUART_1 -> baseRow + 1;
|
||||
case DEMI_A, QUART_2 -> baseRow + 2;
|
||||
case QUART_3 -> baseRow + 3;
|
||||
case DEMI_B, QUART_4, COMPLET -> baseRow + 4;
|
||||
};
|
||||
}
|
||||
|
||||
// Overlap and conflict checking logic
|
||||
|
||||
public boolean overlapsWith(CreneauEntrainement other) {
|
||||
if (this.id != null && this.id.equals(other.id)) {
|
||||
return false; // same slot
|
||||
}
|
||||
if (this.jourSemaine != other.jourSemaine) {
|
||||
return false;
|
||||
}
|
||||
if (this.terrain == null || other.terrain == null || !Objects.equals(this.terrain.getId(), other.terrain.getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Time overlap check: start1 < end2 and start2 < end1
|
||||
boolean timeOverlap = this.heureDebut.isBefore(other.heureFin) && other.heureDebut.isBefore(this.heureFin);
|
||||
if (!timeOverlap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spatial overlap check
|
||||
if (this.zone == null || other.zone == null) {
|
||||
return false;
|
||||
}
|
||||
Set<Integer> q1 = this.zone.getQuarters();
|
||||
Set<Integer> q2 = other.zone.getQuarters();
|
||||
return !Collections.disjoint(q1, q2);
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Categorie getCategorie() {
|
||||
return categorie;
|
||||
}
|
||||
|
||||
public void setCategorie(Categorie categorie) {
|
||||
this.categorie = categorie;
|
||||
}
|
||||
|
||||
public Terrain getTerrain() {
|
||||
return terrain;
|
||||
}
|
||||
|
||||
public void setTerrain(Terrain terrain) {
|
||||
this.terrain = terrain;
|
||||
}
|
||||
|
||||
public ZoneTerrain getZone() {
|
||||
return zone;
|
||||
}
|
||||
|
||||
public void setZone(ZoneTerrain zone) {
|
||||
this.zone = zone;
|
||||
}
|
||||
|
||||
public JourSemaine getJourSemaine() {
|
||||
return jourSemaine;
|
||||
}
|
||||
|
||||
public void setJourSemaine(JourSemaine jourSemaine) {
|
||||
this.jourSemaine = jourSemaine;
|
||||
}
|
||||
|
||||
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 Saison getSaison() {
|
||||
return saison;
|
||||
}
|
||||
|
||||
public void setSaison(Saison saison) {
|
||||
this.saison = saison;
|
||||
}
|
||||
|
||||
public Equipe getEquipe() {
|
||||
return equipe;
|
||||
}
|
||||
|
||||
public void setEquipe(Equipe equipe) {
|
||||
this.equipe = equipe;
|
||||
}
|
||||
|
||||
public boolean isEnConflit() {
|
||||
return enConflit;
|
||||
}
|
||||
|
||||
public void setEnConflit(boolean enConflit) {
|
||||
this.enConflit = enConflit;
|
||||
}
|
||||
|
||||
public Set<String> getCategoriesEnConflit() {
|
||||
return categoriesEnConflit;
|
||||
}
|
||||
|
||||
public void setCategoriesEnConflit(Set<String> categoriesEnConflit) {
|
||||
this.categoriesEnConflit = categoriesEnConflit;
|
||||
}
|
||||
|
||||
public String getInitialesEducateurs() {
|
||||
return initialesEducateurs;
|
||||
}
|
||||
|
||||
public void setInitialesEducateurs(String initialesEducateurs) {
|
||||
this.initialesEducateurs = initialesEducateurs;
|
||||
}
|
||||
}
|
||||
@@ -18,15 +18,24 @@ public class Dotation {
|
||||
@JoinColumn(name = "equipement_id", nullable = false)
|
||||
private Equipement equipement;
|
||||
|
||||
@Column(length = 10)
|
||||
@Column(length = 50)
|
||||
private String taille;
|
||||
|
||||
@Column(length = 50)
|
||||
private String couleur;
|
||||
|
||||
@Column(length = 50)
|
||||
private String flocage;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean fourni = false;
|
||||
|
||||
@Column(length = 50)
|
||||
private String numero;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean choisi = false;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() { return id; }
|
||||
@@ -41,9 +50,121 @@ public class Dotation {
|
||||
public String getTaille() { return taille; }
|
||||
public void setTaille(String taille) { this.taille = taille; }
|
||||
|
||||
public String getCouleur() { return couleur; }
|
||||
public void setCouleur(String couleur) { this.couleur = couleur; }
|
||||
|
||||
public String getFlocage() { return flocage; }
|
||||
public void setFlocage(String flocage) { this.flocage = flocage; }
|
||||
|
||||
public Boolean getFourni() { return fourni; }
|
||||
public void setFourni(Boolean fourni) { this.fourni = fourni; }
|
||||
|
||||
public String getNumero() { return numero; }
|
||||
public void setNumero(String numero) { this.numero = numero; }
|
||||
|
||||
public Boolean getChoisi() { return choisi; }
|
||||
public void setChoisi(Boolean choisi) { this.choisi = choisi; }
|
||||
|
||||
public static boolean isSizeMatch(String option, String adherentSize) {
|
||||
if (option == null || adherentSize == null) return false;
|
||||
String opt = option.trim();
|
||||
String adh = adherentSize.trim();
|
||||
if (opt.isEmpty() || adh.isEmpty()) return false;
|
||||
|
||||
if (opt.equalsIgnoreCase(adh)) return true;
|
||||
|
||||
String optNorm = opt.toLowerCase().replaceAll("\\s+", " ");
|
||||
String adhNorm = adh.toLowerCase().replaceAll("\\s+", " ");
|
||||
|
||||
if (optNorm.equals(adhNorm)) return true;
|
||||
|
||||
// 1. Age bracket matching: 5/6, 7/8, 9/10, 11/12, 13/14, 15/16
|
||||
java.util.regex.Pattern agePattern = java.util.regex.Pattern.compile("(?<!\\d)(5[/\\-]6|7[/\\-]8|9[/\\-]10|11[/\\-]12|13[/\\-]14|15[/\\-]16)(?!\\d)");
|
||||
java.util.regex.Matcher adhAgeMatcher = agePattern.matcher(adhNorm);
|
||||
java.util.regex.Matcher optAgeMatcher = agePattern.matcher(optNorm);
|
||||
boolean adhHasAge = adhAgeMatcher.find();
|
||||
boolean optHasAge = optAgeMatcher.find();
|
||||
|
||||
if (adhHasAge && optHasAge) {
|
||||
String adhAgeKey = adhAgeMatcher.group(1).replace("-", "/");
|
||||
String optAgeKey = optAgeMatcher.group(1).replace("-", "/");
|
||||
return adhAgeKey.equals(optAgeKey);
|
||||
} else if (adhHasAge) {
|
||||
String ageKey = adhAgeMatcher.group(1).replace("-", "/");
|
||||
String altAgeKey = ageKey.replace("/", "-");
|
||||
if (optNorm.contains(ageKey) || optNorm.contains(altAgeKey)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Height matching (3-digit numbers in cm, e.g. 115, 116, 126, 128, 138, 140, 150, 152, 162, 164, 176)
|
||||
java.util.regex.Pattern heightPattern = java.util.regex.Pattern.compile("(?<!\\d)(115|116|126|128|138|140|150|152|162|164|176)(?!\\d)");
|
||||
java.util.regex.Matcher adhHeightMatcher = heightPattern.matcher(adhNorm);
|
||||
java.util.regex.Matcher optHeightMatcher = heightPattern.matcher(optNorm);
|
||||
boolean adhHasHeight = adhHeightMatcher.find();
|
||||
boolean optHasHeight = optHeightMatcher.find();
|
||||
|
||||
if (adhHasHeight && optHasHeight) {
|
||||
int adhH = Integer.parseInt(adhHeightMatcher.group(1));
|
||||
int optH = Integer.parseInt(optHeightMatcher.group(1));
|
||||
return Math.abs(adhH - optH) <= 5;
|
||||
}
|
||||
|
||||
// 3. Shoe size / pointure matching: 27/30, 31/34, 35/38, 39/42, 43/46
|
||||
java.util.regex.Pattern shoePattern = java.util.regex.Pattern.compile("(?<!\\d)(27[/\\-]30|31[/\\-]34|35[/\\-]38|39[/\\-]42|43[/\\-]46)(?!\\d)");
|
||||
java.util.regex.Matcher adhShoeMatcher = shoePattern.matcher(adhNorm);
|
||||
java.util.regex.Matcher optShoeMatcher = shoePattern.matcher(optNorm);
|
||||
boolean adhHasShoe = adhShoeMatcher.find();
|
||||
boolean optHasShoe = optShoeMatcher.find();
|
||||
|
||||
if (adhHasShoe && optHasShoe) {
|
||||
String adhShoeKey = adhShoeMatcher.group(1).replace("-", "/");
|
||||
String optShoeKey = optShoeMatcher.group(1).replace("-", "/");
|
||||
return adhShoeKey.equals(optShoeKey);
|
||||
}
|
||||
|
||||
// 4. Sock size tag matching: "taille 0", "taille 1", "taille 2", "taille 3", "taille 4"
|
||||
java.util.regex.Pattern tNumPattern = java.util.regex.Pattern.compile("(?<![a-z0-9])taille\\s*([0-4])(?![0-9])");
|
||||
java.util.regex.Matcher adhTNumMatcher = tNumPattern.matcher(adhNorm);
|
||||
java.util.regex.Matcher optTNumMatcher = tNumPattern.matcher(optNorm);
|
||||
boolean adhHasTNum = adhTNumMatcher.find();
|
||||
boolean optHasTNum = optTNumMatcher.find();
|
||||
|
||||
if (adhHasTNum && optHasTNum) {
|
||||
return adhTNumMatcher.group(1).equals(optTNumMatcher.group(1));
|
||||
}
|
||||
|
||||
// 5. Letter size matching: XXL, XL, L, M, S, XS
|
||||
java.util.regex.Pattern letterPattern = java.util.regex.Pattern.compile("(?<![a-z0-9])(xxl|xl|l|m|s|xs)(?![a-z0-9])");
|
||||
java.util.regex.Matcher adhLetterMatcher = letterPattern.matcher(adhNorm);
|
||||
java.util.regex.Matcher optLetterMatcher = letterPattern.matcher(optNorm);
|
||||
boolean adhHasLetter = adhLetterMatcher.find();
|
||||
boolean optHasLetter = optLetterMatcher.find();
|
||||
|
||||
if (adhHasLetter && optHasLetter) {
|
||||
return adhLetterMatcher.group(1).equals(optLetterMatcher.group(1));
|
||||
}
|
||||
|
||||
// Substring fallback only if neither age, height, shoe, tag, nor letter pattern were present
|
||||
if (!adhHasAge && !optHasAge && !adhHasHeight && !optHasHeight && !adhHasShoe && !optHasShoe && !adhHasTNum && !optHasTNum && !adhHasLetter && !optHasLetter) {
|
||||
if (optNorm.length() >= 2 && adhNorm.contains(optNorm)) return true;
|
||||
if (adhNorm.length() >= 2 && optNorm.contains(adhNorm)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTailleOptionSelected(String option) {
|
||||
if (option == null) return false;
|
||||
String trimmedOpt = option.trim();
|
||||
if (this.taille != null && !this.taille.trim().isEmpty()) {
|
||||
return this.taille.trim().equalsIgnoreCase(trimmedOpt);
|
||||
}
|
||||
if (this.licence == null || this.licence.getAdherent() == null) {
|
||||
return false;
|
||||
}
|
||||
Adherent adherent = this.licence.getAdherent();
|
||||
return isSizeMatch(trimmedOpt, adherent.getTailleVetement()) || isSizeMatch(trimmedOpt, adherent.getPointure());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "educateur")
|
||||
public class Educateur {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String nom;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String prenom;
|
||||
|
||||
@Column(length = 100)
|
||||
private String email;
|
||||
|
||||
@Column(length = 20)
|
||||
private String telephone;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "categorie_id")
|
||||
private Categorie categorie;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "equipe_id")
|
||||
private Equipe equipe;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
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 Categorie getCategorie() { return categorie; }
|
||||
public void setCategorie(Categorie categorie) { this.categorie = categorie; }
|
||||
|
||||
public Equipe getEquipe() { return equipe; }
|
||||
public void setEquipe(Equipe equipe) { this.equipe = equipe; }
|
||||
|
||||
public String getInitiales() {
|
||||
String p = (prenom != null && !prenom.isEmpty()) ? prenom.substring(0, 1).toUpperCase() : "";
|
||||
String n = (nom != null && !nom.isEmpty()) ? nom.substring(0, 1).toUpperCase() : "";
|
||||
return p + n;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name = "equipe")
|
||||
public class Equipe {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String nom;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "categorie_id", nullable = false)
|
||||
private Categorie categorie;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "saison_id", nullable = false)
|
||||
private Saison saison;
|
||||
|
||||
// Constructors
|
||||
public Equipe() {}
|
||||
|
||||
public Equipe(String nom, Categorie categorie, Saison saison) {
|
||||
this.nom = nom;
|
||||
this.categorie = categorie;
|
||||
this.saison = saison;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
|
||||
public Categorie getCategorie() { return categorie; }
|
||||
public void setCategorie(Categorie categorie) { this.categorie = categorie; }
|
||||
|
||||
public Saison getSaison() { return saison; }
|
||||
public void setSaison(Saison saison) { this.saison = saison; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Equipe equipe = (Equipe) o;
|
||||
return Objects.equals(id, equipe.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "equipement")
|
||||
@@ -13,11 +14,37 @@ public class Equipement {
|
||||
@Column(nullable = false, length = 100)
|
||||
private String nom;
|
||||
|
||||
@Column(length = 100)
|
||||
private String reference;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean obligatoire = false;
|
||||
@Column(name = "gestion_sexe", nullable = false)
|
||||
private boolean gestionSexe = false;
|
||||
|
||||
@Column(name = "type_public", nullable = false, length = 20)
|
||||
private String typePublic = "TOUS"; // JOUEUR, GARDIEN, TOUS
|
||||
|
||||
@Column(name = "tailles_disponibles", length = 500)
|
||||
private String taillesDisponibles;
|
||||
|
||||
@Column(name = "couleurs_disponibles", length = 500)
|
||||
private String couleursDisponibles;
|
||||
|
||||
|
||||
@Column(name = "has_flocage_prenom", nullable = false)
|
||||
private boolean hasFlocagePrenom = false;
|
||||
|
||||
@Column(name = "has_flocage_initiales", nullable = false)
|
||||
private boolean hasFlocageInitiales = false;
|
||||
|
||||
@Column(name = "has_flocage_numero", nullable = false)
|
||||
private boolean hasFlocageNumero = false;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "saison_id", nullable = false)
|
||||
private Saison saison;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
@@ -27,9 +54,33 @@ public class Equipement {
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
|
||||
public String getReference() { return reference; }
|
||||
public void setReference(String reference) { this.reference = reference; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public Boolean getObligatoire() { return obligatoire; }
|
||||
public void setObligatoire(Boolean obligatoire) { this.obligatoire = obligatoire; }
|
||||
public boolean isGestionSexe() { return gestionSexe; }
|
||||
public void setGestionSexe(boolean gestionSexe) { this.gestionSexe = gestionSexe; }
|
||||
|
||||
public String getTypePublic() { return typePublic; }
|
||||
public void setTypePublic(String typePublic) { this.typePublic = typePublic; }
|
||||
|
||||
public String getTaillesDisponibles() { return taillesDisponibles; }
|
||||
public void setTaillesDisponibles(String taillesDisponibles) { this.taillesDisponibles = taillesDisponibles; }
|
||||
|
||||
public String getCouleursDisponibles() { return couleursDisponibles; }
|
||||
public void setCouleursDisponibles(String couleursDisponibles) { this.couleursDisponibles = couleursDisponibles; }
|
||||
|
||||
public boolean isHasFlocagePrenom() { return hasFlocagePrenom; }
|
||||
public void setHasFlocagePrenom(boolean hasFlocagePrenom) { this.hasFlocagePrenom = hasFlocagePrenom; }
|
||||
|
||||
public boolean isHasFlocageInitiales() { return hasFlocageInitiales; }
|
||||
public void setHasFlocageInitiales(boolean hasFlocageInitiales) { this.hasFlocageInitiales = hasFlocageInitiales; }
|
||||
|
||||
public boolean isHasFlocageNumero() { return hasFlocageNumero; }
|
||||
public void setHasFlocageNumero(boolean hasFlocageNumero) { this.hasFlocageNumero = hasFlocageNumero; }
|
||||
|
||||
public Saison getSaison() { return saison; }
|
||||
public void setSaison(Saison saison) { this.saison = saison; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
public enum JourSemaine {
|
||||
LUNDI("Lundi"),
|
||||
MARDI("Mardi"),
|
||||
MERCREDI("Mercredi"),
|
||||
JEUDI("Jeudi"),
|
||||
VENDREDI("Vendredi"),
|
||||
SAMEDI("Samedi"),
|
||||
DIMANCHE("Dimanche");
|
||||
|
||||
private final String libelle;
|
||||
|
||||
JourSemaine(String libelle) {
|
||||
this.libelle = libelle;
|
||||
}
|
||||
|
||||
public String getLibelle() {
|
||||
return libelle;
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,13 @@ public class Licence {
|
||||
@JoinColumn(name = "categorie_id", nullable = false)
|
||||
private Categorie categorie;
|
||||
|
||||
@Column(nullable = false, length = 20)
|
||||
private String saison;
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "saison_id", nullable = false)
|
||||
private Saison saison;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "equipe_id")
|
||||
private Equipe equipe;
|
||||
|
||||
@Column(nullable = false, length = 50)
|
||||
private String etat;
|
||||
@@ -30,15 +35,24 @@ public class Licence {
|
||||
@Column(name = "numero_licence", length = 50)
|
||||
private String numeroLicence;
|
||||
|
||||
@Column(name = "type_demande", length = 50)
|
||||
private String typeDemande;
|
||||
|
||||
@Column(name = "type_licence", length = 50)
|
||||
private String typeLicence;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String commentaire;
|
||||
|
||||
@OneToMany(mappedBy = "licence", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<Paiement> paiements = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "licence", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<Dotation> dotations = new ArrayList<>();
|
||||
|
||||
// Logic for Reste A Payer
|
||||
// Logic for Global Total Price
|
||||
@Transient
|
||||
public BigDecimal getResteAPayer() {
|
||||
public BigDecimal getPrixTotal() {
|
||||
if (categorie == null) return BigDecimal.ZERO;
|
||||
|
||||
BigDecimal prixTotal = (adherent != null && adherent.isResidentTalange())
|
||||
@@ -47,6 +61,25 @@ public class Licence {
|
||||
|
||||
if (prixTotal == null) prixTotal = BigDecimal.ZERO;
|
||||
|
||||
if (dotations != null) {
|
||||
for (Dotation dot : dotations) {
|
||||
if (dot.getChoisi() && dot.getEquipement() != null) {
|
||||
BigDecimal price = categorie.getEquipementPrix(dot.getEquipement().getId());
|
||||
if (price != null) {
|
||||
prixTotal = prixTotal.add(price);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prixTotal;
|
||||
}
|
||||
|
||||
// Logic for Reste A Payer
|
||||
@Transient
|
||||
public BigDecimal getResteAPayer() {
|
||||
BigDecimal prixTotal = getPrixTotal();
|
||||
|
||||
if (paiements == null || paiements.isEmpty()) {
|
||||
return prixTotal;
|
||||
}
|
||||
@@ -59,6 +92,16 @@ public class Licence {
|
||||
return reste.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : reste;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public BigDecimal getSommePayee() {
|
||||
if (paiements == null || paiements.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return paiements.stream()
|
||||
.map(Paiement::getMontant)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() { return id; }
|
||||
@@ -70,21 +113,33 @@ public class Licence {
|
||||
public Categorie getCategorie() { return categorie; }
|
||||
public void setCategorie(Categorie categorie) { this.categorie = categorie; }
|
||||
|
||||
public String getSaison() { return saison; }
|
||||
public void setSaison(String saison) { this.saison = saison; }
|
||||
public Saison getSaison() { return saison; }
|
||||
public void setSaison(Saison saison) { this.saison = saison; }
|
||||
|
||||
public Equipe getEquipe() { return equipe; }
|
||||
public void setEquipe(Equipe equipe) { this.equipe = equipe; }
|
||||
|
||||
public String getEtat() { return etat; }
|
||||
public void setEtat(String etat) { this.etat = etat; }
|
||||
|
||||
public String getNumeroLicence() { return numeroLicence; }
|
||||
public void setNumeroLicence(String numeroLicence) { this.numeroLicence = numeroLicence; }
|
||||
|
||||
public String getTypeDemande() { return typeDemande; }
|
||||
public void setTypeDemande(String typeDemande) { this.typeDemande = typeDemande; }
|
||||
|
||||
public String getTypeLicence() { return typeLicence; }
|
||||
public void setTypeLicence(String typeLicence) { this.typeLicence = typeLicence; }
|
||||
|
||||
public String getCommentaire() { return commentaire; }
|
||||
public void setCommentaire(String commentaire) { this.commentaire = commentaire; }
|
||||
|
||||
public List<Paiement> getPaiements() { return paiements; }
|
||||
public void setPaiements(List<Paiement> paiements) { this.paiements = paiements; }
|
||||
|
||||
public List<Dotation> getDotations() { return dotations; }
|
||||
public void setDotations(List<Dotation> dotations) { this.dotations = dotations; }
|
||||
|
||||
public String getNumeroLicence() { return numeroLicence; }
|
||||
public void setNumeroLicence(String numeroLicence) { this.numeroLicence = numeroLicence; }
|
||||
|
||||
public void addPaiement(Paiement paiement) {
|
||||
paiements.add(paiement);
|
||||
paiement.setLicence(this);
|
||||
|
||||
@@ -26,6 +26,15 @@ public class Paiement {
|
||||
@JoinColumn(name = "mode_paiement_id", nullable = false)
|
||||
private ModePaiement modePaiement;
|
||||
|
||||
@Column(name = "gestionnaire")
|
||||
private String gestionnaire;
|
||||
|
||||
@Column(name = "numero_cheque", length = 50)
|
||||
private String numeroCheque;
|
||||
|
||||
@Column(name = "commentaire", columnDefinition = "TEXT")
|
||||
private String commentaire;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() { return id; }
|
||||
@@ -42,4 +51,13 @@ public class Paiement {
|
||||
|
||||
public ModePaiement getModePaiement() { return modePaiement; }
|
||||
public void setModePaiement(ModePaiement modePaiement) { this.modePaiement = modePaiement; }
|
||||
|
||||
public String getGestionnaire() { return gestionnaire; }
|
||||
public void setGestionnaire(String gestionnaire) { this.gestionnaire = gestionnaire; }
|
||||
|
||||
public String getNumeroCheque() { return numeroCheque; }
|
||||
public void setNumeroCheque(String numeroCheque) { this.numeroCheque = numeroCheque; }
|
||||
|
||||
public String getCommentaire() { return commentaire; }
|
||||
public void setCommentaire(String commentaire) { this.commentaire = commentaire; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "pre_inscription")
|
||||
public class PreInscription {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String nom;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String prenom;
|
||||
|
||||
@Column(nullable = false, length = 10)
|
||||
private String sexe;
|
||||
|
||||
@Column(name = "date_naissance", nullable = false)
|
||||
private LocalDate dateNaissance;
|
||||
|
||||
@Column(name = "lieu_naissance_ville", nullable = false, length = 100)
|
||||
private String lieuNaissanceVille;
|
||||
|
||||
@Column(name = "lieu_naissance_pays", nullable = false, length = 100)
|
||||
private String lieuNaissancePays;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String nationalite;
|
||||
|
||||
@Column(nullable = false, length = 150)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false, length = 20)
|
||||
private String telephone;
|
||||
|
||||
@Column(name = "representant_legal", length = 150)
|
||||
private String representantLegal;
|
||||
|
||||
@Column(name = "statut_traite", nullable = false)
|
||||
private Boolean statutTraite = false;
|
||||
|
||||
@Column(name = "date_creation", nullable = false)
|
||||
private LocalDateTime dateCreation = LocalDateTime.now();
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "saison_id", nullable = false)
|
||||
private Saison saison;
|
||||
|
||||
@Column(name = "consentement_rgpd", nullable = false)
|
||||
private Boolean consentementRgpd = false;
|
||||
|
||||
@Column(name = "type_demande", nullable = false, length = 50)
|
||||
private String typeDemande = "NOUVELLE";
|
||||
|
||||
@Column(name = "ancien_club", length = 150)
|
||||
private String ancienClub;
|
||||
|
||||
@Column(name = "ancienne_categorie", length = 50)
|
||||
private String ancienneCategorie = "NA";
|
||||
|
||||
@Column(name = "raison_changement_club")
|
||||
private String raisonChangementClub;
|
||||
|
||||
@Column(name = "comment_connu_club")
|
||||
private String commentConnuClub;
|
||||
|
||||
@Column(name = "taille_vetement", length = 50)
|
||||
private String tailleVetement;
|
||||
|
||||
@Column(length = 50)
|
||||
private String pointure;
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
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 getSexe() { return sexe; }
|
||||
public void setSexe(String sexe) { this.sexe = sexe; }
|
||||
|
||||
public LocalDate getDateNaissance() { return dateNaissance; }
|
||||
public void setDateNaissance(LocalDate dateNaissance) { this.dateNaissance = dateNaissance; }
|
||||
|
||||
public String getLieuNaissanceVille() { return lieuNaissanceVille; }
|
||||
public void setLieuNaissanceVille(String lieuNaissanceVille) { this.lieuNaissanceVille = lieuNaissanceVille; }
|
||||
|
||||
public String getLieuNaissancePays() { return lieuNaissancePays; }
|
||||
public void setLieuNaissancePays(String lieuNaissancePays) { this.lieuNaissancePays = lieuNaissancePays; }
|
||||
|
||||
public String getNationalite() { return nationalite; }
|
||||
public void setNationalite(String nationalite) { this.nationalite = nationalite; }
|
||||
|
||||
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 String getRepresentantLegal() { return representantLegal; }
|
||||
public void setRepresentantLegal(String representantLegal) { this.representantLegal = representantLegal; }
|
||||
|
||||
public Boolean getStatutTraite() { return statutTraite; }
|
||||
public void setStatutTraite(Boolean statutTraite) { this.statutTraite = statutTraite; }
|
||||
|
||||
public LocalDateTime getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public Saison getSaison() { return saison; }
|
||||
public void setSaison(Saison saison) { this.saison = saison; }
|
||||
|
||||
public Boolean getConsentementRgpd() { return consentementRgpd; }
|
||||
public void setConsentementRgpd(Boolean consentementRgpd) { this.consentementRgpd = consentementRgpd; }
|
||||
|
||||
public String getTypeDemande() { return typeDemande; }
|
||||
public void setTypeDemande(String typeDemande) { this.typeDemande = typeDemande; }
|
||||
|
||||
public String getAncienClub() { return ancienClub; }
|
||||
public void setAncienClub(String ancienClub) { this.ancienClub = ancienClub; }
|
||||
|
||||
public String getAncienneCategorie() { return ancienneCategorie; }
|
||||
public void setAncienneCategorie(String ancienneCategorie) { this.ancienneCategorie = ancienneCategorie; }
|
||||
|
||||
public String getRaisonChangementClub() { return raisonChangementClub; }
|
||||
public void setRaisonChangementClub(String raisonChangementClub) { this.raisonChangementClub = raisonChangementClub; }
|
||||
|
||||
public String getCommentConnuClub() { return commentConnuClub; }
|
||||
public void setCommentConnuClub(String commentConnuClub) { this.commentConnuClub = commentConnuClub; }
|
||||
|
||||
public String getTailleVetement() { return tailleVetement; }
|
||||
public void setTailleVetement(String tailleVetement) { this.tailleVetement = tailleVetement; }
|
||||
|
||||
public String getPointure() { return pointure; }
|
||||
public void setPointure(String pointure) { this.pointure = pointure; }
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name = "saison")
|
||||
public class Saison {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String nom;
|
||||
|
||||
@Column(name = "est_active", nullable = false)
|
||||
private Boolean estActive = false;
|
||||
|
||||
@Column(name = "inscriptions_ouvertes", nullable = false)
|
||||
private Boolean inscriptionsOuvertes = false;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getNom() {
|
||||
return nom;
|
||||
}
|
||||
|
||||
public void setNom(String nom) {
|
||||
this.nom = nom;
|
||||
}
|
||||
|
||||
public Boolean getEstActive() {
|
||||
return estActive;
|
||||
}
|
||||
|
||||
public void setEstActive(Boolean estActive) {
|
||||
this.estActive = estActive;
|
||||
}
|
||||
|
||||
public Boolean getInscriptionsOuvertes() {
|
||||
return inscriptionsOuvertes != null ? inscriptionsOuvertes : false;
|
||||
}
|
||||
|
||||
public void setInscriptionsOuvertes(Boolean inscriptionsOuvertes) {
|
||||
this.inscriptionsOuvertes = inscriptionsOuvertes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Saison saison = (Saison) o;
|
||||
return Objects.equals(id, saison.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "terrain")
|
||||
public class Terrain {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String nom;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getNom() {
|
||||
return nom;
|
||||
}
|
||||
|
||||
public void setNom(String nom) {
|
||||
this.nom = nom;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "token_pre_inscription")
|
||||
public class TokenPreInscription {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "valeur_uuid", nullable = false, unique = true, length = 36)
|
||||
private String valeurUuid;
|
||||
|
||||
@Column(name = "date_expiration", nullable = false)
|
||||
private LocalDateTime dateExpiration;
|
||||
|
||||
@Column(name = "est_utilise", nullable = false)
|
||||
private Boolean estUtilise = false;
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public String getValeurUuid() { return valeurUuid; }
|
||||
public void setValeurUuid(String valeurUuid) { this.valeurUuid = valeurUuid; }
|
||||
|
||||
public LocalDateTime getDateExpiration() { return dateExpiration; }
|
||||
public void setDateExpiration(LocalDateTime dateExpiration) { this.dateExpiration = dateExpiration; }
|
||||
|
||||
public Boolean getEstUtilise() { return estUtilise; }
|
||||
public void setEstUtilise(Boolean estUtilise) { this.estUtilise = estUtilise; }
|
||||
|
||||
@Transient
|
||||
public boolean isValide() {
|
||||
return !estUtilise && dateExpiration.isAfter(LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.astalange.core.entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public enum ZoneTerrain {
|
||||
COMPLET("Terrain Complet", Set.of(1, 2, 3, 4)),
|
||||
DEMI_A("Demi-terrain A", Set.of(1, 2)),
|
||||
DEMI_B("Demi-terrain B", Set.of(3, 4)),
|
||||
QUART_1("Quart 1", Set.of(1)),
|
||||
QUART_2("Quart 2", Set.of(2)),
|
||||
QUART_3("Quart 3", Set.of(3)),
|
||||
QUART_4("Quart 4", Set.of(4));
|
||||
|
||||
private final String libelle;
|
||||
private final Set<Integer> quarters;
|
||||
|
||||
ZoneTerrain(String libelle, Set<Integer> quarters) {
|
||||
this.libelle = libelle;
|
||||
this.quarters = quarters;
|
||||
}
|
||||
|
||||
public String getLibelle() {
|
||||
return libelle;
|
||||
}
|
||||
|
||||
public Set<Integer> getQuarters() {
|
||||
return quarters;
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,10 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface AdherentRepository extends JpaRepository<Adherent, Long> {
|
||||
List<Adherent> findTop5ByOrderByIdDesc();
|
||||
|
||||
@org.springframework.data.jpa.repository.Query("SELECT DISTINCT a FROM Adherent a LEFT JOIN FETCH a.licences l LEFT JOIN FETCH l.categorie c")
|
||||
List<Adherent> findAllWithLicencesAndCategories();
|
||||
|
||||
@org.springframework.data.jpa.repository.Query("SELECT DISTINCT a FROM Adherent a LEFT JOIN a.licences l WHERE LOWER(a.nom) LIKE LOWER(CONCAT('%', :query, '%')) OR LOWER(a.prenom) LIKE LOWER(CONCAT('%', :query, '%')) OR LOWER(l.numeroLicence) LIKE LOWER(CONCAT('%', :query, '%'))")
|
||||
List<Adherent> searchByQuery(@org.springframework.data.repository.query.Param("query") String query);
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.AuditLogPaiement;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
@Repository
|
||||
public interface AuditLogPaiementRepository extends JpaRepository<AuditLogPaiement, Long> {
|
||||
List<AuditLogPaiement> findAllByOrderByDateActionDesc();
|
||||
|
||||
@Query("SELECT a FROM AuditLogPaiement a WHERE " +
|
||||
"(:action IS NULL OR :action = '' OR a.action = :action) AND " +
|
||||
"(:utilisateur IS NULL OR :utilisateur = '' OR LOWER(a.utilisateur) LIKE LOWER(CONCAT('%', :utilisateur, '%'))) AND " +
|
||||
"(:adherent IS NULL OR :adherent = '' OR LOWER(a.adherentNomComplet) LIKE LOWER(CONCAT('%', :adherent, '%'))) " +
|
||||
"ORDER BY a.dateAction DESC")
|
||||
List<AuditLogPaiement> findByFilters(
|
||||
@Param("action") String action,
|
||||
@Param("utilisateur") String utilisateur,
|
||||
@Param("adherent") String adherent
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,16 @@ import com.astalange.core.entity.Categorie;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.astalange.core.entity.Saison;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
@Repository
|
||||
public interface CategorieRepository extends JpaRepository<Categorie, Long> {
|
||||
List<Categorie> findBySaison(Saison saison);
|
||||
|
||||
@Query("SELECT c FROM Categorie c WHERE c.saison = :saison AND :annee BETWEEN c.anneeMin AND c.anneeMax")
|
||||
List<Categorie> findBySaisonAndAnnee(@Param("saison") Saison saison, @Param("annee") Integer annee);
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.CreneauEntrainement;
|
||||
import com.astalange.core.entity.JourSemaine;
|
||||
import com.astalange.core.entity.Saison;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface CreneauEntrainementRepository extends JpaRepository<CreneauEntrainement, Long> {
|
||||
|
||||
@Query("SELECT c FROM CreneauEntrainement c JOIN FETCH c.categorie JOIN FETCH c.terrain WHERE c.saison = :saison")
|
||||
List<CreneauEntrainement> findBySaisonFetch(@Param("saison") Saison saison);
|
||||
|
||||
@Query("SELECT c FROM CreneauEntrainement c JOIN FETCH c.categorie JOIN FETCH c.terrain WHERE c.saison = :saison AND c.jourSemaine = :jourSemaine")
|
||||
List<CreneauEntrainement> findBySaisonAndJourSemaineFetch(@Param("saison") Saison saison, @Param("jourSemaine") JourSemaine jourSemaine);
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.Dotation;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import com.astalange.core.entity.Saison;
|
||||
|
||||
@Repository
|
||||
public interface DotationRepository extends JpaRepository<Dotation, Long> {
|
||||
public interface DotationRepository extends JpaRepository<Dotation, Long>, JpaSpecificationExecutor<Dotation> {
|
||||
List<Dotation> findByLicence_SaisonAndChoisiTrueAndFourniFalse(Saison saison);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.Educateur;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface EducateurRepository extends JpaRepository<Educateur, Long> {
|
||||
|
||||
@Query("SELECT e FROM Educateur e LEFT JOIN FETCH e.categorie LEFT JOIN FETCH e.equipe")
|
||||
List<Educateur> findAllWithCategorieAndEquipe();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.Equipe;
|
||||
import com.astalange.core.entity.Saison;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface EquipeRepository extends JpaRepository<Equipe, Long> {
|
||||
List<Equipe> findByCategorieId(Long categorieId);
|
||||
|
||||
@Query("SELECT e FROM Equipe e JOIN FETCH e.categorie WHERE e.saison = :saison")
|
||||
List<Equipe> findBySaison(Saison saison);
|
||||
|
||||
@Query("SELECT e FROM Equipe e JOIN FETCH e.categorie")
|
||||
List<Equipe> findAllWithCategorie();
|
||||
}
|
||||
@@ -4,6 +4,10 @@ import com.astalange.core.entity.Equipement;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.astalange.core.entity.Saison;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface EquipementRepository extends JpaRepository<Equipement, Long> {
|
||||
List<Equipement> findBySaison(Saison saison);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,14 @@ import org.springframework.stereotype.Repository;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
@Repository
|
||||
public interface LicenceRepository extends JpaRepository<Licence, Long> {
|
||||
public interface LicenceRepository extends JpaRepository<Licence, Long>, JpaSpecificationExecutor<Licence> {
|
||||
List<Licence> findByAdherentId(Long adherentId);
|
||||
|
||||
List<Licence> findBySaisonAndCategorie(com.astalange.core.entity.Saison saison, com.astalange.core.entity.Categorie categorie);
|
||||
|
||||
long countByEtat(String etat);
|
||||
|
||||
@Query("SELECT SUM(c.tarifBase) FROM Licence l JOIN l.categorie c")
|
||||
|
||||
@@ -11,4 +11,12 @@ public interface PaiementRepository extends JpaRepository<Paiement, Long> {
|
||||
|
||||
@Query("SELECT SUM(p.montant) FROM Paiement p")
|
||||
BigDecimal sumMontant();
|
||||
|
||||
@Query("SELECT p FROM Paiement p " +
|
||||
"LEFT JOIN FETCH p.licence l " +
|
||||
"LEFT JOIN FETCH l.adherent a " +
|
||||
"LEFT JOIN FETCH l.categorie c " +
|
||||
"LEFT JOIN FETCH p.modePaiement m " +
|
||||
"ORDER BY p.datePaiement DESC, p.id DESC")
|
||||
java.util.List<Paiement> findAllWithAssociations();
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.PreInscription;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface PreInscriptionRepository extends JpaRepository<PreInscription, Long> {
|
||||
List<PreInscription> findByStatutTraiteFalseOrderByDateCreationDesc();
|
||||
long countByStatutTraiteFalse();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.Role;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface RoleRepository extends JpaRepository<Role, Long> {
|
||||
Optional<Role> findByName(String name);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.Saison;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface SaisonRepository extends JpaRepository<Saison, Long> {
|
||||
Optional<Saison> findByEstActiveTrue();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.Terrain;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface TerrainRepository extends JpaRepository<Terrain, Long> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.astalange.core.repository;
|
||||
|
||||
import com.astalange.core.entity.TokenPreInscription;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface TokenPreInscriptionRepository extends JpaRepository<TokenPreInscription, Long> {
|
||||
Optional<TokenPreInscription> findByValeurUuid(String valeurUuid);
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.astalange.core.security;
|
||||
|
||||
import com.astalange.core.entity.AppUser;
|
||||
import com.astalange.core.repository.AppUserRepository;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||
import org.springframework.security.authentication.event.LogoutSuccessEvent;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.web.session.HttpSessionDestroyedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class AuthenticationEventListener {
|
||||
|
||||
private final AppUserRepository userRepository;
|
||||
|
||||
public AuthenticationEventListener(AppUserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@EventListener
|
||||
@Transactional
|
||||
public void onAuthenticationSuccess(AuthenticationSuccessEvent event) {
|
||||
String username = extractUsername(event.getAuthentication().getPrincipal());
|
||||
if (username != null) {
|
||||
userRepository.findByUsername(username).ifPresent(user -> {
|
||||
user.setLastLoginAt(LocalDateTime.now());
|
||||
userRepository.save(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
@Transactional
|
||||
public void onLogoutSuccess(LogoutSuccessEvent event) {
|
||||
if (event.getAuthentication() != null) {
|
||||
String username = extractUsername(event.getAuthentication().getPrincipal());
|
||||
if (username != null) {
|
||||
userRepository.findByUsername(username).ifPresent(user -> {
|
||||
user.setLastLogoutAt(LocalDateTime.now());
|
||||
userRepository.save(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
@Transactional
|
||||
public void onSessionDestroyed(HttpSessionDestroyedEvent event) {
|
||||
List<SecurityContext> contexts = event.getSecurityContexts();
|
||||
for (SecurityContext context : contexts) {
|
||||
if (context != null && context.getAuthentication() != null) {
|
||||
String username = extractUsername(context.getAuthentication().getPrincipal());
|
||||
if (username != null) {
|
||||
userRepository.findByUsername(username).ifPresent(user -> {
|
||||
if (user.getLastLogoutAt() == null || (user.getLastLoginAt() != null && user.getLastLogoutAt().isBefore(user.getLastLoginAt()))) {
|
||||
user.setLastLogoutAt(LocalDateTime.now());
|
||||
userRepository.save(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String extractUsername(Object principal) {
|
||||
if (principal instanceof UserDetails) {
|
||||
return ((UserDetails) principal).getUsername();
|
||||
} else if (principal instanceof String) {
|
||||
return (String) principal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.astalange.core.security;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CustomUserDetails extends User {
|
||||
private final Long id;
|
||||
private final boolean mustChangePassword;
|
||||
|
||||
public CustomUserDetails(Long id, String username, String password, boolean enabled, boolean mustChangePassword,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, enabled, true, true, true, authorities);
|
||||
this.id = id;
|
||||
this.mustChangePassword = mustChangePassword;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isMustChangePassword() {
|
||||
return mustChangePassword;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -25,11 +25,12 @@ public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
AppUser appUser = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
|
||||
return new User(
|
||||
return new CustomUserDetails(
|
||||
appUser.getId(),
|
||||
appUser.getUsername(),
|
||||
appUser.getPassword(),
|
||||
appUser.isEnabled(),
|
||||
true, true, true,
|
||||
appUser.isMustChangePassword(),
|
||||
appUser.getRoles().stream()
|
||||
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
||||
.collect(Collectors.toList())
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.astalange.core.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class CaptchaValidationService {
|
||||
|
||||
@Value("${captcha.secret:1x0000000000000000000000000000000AA}")
|
||||
private String captchaSecret;
|
||||
|
||||
@Value("${captcha.url:https://challenges.cloudflare.com/turnstile/v0/siteverify}")
|
||||
private String captchaUrl;
|
||||
|
||||
public boolean validateCaptcha(String token) {
|
||||
if (token == null || token.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add("secret", captchaSecret);
|
||||
map.add("response", token);
|
||||
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
|
||||
|
||||
try {
|
||||
ResponseEntity<Map> response = restTemplate.postForEntity(captchaUrl, request, Map.class);
|
||||
if (response.getBody() != null && Boolean.TRUE.equals(response.getBody().get("success"))) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Log error
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package com.astalange.core.service;
|
||||
|
||||
import com.astalange.core.entity.*;
|
||||
import com.astalange.core.repository.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class CategorieService {
|
||||
|
||||
private final CategorieRepository categorieRepository;
|
||||
private final SaisonRepository saisonRepository;
|
||||
private final EquipementRepository equipementRepository;
|
||||
private final LicenceRepository licenceRepository;
|
||||
|
||||
public CategorieService(CategorieRepository categorieRepository, SaisonRepository saisonRepository, EquipementRepository equipementRepository, LicenceRepository licenceRepository) {
|
||||
this.categorieRepository = categorieRepository;
|
||||
this.saisonRepository = saisonRepository;
|
||||
this.equipementRepository = equipementRepository;
|
||||
this.licenceRepository = licenceRepository;
|
||||
}
|
||||
|
||||
public record EquipementConfig(boolean obligatoire, java.math.BigDecimal prix) {}
|
||||
|
||||
@Transactional
|
||||
public void saveCategorie(Categorie categorie, java.util.Map<Long, EquipementConfig> equipementConfigs) {
|
||||
Saison activeSaison;
|
||||
Categorie existing = null;
|
||||
if (categorie.getId() == null) {
|
||||
activeSaison = saisonRepository.findByEstActiveTrue()
|
||||
.orElseThrow(() -> new IllegalStateException("Aucune saison active trouvée"));
|
||||
categorie.setSaison(activeSaison);
|
||||
} else {
|
||||
final Long catId = categorie.getId();
|
||||
existing = categorieRepository.findById(catId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid category ID: " + catId));
|
||||
categorie.setSaison(existing.getSaison());
|
||||
activeSaison = existing.getSaison();
|
||||
}
|
||||
|
||||
// Handle CategorieEquipement
|
||||
if (existing != null) {
|
||||
categorie.getCategorieEquipements().clear();
|
||||
categorie.getCategorieEquipements().addAll(existing.getCategorieEquipements());
|
||||
}
|
||||
|
||||
List<CategorieEquipement> nouveauxEquipements = new ArrayList<>();
|
||||
if (equipementConfigs != null) {
|
||||
for (java.util.Map.Entry<Long, EquipementConfig> entry : equipementConfigs.entrySet()) {
|
||||
Long eqId = entry.getKey();
|
||||
EquipementConfig config = entry.getValue();
|
||||
Equipement eq = equipementRepository.findById(eqId).orElse(null);
|
||||
if (eq != null) {
|
||||
CategorieEquipement ce = new CategorieEquipement();
|
||||
ce.setCategorie(categorie);
|
||||
ce.setEquipement(eq);
|
||||
ce.setObligatoire(config.obligatoire());
|
||||
ce.setPrix(config.prix() != null ? config.prix() : java.math.BigDecimal.ZERO);
|
||||
nouveauxEquipements.add(ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
categorie.getCategorieEquipements().clear();
|
||||
categorie.getCategorieEquipements().addAll(nouveauxEquipements);
|
||||
|
||||
categorie = categorieRepository.save(categorie);
|
||||
|
||||
// Mettre à jour les adhérents (via les licences de la saison actuelle)
|
||||
List<Licence> licences = licenceRepository.findBySaisonAndCategorie(activeSaison, categorie);
|
||||
for (Licence licence : licences) {
|
||||
updateDotationsForLicence(licence, nouveauxEquipements);
|
||||
}
|
||||
}
|
||||
|
||||
public void syncDotationsForLicence(Licence licence) {
|
||||
if (licence.getCategorie() != null) {
|
||||
updateDotationsForLicence(licence, licence.getCategorie().getCategorieEquipements());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDotationsForLicence(Licence licence, List<CategorieEquipement> categorieEquipements) {
|
||||
List<Dotation> currentDotations = licence.getDotations();
|
||||
List<Dotation> toRemove = new ArrayList<>();
|
||||
|
||||
// Remove dotations for equipements no longer in the category or not matching public
|
||||
for (Dotation d : currentDotations) {
|
||||
boolean found = false;
|
||||
for (CategorieEquipement ce : categorieEquipements) {
|
||||
if (ce.getEquipement().getId().equals(d.getEquipement().getId())) {
|
||||
String typePublic = ce.getEquipement().getTypePublic();
|
||||
String typeMaillot = licence.getAdherent() != null ? licence.getAdherent().getTypeMaillot() : "JOUEUR";
|
||||
|
||||
boolean matchPublic = "TOUS".equals(typePublic) ||
|
||||
("GARDIEN".equals(typePublic) && "GARDIEN".equals(typeMaillot)) ||
|
||||
("JOUEUR".equals(typePublic) && "JOUEUR".equals(typeMaillot));
|
||||
|
||||
if (matchPublic) {
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
toRemove.add(d);
|
||||
}
|
||||
}
|
||||
currentDotations.removeAll(toRemove);
|
||||
|
||||
// Add missing dotations
|
||||
for (CategorieEquipement ce : categorieEquipements) {
|
||||
String typePublic = ce.getEquipement().getTypePublic();
|
||||
String typeMaillot = licence.getAdherent() != null ? licence.getAdherent().getTypeMaillot() : "JOUEUR";
|
||||
|
||||
boolean matchPublic = "TOUS".equals(typePublic) ||
|
||||
("GARDIEN".equals(typePublic) && "GARDIEN".equals(typeMaillot)) ||
|
||||
("JOUEUR".equals(typePublic) && "JOUEUR".equals(typeMaillot));
|
||||
|
||||
if (!matchPublic) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String matchedTaille = "";
|
||||
if (licence.getAdherent() != null) {
|
||||
String taillesDispo = ce.getEquipement().getTaillesDisponibles();
|
||||
if (taillesDispo != null && !taillesDispo.trim().isEmpty()) {
|
||||
String[] dispos = taillesDispo.split(",");
|
||||
String tv = licence.getAdherent().getTailleVetement();
|
||||
String pt = licence.getAdherent().getPointure();
|
||||
for (String t : dispos) {
|
||||
String trimmed = t.trim();
|
||||
if (Dotation.isSizeMatch(trimmed, tv) || Dotation.isSizeMatch(trimmed, pt)) {
|
||||
matchedTaille = trimmed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
for (Dotation d : currentDotations) {
|
||||
if (ce.getEquipement().getId().equals(d.getEquipement().getId())) {
|
||||
found = true;
|
||||
if (Boolean.TRUE.equals(ce.getObligatoire()) && !Boolean.TRUE.equals(d.getChoisi())) {
|
||||
d.setChoisi(true);
|
||||
}
|
||||
if ((d.getTaille() == null || d.getTaille().trim().isEmpty()) && !matchedTaille.isEmpty()) {
|
||||
d.setTaille(matchedTaille);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
Dotation newDotation = new Dotation();
|
||||
newDotation.setLicence(licence);
|
||||
newDotation.setEquipement(ce.getEquipement());
|
||||
boolean isMaillot = "Maillot".equalsIgnoreCase(ce.getEquipement().getNom());
|
||||
boolean isNouvelle = false;
|
||||
if (licence.getTypeDemande() != null &&
|
||||
(licence.getTypeDemande().equalsIgnoreCase("Nouvelle demande") || licence.getTypeDemande().equalsIgnoreCase("NOUVELLE")) &&
|
||||
licence.getCategorie() != null) {
|
||||
isNouvelle = true;
|
||||
}
|
||||
newDotation.setChoisi(ce.getObligatoire() || (isMaillot && isNouvelle)); // Checked if obligatoire or if it's a new registration
|
||||
newDotation.setFourni(false);
|
||||
newDotation.setTaille(matchedTaille);
|
||||
newDotation.setNumero("");
|
||||
if (licence.getAdherent() != null) {
|
||||
String defaultFlocage = "";
|
||||
if (ce.getEquipement().isHasFlocagePrenom() && ce.getEquipement().isHasFlocageInitiales()) {
|
||||
String firstInitial = licence.getAdherent().getNom() != null && !licence.getAdherent().getNom().isEmpty() ? licence.getAdherent().getNom().substring(0, 1).toUpperCase() + "." : "";
|
||||
defaultFlocage = (licence.getAdherent().getPrenom() != null ? licence.getAdherent().getPrenom() + " " : "") + firstInitial;
|
||||
} else if (ce.getEquipement().isHasFlocagePrenom()) {
|
||||
defaultFlocage = licence.getAdherent().getPrenom() != null ? licence.getAdherent().getPrenom() : "";
|
||||
} else if (ce.getEquipement().isHasFlocageInitiales()) {
|
||||
String firstInitP = licence.getAdherent().getPrenom() != null && !licence.getAdherent().getPrenom().isEmpty() ? licence.getAdherent().getPrenom().substring(0, 1).toUpperCase() : "";
|
||||
String firstInitN = licence.getAdherent().getNom() != null && !licence.getAdherent().getNom().isEmpty() ? licence.getAdherent().getNom().substring(0, 1).toUpperCase() : "";
|
||||
defaultFlocage = firstInitP + firstInitN;
|
||||
}
|
||||
newDotation.setFlocage(defaultFlocage.trim());
|
||||
}
|
||||
currentDotations.add(newDotation);
|
||||
}
|
||||
}
|
||||
|
||||
licenceRepository.save(licence);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Categorie duplicateCategorie(Long id) {
|
||||
Categorie existing = categorieRepository.findById(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid category ID: " + id));
|
||||
|
||||
Categorie duplicated = new Categorie();
|
||||
// Appending ' (dupliqué)' and truncating if necessary since nom is max 20 chars
|
||||
String newNom = existing.getNom() + " (dupliqué)";
|
||||
if (newNom.length() > 20) {
|
||||
newNom = newNom.substring(0, 20);
|
||||
}
|
||||
duplicated.setNom(newNom);
|
||||
duplicated.setSexe(existing.getSexe());
|
||||
duplicated.setAnneeMin(existing.getAnneeMin());
|
||||
duplicated.setAnneeMax(existing.getAnneeMax());
|
||||
duplicated.setTarifBase(existing.getTarifBase());
|
||||
duplicated.setTarifExterieur(existing.getTarifExterieur());
|
||||
duplicated.setSaison(existing.getSaison());
|
||||
|
||||
List<CategorieEquipement> nouveauxEquipements = new ArrayList<>();
|
||||
for (CategorieEquipement ce : existing.getCategorieEquipements()) {
|
||||
CategorieEquipement newCe = new CategorieEquipement();
|
||||
newCe.setCategorie(duplicated);
|
||||
newCe.setEquipement(ce.getEquipement());
|
||||
newCe.setObligatoire(ce.getObligatoire());
|
||||
newCe.setPrix(ce.getPrix() != null ? ce.getPrix() : java.math.BigDecimal.ZERO);
|
||||
nouveauxEquipements.add(newCe);
|
||||
}
|
||||
duplicated.getCategorieEquipements().addAll(nouveauxEquipements);
|
||||
|
||||
return categorieRepository.save(duplicated);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.astalange.core.service;
|
||||
|
||||
import com.astalange.core.entity.Dotation;
|
||||
import com.astalange.core.entity.Saison;
|
||||
import com.astalange.core.repository.DotationRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class DotationService {
|
||||
|
||||
private final DotationRepository dotationRepository;
|
||||
|
||||
public DotationService(DotationRepository dotationRepository) {
|
||||
this.dotationRepository = dotationRepository;
|
||||
}
|
||||
|
||||
public String genererCsvCommandeEquipement(Saison saisonActive) {
|
||||
List<Dotation> dotations = dotationRepository.findByLicence_SaisonAndChoisiTrueAndFourniFalse(saisonActive);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// BOM for Excel to open UTF-8 correctly
|
||||
sb.append('\ufeff');
|
||||
|
||||
// Header
|
||||
sb.append("Catégorie;Nom;Prénom;Poste;Sexe;Équipement;Référence;Taille;Flocage;Numéro\n");
|
||||
|
||||
for (Dotation d : dotations) {
|
||||
String categorie = d.getLicence().getCategorie() != null ? d.getLicence().getCategorie().getNom() : "";
|
||||
String nom = d.getLicence().getAdherent().getNom();
|
||||
String prenom = d.getLicence().getAdherent().getPrenom();
|
||||
String poste = d.getLicence().getAdherent().getTypeMaillot() != null ? d.getLicence().getAdherent().getTypeMaillot() : "";
|
||||
String sexe = d.getLicence().getAdherent().getSexe() != null ? d.getLicence().getAdherent().getSexe() : "";
|
||||
String equipement = d.getEquipement() != null ? d.getEquipement().getNom() : "";
|
||||
String reference = d.getEquipement() != null && d.getEquipement().getReference() != null ? d.getEquipement().getReference() : "";
|
||||
String taille = d.getTaille() != null ? d.getTaille() : "";
|
||||
String flocage = d.getFlocage() != null ? d.getFlocage() : "";
|
||||
String numero = d.getNumero() != null ? d.getNumero() : "";
|
||||
|
||||
sb.append(escapeCsv(categorie)).append(";")
|
||||
.append(escapeCsv(nom)).append(";")
|
||||
.append(escapeCsv(prenom)).append(";")
|
||||
.append(escapeCsv(poste)).append(";")
|
||||
.append(escapeCsv(sexe)).append(";")
|
||||
.append(escapeCsv(equipement)).append(";")
|
||||
.append(escapeCsv(reference)).append(";")
|
||||
.append(escapeCsv(taille)).append(";")
|
||||
.append(escapeCsv(flocage)).append(";")
|
||||
.append(escapeCsv(numero)).append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String genererCsvSearchEquipement(List<Dotation> dotations) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// BOM for Excel to open UTF-8 correctly
|
||||
sb.append('\ufeff');
|
||||
|
||||
// Header
|
||||
sb.append("Saison;Catégorie;Nom;Prénom;Poste;Sexe;Équipement;Référence;Taille;Flocage;Numéro;Fourni\n");
|
||||
|
||||
for (Dotation d : dotations) {
|
||||
String saison = d.getLicence().getSaison() != null ? d.getLicence().getSaison().getNom() : "";
|
||||
String categorie = d.getLicence().getCategorie() != null ? d.getLicence().getCategorie().getNom() : "";
|
||||
String nom = d.getLicence().getAdherent().getNom();
|
||||
String prenom = d.getLicence().getAdherent().getPrenom();
|
||||
String poste = d.getLicence().getAdherent().getTypeMaillot() != null ? d.getLicence().getAdherent().getTypeMaillot() : "";
|
||||
String sexe = d.getLicence().getAdherent().getSexe() != null ? d.getLicence().getAdherent().getSexe() : "";
|
||||
String equipement = d.getEquipement() != null ? d.getEquipement().getNom() : "";
|
||||
String reference = d.getEquipement() != null && d.getEquipement().getReference() != null ? d.getEquipement().getReference() : "";
|
||||
String taille = d.getTaille() != null ? d.getTaille() : "";
|
||||
String flocage = d.getFlocage() != null ? d.getFlocage() : "";
|
||||
String numero = d.getNumero() != null ? d.getNumero() : "";
|
||||
String fourni = Boolean.TRUE.equals(d.getFourni()) ? "Oui" : "Non";
|
||||
|
||||
sb.append(escapeCsv(saison)).append(";")
|
||||
.append(escapeCsv(categorie)).append(";")
|
||||
.append(escapeCsv(nom)).append(";")
|
||||
.append(escapeCsv(prenom)).append(";")
|
||||
.append(escapeCsv(poste)).append(";")
|
||||
.append(escapeCsv(sexe)).append(";")
|
||||
.append(escapeCsv(equipement)).append(";")
|
||||
.append(escapeCsv(reference)).append(";")
|
||||
.append(escapeCsv(taille)).append(";")
|
||||
.append(escapeCsv(flocage)).append(";")
|
||||
.append(escapeCsv(numero)).append(";")
|
||||
.append(escapeCsv(fourni)).append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String escapeCsv(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
String result = value;
|
||||
if (result.contains("\"")) {
|
||||
result = result.replace("\"", "\"\"");
|
||||
}
|
||||
if (result.contains(";") || result.contains("\n") || result.contains("\"")) {
|
||||
return "\"" + result + "\"";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.astalange.core.service;
|
||||
|
||||
import com.astalange.core.entity.Adherent;
|
||||
import com.astalange.core.entity.Licence;
|
||||
import com.astalange.core.entity.PreInscription;
|
||||
import com.astalange.core.repository.AdherentRepository;
|
||||
import com.astalange.core.repository.LicenceRepository;
|
||||
import com.astalange.core.repository.PreInscriptionRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class PreInscriptionService {
|
||||
|
||||
private final PreInscriptionRepository preInscriptionRepository;
|
||||
private final AdherentRepository adherentRepository;
|
||||
private final LicenceRepository licenceRepository;
|
||||
|
||||
public PreInscriptionService(PreInscriptionRepository preInscriptionRepository,
|
||||
AdherentRepository adherentRepository,
|
||||
LicenceRepository licenceRepository) {
|
||||
this.preInscriptionRepository = preInscriptionRepository;
|
||||
this.adherentRepository = adherentRepository;
|
||||
this.licenceRepository = licenceRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Adherent validerPreInscription(Long preInscriptionId, Long categorieId) {
|
||||
PreInscription pre = preInscriptionRepository.findById(preInscriptionId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Pré-inscription introuvable"));
|
||||
|
||||
if (pre.getStatutTraite()) {
|
||||
throw new IllegalStateException("Cette pré-inscription a déjà été traitée");
|
||||
}
|
||||
|
||||
// Créer l'adhérent
|
||||
Adherent adherent = new Adherent();
|
||||
adherent.setNom(pre.getNom().toUpperCase());
|
||||
adherent.setPrenom(pre.getPrenom());
|
||||
adherent.setDateNaissance(pre.getDateNaissance());
|
||||
adherent.setLieuNaissanceVille(pre.getLieuNaissanceVille());
|
||||
adherent.setLieuNaissancePays(pre.getLieuNaissancePays());
|
||||
adherent.setNationalite(pre.getNationalite());
|
||||
adherent.setEmail(pre.getEmail());
|
||||
adherent.setTelephone(pre.getTelephone());
|
||||
adherent.setRepresentantLegal(pre.getRepresentantLegal());
|
||||
adherent.setTypeDemande(pre.getTypeDemande());
|
||||
adherent.setAncienClub(pre.getAncienClub());
|
||||
adherent.setAncienneCategorie(pre.getAncienneCategorie());
|
||||
adherent.setSexe(pre.getSexe());
|
||||
adherent.setRaisonChangementClub(pre.getRaisonChangementClub());
|
||||
adherent.setCommentConnuClub(pre.getCommentConnuClub());
|
||||
adherent.setTailleVetement(pre.getTailleVetement());
|
||||
adherent.setPointure(pre.getPointure());
|
||||
// Par défaut
|
||||
adherent.setTypeMaillot("JOUEUR");
|
||||
adherent.setResidentTalange(false);
|
||||
|
||||
adherent = adherentRepository.save(adherent);
|
||||
|
||||
pre.setStatutTraite(true);
|
||||
preInscriptionRepository.save(pre);
|
||||
|
||||
return adherent;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void rejeterPreInscription(Long preInscriptionId) {
|
||||
PreInscription pre = preInscriptionRepository.findById(preInscriptionId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Pré-inscription introuvable"));
|
||||
|
||||
pre.setStatutTraite(true);
|
||||
preInscriptionRepository.save(pre);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.astalange.core.service;
|
||||
|
||||
import com.astalange.core.entity.Categorie;
|
||||
import com.astalange.core.entity.Equipement;
|
||||
import com.astalange.core.entity.Saison;
|
||||
import com.astalange.core.repository.CategorieRepository;
|
||||
import com.astalange.core.repository.EquipementRepository;
|
||||
import com.astalange.core.repository.SaisonRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class SaisonService {
|
||||
|
||||
private final SaisonRepository saisonRepository;
|
||||
private final CategorieRepository categorieRepository;
|
||||
private final EquipementRepository equipementRepository;
|
||||
|
||||
public SaisonService(SaisonRepository saisonRepository, CategorieRepository categorieRepository, EquipementRepository equipementRepository) {
|
||||
this.saisonRepository = saisonRepository;
|
||||
this.categorieRepository = categorieRepository;
|
||||
this.equipementRepository = equipementRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Saison creerNouvelleSaison(String nom, boolean importerParametragePrecedent) {
|
||||
Optional<Saison> ancienneSaisonOpt = saisonRepository.findByEstActiveTrue();
|
||||
|
||||
// Désactiver toutes les saisons actuelles (il ne devrait y en avoir qu'une mais on s'assure de tout nettoyer)
|
||||
List<Saison> toutesLesSaisons = saisonRepository.findAll();
|
||||
for (Saison s : toutesLesSaisons) {
|
||||
s.setEstActive(false);
|
||||
saisonRepository.save(s);
|
||||
}
|
||||
|
||||
// Création de la nouvelle saison
|
||||
Saison nouvelleSaison = new Saison();
|
||||
nouvelleSaison.setNom(nom);
|
||||
nouvelleSaison.setEstActive(true);
|
||||
nouvelleSaison = saisonRepository.save(nouvelleSaison);
|
||||
|
||||
if (importerParametragePrecedent && ancienneSaisonOpt.isPresent()) {
|
||||
Saison ancienneSaison = ancienneSaisonOpt.get();
|
||||
dupliquerParametrages(ancienneSaison, nouvelleSaison);
|
||||
}
|
||||
|
||||
return nouvelleSaison;
|
||||
}
|
||||
|
||||
private void dupliquerParametrages(Saison ancienneSaison, Saison nouvelleSaison) {
|
||||
// 1. Dupliquer les équipements
|
||||
List<Equipement> anciensEquipements = equipementRepository.findBySaison(ancienneSaison);
|
||||
java.util.Map<Long, Equipement> oldToNewEquipementMap = new java.util.HashMap<>();
|
||||
|
||||
for (Equipement ancien : anciensEquipements) {
|
||||
Equipement nouvelEquipement = new Equipement();
|
||||
nouvelEquipement.setNom(ancien.getNom());
|
||||
nouvelEquipement.setDescription(ancien.getDescription());
|
||||
nouvelEquipement.setSaison(nouvelleSaison);
|
||||
nouvelEquipement = equipementRepository.save(nouvelEquipement);
|
||||
oldToNewEquipementMap.put(ancien.getId(), nouvelEquipement);
|
||||
}
|
||||
|
||||
// 2. Dupliquer les catégories (avec incrémentation de l'année)
|
||||
List<Categorie> anciennesCategories = categorieRepository.findBySaison(ancienneSaison);
|
||||
for (Categorie ancienne : anciennesCategories) {
|
||||
Categorie nouvelleCategorie = new Categorie();
|
||||
nouvelleCategorie.setNom(ancienne.getNom());
|
||||
// Incrémentation de +1 sur l'année de naissance pivot
|
||||
if (ancienne.getAnneeMin() != null) {
|
||||
nouvelleCategorie.setAnneeMin(ancienne.getAnneeMin() + 1);
|
||||
}
|
||||
if (ancienne.getAnneeMax() != null) {
|
||||
nouvelleCategorie.setAnneeMax(ancienne.getAnneeMax() + 1);
|
||||
}
|
||||
nouvelleCategorie.setTarifBase(ancienne.getTarifBase());
|
||||
nouvelleCategorie.setTarifExterieur(ancienne.getTarifExterieur());
|
||||
nouvelleCategorie.setSaison(nouvelleSaison);
|
||||
|
||||
// Dupliquer les relations avec les équipements
|
||||
if (ancienne.getCategorieEquipements() != null) {
|
||||
for (com.astalange.core.entity.CategorieEquipement oldCatEq : ancienne.getCategorieEquipements()) {
|
||||
Equipement newEq = oldToNewEquipementMap.get(oldCatEq.getEquipement().getId());
|
||||
if (newEq != null) {
|
||||
com.astalange.core.entity.CategorieEquipement newCatEq = new com.astalange.core.entity.CategorieEquipement();
|
||||
newCatEq.setCategorie(nouvelleCategorie);
|
||||
newCatEq.setEquipement(newEq);
|
||||
newCatEq.setObligatoire(oldCatEq.getObligatoire());
|
||||
newCatEq.setPrix(oldCatEq.getPrix());
|
||||
nouvelleCategorie.getCategorieEquipements().add(newCatEq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
categorieRepository.save(nouvelleCategorie);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
-- V10__add_terrains_and_schedules.sql
|
||||
|
||||
-- 1. Table des terrains
|
||||
CREATE TABLE terrain (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
-- Insertion des deux terrains par défaut
|
||||
INSERT INTO terrain (nom) VALUES ('Terrain Vert');
|
||||
INSERT INTO terrain (nom) VALUES ('Terrain Synthétique');
|
||||
|
||||
-- 2. Table des créneaux d'entraînement
|
||||
CREATE TABLE creneau_entrainement (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
categorie_id BIGINT NOT NULL,
|
||||
terrain_id BIGINT NOT NULL,
|
||||
zone VARCHAR(50) NOT NULL,
|
||||
jour_semaine VARCHAR(50) NOT NULL,
|
||||
heure_debut TIME NOT NULL,
|
||||
heure_fin TIME NOT NULL,
|
||||
saison_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_creneau_categorie FOREIGN KEY (categorie_id) REFERENCES categorie(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_creneau_terrain FOREIGN KEY (terrain_id) REFERENCES terrain(id),
|
||||
CONSTRAINT fk_creneau_saison FOREIGN KEY (saison_id) REFERENCES saison(id) ON DELETE CASCADE
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
-- V11__add_equipes.sql
|
||||
|
||||
-- 1. Table des équipes
|
||||
CREATE TABLE equipe (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(255) NOT NULL,
|
||||
categorie_id BIGINT NOT NULL,
|
||||
saison_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_equipe_categorie FOREIGN KEY (categorie_id) REFERENCES categorie(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_equipe_saison FOREIGN KEY (saison_id) REFERENCES saison(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 2. Ajouter equipe_id à la table licence (nullable, facultative)
|
||||
ALTER TABLE licence ADD COLUMN equipe_id BIGINT;
|
||||
ALTER TABLE licence ADD CONSTRAINT fk_licence_equipe FOREIGN KEY (equipe_id) REFERENCES equipe(id) ON DELETE SET NULL;
|
||||
|
||||
-- 3. Ajouter equipe_id à la table creneau_entrainement (nullable, facultative)
|
||||
ALTER TABLE creneau_entrainement ADD COLUMN equipe_id BIGINT;
|
||||
ALTER TABLE creneau_entrainement ADD CONSTRAINT fk_creneau_equipe FOREIGN KEY (equipe_id) REFERENCES equipe(id) ON DELETE SET NULL;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE app_user ADD COLUMN must_change_password BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
INSERT INTO role (name) VALUES ('ROLE_TRESORERIE'), ('ROLE_AGENT_SAISIE') ON CONFLICT (name) DO NOTHING;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- V13__add_equipe_to_educateur.sql
|
||||
ALTER TABLE educateur ADD COLUMN equipe_id BIGINT;
|
||||
ALTER TABLE educateur ADD CONSTRAINT fk_educateur_equipe FOREIGN KEY (equipe_id) REFERENCES equipe(id) ON DELETE SET NULL;
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE categorie_equipement (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
categorie_id BIGINT NOT NULL,
|
||||
equipement_id BIGINT NOT NULL,
|
||||
obligatoire BOOLEAN NOT NULL DEFAULT false,
|
||||
CONSTRAINT fk_cat_equip_categorie FOREIGN KEY (categorie_id) REFERENCES categorie(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_cat_equip_equipement FOREIGN KEY (equipement_id) REFERENCES equipement(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Migrer les données existantes : associer tous les équipements d'une saison à toutes les catégories de la même saison
|
||||
-- et transférer la valeur "obligatoire" de l'équipement vers la nouvelle table de liaison
|
||||
INSERT INTO categorie_equipement (categorie_id, equipement_id, obligatoire)
|
||||
SELECT c.id, e.id, e.obligatoire
|
||||
FROM categorie c
|
||||
JOIN equipement e ON c.saison_id = e.saison_id;
|
||||
|
||||
-- Supprimer la colonne "obligatoire" de la table équipement
|
||||
ALTER TABLE equipement DROP COLUMN obligatoire;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
ALTER TABLE categorie_equipement ADD COLUMN prix NUMERIC(10,2) NOT NULL DEFAULT 0;
|
||||
|
||||
-- Migrer les données existantes
|
||||
UPDATE categorie_equipement ce
|
||||
SET prix = e.prix_contribution
|
||||
FROM equipement e
|
||||
WHERE ce.equipement_id = e.id;
|
||||
|
||||
ALTER TABLE equipement DROP COLUMN IF EXISTS prix_contribution;
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
CREATE TABLE token_pre_inscription (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
valeur_uuid VARCHAR(36) NOT NULL UNIQUE,
|
||||
date_expiration TIMESTAMP NOT NULL,
|
||||
est_utilise BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
|
||||
CREATE TABLE pre_inscription (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(100) NOT NULL,
|
||||
prenom VARCHAR(100) NOT NULL,
|
||||
date_naissance DATE NOT NULL,
|
||||
telephone VARCHAR(20),
|
||||
email VARCHAR(150),
|
||||
adresse TEXT,
|
||||
representant_legal VARCHAR(150),
|
||||
statut_traite BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
date_creation TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
saison_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_pre_inscription_saison FOREIGN KEY (saison_id) REFERENCES saison (id)
|
||||
);
|
||||
+1
@@ -0,0 +1 @@
|
||||
ALTER TABLE saison ADD COLUMN inscriptions_ouvertes BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
-- Drop the global unique constraint on 'nom'
|
||||
ALTER TABLE categorie DROP CONSTRAINT IF EXISTS categorie_nom_key;
|
||||
|
||||
-- Add a composite unique constraint for 'nom' and 'saison_id'
|
||||
ALTER TABLE categorie ADD CONSTRAINT categorie_nom_saison_id_key UNIQUE (nom, saison_id);
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
-- adherent modifications
|
||||
ALTER TABLE adherent DROP COLUMN IF EXISTS adresse;
|
||||
ALTER TABLE adherent ADD COLUMN lieu_naissance_ville VARCHAR(100);
|
||||
ALTER TABLE adherent ADD COLUMN lieu_naissance_pays VARCHAR(100);
|
||||
ALTER TABLE adherent ADD COLUMN nationalite VARCHAR(100);
|
||||
|
||||
-- pre_inscription modifications
|
||||
ALTER TABLE pre_inscription DROP COLUMN IF EXISTS adresse;
|
||||
ALTER TABLE pre_inscription ADD COLUMN lieu_naissance_ville VARCHAR(100);
|
||||
ALTER TABLE pre_inscription ADD COLUMN lieu_naissance_pays VARCHAR(100);
|
||||
ALTER TABLE pre_inscription ADD COLUMN nationalite VARCHAR(100);
|
||||
@@ -1,16 +1,16 @@
|
||||
CREATE TABLE role (
|
||||
CREATE TABLE IF NOT EXISTS role (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(50) UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE app_user (
|
||||
CREATE TABLE IF NOT EXISTS app_user (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
username VARCHAR(100) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
|
||||
CREATE TABLE user_role (
|
||||
CREATE TABLE IF NOT EXISTS user_role (
|
||||
user_id BIGINT NOT NULL,
|
||||
role_id BIGINT NOT NULL,
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
@@ -18,7 +18,7 @@ CREATE TABLE user_role (
|
||||
CONSTRAINT fk_role FOREIGN KEY (role_id) REFERENCES role(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE adherent (
|
||||
CREATE TABLE IF NOT EXISTS adherent (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(100) NOT NULL,
|
||||
prenom VARCHAR(100) NOT NULL,
|
||||
@@ -29,7 +29,7 @@ CREATE TABLE adherent (
|
||||
representant_legal VARCHAR(150)
|
||||
);
|
||||
|
||||
CREATE TABLE categorie (
|
||||
CREATE TABLE IF NOT EXISTS categorie (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(20) UNIQUE NOT NULL,
|
||||
annee_min INT,
|
||||
@@ -37,7 +37,7 @@ CREATE TABLE categorie (
|
||||
tarif_base DECIMAL(10,2) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE licence (
|
||||
CREATE TABLE IF NOT EXISTS licence (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
adherent_id BIGINT NOT NULL,
|
||||
categorie_id BIGINT NOT NULL,
|
||||
@@ -47,7 +47,7 @@ CREATE TABLE licence (
|
||||
CONSTRAINT fk_licence_categorie FOREIGN KEY (categorie_id) REFERENCES categorie(id)
|
||||
);
|
||||
|
||||
CREATE TABLE paiement (
|
||||
CREATE TABLE IF NOT EXISTS paiement (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
licence_id BIGINT NOT NULL,
|
||||
montant DECIMAL(10,2) NOT NULL,
|
||||
@@ -56,14 +56,14 @@ CREATE TABLE paiement (
|
||||
CONSTRAINT fk_paiement_licence FOREIGN KEY (licence_id) REFERENCES licence(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE equipement (
|
||||
CREATE TABLE IF NOT EXISTS equipement (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
obligatoire BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
|
||||
CREATE TABLE dotation (
|
||||
CREATE TABLE IF NOT EXISTS dotation (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
licence_id BIGINT NOT NULL,
|
||||
equipement_id BIGINT NOT NULL,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE licence ADD COLUMN type_demande VARCHAR(50);
|
||||
ALTER TABLE licence ADD COLUMN type_licence VARCHAR(50);
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
-- Default values for existing records in adherent
|
||||
UPDATE adherent SET lieu_naissance_ville = 'Non renseigné' WHERE lieu_naissance_ville IS NULL;
|
||||
UPDATE adherent SET lieu_naissance_pays = 'France' WHERE lieu_naissance_pays IS NULL;
|
||||
UPDATE adherent SET nationalite = 'Française' WHERE nationalite IS NULL;
|
||||
|
||||
-- Default values for existing records in pre_inscription
|
||||
UPDATE pre_inscription SET lieu_naissance_ville = 'Non renseigné' WHERE lieu_naissance_ville IS NULL;
|
||||
UPDATE pre_inscription SET lieu_naissance_pays = 'France' WHERE lieu_naissance_pays IS NULL;
|
||||
UPDATE pre_inscription SET nationalite = 'Française' WHERE nationalite IS NULL;
|
||||
|
||||
-- Now make them NOT NULL
|
||||
ALTER TABLE adherent ALTER COLUMN lieu_naissance_ville SET NOT NULL;
|
||||
ALTER TABLE adherent ALTER COLUMN lieu_naissance_pays SET NOT NULL;
|
||||
ALTER TABLE adherent ALTER COLUMN nationalite SET NOT NULL;
|
||||
|
||||
ALTER TABLE pre_inscription ALTER COLUMN lieu_naissance_ville SET NOT NULL;
|
||||
ALTER TABLE pre_inscription ALTER COLUMN lieu_naissance_pays SET NOT NULL;
|
||||
ALTER TABLE pre_inscription ALTER COLUMN nationalite SET NOT NULL;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
-- Provide fallback email if null
|
||||
UPDATE adherent SET email = 'nonrenseigne@example.com' WHERE email IS NULL OR email = '';
|
||||
UPDATE pre_inscription SET email = 'nonrenseigne@example.com' WHERE email IS NULL OR email = '';
|
||||
|
||||
-- Make email NOT NULL
|
||||
ALTER TABLE adherent ALTER COLUMN email SET NOT NULL;
|
||||
ALTER TABLE pre_inscription ALTER COLUMN email SET NOT NULL;
|
||||
|
||||
-- Remove telephone
|
||||
ALTER TABLE adherent DROP COLUMN IF EXISTS telephone;
|
||||
ALTER TABLE pre_inscription DROP COLUMN IF EXISTS telephone;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE paiement ADD COLUMN gestionnaire VARCHAR(255);
|
||||
+1
@@ -0,0 +1 @@
|
||||
ALTER TABLE pre_inscription ADD COLUMN consentement_rgpd BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE audit_log_paiement (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
action VARCHAR(50) NOT NULL,
|
||||
date_action TIMESTAMP NOT NULL,
|
||||
utilisateur VARCHAR(255) NOT NULL,
|
||||
paiement_id BIGINT,
|
||||
details VARCHAR(1000) NOT NULL,
|
||||
montant DECIMAL(10, 2),
|
||||
adherent_nom_complet VARCHAR(255)
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE adherent ADD COLUMN telephone VARCHAR(20);
|
||||
ALTER TABLE pre_inscription ADD COLUMN telephone VARCHAR(20);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE equipement ADD COLUMN reference VARCHAR(100);
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE pre_inscription
|
||||
ADD COLUMN type_demande VARCHAR(50) DEFAULT 'NOUVELLE' NOT NULL,
|
||||
ADD COLUMN ancien_club VARCHAR(150);
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE adherent
|
||||
ADD COLUMN type_demande VARCHAR(50),
|
||||
ADD COLUMN ancien_club VARCHAR(150);
|
||||
@@ -1,12 +1,18 @@
|
||||
CREATE TABLE mode_paiement (
|
||||
CREATE TABLE IF NOT EXISTS mode_paiement (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(50) UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO mode_paiement (nom) VALUES ('Espèces'), ('Chèque'), ('Pass Sport'), ('Virement');
|
||||
INSERT INTO mode_paiement (nom) VALUES ('Espèces'), ('Chèque'), ('Pass Sport'), ('Virement')
|
||||
ON CONFLICT (nom) DO NOTHING;
|
||||
|
||||
ALTER TABLE paiement ADD COLUMN mode_paiement_id BIGINT;
|
||||
ALTER TABLE paiement ADD COLUMN IF NOT EXISTS mode_paiement_id BIGINT;
|
||||
|
||||
ALTER TABLE paiement ADD CONSTRAINT fk_paiement_mode FOREIGN KEY (mode_paiement_id) REFERENCES mode_paiement(id);
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_paiement_mode') THEN
|
||||
ALTER TABLE paiement ADD CONSTRAINT fk_paiement_mode FOREIGN KEY (mode_paiement_id) REFERENCES mode_paiement(id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
ALTER TABLE paiement DROP COLUMN mode_paiement;
|
||||
ALTER TABLE paiement DROP COLUMN IF EXISTS mode_paiement;
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
ALTER TABLE adherent ADD COLUMN ancienne_categorie VARCHAR(50);
|
||||
ALTER TABLE pre_inscription ADD COLUMN ancienne_categorie VARCHAR(50) DEFAULT 'NA';
|
||||
|
||||
ALTER TABLE categorie ADD COLUMN sexe VARCHAR(10) DEFAULT 'MASCULIN' NOT NULL;
|
||||
|
||||
UPDATE adherent SET telephone = '0000000000' WHERE telephone IS NULL;
|
||||
ALTER TABLE adherent ALTER COLUMN telephone SET NOT NULL;
|
||||
|
||||
UPDATE pre_inscription SET telephone = '0000000000' WHERE telephone IS NULL;
|
||||
ALTER TABLE pre_inscription ALTER COLUMN telephone SET NOT NULL;
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE equipement ADD COLUMN gestion_sexe BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE equipement ADD COLUMN tailles_disponibles VARCHAR(500);
|
||||
ALTER TABLE equipement ADD COLUMN couleurs_disponibles VARCHAR(500);
|
||||
|
||||
ALTER TABLE dotation ADD COLUMN couleur VARCHAR(50);
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE paiement ADD COLUMN numero_cheque VARCHAR(50);
|
||||
ALTER TABLE paiement ADD COLUMN commentaire TEXT;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE equipement ADD COLUMN type_public VARCHAR(20) DEFAULT 'TOUS' NOT NULL;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE pre_inscription ADD COLUMN sexe VARCHAR(10) DEFAULT 'MASCULIN' NOT NULL;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE dotation ALTER COLUMN taille TYPE VARCHAR(50);
|
||||
ALTER TABLE dotation ALTER COLUMN numero TYPE VARCHAR(50);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE licence ADD COLUMN commentaire TEXT;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
ALTER TABLE pre_inscription ADD COLUMN raison_changement_club VARCHAR(255);
|
||||
ALTER TABLE pre_inscription ADD COLUMN comment_connu_club VARCHAR(255);
|
||||
ALTER TABLE pre_inscription ADD COLUMN taille_vetement VARCHAR(50);
|
||||
ALTER TABLE pre_inscription ADD COLUMN pointure VARCHAR(50);
|
||||
|
||||
ALTER TABLE adherent ADD COLUMN raison_changement_club VARCHAR(255);
|
||||
ALTER TABLE adherent ADD COLUMN comment_connu_club VARCHAR(255);
|
||||
ALTER TABLE adherent ADD COLUMN taille_vetement VARCHAR(50);
|
||||
ALTER TABLE adherent ADD COLUMN pointure VARCHAR(50);
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
ALTER TABLE equipement ADD COLUMN has_flocage_prenom BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE equipement ADD COLUMN has_flocage_initiales BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE equipement ADD COLUMN has_flocage_numero BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
|
||||
-- Activation automatique de l'option "numéro" pour les équipements ayant déjà des dotations avec un numéro
|
||||
UPDATE equipement e
|
||||
SET has_flocage_numero = TRUE
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM dotation d WHERE d.equipement_id = e.id AND d.numero IS NOT NULL AND d.numero != ''
|
||||
);
|
||||
|
||||
-- Activation automatique de l'option "prénom" (uniquement) pour les équipements ayant déjà des dotations avec un flocage
|
||||
UPDATE equipement e
|
||||
SET has_flocage_prenom = TRUE
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM dotation d WHERE d.equipement_id = e.id AND d.flocage IS NOT NULL AND d.flocage != ''
|
||||
);
|
||||
|
||||
UPDATE dotation
|
||||
SET flocage = a.prenom
|
||||
FROM licence l
|
||||
JOIN adherent a ON l.adherent_id = a.id
|
||||
WHERE dotation.licence_id = l.id
|
||||
AND dotation.flocage IS NOT NULL
|
||||
AND dotation.flocage != ''
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM equipement e
|
||||
WHERE e.id = dotation.equipement_id
|
||||
AND e.has_flocage_prenom = TRUE
|
||||
AND e.has_flocage_initiales = FALSE
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE app_user ADD COLUMN last_login_at TIMESTAMP;
|
||||
ALTER TABLE app_user ADD COLUMN last_logout_at TIMESTAMP;
|
||||
@@ -1,9 +1,11 @@
|
||||
INSERT INTO role (name) VALUES ('ROLE_ADMIN'), ('ROLE_USER');
|
||||
INSERT INTO role (name) VALUES ('ROLE_ADMIN'), ('ROLE_USER') ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Password is "Talange2026!" hashed with Argon2id
|
||||
INSERT INTO app_user (username, password, enabled) VALUES ('Ucef', '$argon2id$v=19$m=65536,t=3,p=4$q29E/VM1esZVxo9HufgILQ$Nzb+rwwsZUMy04BbewYum2A8L8ujs9VZj9VJ/609Am0', true);
|
||||
INSERT INTO app_user (username, password, enabled) VALUES ('Ucef', '$argon2id$v=19$m=65536,t=3,p=4$q29E/VM1esZVxo9HufgILQ$Nzb+rwwsZUMy04BbewYum2A8L8ujs9VZj9VJ/609Am0', true)
|
||||
ON CONFLICT (username) DO NOTHING;
|
||||
|
||||
INSERT INTO user_role (user_id, role_id) VALUES ((SELECT id FROM app_user WHERE username = 'Ucef'), (SELECT id FROM role WHERE name = 'ROLE_ADMIN'));
|
||||
INSERT INTO user_role (user_id, role_id) VALUES ((SELECT id FROM app_user WHERE username = 'Ucef'), (SELECT id FROM role WHERE name = 'ROLE_ADMIN'))
|
||||
ON CONFLICT (user_id, role_id) DO NOTHING;
|
||||
|
||||
INSERT INTO categorie (nom, annee_min, annee_max, tarif_base) VALUES
|
||||
('U6', 2020, 2020, 100.00),
|
||||
@@ -14,10 +16,14 @@ INSERT INTO categorie (nom, annee_min, annee_max, tarif_base) VALUES
|
||||
('U11', 2015, 2015, 130.00),
|
||||
('U12', 2014, 2014, 140.00),
|
||||
('U13', 2013, 2013, 140.00),
|
||||
('Senior', 1900, 2005, 180.00);
|
||||
('Senior', 1900, 2005, 180.00)
|
||||
ON CONFLICT (nom) DO NOTHING;
|
||||
|
||||
INSERT INTO equipement (nom, obligatoire) VALUES
|
||||
('Maillot', true),
|
||||
('Short', true),
|
||||
('Chaussettes', true),
|
||||
('Survêtement', false);
|
||||
INSERT INTO equipement (nom, obligatoire)
|
||||
SELECT 'Maillot', true WHERE NOT EXISTS (SELECT 1 FROM equipement WHERE nom = 'Maillot');
|
||||
INSERT INTO equipement (nom, obligatoire)
|
||||
SELECT 'Short', true WHERE NOT EXISTS (SELECT 1 FROM equipement WHERE nom = 'Short');
|
||||
INSERT INTO equipement (nom, obligatoire)
|
||||
SELECT 'Chaussettes', true WHERE NOT EXISTS (SELECT 1 FROM equipement WHERE nom = 'Chaussettes');
|
||||
INSERT INTO equipement (nom, obligatoire)
|
||||
SELECT 'Survêtement', false WHERE NOT EXISTS (SELECT 1 FROM equipement WHERE nom = 'Survêtement');
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-- Ajouter la colonne pour savoir si l'adhérent est résident de Talange (par défaut oui pour les existants)
|
||||
ALTER TABLE adherent ADD COLUMN resident_talange BOOLEAN DEFAULT TRUE;
|
||||
ALTER TABLE adherent ADD COLUMN IF NOT EXISTS resident_talange BOOLEAN DEFAULT TRUE;
|
||||
|
||||
-- Ajouter le tarif extérieur aux catégories
|
||||
ALTER TABLE categorie ADD COLUMN tarif_exterieur DECIMAL(10,2);
|
||||
ALTER TABLE categorie ADD COLUMN IF NOT EXISTS tarif_exterieur DECIMAL(10,2);
|
||||
|
||||
-- Par défaut, mettre le tarif extérieur égal au tarif de base pour ne pas casser les licences existantes
|
||||
UPDATE categorie SET tarif_exterieur = tarif_base;
|
||||
UPDATE categorie SET tarif_exterieur = tarif_base*1.2 WHERE tarif_exterieur IS NULL;
|
||||
|
||||
@@ -1 +1 @@
|
||||
ALTER TABLE licence ADD COLUMN numero_licence VARCHAR(50);
|
||||
ALTER TABLE licence ADD COLUMN IF NOT EXISTS numero_licence VARCHAR(50);
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
ALTER TABLE dotation ADD COLUMN IF NOT EXISTS numero VARCHAR(10);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS educateur (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(100) NOT NULL,
|
||||
prenom VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(100),
|
||||
telephone VARCHAR(20),
|
||||
categorie_id BIGINT,
|
||||
CONSTRAINT fk_educateur_categorie FOREIGN KEY (categorie_id) REFERENCES categorie(id) ON DELETE SET NULL
|
||||
);
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
-- Ajouter la colonne prix_contribution à la table equipement (avec valeur par défaut 0)
|
||||
ALTER TABLE equipement ADD COLUMN IF NOT EXISTS prix_contribution DECIMAL(10,2) NOT NULL DEFAULT 0.00;
|
||||
|
||||
-- Ajouter la colonne choisi à la table dotation (avec valeur par défaut false)
|
||||
ALTER TABLE dotation ADD COLUMN IF NOT EXISTS choisi BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
|
||||
-- Mettre choisi à true pour tous les équipements obligatoires existants
|
||||
UPDATE dotation d
|
||||
SET choisi = TRUE
|
||||
FROM equipement e
|
||||
WHERE d.equipement_id = e.id AND e.obligatoire = TRUE;
|
||||
|
||||
-- Mettre à jour le prix de contribution du Survêtement à 30.00 € à titre d'exemple
|
||||
UPDATE equipement SET prix_contribution = 30.00 WHERE nom = 'Survêtement';
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE adherent ADD COLUMN sexe VARCHAR(10) DEFAULT 'MASCULIN' NOT NULL;
|
||||
ALTER TABLE adherent ADD COLUMN type_maillot VARCHAR(20) DEFAULT 'JOUEUR' NOT NULL;
|
||||
@@ -0,0 +1,43 @@
|
||||
-- V9__introduction_saison.sql
|
||||
-- 1. Création de la table saison
|
||||
CREATE TABLE saison (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
nom VARCHAR(255) NOT NULL,
|
||||
est_active BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
|
||||
-- Création d'une saison par défaut pour les données existantes
|
||||
INSERT INTO saison (nom, est_active) VALUES ('Saison Actuelle', TRUE);
|
||||
|
||||
-- 2. Ajout de saison_id dans les tables de paramétrage
|
||||
ALTER TABLE categorie ADD COLUMN saison_id BIGINT;
|
||||
ALTER TABLE equipement ADD COLUMN saison_id BIGINT;
|
||||
-- Il n'y a pas de table tarif, les tarifs sont dans categorie.
|
||||
|
||||
-- Affecter la saison par défaut aux paramètres existants
|
||||
UPDATE categorie SET saison_id = (SELECT id FROM saison LIMIT 1);
|
||||
UPDATE equipement SET saison_id = (SELECT id FROM saison LIMIT 1);
|
||||
|
||||
-- Rendre saison_id NOT NULL et ajouter les contraintes
|
||||
ALTER TABLE categorie ALTER COLUMN saison_id SET NOT NULL;
|
||||
ALTER TABLE categorie ADD CONSTRAINT fk_categorie_saison FOREIGN KEY (saison_id) REFERENCES saison(id);
|
||||
|
||||
ALTER TABLE equipement ALTER COLUMN saison_id SET NOT NULL;
|
||||
ALTER TABLE equipement ADD CONSTRAINT fk_equipement_saison FOREIGN KEY (saison_id) REFERENCES saison(id);
|
||||
|
||||
-- 3. Ajout de saison_id sur licence
|
||||
-- Licence a déjà une colonne saison (String). On va la remplacer par saison_id
|
||||
ALTER TABLE licence RENAME COLUMN saison TO ancienne_saison;
|
||||
ALTER TABLE licence ADD COLUMN saison_id BIGINT;
|
||||
UPDATE licence SET saison_id = (SELECT id FROM saison LIMIT 1);
|
||||
ALTER TABLE licence ALTER COLUMN saison_id SET NOT NULL;
|
||||
ALTER TABLE licence ADD CONSTRAINT fk_licence_saison FOREIGN KEY (saison_id) REFERENCES saison(id);
|
||||
ALTER TABLE licence DROP COLUMN ancienne_saison;
|
||||
|
||||
-- 4. Migration de paiement et dotation pour pointer sur licence_id au lieu de adherent_id
|
||||
-- Ajout des colonnes licence_id
|
||||
-- (Paiement et Dotation avaient un adherent_id qui n'est pas dans l'entité actuelle mais peut-être en base ?)
|
||||
-- D'après les entités, Paiement et Dotation ont DEJA licence_id et n'ont PAS adherent_id !
|
||||
-- Le plan proposait de modifier ça mais le code a DÉJÀ ces modifications.
|
||||
-- Je vais juste vérifier s'il faut modifier la base de données.
|
||||
-- Les entités Paiement.java et Dotation.java ont déjà `private Licence licence;`
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.astalange.core;
|
||||
|
||||
import com.astalange.core.entity.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class AdherentRecalculationTest {
|
||||
|
||||
@Test
|
||||
public void testLicencePriceCalculationBasedOnResidencyAndCategory() {
|
||||
Adherent adherent = new Adherent();
|
||||
adherent.setNom("Doe");
|
||||
adherent.setPrenom("John");
|
||||
adherent.setDateNaissance(LocalDate.of(2015, 5, 10)); // born 2015
|
||||
adherent.setResidentTalange(true);
|
||||
|
||||
Categorie u11 = new Categorie();
|
||||
u11.setNom("U11");
|
||||
u11.setAnneeMin(2015);
|
||||
u11.setAnneeMax(2015);
|
||||
u11.setTarifBase(new BigDecimal("130.00"));
|
||||
u11.setTarifExterieur(new BigDecimal("160.00"));
|
||||
|
||||
Licence licence = new Licence();
|
||||
licence.setAdherent(adherent);
|
||||
licence.setCategorie(u11);
|
||||
|
||||
// Under residentTalange = true, base price should be 130
|
||||
assertEquals(new BigDecimal("130.00"), licence.getPrixTotal());
|
||||
|
||||
// Under residentTalange = false, base price should be 160
|
||||
adherent.setResidentTalange(false);
|
||||
assertEquals(new BigDecimal("160.00"), licence.getPrixTotal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCategoryUpdateOnBirthdateChangeSimulation() {
|
||||
// Set up adherent
|
||||
Adherent adherent = new Adherent();
|
||||
adherent.setDateNaissance(LocalDate.of(2015, 5, 10)); // 2015 birth year
|
||||
|
||||
Saison saison = new Saison();
|
||||
saison.setNom("2025-2026");
|
||||
saison.setEstActive(true);
|
||||
|
||||
// Set up categories
|
||||
Categorie u11 = new Categorie();
|
||||
u11.setNom("U11");
|
||||
u11.setAnneeMin(2015);
|
||||
u11.setAnneeMax(2015);
|
||||
u11.setSaison(saison);
|
||||
u11.setTarifBase(new BigDecimal("130.00"));
|
||||
|
||||
Categorie u12 = new Categorie();
|
||||
u12.setNom("U12");
|
||||
u12.setAnneeMin(2014);
|
||||
u12.setAnneeMax(2014);
|
||||
u12.setSaison(saison);
|
||||
u12.setTarifBase(new BigDecimal("140.00"));
|
||||
|
||||
List<Categorie> categories = List.of(u11, u12);
|
||||
|
||||
// Licence initially created for U11
|
||||
Licence licence = new Licence();
|
||||
licence.setAdherent(adherent);
|
||||
licence.setCategorie(u11);
|
||||
licence.setSaison(saison);
|
||||
|
||||
// Simulation of date of birth changing to 2014 (U12)
|
||||
adherent.setDateNaissance(LocalDate.of(2014, 5, 10));
|
||||
int newBirthYear = adherent.getDateNaissance().getYear();
|
||||
|
||||
// Simulate Controller's update logic
|
||||
Categorie newCat = categories.stream()
|
||||
.filter(c -> newBirthYear >= c.getAnneeMin() && newBirthYear <= c.getAnneeMax())
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
assertNotNull(newCat);
|
||||
assertEquals("U12", newCat.getNom());
|
||||
licence.setCategorie(newCat);
|
||||
|
||||
// Verify the licence's category has updated to U12
|
||||
assertEquals("U12", licence.getCategorie().getNom());
|
||||
// Verify price total is updated dynamically
|
||||
assertEquals(new BigDecimal("140.00"), licence.getPrixTotal());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.astalange.core;
|
||||
|
||||
import com.astalange.core.entity.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalTime;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CreneauEntrainementTest {
|
||||
|
||||
@Test
|
||||
public void testStartAndEndColumns() {
|
||||
CreneauEntrainement c1 = new CreneauEntrainement();
|
||||
c1.setHeureDebut(LocalTime.of(8, 0));
|
||||
c1.setHeureFin(LocalTime.of(9, 30));
|
||||
|
||||
// Start time 08:00 is (8 * 60) = 480 mins. Offset from 08:00 is 0 mins.
|
||||
// Column is (0 / 15) + 3 = 3.
|
||||
assertEquals(3, c1.getStartColumn());
|
||||
|
||||
// End time 09:30 is (9*60 + 30) = 570 mins. Offset from 08:00 is 90 mins.
|
||||
// Column is (90 / 15) + 3 = 9.
|
||||
assertEquals(9, c1.getEndColumn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartAndEndRows() {
|
||||
CreneauEntrainement c1 = new CreneauEntrainement();
|
||||
|
||||
// Test terrain complet (baseRow index 0 is 3, index 1 is 8)
|
||||
c1.setZone(ZoneTerrain.COMPLET);
|
||||
assertEquals(3, c1.getStartRow(0));
|
||||
assertEquals(7, c1.getEndRow(0));
|
||||
|
||||
assertEquals(8, c1.getStartRow(1));
|
||||
assertEquals(12, c1.getEndRow(1));
|
||||
|
||||
// Test demi-terrain A (Quarts 1 and 2)
|
||||
c1.setZone(ZoneTerrain.DEMI_A);
|
||||
assertEquals(3, c1.getStartRow(0));
|
||||
assertEquals(5, c1.getEndRow(0));
|
||||
|
||||
// Test demi-terrain B (Quarts 3 and 4)
|
||||
c1.setZone(ZoneTerrain.DEMI_B);
|
||||
assertEquals(5, c1.getStartRow(0));
|
||||
assertEquals(7, c1.getEndRow(0));
|
||||
|
||||
// Test single Quarts
|
||||
c1.setZone(ZoneTerrain.QUART_1);
|
||||
assertEquals(3, c1.getStartRow(0));
|
||||
assertEquals(4, c1.getEndRow(0));
|
||||
|
||||
c1.setZone(ZoneTerrain.QUART_4);
|
||||
assertEquals(6, c1.getStartRow(0));
|
||||
assertEquals(7, c1.getEndRow(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlapsWith() {
|
||||
Terrain t1 = new Terrain();
|
||||
t1.setId(1L);
|
||||
Terrain t2 = new Terrain();
|
||||
t2.setId(2L);
|
||||
|
||||
CreneauEntrainement c1 = new CreneauEntrainement();
|
||||
c1.setJourSemaine(JourSemaine.LUNDI);
|
||||
c1.setTerrain(t1);
|
||||
c1.setZone(ZoneTerrain.DEMI_A);
|
||||
c1.setHeureDebut(LocalTime.of(18, 0));
|
||||
c1.setHeureFin(LocalTime.of(19, 30));
|
||||
|
||||
// 1. Different day -> No overlap
|
||||
CreneauEntrainement c2 = new CreneauEntrainement();
|
||||
c2.setJourSemaine(JourSemaine.MARDI);
|
||||
c2.setTerrain(t1);
|
||||
c2.setZone(ZoneTerrain.DEMI_A);
|
||||
c2.setHeureDebut(LocalTime.of(18, 0));
|
||||
c2.setHeureFin(LocalTime.of(19, 30));
|
||||
assertFalse(c1.overlapsWith(c2));
|
||||
|
||||
// 2. Different terrain -> No overlap
|
||||
c2.setJourSemaine(JourSemaine.LUNDI);
|
||||
c2.setTerrain(t2);
|
||||
assertFalse(c1.overlapsWith(c2));
|
||||
|
||||
// 3. Same day, same terrain, non-overlapping times -> No overlap
|
||||
c2.setTerrain(t1);
|
||||
c2.setHeureDebut(LocalTime.of(19, 30));
|
||||
c2.setHeureFin(LocalTime.of(21, 0));
|
||||
assertFalse(c1.overlapsWith(c2));
|
||||
|
||||
// 4. Same day, same terrain, overlapping times, non-overlapping zones (Demi_A and Demi_B don't overlap)
|
||||
c2.setHeureDebut(LocalTime.of(18, 30));
|
||||
c2.setHeureFin(LocalTime.of(20, 0));
|
||||
c2.setZone(ZoneTerrain.DEMI_B);
|
||||
assertFalse(c1.overlapsWith(c2));
|
||||
|
||||
// 5. Same day, same terrain, overlapping times, overlapping zones (Demi_A and Complet overlap!)
|
||||
c2.setZone(ZoneTerrain.COMPLET);
|
||||
assertTrue(c1.overlapsWith(c2));
|
||||
|
||||
// 6. Same day, same terrain, overlapping times, overlapping zones (Demi_A and Quart_1 overlap!)
|
||||
c2.setZone(ZoneTerrain.QUART_1);
|
||||
assertTrue(c1.overlapsWith(c2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.astalange.core;
|
||||
|
||||
import com.astalange.core.entity.Dotation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class DotationSizeMatchTest {
|
||||
|
||||
@Test
|
||||
public void testAdherent60SizeMatchBugFix() {
|
||||
String adherentTaille = "11/12ANS (Taille 152cm)";
|
||||
String adherentPointure = "35/38 (Taille 2)";
|
||||
|
||||
// Equipment options for Junior Maillot / Shorts / Tracksuits
|
||||
String opt56 = "5/6ANS (Taille 116cm)";
|
||||
String opt78 = "7/8ANS (Taille 128cm)";
|
||||
String opt910 = "9/10ANS (Taille 140cm)";
|
||||
String opt1112 = "11/12ANS (Taille 152cm)";
|
||||
String opt1314 = "13/14ANS (Taille 164cm)";
|
||||
|
||||
assertFalse(Dotation.isSizeMatch(opt56, adherentTaille), "5/6ANS should NOT match 11/12ANS");
|
||||
assertFalse(Dotation.isSizeMatch(opt78, adherentTaille), "7/8ANS should NOT match 11/12ANS");
|
||||
assertFalse(Dotation.isSizeMatch(opt910, adherentTaille), "9/10ANS should NOT match 11/12ANS");
|
||||
assertTrue(Dotation.isSizeMatch(opt1112, adherentTaille), "11/12ANS MUST match 11/12ANS");
|
||||
assertFalse(Dotation.isSizeMatch(opt1314, adherentTaille), "13/14ANS should NOT match 11/12ANS");
|
||||
|
||||
// Sock sizes
|
||||
String sock2730 = "27/30 (Taille 0)";
|
||||
String sock3134 = "31/34 (Taille 1)";
|
||||
String sock3538 = "35/38 (Taille 2)";
|
||||
String sock3942 = "39/42 (Taille 3)";
|
||||
|
||||
assertFalse(Dotation.isSizeMatch(sock2730, adherentPointure), "27/30 should NOT match 35/38");
|
||||
assertFalse(Dotation.isSizeMatch(sock3134, adherentPointure), "31/34 should NOT match 35/38");
|
||||
assertTrue(Dotation.isSizeMatch(sock3538, adherentPointure), "35/38 MUST match 35/38");
|
||||
assertFalse(Dotation.isSizeMatch(sock3942, adherentPointure), "39/42 should NOT match 35/38");
|
||||
|
||||
// Ensure sock sizes do not match clothing size 152cm due to "Taille 1"
|
||||
assertFalse(Dotation.isSizeMatch(sock3134, adherentTaille), "Sock 31/34 (Taille 1) should NOT match clothing 152cm");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLetterSizes() {
|
||||
assertFalse(Dotation.isSizeMatch("S", "XL"));
|
||||
assertFalse(Dotation.isSizeMatch("M", "XL"));
|
||||
assertTrue(Dotation.isSizeMatch("XL", "XL"));
|
||||
assertTrue(Dotation.isSizeMatch("xxl", "XXL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpaceVariations() {
|
||||
assertTrue(Dotation.isSizeMatch("5/6 ANS (Taille 116cm)", "5/6ANS"));
|
||||
assertTrue(Dotation.isSizeMatch("11/12 ANS (Taille 152cm)", "11/12ANS (Taille 152 cm)"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.astalange.core;
|
||||
|
||||
import com.astalange.core.entity.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class EducateurTest {
|
||||
|
||||
@Test
|
||||
public void testEducateurEntityAndAssociations() {
|
||||
Categorie U15 = new Categorie();
|
||||
U15.setNom("U15");
|
||||
|
||||
Equipe equipeA = new Equipe();
|
||||
equipeA.setNom("Équipe A");
|
||||
equipeA.setCategorie(U15);
|
||||
|
||||
Educateur educateur = new Educateur();
|
||||
educateur.setNom("Dupont");
|
||||
educateur.setPrenom("Jean");
|
||||
educateur.setTelephone("0612345678");
|
||||
educateur.setEmail("jean.dupont@example.com");
|
||||
educateur.setCategorie(U15);
|
||||
educateur.setEquipe(equipeA);
|
||||
|
||||
assertEquals("Dupont", educateur.getNom());
|
||||
assertEquals("Jean", educateur.getPrenom());
|
||||
assertEquals("0612345678", educateur.getTelephone());
|
||||
assertEquals("jean.dupont@example.com", educateur.getEmail());
|
||||
assertEquals(U15, educateur.getCategorie());
|
||||
assertEquals(equipeA, educateur.getEquipe());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.astalange.core;
|
||||
|
||||
import com.astalange.core.entity.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class EquipeTest {
|
||||
|
||||
@Test
|
||||
public void testEquipeEntityAndAssociations() {
|
||||
Categorie U15 = new Categorie();
|
||||
U15.setNom("U15");
|
||||
|
||||
Equipe equipeA = new Equipe();
|
||||
equipeA.setNom("Équipe 1");
|
||||
equipeA.setCategorie(U15);
|
||||
|
||||
assertEquals("Équipe 1", equipeA.getNom());
|
||||
assertEquals(U15, equipeA.getCategorie());
|
||||
|
||||
Licence licence = new Licence();
|
||||
licence.setCategorie(U15);
|
||||
licence.setEquipe(equipeA);
|
||||
|
||||
assertEquals(equipeA, licence.getEquipe());
|
||||
|
||||
CreneauEntrainement creneau = new CreneauEntrainement();
|
||||
creneau.setCategorie(U15);
|
||||
creneau.setEquipe(equipeA);
|
||||
|
||||
assertEquals(equipeA, creneau.getEquipe());
|
||||
}
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
package com.astalange.core.service;
|
||||
|
||||
import com.astalange.core.entity.*;
|
||||
import com.astalange.core.repository.CategorieRepository;
|
||||
import com.astalange.core.repository.DotationRepository;
|
||||
import com.astalange.core.repository.EquipementRepository;
|
||||
import com.astalange.core.repository.SaisonRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class DotationIntegrationTest {
|
||||
|
||||
@Mock
|
||||
private CategorieRepository categorieRepository;
|
||||
|
||||
@Mock
|
||||
private SaisonRepository saisonRepository;
|
||||
|
||||
@Mock
|
||||
private EquipementRepository equipementRepository;
|
||||
|
||||
@Mock
|
||||
private com.astalange.core.repository.LicenceRepository licenceRepository;
|
||||
|
||||
@InjectMocks
|
||||
private CategorieService categorieService;
|
||||
|
||||
private Equipement maillotJunior;
|
||||
private Equipement chaussettesJunior;
|
||||
private Equipement maillotAdulte;
|
||||
private Equipement chaussettesAdulte;
|
||||
private Categorie catJunior;
|
||||
private Categorie catAdulte;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// 1. Junior Equipment
|
||||
maillotJunior = new Equipement();
|
||||
maillotJunior.setId(1L);
|
||||
maillotJunior.setNom("Maillot de match Puma (Junior)");
|
||||
maillotJunior.setTypePublic("TOUS");
|
||||
maillotJunior.setTaillesDisponibles("5/6ANS (Taille 116cm),7/8ANS (Taille 128cm),9/10ANS (Taille 140cm),11/12ANS (Taille 152cm),13/14ANS (Taille 164cm),15/16ANS (Taille 176cm)");
|
||||
|
||||
chaussettesJunior = new Equipement();
|
||||
chaussettesJunior.setId(2L);
|
||||
chaussettesJunior.setNom("Chaussettes puma (Junior)");
|
||||
chaussettesJunior.setTypePublic("TOUS");
|
||||
chaussettesJunior.setTaillesDisponibles("27/30 (Taille 0),31/34 (Taille 1),35/38 (Taille 2),39/42 (Taille 3)");
|
||||
|
||||
catJunior = new Categorie();
|
||||
catJunior.setId(10L);
|
||||
catJunior.setNom("U11");
|
||||
|
||||
CategorieEquipement ce1 = new CategorieEquipement();
|
||||
ce1.setCategorie(catJunior);
|
||||
ce1.setEquipement(maillotJunior);
|
||||
ce1.setObligatoire(true);
|
||||
|
||||
CategorieEquipement ce2 = new CategorieEquipement();
|
||||
ce2.setCategorie(catJunior);
|
||||
ce2.setEquipement(chaussettesJunior);
|
||||
ce2.setObligatoire(true);
|
||||
|
||||
catJunior.setCategorieEquipements(List.of(ce1, ce2));
|
||||
|
||||
// 2. Adult Equipment
|
||||
maillotAdulte = new Equipement();
|
||||
maillotAdulte.setId(3L);
|
||||
maillotAdulte.setNom("Maillot de match Puma (Adulte)");
|
||||
maillotAdulte.setTypePublic("TOUS");
|
||||
maillotAdulte.setTaillesDisponibles("XS,S,M,L,XL,XXL");
|
||||
|
||||
chaussettesAdulte = new Equipement();
|
||||
chaussettesAdulte.setId(4L);
|
||||
chaussettesAdulte.setNom("Chaussettes puma (Adulte)");
|
||||
chaussettesAdulte.setTypePublic("TOUS");
|
||||
chaussettesAdulte.setTaillesDisponibles("35/38 (Taille 2),39/42 (Taille 3),43/46 (Taille 4)");
|
||||
|
||||
catAdulte = new Categorie();
|
||||
catAdulte.setId(20L);
|
||||
catAdulte.setNom("Seniors");
|
||||
|
||||
CategorieEquipement ce3 = new CategorieEquipement();
|
||||
ce3.setCategorie(catAdulte);
|
||||
ce3.setEquipement(maillotAdulte);
|
||||
ce3.setObligatoire(true);
|
||||
|
||||
CategorieEquipement ce4 = new CategorieEquipement();
|
||||
ce4.setCategorie(catAdulte);
|
||||
ce4.setEquipement(chaussettesAdulte);
|
||||
ce4.setObligatoire(true);
|
||||
|
||||
catAdulte.setCategorieEquipements(List.of(ce3, ce4));
|
||||
}
|
||||
|
||||
private Licence createLicence(Categorie cat, String tailleVetement, String pointure) {
|
||||
Adherent adherent = new Adherent();
|
||||
adherent.setTypeMaillot("JOUEUR");
|
||||
adherent.setTailleVetement(tailleVetement);
|
||||
adherent.setPointure(pointure);
|
||||
|
||||
Licence licence = new Licence();
|
||||
licence.setId(100L);
|
||||
licence.setAdherent(adherent);
|
||||
licence.setCategorie(cat);
|
||||
licence.setDotations(new ArrayList<>());
|
||||
return licence;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Junior 11/12ANS (Bug initial Adhérent 60) -> Doit reporter 11/12ANS et 35/38")
|
||||
public void testAdherent60Synchronization() {
|
||||
Licence licence = createLicence(catJunior, "11/12ANS (Taille 152cm)", "35/38 (Taille 2)");
|
||||
|
||||
categorieService.syncDotationsForLicence(licence);
|
||||
|
||||
List<Dotation> dotations = licence.getDotations();
|
||||
assertEquals(2, dotations.size());
|
||||
Dotation dMaillot = dotations.stream().filter(d -> d.getEquipement().getId().equals(1L)).findFirst().orElseThrow();
|
||||
Dotation dChaussettes = dotations.stream().filter(d -> d.getEquipement().getId().equals(2L)).findFirst().orElseThrow();
|
||||
|
||||
assertEquals("11/12ANS (Taille 152cm)", dMaillot.getTaille(), "Le maillot doit être 11/12ANS et non 5/6ANS");
|
||||
assertEquals("35/38 (Taille 2)", dChaussettes.getTaille(), "Les chaussettes doivent être 35/38 et non 31/34");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Junior - Test de toutes les tailles (5/6, 7/8, 9/10, 11/12, 13/14, 15/16)")
|
||||
public void testAllJuniorSizes() {
|
||||
String[][] cases = {
|
||||
{"5/6ANS (Taille 116cm)", "27/30 (Taille 0)", "5/6ANS (Taille 116cm)", "27/30 (Taille 0)"},
|
||||
{"7/8ANS (Taille 128cm)", "31/34 (Taille 1)", "7/8ANS (Taille 128cm)", "31/34 (Taille 1)"},
|
||||
{"9/10ANS (Taille 140cm)", "31/34 (Taille 1)", "9/10ANS (Taille 140cm)", "31/34 (Taille 1)"},
|
||||
{"11/12ANS (Taille 152cm)", "35/38 (Taille 2)", "11/12ANS (Taille 152cm)", "35/38 (Taille 2)"},
|
||||
{"13/14ANS (Taille 164cm)", "35/38 (Taille 2)", "13/14ANS (Taille 164cm)", "35/38 (Taille 2)"},
|
||||
{"15/16ANS (Taille 176cm)", "39/42 (Taille 3)", "15/16ANS (Taille 176cm)", "39/42 (Taille 3)"}
|
||||
};
|
||||
|
||||
for (String[] testCase : cases) {
|
||||
String tv = testCase[0];
|
||||
String pt = testCase[1];
|
||||
String expectedMaillot = testCase[2];
|
||||
String expectedChaussettes = testCase[3];
|
||||
|
||||
Licence licence = createLicence(catJunior, tv, pt);
|
||||
categorieService.syncDotationsForLicence(licence);
|
||||
|
||||
List<Dotation> dotations = licence.getDotations();
|
||||
Dotation dMaillot = dotations.stream().filter(d -> d.getEquipement().getId().equals(1L)).findFirst().orElseThrow();
|
||||
Dotation dChaussettes = dotations.stream().filter(d -> d.getEquipement().getId().equals(2L)).findFirst().orElseThrow();
|
||||
|
||||
assertEquals(expectedMaillot, dMaillot.getTaille(), "Erreur pour la taille vêtement: " + tv);
|
||||
assertEquals(expectedChaussettes, dChaussettes.getTaille(), "Erreur pour la pointure: " + pt);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Adulte - Test de toutes les tailles (XS, S, M, L, XL, XXL)")
|
||||
public void testAllAdultSizes() {
|
||||
String[][] cases = {
|
||||
{"XS", "35/38 (Taille 2)", "XS", "35/38 (Taille 2)"},
|
||||
{"S", "39/42 (Taille 3)", "S", "39/42 (Taille 3)"},
|
||||
{"M", "39/42 (Taille 3)", "M", "39/42 (Taille 3)"},
|
||||
{"L", "43/46 (Taille 4)", "L", "43/46 (Taille 4)"},
|
||||
{"XL", "43/46 (Taille 4)", "XL", "43/46 (Taille 4)"},
|
||||
{"XXL", "43/46 (Taille 4)", "XXL", "43/46 (Taille 4)"}
|
||||
};
|
||||
|
||||
for (String[] testCase : cases) {
|
||||
String tv = testCase[0];
|
||||
String pt = testCase[1];
|
||||
String expectedMaillot = testCase[2];
|
||||
String expectedChaussettes = testCase[3];
|
||||
|
||||
Licence licence = createLicence(catAdulte, tv, pt);
|
||||
categorieService.syncDotationsForLicence(licence);
|
||||
|
||||
List<Dotation> dotations = licence.getDotations();
|
||||
Dotation dMaillot = dotations.stream().filter(d -> d.getEquipement().getId().equals(3L)).findFirst().orElseThrow();
|
||||
Dotation dChaussettes = dotations.stream().filter(d -> d.getEquipement().getId().equals(4L)).findFirst().orElseThrow();
|
||||
|
||||
assertEquals(expectedMaillot, dMaillot.getTaille(), "Erreur pour la taille adulte vêtement: " + tv);
|
||||
assertEquals(expectedChaussettes, dChaussettes.getTaille(), "Erreur pour la pointure adulte: " + pt);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Formats alternatifs (Espaces, sans mention de taille)")
|
||||
public void testAlternativeFormats() {
|
||||
Licence licence1 = createLicence(catJunior, "11/12 ANS (Taille 152 cm)", "35/38 (Taille 2)");
|
||||
categorieService.syncDotationsForLicence(licence1);
|
||||
|
||||
Dotation dMaillot1 = licence1.getDotations().stream().filter(d -> d.getEquipement().getId().equals(1L)).findFirst().orElseThrow();
|
||||
assertEquals("11/12ANS (Taille 152cm)", dMaillot1.getTaille());
|
||||
|
||||
Licence licence2 = createLicence(catJunior, "11/12ANS", "35/38");
|
||||
categorieService.syncDotationsForLicence(licence2);
|
||||
|
||||
Dotation dMaillot2 = licence2.getDotations().stream().filter(d -> d.getEquipement().getId().equals(1L)).findFirst().orElseThrow();
|
||||
Dotation dChaussettes2 = licence2.getDotations().stream().filter(d -> d.getEquipement().getId().equals(2L)).findFirst().orElseThrow();
|
||||
assertEquals("11/12ANS (Taille 152cm)", dMaillot2.getTaille());
|
||||
assertEquals("35/38 (Taille 2)", dChaussettes2.getTaille());
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>as-talange-parent</artifactId>
|
||||
<groupId>com.astalange</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>1.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.astalange.web.config;
|
||||
|
||||
import com.astalange.core.security.CustomUserDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class PasswordChangeInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth != null && auth.isAuthenticated() && auth.getPrincipal() instanceof CustomUserDetails) {
|
||||
CustomUserDetails userDetails = (CustomUserDetails) auth.getPrincipal();
|
||||
if (userDetails.isMustChangePassword()) {
|
||||
String uri = request.getRequestURI();
|
||||
// Exclude /change-password, /logout, static assets, error pages
|
||||
if (!uri.equals("/change-password") &&
|
||||
!uri.equals("/logout") &&
|
||||
!uri.startsWith("/css/") &&
|
||||
!uri.startsWith("/js/") &&
|
||||
!uri.startsWith("/images/") &&
|
||||
!uri.equals("/error")) {
|
||||
response.sendRedirect("/change-password");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@@ -25,7 +28,12 @@ public class SecurityConfig {
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
|
||||
.requestMatchers("/css/**", "/js/**", "/images/**", "/inscription-public/**").permitAll()
|
||||
.requestMatchers("/change-password").authenticated()
|
||||
.requestMatchers("/utilisateurs/**", "/saisons/**", "/categories/**", "/equipes/**", "/modespaiement/**", "/equipements/**", "/admin/logs/**").hasRole("ADMIN")
|
||||
.requestMatchers("/paiements/**", "/paiement/**").hasAnyRole("ADMIN", "TRESORERIE", "AGENT_SAISIE")
|
||||
.requestMatchers("/planning/**").hasAnyRole("ADMIN", "AGENT_SAISIE")
|
||||
.requestMatchers("/adherents/**", "/dotations/**").hasAnyRole("ADMIN", "TRESORERIE", "AGENT_SAISIE")
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.formLogin(form -> form
|
||||
@@ -36,6 +44,10 @@ public class SecurityConfig {
|
||||
.logout(logout -> logout
|
||||
.logoutSuccessUrl("/login?logout")
|
||||
.permitAll()
|
||||
)
|
||||
.sessionManagement(session -> session
|
||||
.maximumSessions(100)
|
||||
.sessionRegistry(sessionRegistry())
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
@@ -52,4 +64,14 @@ public class SecurityConfig {
|
||||
authProvider.setPasswordEncoder(passwordEncoder());
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionRegistry sessionRegistry() {
|
||||
return new SessionRegistryImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpSessionEventPublisher httpSessionEventPublisher() {
|
||||
return new HttpSessionEventPublisher();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.astalange.web.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
private final PasswordChangeInterceptor passwordChangeInterceptor;
|
||||
|
||||
public WebConfig(PasswordChangeInterceptor passwordChangeInterceptor) {
|
||||
this.passwordChangeInterceptor = passwordChangeInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(passwordChangeInterceptor);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.astalange.web.controller;
|
||||
|
||||
import com.astalange.core.entity.Adherent;
|
||||
import com.astalange.core.entity.Categorie;
|
||||
import com.astalange.core.entity.Licence;
|
||||
import com.astalange.core.entity.Saison;
|
||||
import com.astalange.core.repository.AdherentRepository;
|
||||
import com.astalange.core.repository.CategorieRepository;
|
||||
import com.astalange.core.repository.SaisonRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -18,18 +22,144 @@ public class AdherentController {
|
||||
private final CategorieRepository categorieRepository;
|
||||
private final com.astalange.core.repository.LicenceRepository licenceRepository;
|
||||
private final com.astalange.core.repository.ModePaiementRepository modePaiementRepository;
|
||||
private final SaisonRepository saisonRepository;
|
||||
private final com.astalange.core.service.CategorieService categorieService;
|
||||
|
||||
public AdherentController(AdherentRepository adherentRepository, CategorieRepository categorieRepository, com.astalange.core.repository.LicenceRepository licenceRepository, com.astalange.core.repository.ModePaiementRepository modePaiementRepository) {
|
||||
public AdherentController(AdherentRepository adherentRepository, CategorieRepository categorieRepository, com.astalange.core.repository.LicenceRepository licenceRepository, com.astalange.core.repository.ModePaiementRepository modePaiementRepository, SaisonRepository saisonRepository, com.astalange.core.service.CategorieService categorieService) {
|
||||
this.adherentRepository = adherentRepository;
|
||||
this.categorieRepository = categorieRepository;
|
||||
this.licenceRepository = licenceRepository;
|
||||
this.modePaiementRepository = modePaiementRepository;
|
||||
this.saisonRepository = saisonRepository;
|
||||
this.categorieService = categorieService;
|
||||
}
|
||||
|
||||
@org.springframework.web.bind.annotation.ModelAttribute("equipes")
|
||||
public List<com.astalange.core.entity.Equipe> populateEquipes() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String listAdherents(Model model) {
|
||||
List<Adherent> adherents = adherentRepository.findAll();
|
||||
model.addAttribute("adherents", adherents);
|
||||
public String listAdherents(
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String query,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String nom,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String prenom,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String categorie,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String licence,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String email,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false) String paiement,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false, defaultValue = "nom") String sortField,
|
||||
@org.springframework.web.bind.annotation.RequestParam(required = false, defaultValue = "asc") String sortDirection,
|
||||
@org.springframework.web.bind.annotation.RequestParam(defaultValue = "0") int page,
|
||||
@org.springframework.web.bind.annotation.RequestParam(defaultValue = "20") int size,
|
||||
Model model) {
|
||||
|
||||
List<Adherent> adherents = adherentRepository.findAllWithLicencesAndCategories();
|
||||
|
||||
// 1. Filter by global query
|
||||
if (query != null && !query.trim().isEmpty()) {
|
||||
String q = query.trim().toLowerCase();
|
||||
adherents = adherents.stream().filter(a ->
|
||||
(a.getNom() != null && a.getNom().toLowerCase().contains(q)) ||
|
||||
(a.getPrenom() != null && a.getPrenom().toLowerCase().contains(q)) ||
|
||||
(a.getLicenceActuelle() != null && a.getLicenceActuelle().getNumeroLicence() != null && a.getLicenceActuelle().getNumeroLicence().toLowerCase().contains(q))
|
||||
).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("searchQuery", query.trim());
|
||||
}
|
||||
|
||||
// 2. Filter by specific column filters
|
||||
if (nom != null && !nom.trim().isEmpty()) {
|
||||
String n = nom.trim().toLowerCase();
|
||||
adherents = adherents.stream().filter(a -> a.getNom() != null && a.getNom().toLowerCase().contains(n)).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("nomFilter", nom.trim());
|
||||
}
|
||||
if (prenom != null && !prenom.trim().isEmpty()) {
|
||||
String p = prenom.trim().toLowerCase();
|
||||
adherents = adherents.stream().filter(a -> a.getPrenom() != null && a.getPrenom().toLowerCase().contains(p)).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("prenomFilter", prenom.trim());
|
||||
}
|
||||
if (categorie != null && !categorie.trim().isEmpty()) {
|
||||
adherents = adherents.stream().filter(a ->
|
||||
a.getLicenceActuelle() != null &&
|
||||
a.getLicenceActuelle().getCategorie() != null &&
|
||||
a.getLicenceActuelle().getCategorie().getNom().equalsIgnoreCase(categorie.trim())
|
||||
).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("categorieFilter", categorie.trim());
|
||||
}
|
||||
if (licence != null && !licence.trim().isEmpty()) {
|
||||
String l = licence.trim().toLowerCase();
|
||||
adherents = adherents.stream().filter(a ->
|
||||
a.getLicenceActuelle() != null &&
|
||||
a.getLicenceActuelle().getNumeroLicence() != null &&
|
||||
a.getLicenceActuelle().getNumeroLicence().toLowerCase().contains(l)
|
||||
).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("licenceFilter", licence.trim());
|
||||
}
|
||||
if (email != null && !email.trim().isEmpty()) {
|
||||
String e = email.trim().toLowerCase();
|
||||
adherents = adherents.stream().filter(a -> a.getEmail() != null && a.getEmail().toLowerCase().contains(e)).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("emailFilter", email.trim());
|
||||
}
|
||||
if (paiement != null && !paiement.trim().isEmpty()) {
|
||||
adherents = adherents.stream().filter(a -> {
|
||||
String statut = a.getStatutPaiement();
|
||||
if ("A_JOUR".equalsIgnoreCase(paiement)) {
|
||||
return "À jour".equalsIgnoreCase(statut);
|
||||
} else if ("RESTE".equalsIgnoreCase(paiement)) {
|
||||
return statut != null && statut.startsWith("Reste");
|
||||
} else if ("AUCUNE".equalsIgnoreCase(paiement)) {
|
||||
return "Aucune licence".equalsIgnoreCase(statut);
|
||||
}
|
||||
return true;
|
||||
}).collect(java.util.stream.Collectors.toList());
|
||||
model.addAttribute("paiementFilter", paiement.trim());
|
||||
}
|
||||
|
||||
// 3. Sort
|
||||
java.util.Comparator<Adherent> comparator = (a1, a2) -> 0;
|
||||
if ("nom".equalsIgnoreCase(sortField)) {
|
||||
comparator = java.util.Comparator.comparing(a -> a.getNom() != null ? a.getNom() : "");
|
||||
} else if ("prenom".equalsIgnoreCase(sortField)) {
|
||||
comparator = java.util.Comparator.comparing(a -> a.getPrenom() != null ? a.getPrenom() : "");
|
||||
} else if ("categorie".equalsIgnoreCase(sortField)) {
|
||||
comparator = java.util.Comparator.comparing(a -> (a.getLicenceActuelle() != null && a.getLicenceActuelle().getCategorie() != null && a.getLicenceActuelle().getCategorie().getNom() != null) ? a.getLicenceActuelle().getCategorie().getNom() : "");
|
||||
} else if ("licence".equalsIgnoreCase(sortField)) {
|
||||
comparator = java.util.Comparator.comparing(a -> (a.getLicenceActuelle() != null && a.getLicenceActuelle().getNumeroLicence() != null) ? a.getLicenceActuelle().getNumeroLicence() : "");
|
||||
} else if ("email".equalsIgnoreCase(sortField)) {
|
||||
comparator = java.util.Comparator.comparing(a -> a.getEmail() != null ? a.getEmail() : "");
|
||||
}
|
||||
|
||||
if ("desc".equalsIgnoreCase(sortDirection)) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
adherents.sort(comparator);
|
||||
|
||||
model.addAttribute("sortField", sortField);
|
||||
model.addAttribute("sortDirection", sortDirection);
|
||||
|
||||
// 4. Paginate
|
||||
int totalElements = adherents.size();
|
||||
int totalPages = (int) Math.ceil((double) totalElements / size);
|
||||
if (page < 0) page = 0;
|
||||
if (page >= totalPages && totalPages > 0) page = totalPages - 1;
|
||||
|
||||
int start = page * size;
|
||||
int end = Math.min(start + size, totalElements);
|
||||
List<Adherent> pageContent = (start < totalElements) ? adherents.subList(start, end) : List.of();
|
||||
|
||||
model.addAttribute("adherents", pageContent);
|
||||
model.addAttribute("currentPage", page);
|
||||
model.addAttribute("totalPages", totalPages);
|
||||
model.addAttribute("totalElements", totalElements);
|
||||
model.addAttribute("pageSize", size);
|
||||
|
||||
Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (saisonActive != null) {
|
||||
model.addAttribute("categories", categorieRepository.findBySaison(saisonActive));
|
||||
} else {
|
||||
model.addAttribute("categories", categorieRepository.findAll());
|
||||
}
|
||||
|
||||
return "adherents/list";
|
||||
}
|
||||
|
||||
@@ -46,19 +176,102 @@ public class AdherentController {
|
||||
Model model) {
|
||||
|
||||
if (result.hasErrors()) {
|
||||
if (adherent.getId() != null) {
|
||||
Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (saisonActive != null) {
|
||||
model.addAttribute("categories", categorieRepository.findBySaison(saisonActive));
|
||||
model.addAttribute("saisonActive", saisonActive);
|
||||
} else {
|
||||
model.addAttribute("categories", categorieRepository.findAll());
|
||||
}
|
||||
model.addAttribute("licences", licenceRepository.findByAdherentId(adherent.getId()));
|
||||
model.addAttribute("modesPaiement", modePaiementRepository.findAll());
|
||||
} else {
|
||||
Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (saisonActive != null) {
|
||||
model.addAttribute("categories", categorieRepository.findBySaison(saisonActive));
|
||||
} else {
|
||||
model.addAttribute("categories", categorieRepository.findAll());
|
||||
}
|
||||
}
|
||||
return "adherents/form";
|
||||
}
|
||||
|
||||
if (adherent.getId() != null) {
|
||||
Adherent existing = adherentRepository.findById(adherent.getId()).orElse(null);
|
||||
if (existing != null) {
|
||||
boolean dateChanged = !existing.getDateNaissance().equals(adherent.getDateNaissance());
|
||||
boolean typeMaillotChanged = !existing.getTypeMaillot().equals(adherent.getTypeMaillot());
|
||||
|
||||
if (dateChanged || typeMaillotChanged) {
|
||||
int newBirthYear = adherent.getDateNaissance().getYear();
|
||||
List<Licence> licences = licenceRepository.findByAdherentId(adherent.getId());
|
||||
for (Licence licence : licences) {
|
||||
if (dateChanged) {
|
||||
Saison saison = licence.getSaison();
|
||||
Categorie newCat = categorieRepository.findBySaison(saison).stream()
|
||||
.filter(c -> newBirthYear >= c.getAnneeMin() && newBirthYear <= c.getAnneeMax())
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (newCat != null) {
|
||||
licence.setCategorie(newCat);
|
||||
licence = licenceRepository.save(licence);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to update the entity's state before syncing dotations so it reads the new typeMaillot.
|
||||
// We haven't updated 'existing' yet, so let's temporarily set it on the licence's adherent or wait.
|
||||
// Actually, 'adherent' has the new typeMaillot.
|
||||
licence.getAdherent().setTypeMaillot(adherent.getTypeMaillot());
|
||||
categorieService.syncDotationsForLicence(licence);
|
||||
}
|
||||
}
|
||||
|
||||
existing.setNom(adherent.getNom());
|
||||
existing.setPrenom(adherent.getPrenom());
|
||||
existing.setDateNaissance(adherent.getDateNaissance());
|
||||
existing.setLieuNaissanceVille(adherent.getLieuNaissanceVille());
|
||||
existing.setLieuNaissancePays(adherent.getLieuNaissancePays());
|
||||
existing.setNationalite(adherent.getNationalite());
|
||||
existing.setEmail(adherent.getEmail());
|
||||
existing.setTelephone(adherent.getTelephone());
|
||||
existing.setRepresentantLegal(adherent.getRepresentantLegal());
|
||||
existing.setResidentTalange(adherent.isResidentTalange());
|
||||
existing.setSexe(adherent.getSexe());
|
||||
existing.setTypeMaillot(adherent.getTypeMaillot());
|
||||
existing.setTailleVetement(adherent.getTailleVetement());
|
||||
existing.setPointure(adherent.getPointure());
|
||||
|
||||
adherentRepository.save(existing);
|
||||
|
||||
List<Licence> licences = licenceRepository.findByAdherentId(existing.getId());
|
||||
for (Licence licence : licences) {
|
||||
categorieService.syncDotationsForLicence(licence);
|
||||
}
|
||||
} else {
|
||||
adherentRepository.save(adherent);
|
||||
}
|
||||
return "redirect:/adherents";
|
||||
} else {
|
||||
Adherent saved = adherentRepository.save(adherent);
|
||||
return "redirect:/adherents/" + saved.getId() + "/edit";
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/edit")
|
||||
public String editAdherent(@org.springframework.web.bind.annotation.PathVariable Long id, Model model) {
|
||||
Adherent adherent = adherentRepository.findById(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Adhérent invalide : " + id));
|
||||
model.addAttribute("adherent", adherent);
|
||||
|
||||
Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (saisonActive != null) {
|
||||
model.addAttribute("categories", categorieRepository.findBySaison(saisonActive));
|
||||
model.addAttribute("saisonActive", saisonActive);
|
||||
} else {
|
||||
model.addAttribute("categories", categorieRepository.findAll());
|
||||
}
|
||||
|
||||
model.addAttribute("adherent", adherent);
|
||||
model.addAttribute("licences", licenceRepository.findByAdherentId(id));
|
||||
model.addAttribute("modesPaiement", modePaiementRepository.findAll());
|
||||
return "adherents/form";
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.astalange.web.controller;
|
||||
|
||||
import com.astalange.core.entity.Adherent;
|
||||
import com.astalange.core.repository.PreInscriptionRepository;
|
||||
import com.astalange.core.service.PreInscriptionService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/admin/pre-inscriptions")
|
||||
public class AdminPreInscriptionController {
|
||||
|
||||
private final PreInscriptionRepository preInscriptionRepository;
|
||||
private final PreInscriptionService preInscriptionService;
|
||||
|
||||
public AdminPreInscriptionController(PreInscriptionRepository preInscriptionRepository,
|
||||
PreInscriptionService preInscriptionService) {
|
||||
this.preInscriptionRepository = preInscriptionRepository;
|
||||
this.preInscriptionService = preInscriptionService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String listPreInscriptions(Model model) {
|
||||
model.addAttribute("preInscriptions", preInscriptionRepository.findByStatutTraiteFalseOrderByDateCreationDesc());
|
||||
return "preinscriptions/list";
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/valider")
|
||||
@ResponseBody
|
||||
public String valider(@PathVariable Long id, HttpServletResponse response) {
|
||||
Adherent adherent = preInscriptionService.validerPreInscription(id, null);
|
||||
response.setHeader("HX-Trigger", "refreshBadge");
|
||||
// En HTMX, on renvoie une ligne vide pour la faire disparaître, ou on redirige via HX-Redirect
|
||||
// Mais comme on veut aller sur la page de l'adhérent pour finaliser la licence :
|
||||
response.setHeader("HX-Redirect", "/adherents/" + adherent.getId() + "/edit");
|
||||
return "";
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/rejeter")
|
||||
@ResponseBody
|
||||
public String rejeter(@PathVariable Long id, HttpServletResponse response) {
|
||||
preInscriptionService.rejeterPreInscription(id);
|
||||
response.setHeader("HX-Trigger", "refreshBadge");
|
||||
return ""; // HTMX target la ligne avec outerHTML -> supprime la ligne
|
||||
}
|
||||
|
||||
@GetMapping("/count")
|
||||
@ResponseBody
|
||||
public String countBadge() {
|
||||
long count = preInscriptionRepository.countByStatutTraiteFalse();
|
||||
if (count == 0) return "";
|
||||
return "<span class=\"bg-red-500 text-white rounded-full px-2 py-0.5 text-xs font-bold ml-2\">" + count + "</span>";
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.astalange.web.controller;
|
||||
|
||||
import com.astalange.core.repository.AuditLogPaiementRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/admin/logs/paiements")
|
||||
public class AuditLogPaiementController {
|
||||
|
||||
private final AuditLogPaiementRepository auditLogPaiementRepository;
|
||||
|
||||
public AuditLogPaiementController(AuditLogPaiementRepository auditLogPaiementRepository) {
|
||||
this.auditLogPaiementRepository = auditLogPaiementRepository;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String listLogs(
|
||||
@RequestParam(required = false) String action,
|
||||
@RequestParam(required = false) String utilisateur,
|
||||
@RequestParam(required = false) String adherent,
|
||||
Model model) {
|
||||
|
||||
model.addAttribute("logs", auditLogPaiementRepository.findByFilters(action, utilisateur, adherent));
|
||||
model.addAttribute("paramAction", action);
|
||||
model.addAttribute("paramUtilisateur", utilisateur);
|
||||
model.addAttribute("paramAdherent", adherent);
|
||||
|
||||
return "audit/paiements_logs";
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,31 @@
|
||||
package com.astalange.web.controller;
|
||||
|
||||
import com.astalange.core.entity.Categorie;
|
||||
import com.astalange.core.entity.Saison;
|
||||
import com.astalange.core.repository.CategorieRepository;
|
||||
import com.astalange.core.repository.SaisonRepository;
|
||||
import com.astalange.core.repository.EquipementRepository;
|
||||
import com.astalange.core.service.CategorieService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/categories")
|
||||
public class CategorieController {
|
||||
|
||||
private final CategorieRepository categorieRepository;
|
||||
private final SaisonRepository saisonRepository;
|
||||
private final EquipementRepository equipementRepository;
|
||||
private final CategorieService categorieService;
|
||||
|
||||
public CategorieController(CategorieRepository categorieRepository) {
|
||||
public CategorieController(CategorieRepository categorieRepository, SaisonRepository saisonRepository, EquipementRepository equipementRepository, CategorieService categorieService) {
|
||||
this.categorieRepository = categorieRepository;
|
||||
this.saisonRepository = saisonRepository;
|
||||
this.equipementRepository = equipementRepository;
|
||||
this.categorieService = categorieService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@@ -24,7 +36,11 @@ public class CategorieController {
|
||||
|
||||
@GetMapping("/new")
|
||||
public String showCreateForm(Model model) {
|
||||
if (!model.containsAttribute("categorie")) {
|
||||
model.addAttribute("categorie", new Categorie());
|
||||
}
|
||||
Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
model.addAttribute("allEquipements", activeSaison != null ? equipementRepository.findBySaison(activeSaison) : List.of());
|
||||
return "parametrage/categories_form";
|
||||
}
|
||||
|
||||
@@ -33,12 +49,61 @@ public class CategorieController {
|
||||
Categorie categorie = categorieRepository.findById(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid category ID: " + id));
|
||||
model.addAttribute("categorie", categorie);
|
||||
|
||||
Saison saison = categorie.getSaison();
|
||||
if (saison == null) {
|
||||
saison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
}
|
||||
|
||||
model.addAttribute("allEquipements", saison != null ? equipementRepository.findBySaison(saison) : List.of());
|
||||
return "parametrage/categories_form";
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String saveCategorie(@ModelAttribute("categorie") Categorie categorie) {
|
||||
categorieRepository.save(categorie);
|
||||
public String saveCategorie(@ModelAttribute("categorie") Categorie categorie,
|
||||
jakarta.servlet.http.HttpServletRequest request,
|
||||
org.springframework.web.servlet.mvc.support.RedirectAttributes redirectAttributes) {
|
||||
|
||||
Saison activeSaison;
|
||||
if (categorie.getId() == null) {
|
||||
activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
} else {
|
||||
Categorie existing = categorieRepository.findById(categorie.getId()).orElse(null);
|
||||
activeSaison = existing != null ? existing.getSaison() : null;
|
||||
}
|
||||
|
||||
if (activeSaison != null) {
|
||||
for (Categorie c : categorieRepository.findBySaison(activeSaison)) {
|
||||
if (c.getNom().equalsIgnoreCase(categorie.getNom()) && (categorie.getId() == null || !c.getId().equals(categorie.getId()))) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "Erreur : La catégorie '" + categorie.getNom() + "' existe déjà pour cette saison.");
|
||||
redirectAttributes.addFlashAttribute("categorie", categorie);
|
||||
return categorie.getId() == null ? "redirect:/categories/new" : "redirect:/categories/" + categorie.getId() + "/edit";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java.util.Map<Long, com.astalange.core.service.CategorieService.EquipementConfig> configs = new java.util.HashMap<>();
|
||||
|
||||
request.getParameterMap().forEach((key, values) -> {
|
||||
if (key.startsWith("etatEquipement_") && values.length > 0) {
|
||||
String idStr = key.substring("etatEquipement_".length());
|
||||
try {
|
||||
Long eqId = Long.parseLong(idStr);
|
||||
String etat = values[0];
|
||||
if (!"NON_LIE".equals(etat)) {
|
||||
boolean obligatoire = "OBLIGATOIRE".equals(etat);
|
||||
String prixStr = request.getParameter("prixEquipement_" + eqId);
|
||||
java.math.BigDecimal prix = java.math.BigDecimal.ZERO;
|
||||
if (prixStr != null && !prixStr.trim().isEmpty()) {
|
||||
prix = new java.math.BigDecimal(prixStr.trim());
|
||||
}
|
||||
configs.put(eqId, new com.astalange.core.service.CategorieService.EquipementConfig(obligatoire, prix));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
});
|
||||
|
||||
categorieService.saveCategorie(categorie, configs);
|
||||
return "redirect:/categories";
|
||||
}
|
||||
|
||||
@@ -49,4 +114,10 @@ public class CategorieController {
|
||||
categorieRepository.delete(categorie);
|
||||
return "redirect:/categories";
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/duplicate")
|
||||
public String duplicateCategorie(@PathVariable Long id) {
|
||||
categorieService.duplicateCategorie(id);
|
||||
return "redirect:/categories";
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user