Initial commit
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package com.pmumali.quatro.controller;
|
||||
|
||||
import com.pmumali.quatro.model.*;
|
||||
import com.pmumali.quatro.repository.*;
|
||||
import com.pmumali.quatro.service.ServiceQuatro;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/quatro")
|
||||
@RequiredArgsConstructor
|
||||
public class ControllerQuatro {
|
||||
|
||||
private final ServiceQuatro serviceQuatro;
|
||||
private final PariRepository pariRepository;
|
||||
private final PaiementRepository paiementRepository;
|
||||
|
||||
@PostMapping("/pari")
|
||||
public ResponseEntity<Pari> placerPari(@RequestBody RequetePari requetePari) {
|
||||
try {
|
||||
Pari pari = serviceQuatro.placerPari(requetePari);
|
||||
return ResponseEntity.ok(pari);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.badRequest().body(null);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/calculer-paiements")
|
||||
public ResponseEntity<List<ReponsePaiement>> calculerPaiements(@RequestBody RequeteResultatCourse requeteResultat) {
|
||||
try {
|
||||
List<ReponsePaiement> paiements = serviceQuatro.calculerPaiements(requeteResultat);
|
||||
return ResponseEntity.ok(paiements);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.badRequest().body(null);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/gerer-dead-heat")
|
||||
public ResponseEntity<List<ReponsePaiement>> gererDeadHeat(@RequestBody RequeteResultatCourse requeteResultat) {
|
||||
try {
|
||||
List<ReponsePaiement> paiements = serviceQuatro.gererDeadHeat(requeteResultat);
|
||||
return ResponseEntity.ok(paiements);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.badRequest().body(null);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/paris/course/{courseId}")
|
||||
public ResponseEntity<List<Pari>> getParisParCourse(@PathVariable Long courseId) {
|
||||
return ResponseEntity.ok(pariRepository.findByCourseId(courseId));
|
||||
}
|
||||
|
||||
@GetMapping("/paiements/pari/{pariId}")
|
||||
public ResponseEntity<List<Paiement>> getPaiementsParPari(@PathVariable Long pariId) {
|
||||
return ResponseEntity.ok(paiementRepository.findByPariId(pariId));
|
||||
}
|
||||
|
||||
@GetMapping("/calcul-combinaisons")
|
||||
public ResponseEntity<Integer> calculerCombinaisons(
|
||||
@RequestParam TypePari typePari,
|
||||
@RequestParam int nombreChevaux) {
|
||||
int nombreCombinaisons = serviceQuatro.calculerNombreCombinaisons(typePari, nombreChevaux);
|
||||
return ResponseEntity.ok(nombreCombinaisons);
|
||||
}
|
||||
|
||||
@GetMapping("/calcul-valeur-mise")
|
||||
public ResponseEntity<Double> calculerValeurMise(
|
||||
@RequestParam TypePari typePari,
|
||||
@RequestParam int nombreChevaux) {
|
||||
double valeurMise = serviceQuatro.calculerValeurMise(typePari, nombreChevaux);
|
||||
return ResponseEntity.ok(valeurMise);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pmumali.quatro.exception;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GestionnaireExceptionsGlobal {
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
public ResponseEntity<String> handleIllegalArgument(IllegalArgumentException ex) {
|
||||
return ResponseEntity.badRequest().body(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
|
||||
return ResponseEntity.badRequest().body("Erreur: " + ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<String> handleExceptionGenerale(Exception ex) {
|
||||
return ResponseEntity.internalServerError().body("Une erreur s'est produite: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/pmumali/quatro/model/Cheval.java
Normal file
29
src/main/java/com/pmumali/quatro/model/Cheval.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(name = "cheval")
|
||||
public class Cheval {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "nom")
|
||||
private String nom;
|
||||
|
||||
@Column(name = "numero")
|
||||
private Integer numero;
|
||||
|
||||
@Column(name = "non_partant")
|
||||
private boolean nonPartant;
|
||||
}
|
||||
35
src/main/java/com/pmumali/quatro/model/Course.java
Normal file
35
src/main/java/com/pmumali/quatro/model/Course.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(name = "course")
|
||||
public class Course {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "nom")
|
||||
private String nom;
|
||||
|
||||
@Column(name = "heure_course")
|
||||
private LocalDateTime heureCourse;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "course_chevaux",
|
||||
joinColumns = @JoinColumn(name = "course_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "cheval_id"))
|
||||
private List<Cheval> chevaux;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "statut")
|
||||
private StatutCourse statut;
|
||||
}
|
||||
32
src/main/java/com/pmumali/quatro/model/Paiement.java
Normal file
32
src/main/java/com/pmumali/quatro/model/Paiement.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(name = "paiement")
|
||||
public class Paiement {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "pari_id")
|
||||
private Pari pari;
|
||||
|
||||
@Column(name = "montant")
|
||||
private Double montant;
|
||||
|
||||
@Column(name = "heure_paiement")
|
||||
private LocalDateTime heurePaiement;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "type_paiement")
|
||||
private TypePaiement typePaiement;
|
||||
}
|
||||
43
src/main/java/com/pmumali/quatro/model/Pari.java
Normal file
43
src/main/java/com/pmumali/quatro/model/Pari.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(name = "pari")
|
||||
public class Pari {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "course_id")
|
||||
private Course course;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "pari_chevaux",
|
||||
joinColumns = @JoinColumn(name = "pari_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "cheval_id"))
|
||||
private List<Cheval> chevauxSelectionnes;
|
||||
|
||||
@Column(name = "mise")
|
||||
private Double mise;
|
||||
|
||||
@Column(name = "heure_pari")
|
||||
private LocalDateTime heurePari;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "type_pari")
|
||||
private TypePari typePari;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "parieur_id")
|
||||
private Parieur parieur;
|
||||
}
|
||||
25
src/main/java/com/pmumali/quatro/model/Parieur.java
Normal file
25
src/main/java/com/pmumali/quatro/model/Parieur.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(name = "parieur")
|
||||
public class Parieur {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "nom")
|
||||
private String nom;
|
||||
|
||||
@Column(name = "identification")
|
||||
private String identification;
|
||||
|
||||
@Column(name = "mise_totale")
|
||||
private Double miseTotale;
|
||||
}
|
||||
5
src/main/java/com/pmumali/quatro/model/Position.java
Normal file
5
src/main/java/com/pmumali/quatro/model/Position.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
public enum Position {
|
||||
PREMIER, SECOND, TROISIEME, QUATRIEME
|
||||
}
|
||||
13
src/main/java/com/pmumali/quatro/model/ReponsePaiement.java
Normal file
13
src/main/java/com/pmumali/quatro/model/ReponsePaiement.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ReponsePaiement {
|
||||
private Long pariId;
|
||||
private Double montant;
|
||||
private TypePaiement typePaiement;
|
||||
private String message;
|
||||
}
|
||||
13
src/main/java/com/pmumali/quatro/model/RequetePari.java
Normal file
13
src/main/java/com/pmumali/quatro/model/RequetePari.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RequetePari {
|
||||
private Long courseId;
|
||||
private List<Long> chevalIds;
|
||||
private Double mise;
|
||||
private TypePari typePari;
|
||||
private Long parieurId;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RequeteResultatCourse {
|
||||
private Long courseId;
|
||||
private List<Long> chevauxPremiers;
|
||||
private List<Long> chevauxSeconds;
|
||||
private List<Long> chevauxTroisiemes;
|
||||
private List<Long> chevauxQuatriemes;
|
||||
private Double recetteNette;
|
||||
private Double prelevementsLegaux;
|
||||
}
|
||||
59
src/main/java/com/pmumali/quatro/model/ResultatCourse.java
Normal file
59
src/main/java/com/pmumali/quatro/model/ResultatCourse.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(name = "resultat_course")
|
||||
public class ResultatCourse {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "course_id")
|
||||
private Course course;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "resultat_premiers",
|
||||
joinColumns = @JoinColumn(name = "resultat_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "cheval_id"))
|
||||
@OrderColumn(name = "ordre_position")
|
||||
private List<Cheval> premiers;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "resultat_seconds",
|
||||
joinColumns = @JoinColumn(name = "resultat_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "cheval_id"))
|
||||
private List<Cheval> seconds;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "resultat_troisiemes",
|
||||
joinColumns = @JoinColumn(name = "resultat_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "cheval_id"))
|
||||
private List<Cheval> troisiemes;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "resultat_quatriemes",
|
||||
joinColumns = @JoinColumn(name = "resultat_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "cheval_id"))
|
||||
private List<Cheval> quatriemes;
|
||||
|
||||
@Column(name = "masse_partager")
|
||||
private Double massePartager;
|
||||
|
||||
@Column(name = "recette_nette")
|
||||
private Double recetteNette;
|
||||
|
||||
@Column(name = "montant_rembourse")
|
||||
private Double montantRembourse;
|
||||
|
||||
@Column(name = "prelevements_legaux")
|
||||
private Double prelevementsLegaux;
|
||||
}
|
||||
5
src/main/java/com/pmumali/quatro/model/StatutCourse.java
Normal file
5
src/main/java/com/pmumali/quatro/model/StatutCourse.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
public enum StatutCourse {
|
||||
PROGRAMMEE, EN_COURS, TERMINEE, ANNULEE
|
||||
}
|
||||
5
src/main/java/com/pmumali/quatro/model/TypePaiement.java
Normal file
5
src/main/java/com/pmumali/quatro/model/TypePaiement.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
public enum TypePaiement {
|
||||
QUATRO, SPECIAL_TRIO, SPECIAL_JUMELE, SPECIAL_GAGNANT, REMBOURSEMENT
|
||||
}
|
||||
6
src/main/java/com/pmumali/quatro/model/TypePari.java
Normal file
6
src/main/java/com/pmumali/quatro/model/TypePari.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.pmumali.quatro.model;
|
||||
|
||||
public enum TypePari {
|
||||
UNITAIRE, COMBINE, CHAMP_TOTAL_3, CHAMP_PARTIEL_3,
|
||||
CHAMP_TOTAL_2, CHAMP_PARTIEL_2, CHAMP_TOTAL_1, CHAMP_PARTIEL_1
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pmumali.quatro.repository;
|
||||
|
||||
import com.pmumali.quatro.model.Cheval;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ChevalRepository extends JpaRepository<Cheval, Long> {
|
||||
List<Cheval> findByNonPartant(boolean nonPartant);
|
||||
List<Cheval> findByIdIn(List<Long> ids);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pmumali.quatro.repository;
|
||||
|
||||
import com.pmumali.quatro.model.Course;
|
||||
import com.pmumali.quatro.model.StatutCourse;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CourseRepository extends JpaRepository<Course, Long> {
|
||||
List<Course> findByStatut(StatutCourse statut);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pmumali.quatro.repository;
|
||||
|
||||
import com.pmumali.quatro.model.Paiement;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PaiementRepository extends JpaRepository<Paiement, Long> {
|
||||
List<Paiement> findByPariId(Long pariId);
|
||||
List<Paiement> findByPariCourseId(Long courseId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pmumali.quatro.repository;
|
||||
|
||||
import com.pmumali.quatro.model.Pari;
|
||||
import com.pmumali.quatro.model.TypePari;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import java.util.List;
|
||||
|
||||
public interface PariRepository extends JpaRepository<Pari, Long> {
|
||||
List<Pari> findByCourseId(Long courseId);
|
||||
List<Pari> findByParieurId(Long parieurId);
|
||||
List<Pari> findByCourseIdAndTypePari(Long courseId, TypePari typePari);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.pmumali.quatro.repository;
|
||||
|
||||
import com.pmumali.quatro.model.Parieur;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ParieurRepository extends JpaRepository<Parieur, Long> {
|
||||
List<Parieur> findByNomContaining(String nom);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.pmumali.quatro.repository;
|
||||
|
||||
import com.pmumali.quatro.model.ResultatCourse;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ResultatCourseRepository extends JpaRepository<ResultatCourse, Long> {
|
||||
ResultatCourse findByCourseId(Long courseId);
|
||||
}
|
||||
283
src/main/java/com/pmumali/quatro/service/ServiceQuatro.java
Normal file
283
src/main/java/com/pmumali/quatro/service/ServiceQuatro.java
Normal file
@@ -0,0 +1,283 @@
|
||||
package com.pmumali.quatro.service;
|
||||
|
||||
import com.pmumali.quatro.model.*;
|
||||
import com.pmumali.quatro.repository.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ServiceQuatro {
|
||||
|
||||
private final PariRepository pariRepository;
|
||||
private final CourseRepository courseRepository;
|
||||
private final ChevalRepository chevalRepository;
|
||||
private final PaiementRepository paiementRepository;
|
||||
private final ParieurRepository parieurRepository;
|
||||
private final ResultatCourseRepository resultatCourseRepository;
|
||||
|
||||
private static final double MISE_BASE = 500.0;
|
||||
private static final double MISE_UNITAIRE_MAX = 20 * MISE_BASE;
|
||||
|
||||
@Transactional
|
||||
public Pari placerPari(RequetePari requete) {
|
||||
// Validation de la mise
|
||||
if (requete.getMise() < MISE_BASE) {
|
||||
throw new IllegalArgumentException("La mise doit être au moins " + MISE_BASE + " FCFA");
|
||||
}
|
||||
|
||||
Course course = courseRepository.findById(requete.getCourseId())
|
||||
.orElseThrow(() -> new RuntimeException("Course non trouvée"));
|
||||
|
||||
List<Cheval> chevaux = chevalRepository.findAllById(requete.getChevalIds());
|
||||
|
||||
if (chevaux.size() != 4) {
|
||||
throw new IllegalArgumentException("Exactement 4 chevaux doivent être sélectionnés");
|
||||
}
|
||||
|
||||
// Vérification des chevaux non-partants
|
||||
long nombreNonPartants = chevaux.stream().filter(Cheval::isNonPartant).count();
|
||||
if (nombreNonPartants > 0) {
|
||||
throw new IllegalArgumentException("Impossible de parier sur des chevaux non-partants");
|
||||
}
|
||||
|
||||
// Limitation de la mise selon l'article 2
|
||||
double miseEffective = Math.min(requete.getMise(), MISE_UNITAIRE_MAX);
|
||||
|
||||
Parieur parieur = parieurRepository.findById(requete.getParieurId())
|
||||
.orElseThrow(() -> new RuntimeException("Parieur non trouvé"));
|
||||
|
||||
Pari pari = Pari.builder()
|
||||
.course(course)
|
||||
.chevauxSelectionnes(chevaux)
|
||||
.mise(miseEffective)
|
||||
.heurePari(LocalDateTime.now())
|
||||
.typePari(requete.getTypePari())
|
||||
.parieur(parieur)
|
||||
.build();
|
||||
|
||||
return pariRepository.save(pari);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<ReponsePaiement> calculerPaiements(RequeteResultatCourse requeteResultat) {
|
||||
ResultatCourse resultat = creerResultatCourse(requeteResultat);
|
||||
List<Pari> tousLesParis = pariRepository.findByCourseId(requeteResultat.getCourseId());
|
||||
List<ReponsePaiement> paiements = new ArrayList<>();
|
||||
|
||||
for (Pari pari : tousLesParis) {
|
||||
ReponsePaiement paiement = calculerPaiementPourPari(pari, resultat);
|
||||
if (paiement != null) {
|
||||
paiements.add(paiement);
|
||||
creerEnregistrementPaiement(pari, paiement);
|
||||
}
|
||||
}
|
||||
|
||||
return paiements;
|
||||
}
|
||||
|
||||
private ReponsePaiement calculerPaiementPourPari(Pari pari, ResultatCourse resultat) {
|
||||
List<Cheval> chevauxSelectionnes = pari.getChevauxSelectionnes();
|
||||
long nombreNonPartants = chevauxSelectionnes.stream().filter(Cheval::isNonPartant).count();
|
||||
|
||||
// Article 4: Cas des non-partants
|
||||
if (nombreNonPartants >= 1) {
|
||||
return gererCasNonPartants(pari, resultat, nombreNonPartants);
|
||||
}
|
||||
|
||||
// Vérifier si tous les chevaux sélectionnés sont dans les 4 premières positions
|
||||
boolean tousEnTop4 = chevauxSelectionnes.stream().allMatch(cheval ->
|
||||
estChevalEnPosition(cheval, resultat.getPremiers()) ||
|
||||
estChevalEnPosition(cheval, resultat.getSeconds()) ||
|
||||
estChevalEnPosition(cheval, resultat.getTroisiemes()) ||
|
||||
estChevalEnPosition(cheval, resultat.getQuatriemes()));
|
||||
|
||||
if (tousEnTop4) {
|
||||
double part = calculerPartQuatro(resultat);
|
||||
return new ReponsePaiement(pari.getId(), part, TypePaiement.QUATRO, "Paiement QUATRO");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ReponsePaiement gererCasNonPartants(Pari pari, ResultatCourse resultat, long nombreNonPartants) {
|
||||
List<Cheval> chevauxParticipants = pari.getChevauxSelectionnes().stream()
|
||||
.filter(cheval -> !cheval.isNonPartant())
|
||||
.toList();
|
||||
|
||||
switch ((int) nombreNonPartants) {
|
||||
case 1:
|
||||
if (chevauxParticipants.size() == 3 &&
|
||||
sontChevauxEnPositionsTop(chevauxParticipants, resultat, 3)) {
|
||||
double partQuatro = calculerPartQuatro(resultat);
|
||||
double partSpecialTrio = partQuatro / 4; // 1/4 du QUATRO
|
||||
return new ReponsePaiement(pari.getId(), partSpecialTrio,
|
||||
TypePaiement.SPECIAL_TRIO, "Paiement Spécial Trio");
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (chevauxParticipants.size() == 2 &&
|
||||
sontChevauxEnPositionsTop(chevauxParticipants, resultat, 2)) {
|
||||
double partQuatro = calculerPartQuatro(resultat);
|
||||
double partSpecialJumele = partQuatro / 8; // 1/8 du QUATRO
|
||||
return new ReponsePaiement(pari.getId(), partSpecialJumele,
|
||||
TypePaiement.SPECIAL_JUMELE, "Paiement Spécial Jumelé");
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (chevauxParticipants.size() == 1 &&
|
||||
sontChevauxEnPositionsTop(chevauxParticipants, resultat, 1)) {
|
||||
double partQuatro = calculerPartQuatro(resultat);
|
||||
double partSpecialGagnant = partQuatro / 16; // 1/16 du QUATRO
|
||||
return new ReponsePaiement(pari.getId(), partSpecialGagnant,
|
||||
TypePaiement.SPECIAL_GAGNANT, "Paiement Spécial Gagnant");
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
return new ReponsePaiement(pari.getId(), pari.getMise(),
|
||||
TypePaiement.REMBOURSEMENT, "Remboursement complet - tous chevaux non-partants");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean sontChevauxEnPositionsTop(List<Cheval> chevaux, ResultatCourse resultat, int positionTop) {
|
||||
return chevaux.stream().allMatch(cheval ->
|
||||
estChevalEnPosition(cheval, resultat.getPremiers()) ||
|
||||
(positionTop >= 2 && estChevalEnPosition(cheval, resultat.getSeconds())) ||
|
||||
(positionTop >= 3 && estChevalEnPosition(cheval, resultat.getTroisiemes())));
|
||||
}
|
||||
|
||||
private boolean estChevalEnPosition(Cheval cheval, List<Cheval> chevauxPosition) {
|
||||
return chevauxPosition != null && chevauxPosition.contains(cheval);
|
||||
}
|
||||
|
||||
private double calculerPartQuatro(ResultatCourse resultat) {
|
||||
double masseAPartager = resultat.getRecetteNette() - resultat.getMontantRembourse() - resultat.getPrelevementsLegaux();
|
||||
// Calcul simplifié - l'implémentation réelle considérerait le nombre de paris gagnants
|
||||
return masseAPartager; // Devrait être distribué entre les paris gagnants
|
||||
}
|
||||
|
||||
private void creerEnregistrementPaiement(Pari pari, ReponsePaiement paiement) {
|
||||
Paiement enregistrementPaiement = Paiement.builder()
|
||||
.pari(pari)
|
||||
.montant(paiement.getMontant())
|
||||
.heurePaiement(LocalDateTime.now())
|
||||
.typePaiement(paiement.getTypePaiement())
|
||||
.build();
|
||||
paiementRepository.save(enregistrementPaiement);
|
||||
}
|
||||
|
||||
private ResultatCourse creerResultatCourse(RequeteResultatCourse requete) {
|
||||
Course course = courseRepository.findById(requete.getCourseId())
|
||||
.orElseThrow(() -> new RuntimeException("Course non trouvée"));
|
||||
|
||||
ResultatCourse resultat = ResultatCourse.builder()
|
||||
.course(course)
|
||||
.premiers(chevalRepository.findAllById(requete.getChevauxPremiers()))
|
||||
.seconds(chevalRepository.findAllById(requete.getChevauxSeconds()))
|
||||
.troisiemes(chevalRepository.findAllById(requete.getChevauxTroisiemes()))
|
||||
.quatriemes(chevalRepository.findAllById(requete.getChevauxQuatriemes()))
|
||||
.recetteNette(requete.getRecetteNette())
|
||||
.prelevementsLegaux(requete.getPrelevementsLegaux())
|
||||
.montantRembourse(0.0) // Serait calculé basé sur les remboursements
|
||||
.build();
|
||||
|
||||
return resultatCourseRepository.save(resultat);
|
||||
}
|
||||
|
||||
// Méthodes pour gérer les dead-heat (Article 3)
|
||||
@Transactional
|
||||
public List<ReponsePaiement> gererDeadHeat(RequeteResultatCourse requeteResultat) {
|
||||
ResultatCourse resultat = creerResultatCourse(requeteResultat);
|
||||
List<Pari> tousLesParis = pariRepository.findByCourseId(requeteResultat.getCourseId());
|
||||
List<ReponsePaiement> paiements = new ArrayList<>();
|
||||
|
||||
// Implémentation des règles complexes de dead-heat
|
||||
Map<String, List<Pari>> combinaisonsPayables = identifierCombinaisonsPayablesDeadHeat(resultat, tousLesParis);
|
||||
|
||||
for (Map.Entry<String, List<Pari>> entry : combinaisonsPayables.entrySet()) {
|
||||
double part = calculerPartDeadHeat(resultat, entry.getValue());
|
||||
for (Pari pari : entry.getValue()) {
|
||||
ReponsePaiement paiement = new ReponsePaiement(pari.getId(), part, TypePaiement.QUATRO, "Paiement Dead-Heat");
|
||||
paiements.add(paiement);
|
||||
creerEnregistrementPaiement(pari, paiement);
|
||||
}
|
||||
}
|
||||
|
||||
return paiements;
|
||||
}
|
||||
|
||||
private Map<String, List<Pari>> identifierCombinaisonsPayablesDeadHeat(ResultatCourse resultat, List<Pari> paris) {
|
||||
Map<String, List<Pari>> combinaisons = new HashMap<>();
|
||||
|
||||
for (Pari pari : paris) {
|
||||
String combinaison = genererCleCombinaison(pari.getChevauxSelectionnes());
|
||||
if (estCombinaisonPayableDeadHeat(pari.getChevauxSelectionnes(), resultat)) {
|
||||
combinaisons.computeIfAbsent(combinaison, k -> new ArrayList<>()).add(pari);
|
||||
}
|
||||
}
|
||||
|
||||
return combinaisons;
|
||||
}
|
||||
|
||||
private boolean estCombinaisonPayableDeadHeat(List<Cheval> chevaux, ResultatCourse resultat) {
|
||||
// Implémentation des règles spécifiques de dead-heat selon l'article 3
|
||||
// Cette méthode devrait implémenter toutes les sous-règles a) à h)
|
||||
return chevaux.stream().allMatch(cheval ->
|
||||
estChevalEnPosition(cheval, resultat.getPremiers()) ||
|
||||
estChevalEnPosition(cheval, resultat.getSeconds()) ||
|
||||
estChevalEnPosition(cheval, resultat.getTroisiemes()) ||
|
||||
estChevalEnPosition(cheval, resultat.getQuatriemes()));
|
||||
}
|
||||
|
||||
private String genererCleCombinaison(List<Cheval> chevaux) {
|
||||
return chevaux.stream()
|
||||
.map(cheval -> String.valueOf(cheval.getId()))
|
||||
.sorted()
|
||||
.collect(Collectors.joining("-"));
|
||||
}
|
||||
|
||||
private double calculerPartDeadHeat(ResultatCourse resultat, List<Pari> parisCombinaison) {
|
||||
double masseAPartager = resultat.getMassePartager();
|
||||
double totalMisesCombinaison = parisCombinaison.stream().mapToDouble(Pari::getMise).sum();
|
||||
return (masseAPartager / parisCombinaison.size()) * (totalMisesCombinaison / masseAPartager);
|
||||
}
|
||||
|
||||
// Méthodes pour les formules de pari (Article 6)
|
||||
public int calculerNombreCombinaisons(TypePari typePari, int nombreChevaux) {
|
||||
switch (typePari) {
|
||||
case UNITAIRE:
|
||||
return 1;
|
||||
case COMBINE:
|
||||
return (nombreChevaux * (nombreChevaux - 1) * (nombreChevaux - 2) * (nombreChevaux - 3)) / 24;
|
||||
case CHAMP_TOTAL_3:
|
||||
return 24 * (nombreChevaux - 3);
|
||||
case CHAMP_PARTIEL_3:
|
||||
return 24 * nombreChevaux;
|
||||
case CHAMP_TOTAL_2:
|
||||
return 12 * (nombreChevaux - 2) * (nombreChevaux - 3);
|
||||
case CHAMP_PARTIEL_2:
|
||||
return 12 * nombreChevaux * (nombreChevaux - 1);
|
||||
case CHAMP_TOTAL_1:
|
||||
return 4 * (nombreChevaux - 1) * (nombreChevaux - 2) * (nombreChevaux - 3);
|
||||
case CHAMP_PARTIEL_1:
|
||||
return 4 * nombreChevaux * (nombreChevaux - 1) * (nombreChevaux - 2);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public double calculerValeurMise(TypePari typePari, int nombreChevaux) {
|
||||
int nombreCombinaisons = calculerNombreCombinaisons(typePari, nombreChevaux);
|
||||
return nombreCombinaisons * MISE_BASE;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user