From d157d4d55ae1e366f96dfe385201557a50dff90c Mon Sep 17 00:00:00 2001 From: sidibe Date: Thu, 28 Aug 2025 08:28:44 +0000 Subject: [PATCH] =?UTF-8?q?Fin=20int=C3=A9gration=20jumele=20gagnant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ChevalController.java | 33 ++ .../controller/CourseController.java | 43 ++ .../controller/GainsController.java | 28 + .../ch1_simple/controller/PariController.java | 39 ++ .../com/pmumali/ch1_simple/dto/ChevalDto.java | 13 + .../com/pmumali/ch1_simple/dto/CourseDto.java | 16 + .../com/pmumali/ch1_simple/dto/GainsDto.java | 17 + .../pmumali/ch1_simple/dto/PariSimpleDto.java | 16 + .../ch1_simple/dto/ResultatCourseDto.java | 15 + .../com/pmumali/ch1_simple/model/Cheval.java | 25 + .../com/pmumali/ch1_simple/model/Course.java | 32 ++ .../com/pmumali/ch1_simple/model/Gains.java | 31 ++ .../pmumali/ch1_simple/model/PariSimple.java | 31 ++ .../ch1_simple/model/ResultatCourse.java | 32 ++ .../repository/ChevalRepository.java | 13 + .../repository/CourseRepository.java | 11 + .../repository/GainsRepository.java | 10 + .../repository/PariSimpleRepository.java | 15 + .../repository/ResultatCourseRepository.java | 10 + .../ch1_simple/service/ChevalService.java | 27 + .../ch1_simple/service/CourseService.java | 37 ++ .../ch1_simple/service/GainsService.java | 479 ++++++++++++++++++ .../ch1_simple/service/PariSimpleService.java | 52 ++ .../controller/ChevalController.java | 32 ++ .../controller/CourseController.java | 48 ++ .../controller/GainsController.java | 27 + .../controller/PariJumeleController.java | 46 ++ .../ch2_jumelegagnant/dto/ChevalDto.java | 12 + .../ch2_jumelegagnant/dto/CourseDto.java | 17 + .../ch2_jumelegagnant/dto/GainsDto.java | 16 + .../ch2_jumelegagnant/dto/PariJumeleDto.java | 18 + .../dto/ResultatCourseDto.java | 14 + .../ch2_jumelegagnant/model/Cheval.java | 23 + .../ch2_jumelegagnant/model/Course.java | 33 ++ .../ch2_jumelegagnant/model/Gains.java | 30 ++ .../model/PariJumeleGagnant.java | 36 ++ .../model/ResultatCourse.java | 29 ++ .../repository/ChevalRepository.java | 13 + .../repository/CourseRepository.java | 12 + .../repository/GainsRepository.java | 10 + .../repository/PariJumeleRepository.java | 14 + .../repository/ResultatCourseRepository.java | 10 + .../service/ChevalService.java | 27 + .../service/CourseService.java | 40 ++ .../service/GainsService.java | 329 ++++++++++++ .../service/PariJumeleService.java | 63 +++ .../simple/controller/CourseController.java | 28 - .../simple/controller/PariController.java | 68 --- .../com/pmumali/simple/dto/ChevalDto.java | 23 - .../pmumali/simple/dto/CombinaisonDto.java | 12 - .../com/pmumali/simple/dto/PariRequest.java | 15 - .../com/pmumali/simple/dto/PariResponse.java | 211 -------- .../pmumali/simple/dto/ResultatCourseDto.java | 16 - .../simple/exception/PariException.java | 84 --- .../java/com/pmumali/simple/model/Cheval.java | 68 --- .../java/com/pmumali/simple/model/Client.java | 287 ----------- .../com/pmumali/simple/model/Combinaison.java | 35 -- .../java/com/pmumali/simple/model/Course.java | 92 ---- .../java/com/pmumali/simple/model/Pari.java | 108 ---- .../pmumali/simple/model/ResultatCourse.java | 192 ------- .../com/pmumali/simple/model/Transaction.java | 33 -- .../pmumali/simple/model/enums/TypePari.java | 6 - .../simple/repository/ChevalRepository.java | 7 - .../simple/repository/CourseRepository.java | 7 - .../simple/repository/PariRepository.java | 72 --- .../simple/service/CalculRapportService.java | 138 ----- .../simple/service/FormulaireService.java | 48 -- .../pmumali/simple/service/PariService.java | 309 ----------- .../simple/service/PariServiceTest.java | 43 -- .../simple/service/ValidationPariService.java | 116 ----- 70 files changed, 1924 insertions(+), 2018 deletions(-) create mode 100644 src/main/java/com/pmumali/ch1_simple/controller/ChevalController.java create mode 100644 src/main/java/com/pmumali/ch1_simple/controller/CourseController.java create mode 100644 src/main/java/com/pmumali/ch1_simple/controller/GainsController.java create mode 100644 src/main/java/com/pmumali/ch1_simple/controller/PariController.java create mode 100644 src/main/java/com/pmumali/ch1_simple/dto/ChevalDto.java create mode 100644 src/main/java/com/pmumali/ch1_simple/dto/CourseDto.java create mode 100644 src/main/java/com/pmumali/ch1_simple/dto/GainsDto.java create mode 100644 src/main/java/com/pmumali/ch1_simple/dto/PariSimpleDto.java create mode 100644 src/main/java/com/pmumali/ch1_simple/dto/ResultatCourseDto.java create mode 100644 src/main/java/com/pmumali/ch1_simple/model/Cheval.java create mode 100644 src/main/java/com/pmumali/ch1_simple/model/Course.java create mode 100644 src/main/java/com/pmumali/ch1_simple/model/Gains.java create mode 100644 src/main/java/com/pmumali/ch1_simple/model/PariSimple.java create mode 100644 src/main/java/com/pmumali/ch1_simple/model/ResultatCourse.java create mode 100644 src/main/java/com/pmumali/ch1_simple/repository/ChevalRepository.java create mode 100644 src/main/java/com/pmumali/ch1_simple/repository/CourseRepository.java create mode 100644 src/main/java/com/pmumali/ch1_simple/repository/GainsRepository.java create mode 100644 src/main/java/com/pmumali/ch1_simple/repository/PariSimpleRepository.java create mode 100644 src/main/java/com/pmumali/ch1_simple/repository/ResultatCourseRepository.java create mode 100644 src/main/java/com/pmumali/ch1_simple/service/ChevalService.java create mode 100644 src/main/java/com/pmumali/ch1_simple/service/CourseService.java create mode 100644 src/main/java/com/pmumali/ch1_simple/service/GainsService.java create mode 100644 src/main/java/com/pmumali/ch1_simple/service/PariSimpleService.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/controller/ChevalController.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/controller/CourseController.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/controller/GainsController.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/controller/PariJumeleController.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/dto/ChevalDto.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/dto/CourseDto.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/dto/GainsDto.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/dto/PariJumeleDto.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/dto/ResultatCourseDto.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/model/Cheval.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/model/Course.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/model/Gains.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/model/PariJumeleGagnant.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/model/ResultatCourse.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/repository/ChevalRepository.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/repository/CourseRepository.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/repository/GainsRepository.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/repository/PariJumeleRepository.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/repository/ResultatCourseRepository.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/service/ChevalService.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/service/CourseService.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/service/GainsService.java create mode 100644 src/main/java/com/pmumali/ch2_jumelegagnant/service/PariJumeleService.java delete mode 100644 src/main/java/com/pmumali/simple/controller/CourseController.java delete mode 100644 src/main/java/com/pmumali/simple/controller/PariController.java delete mode 100644 src/main/java/com/pmumali/simple/dto/ChevalDto.java delete mode 100644 src/main/java/com/pmumali/simple/dto/CombinaisonDto.java delete mode 100644 src/main/java/com/pmumali/simple/dto/PariRequest.java delete mode 100644 src/main/java/com/pmumali/simple/dto/PariResponse.java delete mode 100644 src/main/java/com/pmumali/simple/dto/ResultatCourseDto.java delete mode 100644 src/main/java/com/pmumali/simple/exception/PariException.java delete mode 100644 src/main/java/com/pmumali/simple/model/Cheval.java delete mode 100644 src/main/java/com/pmumali/simple/model/Client.java delete mode 100644 src/main/java/com/pmumali/simple/model/Combinaison.java delete mode 100644 src/main/java/com/pmumali/simple/model/Course.java delete mode 100644 src/main/java/com/pmumali/simple/model/Pari.java delete mode 100644 src/main/java/com/pmumali/simple/model/ResultatCourse.java delete mode 100644 src/main/java/com/pmumali/simple/model/Transaction.java delete mode 100644 src/main/java/com/pmumali/simple/model/enums/TypePari.java delete mode 100644 src/main/java/com/pmumali/simple/repository/ChevalRepository.java delete mode 100644 src/main/java/com/pmumali/simple/repository/CourseRepository.java delete mode 100644 src/main/java/com/pmumali/simple/repository/PariRepository.java delete mode 100644 src/main/java/com/pmumali/simple/service/CalculRapportService.java delete mode 100644 src/main/java/com/pmumali/simple/service/FormulaireService.java delete mode 100644 src/main/java/com/pmumali/simple/service/PariService.java delete mode 100644 src/main/java/com/pmumali/simple/service/PariServiceTest.java delete mode 100644 src/main/java/com/pmumali/simple/service/ValidationPariService.java diff --git a/src/main/java/com/pmumali/ch1_simple/controller/ChevalController.java b/src/main/java/com/pmumali/ch1_simple/controller/ChevalController.java new file mode 100644 index 0000000..f7af9bd --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/controller/ChevalController.java @@ -0,0 +1,33 @@ +package com.pmumali.ch1_simple.controller; + +import com.pmumali.ch1_simple.model.Cheval; +import com.pmumali.ch1_simple.service.ChevalService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/chevaux") +public class ChevalController { + + @Autowired + private ChevalService chevalService; + + @PostMapping + public ResponseEntity ajouterCheval(@RequestBody Cheval cheval) { + return ResponseEntity.ok(chevalService.ajouterCheval(cheval)); + } + + @GetMapping("/course/{courseId}") + public ResponseEntity> obtenirChevauxParCourse(@PathVariable Long courseId) { + return ResponseEntity.ok(chevalService.obtenirChevauxParCourse(courseId)); + } + + @GetMapping("/ecurie/{nomEcurie}") + public ResponseEntity> obtenirChevauxParEcurie(@PathVariable String nomEcurie) { + return ResponseEntity.ok(chevalService.obtenirChevauxParEcurie(nomEcurie)); + } +} + diff --git a/src/main/java/com/pmumali/ch1_simple/controller/CourseController.java b/src/main/java/com/pmumali/ch1_simple/controller/CourseController.java new file mode 100644 index 0000000..df255e2 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/controller/CourseController.java @@ -0,0 +1,43 @@ +package com.pmumali.ch1_simple.controller; + +import com.pmumali.ch1_simple.model.Course; +import com.pmumali.ch1_simple.service.CourseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.List; + +@RestController +@RequestMapping("/api/courses") +public class CourseController { + + @Autowired + private CourseService courseService; + + @PostMapping + public ResponseEntity creerCourse(@RequestBody Course course) { + return ResponseEntity.ok(courseService.creerCourse(course)); + } + + @GetMapping + public ResponseEntity> obtenirToutesCourses() { + return ResponseEntity.ok(courseService.obtenirToutesCourses()); + } + + @GetMapping("/{id}") + public ResponseEntity obtenirCourseParId(@PathVariable Long id) { + Course course = courseService.obtenirCourseParId(id); + return course != null ? ResponseEntity.ok(course) : ResponseEntity.notFound().build(); + } + + @GetMapping("/terminees") + public ResponseEntity> obtenirCoursesTerminees() { + return ResponseEntity.ok(courseService.obtenirCoursesTerminees()); + } + + @GetMapping("/avenir") + public ResponseEntity> obtenirCoursesAVenir() { + return ResponseEntity.ok(courseService.obtenirCoursesAVenir()); + } +} + diff --git a/src/main/java/com/pmumali/ch1_simple/controller/GainsController.java b/src/main/java/com/pmumali/ch1_simple/controller/GainsController.java new file mode 100644 index 0000000..f6d81f3 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/controller/GainsController.java @@ -0,0 +1,28 @@ +package com.pmumali.ch1_simple.controller; + +import com.pmumali.ch1_simple.model.Gains; +import com.pmumali.ch1_simple.model.ResultatCourse; +import com.pmumali.ch1_simple.service.GainsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/gains") +public class GainsController { + + @Autowired + private GainsService gainsService; + + @PostMapping("/calculer/{courseId}") + public ResponseEntity calculerGains(@PathVariable Long courseId, @RequestBody ResultatCourse resultat) { + return ResponseEntity.ok(gainsService.calculerGains(courseId, resultat)); + } + + @GetMapping("/course/{courseId}") + public ResponseEntity obtenirGainsParCourse(@PathVariable Long courseId) { + Gains gains = gainsService.obtenirGainsParCourse(courseId); + return gains != null ? ResponseEntity.ok(gains) : ResponseEntity.notFound().build(); + } +} + diff --git a/src/main/java/com/pmumali/ch1_simple/controller/PariController.java b/src/main/java/com/pmumali/ch1_simple/controller/PariController.java new file mode 100644 index 0000000..00ffed0 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/controller/PariController.java @@ -0,0 +1,39 @@ +package com.pmumali.ch1_simple.controller; + +import com.pmumali.ch1_simple.model.PariSimple; +import com.pmumali.ch1_simple.service.PariSimpleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/paris") +public class PariController { + + @Autowired + private PariSimpleService pariService; + + @PostMapping + public ResponseEntity placerPari(@RequestBody PariSimple pari) { + return ResponseEntity.ok(pariService.placerPari(pari)); + } + + @GetMapping("/course/{courseId}") + public ResponseEntity> obtenirParisParCourse(@PathVariable Long courseId) { + return ResponseEntity.ok(pariService.obtenirParisParCourse(courseId)); + } + + @GetMapping("/course/{courseId}/type/{typePari}") + public ResponseEntity> obtenirParisParCourseEtType( + @PathVariable Long courseId, @PathVariable String typePari) { + return ResponseEntity.ok(pariService.obtenirParisParCourseEtType(courseId, typePari)); + } + + @GetMapping("/cheval/{chevalId}") + public ResponseEntity> obtenirParisParCheval(@PathVariable Long chevalId) { + return ResponseEntity.ok(pariService.obtenirParisParCheval(chevalId)); + } +} + diff --git a/src/main/java/com/pmumali/ch1_simple/dto/ChevalDto.java b/src/main/java/com/pmumali/ch1_simple/dto/ChevalDto.java new file mode 100644 index 0000000..16cd149 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/dto/ChevalDto.java @@ -0,0 +1,13 @@ +package com.pmumali.ch1_simple.dto; + +import lombok.Data; + +@Data +public class ChevalDto { + private Long id; + private String nom; + private int numero; + private boolean estNonPartant; + private String nomEcurie; + private Long courseId; +} diff --git a/src/main/java/com/pmumali/ch1_simple/dto/CourseDto.java b/src/main/java/com/pmumali/ch1_simple/dto/CourseDto.java new file mode 100644 index 0000000..674c709 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/dto/CourseDto.java @@ -0,0 +1,16 @@ +package com.pmumali.ch1_simple.dto; + +import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class CourseDto { + private Long id; + private String nom; + private LocalDateTime date; + private String lieu; + private int nombreChevauxInscrits; + private boolean estTerminee; + private List chevauxIds; +} diff --git a/src/main/java/com/pmumali/ch1_simple/dto/GainsDto.java b/src/main/java/com/pmumali/ch1_simple/dto/GainsDto.java new file mode 100644 index 0000000..0b243c8 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/dto/GainsDto.java @@ -0,0 +1,17 @@ +package com.pmumali.ch1_simple.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class GainsDto { + private Long id; + private Long courseId; + private double masseGagnant; + private double massePlace; + private double rapportGagnant; + private double rapportPlace; + private double montantCagnotte; + private LocalDateTime dateCalcul; +} diff --git a/src/main/java/com/pmumali/ch1_simple/dto/PariSimpleDto.java b/src/main/java/com/pmumali/ch1_simple/dto/PariSimpleDto.java new file mode 100644 index 0000000..5fd2e1e --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/dto/PariSimpleDto.java @@ -0,0 +1,16 @@ +package com.pmumali.ch1_simple.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class PariSimpleDto { + private Long id; + private String typePari; + private double mise; + private LocalDateTime datePari; + private Long chevalId; + private Long courseId; + private boolean estPaye; +} diff --git a/src/main/java/com/pmumali/ch1_simple/dto/ResultatCourseDto.java b/src/main/java/com/pmumali/ch1_simple/dto/ResultatCourseDto.java new file mode 100644 index 0000000..9c71794 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/dto/ResultatCourseDto.java @@ -0,0 +1,15 @@ +package com.pmumali.ch1_simple.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ResultatCourseDto { + private Long id; + private Long courseId; + private List chevauxPremiers; + private List chevauxDeuxiemes; + private List chevauxTroisiemes; + private boolean aDeadHeat; +} diff --git a/src/main/java/com/pmumali/ch1_simple/model/Cheval.java b/src/main/java/com/pmumali/ch1_simple/model/Cheval.java new file mode 100644 index 0000000..3d30d62 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/model/Cheval.java @@ -0,0 +1,25 @@ +package com.pmumali.ch1_simple.model; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "cheval") +public class Cheval { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nom; + private int numero; + private boolean estNonPartant; + private String nomEcurie; + + @ManyToOne + @JoinColumn(name = "course_id") + private Course course; +} + diff --git a/src/main/java/com/pmumali/ch1_simple/model/Course.java b/src/main/java/com/pmumali/ch1_simple/model/Course.java new file mode 100644 index 0000000..fea0ba7 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/model/Course.java @@ -0,0 +1,32 @@ +package com.pmumali.ch1_simple.model; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "course") +public class Course { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nom; + private LocalDateTime date; + private String lieu; + private int nombreChevauxInscrits; + private boolean estTerminee; + + @OneToMany(mappedBy = "course", cascade = CascadeType.ALL) + private List chevaux; + + @OneToOne(mappedBy = "course", cascade = CascadeType.ALL) + private ResultatCourse resultat; +} diff --git a/src/main/java/com/pmumali/ch1_simple/model/Gains.java b/src/main/java/com/pmumali/ch1_simple/model/Gains.java new file mode 100644 index 0000000..4895c70 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/model/Gains.java @@ -0,0 +1,31 @@ +package com.pmumali.ch1_simple.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "gains") +public class Gains { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "course_id") + private Course course; + + private double masseGagnant; + private double massePlace; + + private double rapportGagnant; + private double rapportPlace; + + private double montantCagnotte; + + private LocalDateTime dateCalcul; +} diff --git a/src/main/java/com/pmumali/ch1_simple/model/PariSimple.java b/src/main/java/com/pmumali/ch1_simple/model/PariSimple.java new file mode 100644 index 0000000..711de4a --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/model/PariSimple.java @@ -0,0 +1,31 @@ +package com.pmumali.ch1_simple.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "pari_simple") +public class PariSimple { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String typePari; // GAGNANT ou PLACE + private double mise = 500.0; + private LocalDateTime datePari; + + @ManyToOne + @JoinColumn(name = "cheval_id") + private Cheval cheval; + + @ManyToOne + @JoinColumn(name = "course_id") + private Course course; + + private boolean estPaye; +} diff --git a/src/main/java/com/pmumali/ch1_simple/model/ResultatCourse.java b/src/main/java/com/pmumali/ch1_simple/model/ResultatCourse.java new file mode 100644 index 0000000..8b8a7b6 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/model/ResultatCourse.java @@ -0,0 +1,32 @@ +package com.pmumali.ch1_simple.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "resultat_course") +public class ResultatCourse { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + @JoinColumn(name = "course_id") + private Course course; + + @ElementCollection + private List chevauxPremiers; // Pour gérer les dead-heats + + @ElementCollection + private List chevauxDeuxiemes; // Pour gérer les dead-heats + + @ElementCollection + private List chevauxTroisiemes; // Pour gérer les dead-heats + + private boolean aDeadHeat; +} diff --git a/src/main/java/com/pmumali/ch1_simple/repository/ChevalRepository.java b/src/main/java/com/pmumali/ch1_simple/repository/ChevalRepository.java new file mode 100644 index 0000000..58eb6c0 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/repository/ChevalRepository.java @@ -0,0 +1,13 @@ +package com.pmumali.ch1_simple.repository; + +import com.pmumali.ch1_simple.model.Cheval; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ChevalRepository extends JpaRepository { + List findByCourseId(Long courseId); + List findByNomEcurie(String nomEcurie); +} diff --git a/src/main/java/com/pmumali/ch1_simple/repository/CourseRepository.java b/src/main/java/com/pmumali/ch1_simple/repository/CourseRepository.java new file mode 100644 index 0000000..d7dac4d --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/repository/CourseRepository.java @@ -0,0 +1,11 @@ +package com.pmumali.ch1_simple.repository; + +import com.pmumali.ch1_simple.model.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + List findByEstTerminee(boolean estTerminee); +} diff --git a/src/main/java/com/pmumali/ch1_simple/repository/GainsRepository.java b/src/main/java/com/pmumali/ch1_simple/repository/GainsRepository.java new file mode 100644 index 0000000..86e84b0 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/repository/GainsRepository.java @@ -0,0 +1,10 @@ +package com.pmumali.ch1_simple.repository; + +import com.pmumali.ch1_simple.model.Gains; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface GainsRepository extends JpaRepository { + Gains findByCourseId(Long courseId); +} diff --git a/src/main/java/com/pmumali/ch1_simple/repository/PariSimpleRepository.java b/src/main/java/com/pmumali/ch1_simple/repository/PariSimpleRepository.java new file mode 100644 index 0000000..0a561e4 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/repository/PariSimpleRepository.java @@ -0,0 +1,15 @@ +package com.pmumali.ch1_simple.repository; + +import com.pmumali.ch1_simple.model.PariSimple; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PariSimpleRepository extends JpaRepository { + List findByCourseId(Long courseId); + List findByCourseIdAndTypePari(Long courseId, String typePari); + List findByChevalId(Long chevalId); + List findByChevalIdAndTypePari(Long chevalId, String typePari); +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch1_simple/repository/ResultatCourseRepository.java b/src/main/java/com/pmumali/ch1_simple/repository/ResultatCourseRepository.java new file mode 100644 index 0000000..dedb936 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/repository/ResultatCourseRepository.java @@ -0,0 +1,10 @@ +package com.pmumali.ch1_simple.repository; + +import com.pmumali.ch1_simple.model.ResultatCourse; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ResultatCourseRepository extends JpaRepository { + ResultatCourse findByCourseId(Long courseId); +} diff --git a/src/main/java/com/pmumali/ch1_simple/service/ChevalService.java b/src/main/java/com/pmumali/ch1_simple/service/ChevalService.java new file mode 100644 index 0000000..e657ebe --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/service/ChevalService.java @@ -0,0 +1,27 @@ +package com.pmumali.ch1_simple.service; + +import com.pmumali.ch1_simple.model.Cheval; +import com.pmumali.ch1_simple.repository.ChevalRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ChevalService { + + @Autowired + private ChevalRepository chevalRepository; + + public Cheval ajouterCheval(Cheval cheval) { + return chevalRepository.save(cheval); + } + + public List obtenirChevauxParCourse(Long courseId) { + return chevalRepository.findByCourseId(courseId); + } + + public List obtenirChevauxParEcurie(String nomEcurie) { + return chevalRepository.findByNomEcurie(nomEcurie); + } +} diff --git a/src/main/java/com/pmumali/ch1_simple/service/CourseService.java b/src/main/java/com/pmumali/ch1_simple/service/CourseService.java new file mode 100644 index 0000000..bff7bf6 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/service/CourseService.java @@ -0,0 +1,37 @@ +package com.pmumali.ch1_simple.service; + + +import com.pmumali.ch1_simple.model.Course; +import com.pmumali.ch1_simple.repository.CourseRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + + +@Service +public class CourseService { + + @Autowired + private CourseRepository courseRepository; + + public Course creerCourse(Course course) { + return courseRepository.save(course); + } + + public List obtenirToutesCourses() { + return courseRepository.findAll(); + } + + public Course obtenirCourseParId(Long id) { + return courseRepository.findById(id).orElse(null); + } + + public List obtenirCoursesTerminees() { + return courseRepository.findByEstTerminee(true); + } + + public List obtenirCoursesAVenir() { + return courseRepository.findByEstTerminee(false); + } +} diff --git a/src/main/java/com/pmumali/ch1_simple/service/GainsService.java b/src/main/java/com/pmumali/ch1_simple/service/GainsService.java new file mode 100644 index 0000000..f4c84db --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/service/GainsService.java @@ -0,0 +1,479 @@ +package com.pmumali.ch1_simple.service; + +import com.pmumali.ch1_simple.model.*; +import com.pmumali.ch1_simple.repository.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Transactional +public class GainsService { + + @Autowired + private PariSimpleRepository pariRepository; + + @Autowired + private GainsRepository gainsRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ChevalRepository chevalRepository; + + @Autowired + private ResultatCourseRepository resultatRepository; + + private static final double RAPPORT_MINIMUM = 1.1; + private static final double PRELEVEMENTS = 0.15; // 15% de prélèvements + + public Gains calculerGains(Long courseId, ResultatCourse resultat) { + Course course = courseRepository.findById(courseId) + .orElseThrow(() -> new RuntimeException("Course non trouvée")); + + List tousParis = pariRepository.findByCourseId(courseId); + + // Calcul de la recette nette (Article 5) + double totalMises = tousParis.stream().mapToDouble(PariSimple::getMise).sum(); + double recetteNette = totalMises; + + // Calcul des remboursements (Article 4) + double montantRemboursements = calculerRemboursements(tousParis); + + // Masse à partager (Article 5) + double masseAPartager = recetteNette - montantRemboursements - (recetteNette * PRELEVEMENTS); + + // Séparation des paris GAGNANT et PLACE + List parisGagnant = tousParis.stream() + .filter(p -> "GAGNANT".equals(p.getTypePari())) + .collect(Collectors.toList()); + + List parisPlace = tousParis.stream() + .filter(p -> "PLACE".equals(p.getTypePari())) + .collect(Collectors.toList()); + + // Calcul des masses à partager pour chaque type de pari + double masseGagnant = masseAPartager * (parisGagnant.stream().mapToDouble(PariSimple::getMise).sum() / totalMises); + double massePlace = masseAPartager * (parisPlace.stream().mapToDouble(PariSimple::getMise).sum() / totalMises); + + // Calcul des rapports + Gains gains = new Gains(); + gains.setCourse(course); + gains.setMasseGagnant(masseGagnant); + gains.setMassePlace(massePlace); + gains.setDateCalcul(LocalDateTime.now()); + + // Calcul détaillé des gains selon les règles + calculerDetailsGains(gains, resultat, parisGagnant, parisPlace); + + // Gérer la cagnotte si nécessaire (Article 6 et 7) + gererCagnotte(gains, resultat, parisGagnant, parisPlace); + + return gainsRepository.save(gains); + } + + private double calculerRemboursements(List paris) { + double remboursements = 0.0; + + for (PariSimple pari : paris) { + if (pari.getCheval().isEstNonPartant()) { + remboursements += pari.getMise(); + pari.setEstPaye(true); // Marquer comme remboursé + } + } + + return remboursements; + } + + private void calculerDetailsGains(Gains gains, ResultatCourse resultat, + List parisGagnant, List parisPlace) { + // Calcul des rapports GAGNANT + if (resultat.isADeadHeat()) { + calculerRapportsGagnantDeadHeat(gains, resultat, parisGagnant); + } else { + calculerRapportsGagnantNormal(gains, resultat, parisGagnant); + } + + // Calcul des rapports PLACE + if (resultat.isADeadHeat()) { + calculerRapportsPlaceDeadHeat(gains, resultat, parisPlace); + } else { + calculerRapportsPlaceNormal(gains, resultat, parisPlace); + } + + // Garantir un rapport minimum de 1.1 par unité de mise (Article 5d) + gains.setRapportGagnant(Math.max(gains.getRapportGagnant(), RAPPORT_MINIMUM)); + gains.setRapportPlace(Math.max(gains.getRapportPlace(), RAPPORT_MINIMUM)); + } + + private void calculerRapportsGagnantNormal(Gains gains, ResultatCourse resultat, List parisGagnant) { + // Article 5a: Cas d'arrivée normale - Calcul du rapport "gagnant" + if (resultat.getChevauxPremiers().isEmpty()) { + gains.setRapportGagnant(0.0); + return; + } + + // Gestion des écuries (Article 2) + Long chevalGagnantId = resultat.getChevauxPremiers().get(0); + Cheval chevalGagnant = chevalRepository.findById(chevalGagnantId).orElse(null); + + if (chevalGagnant == null) { + gains.setRapportGagnant(0.0); + return; + } + + // Trouver tous les chevaux de la même écurie + List chevauxEcurie = Collections.singletonList(chevalGagnant); + if (chevalGagnant.getNomEcurie() != null) { + chevauxEcurie = chevalRepository.findByNomEcurie(chevalGagnant.getNomEcurie()); + } + + // Calculer le total des mises sur les chevaux de l'écurie + double totalMisesEcurie = 0.0; + for (Cheval cheval : chevauxEcurie) { + double misesCheval = parisGagnant.stream() + .filter(p -> p.getCheval().getId().equals(cheval.getId())) + .mapToDouble(PariSimple::getMise) + .sum(); + totalMisesEcurie += misesCheval; + } + + if (totalMisesEcurie > 0) { + gains.setRapportGagnant(gains.getMasseGagnant() / totalMisesEcurie); + } else { + gains.setRapportGagnant(0.0); + } + } + + private void calculerRapportsGagnantDeadHeat(Gains gains, ResultatCourse resultat, List parisGagnant) { + // Article 5a: Cas d'arrivée "dead-heat" - Calcul des rapports "gagnant" + if (resultat.getChevauxPremiers().isEmpty()) { + gains.setRapportGagnant(0.0); + return; + } + + // Calculer le bénéfice à répartir (Article 5a) + double totalMisesPayables = 0.0; + for (Long chevalId : resultat.getChevauxPremiers()) { + double misesCheval = parisGagnant.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + totalMisesPayables += misesCheval; + } + + double beneficeARepartir = gains.getMasseGagnant() - totalMisesPayables; + + if (beneficeARepartir <= 0) { + gains.setRapportGagnant(0.0); + return; + } + + // Diviser le bénéfice en autant de parties qu'il y a de chevaux classés premiers + double partParCheval = beneficeARepartir / resultat.getChevauxPremiers().size(); + + // Pour chaque cheval, calculer son rapport + double rapportTotal = 0.0; + int chevauxAvecMises = 0; + + for (Long chevalId : resultat.getChevauxPremiers()) { + double misesCheval = parisGagnant.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + + if (misesCheval > 0) { + double rapportCheval = (partParCheval / misesCheval) + 1; + rapportTotal += rapportCheval; + chevauxAvecMises++; + } + } + + // Article 6: Si aucun mise sur un cheval, partager entre les autres + if (chevauxAvecMises > 0) { + gains.setRapportGagnant(rapportTotal / chevauxAvecMises); + } else { + gains.setRapportGagnant(0.0); + } + } + + private void calculerRapportsPlaceNormal(Gains gains, ResultatCourse resultat, List parisPlace) { + // Article 5b: Cas d'arrivée normale - Calcul du rapport "placé" + int nombreChevauxInscrits = gains.getCourse().getNombreChevauxInscrits(); + List chevauxPayables = new ArrayList<>(); + + // Déterminer les chevaux payables selon le nombre de partants + if (nombreChevauxInscrits >= 4 && nombreChevauxInscrits <= 7) { + // 2 premiers + chevauxPayables.addAll(resultat.getChevauxPremiers()); + chevauxPayables.addAll(resultat.getChevauxDeuxiemes()); + } else if (nombreChevauxInscrits >= 8) { + // 3 premiers + chevauxPayables.addAll(resultat.getChevauxPremiers()); + chevauxPayables.addAll(resultat.getChevauxDeuxiemes()); + chevauxPayables.addAll(resultat.getChevauxTroisiemes()); + } + + if (chevauxPayables.isEmpty()) { + gains.setRapportPlace(0.0); + return; + } + + // Calculer le bénéfice à répartir (Article 5b) + double totalMisesPayables = 0.0; + for (Long chevalId : chevauxPayables) { + double misesCheval = parisPlace.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + totalMisesPayables += misesCheval; + } + + double beneficeARepartir = gains.getMassePlace() - totalMisesPayables; + + if (beneficeARepartir <= 0) { + gains.setRapportPlace(0.0); + return; + } + + // Diviser le bénéfice en autant de parties qu'il y a de chevaux payables + double partParCheval = beneficeARepartir / chevauxPayables.size(); + + // Pour chaque cheval, calculer son rapport + double rapportTotal = 0.0; + int chevauxAvecMises = 0; + + for (Long chevalId : chevauxPayables) { + double misesCheval = parisPlace.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + + if (misesCheval > 0) { + double rapportCheval = (partParCheval / misesCheval) + 1; + rapportTotal += rapportCheval; + chevauxAvecMises++; + } + } + + // Article 6: Si aucun mise sur un cheval, partager entre les autres + if (chevauxAvecMises > 0) { + gains.setRapportPlace(rapportTotal / chevauxAvecMises); + } else { + gains.setRapportPlace(0.0); + } + } + + private void calculerRapportsPlaceDeadHeat(Gains gains, ResultatCourse resultat, List parisPlace) { + // Article 5b et 5c: Cas d'arrivée "dead-heat" - Calcul des rapports "placé" + int nombreChevauxInscrits = gains.getCourse().getNombreChevauxInscrits(); + + // Déterminer les chevaux payables selon le nombre de partants et le type de dead-heat + List chevauxPayables = determinerChevauxPayablesPlace(resultat, nombreChevauxInscrits); + + if (chevauxPayables.isEmpty()) { + gains.setRapportPlace(0.0); + return; + } + + // Calculer le bénéfice à répartir + double totalMisesPayables = 0.0; + for (Long chevalId : chevauxPayables) { + double misesCheval = parisPlace.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + totalMisesPayables += misesCheval; + } + + double beneficeARepartir = gains.getMassePlace() - totalMisesPayables; + + if (beneficeARepartir <= 0) { + gains.setRapportPlace(0.0); + return; + } + + // Application des règles spécifiques pour les dead-heats (Article 5c) + if (nombreChevauxInscrits < 8) { + beneficeARepartir = appliquerReglesPlaceMoinsHuit(resultat, beneficeARepartir); + } else { + beneficeARepartir = appliquerReglesPlaceHuitPlus(resultat, beneficeARepartir); + } + + // Diviser le bénéfice entre les chevaux payables + double partParCheval = beneficeARepartir / chevauxPayables.size(); + + // Pour chaque cheval, calculer son rapport + double rapportTotal = 0.0; + int chevauxAvecMises = 0; + + for (Long chevalId : chevauxPayables) { + double misesCheval = parisPlace.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + + if (misesCheval > 0) { + double rapportCheval = (partParCheval / misesCheval) + 1; + rapportTotal += rapportCheval; + chevauxAvecMises++; + } + } + + // Article 6: Si aucun mise sur un cheval, partager entre les autres + if (chevauxAvecMises > 0) { + gains.setRapportPlace(rapportTotal / chevauxAvecMises); + } else { + gains.setRapportPlace(0.0); + } + } + + private List determinerChevauxPayablesPlace(ResultatCourse resultat, int nombreChevauxInscrits) { + List chevauxPayables = new ArrayList<>(); + + // Article 3: Déterminer les chevaux payables selon le nombre de partants + if (nombreChevauxInscrits >= 4 && nombreChevauxInscrits <= 7) { + // 2 premiers + chevauxPayables.addAll(resultat.getChevauxPremiers()); + chevauxPayables.addAll(resultat.getChevauxDeuxiemes()); + } else if (nombreChevauxInscrits >= 8) { + // 3 premiers + chevauxPayables.addAll(resultat.getChevauxPremiers()); + chevauxPayables.addAll(resultat.getChevauxDeuxiemes()); + chevauxPayables.addAll(resultat.getChevauxTroisiemes()); + } + + return chevauxPayables; + } + + private double appliquerReglesPlaceMoinsHuit(ResultatCourse resultat, double beneficeARepartir) { + // Article 5c: Règles pour les courses de moins de 8 chevaux avec dead-heat + int nbPremiers = resultat.getChevauxPremiers().size(); + int nbDeuxiemes = resultat.getChevauxDeuxiemes().size(); + + if (nbPremiers > 1) { + // Plus d'un cheval classé premier + return beneficeARepartir / nbPremiers; + } else if (nbDeuxiemes > 1) { + // Plus d'un cheval classé deuxième + double partPremier = beneficeARepartir / 2; + double partDeuxiemes = beneficeARepartir / 2; + return partPremier + (partDeuxiemes / nbDeuxiemes); + } + + return beneficeARepartir; + } + + private double appliquerReglesPlaceHuitPlus(ResultatCourse resultat, double beneficeARepartir) { + // Article 5c: Règles pour les courses de 8 chevaux et plus avec dead-heat + int nbPremiers = resultat.getChevauxPremiers().size(); + int nbDeuxiemes = resultat.getChevauxDeuxiemes().size(); + int nbTroisiemes = resultat.getChevauxTroisiemes().size(); + + if (nbPremiers == 1 && nbDeuxiemes == 1) { + // Un seul premier et un seul deuxième, plusieurs troisièmes + double partPremier = beneficeARepartir / 3; + double partDeuxieme = beneficeARepartir / 3; + double partTroisiemes = beneficeARepartir / 3; + return partPremier + partDeuxieme + (partTroisiemes / nbTroisiemes); + } else if (nbPremiers == 1 && nbDeuxiemes > 1) { + // Un seul premier, plusieurs deuxièmes + double partPremier = beneficeARepartir / 3; + double partDeuxiemes = beneficeARepartir * 2 / 3; + return partPremier + (partDeuxiemes / nbDeuxiemes); + } else if (nbPremiers == 2) { + // Deux chevaux classés premiers + double partParPremier = beneficeARepartir / 3; + double partTroisiemes = beneficeARepartir / 3; + return (2 * partParPremier) + (partTroisiemes / nbTroisiemes); + } else if (nbPremiers > 2) { + // Plus de deux chevaux classés premiers + return beneficeARepartir / nbPremiers; + } + + return beneficeARepartir; + } + + private void gererCagnotte(Gains gains, ResultatCourse resultat, + List parisGagnant, List parisPlace) { + // Article 6 et 7: Gestion de la cagnotte (tirelire) + double montantCagnotte = 0.0; + + // Vérifier les conditions pour la cagnotte GAGNANT + boolean cagnotteGagnant = false; + if (resultat.getChevauxPremiers().isEmpty()) { + // Aucun cheval classé premier + cagnotteGagnant = true; + } else { + // Vérifier s'il n'y a aucune mise sur les chevaux premiers + boolean aucuneMiseGagnant = true; + for (Long chevalId : resultat.getChevauxPremiers()) { + double mises = parisGagnant.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + if (mises > 0) { + aucuneMiseGagnant = false; + break; + } + } + cagnotteGagnant = aucuneMiseGagnant; + } + + if (cagnotteGagnant) { + montantCagnotte += gains.getMasseGagnant(); + gains.setMasseGagnant(0.0); + gains.setRapportGagnant(0.0); + } + + // Vérifier les conditions pour la cagnotte PLACE + boolean cagnottePlace = false; + int nombreChevauxInscrits = gains.getCourse().getNombreChevauxInscrits(); + + // Article 6.3: Si moins de 4 chevaux ont pris part à la course + if (nombreChevauxInscrits < 4) { + cagnottePlace = true; + } else { + List chevauxPayables = determinerChevauxPayablesPlace(resultat, nombreChevauxInscrits); + + if (chevauxPayables.isEmpty()) { + cagnottePlace = true; + } else { + // Vérifier s'il n'y a aucune mise sur les chevaux payables + boolean aucuneMisePlace = true; + for (Long chevalId : chevauxPayables) { + double mises = parisPlace.stream() + .filter(p -> p.getCheval().getId().equals(chevalId)) + .mapToDouble(PariSimple::getMise) + .sum(); + if (mises > 0) { + aucuneMisePlace = false; + break; + } + } + cagnottePlace = aucuneMisePlace; + } + } + + if (cagnottePlace) { + montantCagnotte += gains.getMassePlace(); + gains.setMassePlace(0.0); + gains.setRapportPlace(0.0); + } + + gains.setMontantCagnotte(montantCagnotte); + + // TODO: Implémenter la logique de report de la cagnotte selon l'article 7 + } + + public Gains obtenirGainsParCourse(Long courseId) { + return gainsRepository.findByCourseId(courseId); + } +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch1_simple/service/PariSimpleService.java b/src/main/java/com/pmumali/ch1_simple/service/PariSimpleService.java new file mode 100644 index 0000000..8e63f54 --- /dev/null +++ b/src/main/java/com/pmumali/ch1_simple/service/PariSimpleService.java @@ -0,0 +1,52 @@ +package com.pmumali.ch1_simple.service; + +import com.pmumali.ch1_simple.model.Course; +import com.pmumali.ch1_simple.model.PariSimple; +import com.pmumali.ch1_simple.repository.ChevalRepository; +import com.pmumali.ch1_simple.repository.CourseRepository; +import com.pmumali.ch1_simple.repository.PariSimpleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PariSimpleService { + + @Autowired + private PariSimpleRepository pariRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ChevalRepository chevalRepository; + + private static final double MISE_DE_BASE = 500.0; + + public PariSimple placerPari(PariSimple pari) { + // Vérifier que le type de pari est valide pour la course + Course course = pari.getCourse(); + if ("GAGNANT".equals(pari.getTypePari()) && course.getNombreChevauxInscrits() < 2) { + throw new IllegalArgumentException("Pari GAGNANT impossible: moins de 2 chevaux"); + } + + if ("PLACE".equals(pari.getTypePari()) && course.getNombreChevauxInscrits() < 3) { + throw new IllegalArgumentException("Pari PLACE impossible: moins de 3 chevaux"); + } + + return pariRepository.save(pari); + } + + public List obtenirParisParCourse(Long courseId) { + return pariRepository.findByCourseId(courseId); + } + + public List obtenirParisParCourseEtType(Long courseId, String typePari) { + return pariRepository.findByCourseIdAndTypePari(courseId, typePari); + } + + public List obtenirParisParCheval(Long chevalId) { + return pariRepository.findByChevalId(chevalId); + } +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/controller/ChevalController.java b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/ChevalController.java new file mode 100644 index 0000000..abaa1a5 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/ChevalController.java @@ -0,0 +1,32 @@ +package com.pmumali.ch2_jumelegagnant.controller; + +import com.pmumali.ch2_jumelegagnant.model.Cheval; +import com.pmumali.ch2_jumelegagnant.service.ChevalService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/chevaux") +public class ChevalController { + + @Autowired + private ChevalService chevalService; + + @PostMapping + public ResponseEntity ajouterCheval(@RequestBody Cheval cheval) { + return ResponseEntity.ok(chevalService.ajouterCheval(cheval)); + } + + @GetMapping("/course/{courseId}") + public ResponseEntity> obtenirChevauxParCourse(@PathVariable Long courseId) { + return ResponseEntity.ok(chevalService.obtenirChevauxParCourse(courseId)); + } + + @GetMapping("/non-partants") + public ResponseEntity> obtenirChevauxNonPartants() { + return ResponseEntity.ok(chevalService.obtenirChevauxNonPartants()); + } +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/controller/CourseController.java b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/CourseController.java new file mode 100644 index 0000000..cdc653b --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/CourseController.java @@ -0,0 +1,48 @@ +package com.pmumali.ch2_jumelegagnant.controller; + +import com.pmumali.ch2_jumelegagnant.model.Course; +import com.pmumali.ch2_jumelegagnant.service.CourseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.List; + +@RestController +@RequestMapping("/api/courses") +public class CourseController { + + @Autowired + private CourseService courseService; + + @PostMapping + public ResponseEntity creerCourse(@RequestBody Course course) { + return ResponseEntity.ok(courseService.creerCourse(course)); + } + + @GetMapping + public ResponseEntity> obtenirToutesCourses() { + return ResponseEntity.ok(courseService.obtenirToutesCourses()); + } + + @GetMapping("/{id}") + public ResponseEntity obtenirCourseParId(@PathVariable Long id) { + Course course = courseService.obtenirCourseParId(id); + return course != null ? ResponseEntity.ok(course) : ResponseEntity.notFound().build(); + } + + @GetMapping("/terminees") + public ResponseEntity> obtenirCoursesTerminees() { + return ResponseEntity.ok(courseService.obtenirCoursesTerminees()); + } + + @GetMapping("/avenir") + public ResponseEntity> obtenirCoursesAVenir() { + return ResponseEntity.ok(courseService.obtenirCoursesAVenir()); + } + + @GetMapping("/annulees") + public ResponseEntity> obtenirCoursesAnnulees() { + return ResponseEntity.ok(courseService.obtenirCoursesAnnulees()); + } +} + diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/controller/GainsController.java b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/GainsController.java new file mode 100644 index 0000000..058b377 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/GainsController.java @@ -0,0 +1,27 @@ +package com.pmumali.ch2_jumelegagnant.controller; + +import com.pmumali.ch2_jumelegagnant.model.Gains; +import com.pmumali.ch2_jumelegagnant.model.ResultatCourse; +import com.pmumali.ch2_jumelegagnant.service.GainsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/gains") +public class GainsController { + + @Autowired + private GainsService gainsService; + + @PostMapping("/calculer/{courseId}") + public ResponseEntity calculerGains(@PathVariable Long courseId, @RequestBody ResultatCourse resultat) { + return ResponseEntity.ok(gainsService.calculerGains(courseId, resultat)); + } + + @GetMapping("/course/{courseId}") + public ResponseEntity obtenirGainsParCourse(@PathVariable Long courseId) { + Gains gains = gainsService.obtenirGainsParCourse(courseId); + return gains != null ? ResponseEntity.ok(gains) : ResponseEntity.notFound().build(); + } +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/controller/PariJumeleController.java b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/PariJumeleController.java new file mode 100644 index 0000000..c05c8d5 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/controller/PariJumeleController.java @@ -0,0 +1,46 @@ +package com.pmumali.ch2_jumelegagnant.controller; + +import com.pmumali.ch2_jumelegagnant.model.PariJumeleGagnant; +import com.pmumali.ch2_jumelegagnant.service.PariJumeleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/paris-jumele") +public class PariJumeleController { + + @Autowired + private PariJumeleService pariService; + + @PostMapping + public ResponseEntity placerPari(@RequestBody PariJumeleGagnant pari) { + return ResponseEntity.ok(pariService.placerPari(pari)); + } + + @GetMapping("/course/{courseId}") + public ResponseEntity> obtenirParisParCourse(@PathVariable Long courseId) { + return ResponseEntity.ok(pariService.obtenirParisParCourse(courseId)); + } + + @GetMapping("/cheval/{chevalId}") + public ResponseEntity> obtenirParisParCheval(@PathVariable Long chevalId) { + return ResponseEntity.ok(pariService.obtenirParisParCheval(chevalId)); + } + + @GetMapping("/calculer-formule-combinee/{nombreChevaux}") + public ResponseEntity calculerCoutFormuleCombinee(@PathVariable int nombreChevaux) { + return ResponseEntity.ok(pariService.calculerCoutFormuleCombinee(nombreChevaux)); + } + + @GetMapping("/calculer-formule-champ") + public ResponseEntity calculerCoutFormuleChamp( + @RequestParam int nombreChevauxPartants, + @RequestParam int nombreChevauxSelectionnes, + @RequestParam boolean estChampTotal) { + return ResponseEntity.ok(pariService.calculerCoutFormuleChamp( + nombreChevauxPartants, nombreChevauxSelectionnes, estChampTotal)); + } +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/dto/ChevalDto.java b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/ChevalDto.java new file mode 100644 index 0000000..2ee971c --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/ChevalDto.java @@ -0,0 +1,12 @@ +package com.pmumali.ch2_jumelegagnant.dto; + +import lombok.Data; + +@Data +public class ChevalDto { + private Long id; + private String nom; + private int numero; + private boolean estNonPartant; + private Long courseId; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/dto/CourseDto.java b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/CourseDto.java new file mode 100644 index 0000000..3157503 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/CourseDto.java @@ -0,0 +1,17 @@ +package com.pmumali.ch2_jumelegagnant.dto; + +import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class CourseDto { + private Long id; + private String nom; + private LocalDateTime date; + private String lieu; + private int nombreChevauxInscrits; + private boolean estTerminee; + private boolean estAnnulee; + private List chevauxIds; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/dto/GainsDto.java b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/GainsDto.java new file mode 100644 index 0000000..48b3c45 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/GainsDto.java @@ -0,0 +1,16 @@ +package com.pmumali.ch2_jumelegagnant.dto; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class GainsDto { + private Long id; + private Long courseId; + private double masseAPartager; + private double montantCagnotte; + private List rapports; + private LocalDateTime dateCalcul; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/dto/PariJumeleDto.java b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/PariJumeleDto.java new file mode 100644 index 0000000..51ec0cb --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/PariJumeleDto.java @@ -0,0 +1,18 @@ +package com.pmumali.ch2_jumelegagnant.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class PariJumeleDto { + private Long id; + private String typePari; + private double mise; + private LocalDateTime datePari; + private Long cheval1Id; + private Long cheval2Id; + private Long courseId; + private boolean estPaye; + private boolean estRembourse; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/dto/ResultatCourseDto.java b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/ResultatCourseDto.java new file mode 100644 index 0000000..4b20258 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/dto/ResultatCourseDto.java @@ -0,0 +1,14 @@ +package com.pmumali.ch2_jumelegagnant.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ResultatCourseDto { + private Long id; + private Long courseId; + private List chevauxPremiers; + private List chevauxDeuxiemes; + private boolean aDeadHeat; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/model/Cheval.java b/src/main/java/com/pmumali/ch2_jumelegagnant/model/Cheval.java new file mode 100644 index 0000000..db6e3b6 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/model/Cheval.java @@ -0,0 +1,23 @@ +package com.pmumali.ch2_jumelegagnant.model; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "cheval") +public class Cheval { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nom; + private int numero; + private boolean estNonPartant; + + @ManyToOne + @JoinColumn(name = "course_id") + private Course course; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/model/Course.java b/src/main/java/com/pmumali/ch2_jumelegagnant/model/Course.java new file mode 100644 index 0000000..16f7f3b --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/model/Course.java @@ -0,0 +1,33 @@ +package com.pmumali.ch2_jumelegagnant.model; + +import jakarta.persistence.*; +import lombok.*; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "course") +public class Course { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nom; + private LocalDateTime date; + private String lieu; + private int nombreChevauxInscrits; + private boolean estTerminee; + private boolean estAnnulee; + + @OneToMany(mappedBy = "course", cascade = CascadeType.ALL) + private List chevaux; + + @OneToOne(mappedBy = "course", cascade = CascadeType.ALL) + private ResultatCourse resultat; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/model/Gains.java b/src/main/java/com/pmumali/ch2_jumelegagnant/model/Gains.java new file mode 100644 index 0000000..f4b6c4f --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/model/Gains.java @@ -0,0 +1,30 @@ +package com.pmumali.ch2_jumelegagnant.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "gains") +public class Gains { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "course_id") + private Course course; + + private double masseAPartager; + private double montantCagnotte; + + @ElementCollection + private List rapports; // Rapports pour chaque combinaison payable + + private LocalDateTime dateCalcul; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/model/PariJumeleGagnant.java b/src/main/java/com/pmumali/ch2_jumelegagnant/model/PariJumeleGagnant.java new file mode 100644 index 0000000..e723c24 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/model/PariJumeleGagnant.java @@ -0,0 +1,36 @@ +package com.pmumali.ch2_jumelegagnant.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "pari_jumele_gagnant") +public class PariJumeleGagnant { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String typePari; // UNITAIRE, COMBINE, CHAMP_TOTAL, CHAMP_PARTIEL + private double mise = 500.0; + private LocalDateTime datePari; + + @ManyToOne + @JoinColumn(name = "cheval1_id") + private Cheval cheval1; + + @ManyToOne + @JoinColumn(name = "cheval2_id") + private Cheval cheval2; + + @ManyToOne + @JoinColumn(name = "course_id") + private Course course; + + private boolean estPaye; + private boolean estRembourse; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/model/ResultatCourse.java b/src/main/java/com/pmumali/ch2_jumelegagnant/model/ResultatCourse.java new file mode 100644 index 0000000..e4d182c --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/model/ResultatCourse.java @@ -0,0 +1,29 @@ +package com.pmumali.ch2_jumelegagnant.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "resultat_course") +public class ResultatCourse { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + @JoinColumn(name = "course_id") + private Course course; + + @ElementCollection + private List chevauxPremiers; // Pour gérer les dead-heats + + @ElementCollection + private List chevauxDeuxiemes; // Pour gérer les dead-heats + + private boolean aDeadHeat; +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/repository/ChevalRepository.java b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/ChevalRepository.java new file mode 100644 index 0000000..5bba280 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/ChevalRepository.java @@ -0,0 +1,13 @@ +package com.pmumali.ch2_jumelegagnant.repository; + +import com.pmumali.ch2_jumelegagnant.model.Cheval; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ChevalRepository extends JpaRepository { + List findByCourseId(Long courseId); + List findByEstNonPartant(boolean estNonPartant); +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/repository/CourseRepository.java b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/CourseRepository.java new file mode 100644 index 0000000..db7b47d --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/CourseRepository.java @@ -0,0 +1,12 @@ +package com.pmumali.ch2_jumelegagnant.repository; + +import com.pmumali.ch2_jumelegagnant.model.Course; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface CourseRepository extends JpaRepository { + List findByEstTerminee(boolean estTerminee); + List findByEstAnnulee(boolean estAnnulee); +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/repository/GainsRepository.java b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/GainsRepository.java new file mode 100644 index 0000000..a8d0065 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/GainsRepository.java @@ -0,0 +1,10 @@ +package com.pmumali.ch2_jumelegagnant.repository; + +import com.pmumali.ch2_jumelegagnant.model.Gains; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface GainsRepository extends JpaRepository { + Gains findByCourseId(Long courseId); +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/repository/PariJumeleRepository.java b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/PariJumeleRepository.java new file mode 100644 index 0000000..1698c9f --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/PariJumeleRepository.java @@ -0,0 +1,14 @@ +package com.pmumali.ch2_jumelegagnant.repository; + +import com.pmumali.ch2_jumelegagnant.model.PariJumeleGagnant; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PariJumeleRepository extends JpaRepository { + List findByCourseId(Long courseId); + List findByCheval1IdOrCheval2Id(Long cheval1Id, Long cheval2Id); + List findByEstRembourse(boolean estRembourse); +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/repository/ResultatCourseRepository.java b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/ResultatCourseRepository.java new file mode 100644 index 0000000..5f274b0 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/repository/ResultatCourseRepository.java @@ -0,0 +1,10 @@ +package com.pmumali.ch2_jumelegagnant.repository; + +import com.pmumali.ch2_jumelegagnant.model.ResultatCourse; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ResultatCourseRepository extends JpaRepository { + ResultatCourse findByCourseId(Long courseId); +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/service/ChevalService.java b/src/main/java/com/pmumali/ch2_jumelegagnant/service/ChevalService.java new file mode 100644 index 0000000..823a4f7 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/service/ChevalService.java @@ -0,0 +1,27 @@ +package com.pmumali.ch2_jumelegagnant.service; + +import com.pmumali.ch2_jumelegagnant.model.Cheval; +import com.pmumali.ch2_jumelegagnant.repository.ChevalRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ChevalService { + + @Autowired + private ChevalRepository chevalRepository; + + public Cheval ajouterCheval(Cheval cheval) { + return chevalRepository.save(cheval); + } + + public List obtenirChevauxParCourse(Long courseId) { + return chevalRepository.findByCourseId(courseId); + } + + public List obtenirChevauxNonPartants() { + return chevalRepository.findByEstNonPartant(true); + } +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/service/CourseService.java b/src/main/java/com/pmumali/ch2_jumelegagnant/service/CourseService.java new file mode 100644 index 0000000..d25e20b --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/service/CourseService.java @@ -0,0 +1,40 @@ +package com.pmumali.ch2_jumelegagnant.service; + +import com.pmumali.ch2_jumelegagnant.model.Course; +import com.pmumali.ch2_jumelegagnant.repository.CourseRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + + +@Service +public class CourseService { + + @Autowired + private CourseRepository courseRepository; + + public Course creerCourse(Course course) { + return courseRepository.save(course); + } + + public List obtenirToutesCourses() { + return courseRepository.findAll(); + } + + public Course obtenirCourseParId(Long id) { + return courseRepository.findById(id).orElse(null); + } + + public List obtenirCoursesTerminees() { + return courseRepository.findByEstTerminee(true); + } + + public List obtenirCoursesAVenir() { + return courseRepository.findByEstTerminee(false); + } + + public List obtenirCoursesAnnulees() { + return courseRepository.findByEstAnnulee(true); + } +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/service/GainsService.java b/src/main/java/com/pmumali/ch2_jumelegagnant/service/GainsService.java new file mode 100644 index 0000000..31e4541 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/service/GainsService.java @@ -0,0 +1,329 @@ +package com.pmumali.ch2_jumelegagnant.service; + +import com.pmumali.ch2_jumelegagnant.model.Course; +import com.pmumali.ch2_jumelegagnant.model.Gains; +import com.pmumali.ch2_jumelegagnant.model.PariJumeleGagnant; +import com.pmumali.ch2_jumelegagnant.model.ResultatCourse; +import com.pmumali.ch2_jumelegagnant.repository.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.*; + +@Service +@Transactional +public class GainsService { + + @Autowired + private PariJumeleRepository pariRepository; + + @Autowired + private GainsRepository gainsRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ChevalRepository chevalRepository; + + @Autowired + private ResultatCourseRepository resultatRepository; + + private static final double RAPPORT_MINIMUM = 1.1; + private static final double PRELEVEMENTS = 0.15; // 15% de prélèvements + + public Gains calculerGains(Long courseId, ResultatCourse resultat) { + Course course = courseRepository.findById(courseId) + .orElseThrow(() -> new RuntimeException("Course non trouvée")); + + List tousParis = pariRepository.findByCourseId(courseId); + + // Calcul de la recette nette (Article 5) + double totalMises = tousParis.stream().mapToDouble(PariJumeleGagnant::getMise).sum(); + double recetteNette = totalMises; + + // Calcul des remboursements (Article 4) + double montantRemboursements = calculerRemboursements(tousParis); + + // Masse à partager (Article 5) + double masseAPartager = recetteNette - montantRemboursements - (recetteNette * PRELEVEMENTS); + + // Déterminer les combinaisons payables + List combinaisonsPayables = determinerCombinaisonsPayables(resultat); + + // Calcul des rapports + Gains gains = new Gains(); + gains.setCourse(course); + gains.setMasseAPartager(masseAPartager); + gains.setDateCalcul(LocalDateTime.now()); + + // Calcul détaillé des gains selon les règles + if (resultat.isADeadHeat()) { + calculerRapportsDeadHeat(gains, combinaisonsPayables, tousParis); + } else { + calculerRapportsNormaux(gains, combinaisonsPayables, tousParis); + } + + // Gérer la cagnotte si nécessaire (Article 8 et 9) + gererCagnotte(gains, combinaisonsPayables); + + return gainsRepository.save(gains); + } + + private double calculerRemboursements(List paris) { + double remboursements = 0.0; + + for (PariJumeleGagnant pari : paris) { + // Article 4: Remboursement si un ou deux chevaux non partants + if (pari.getCheval1().isEstNonPartant() || pari.getCheval2().isEstNonPartant()) { + remboursements += pari.getMise(); + pari.setEstRembourse(true); + pariRepository.save(pari); + } + } + + return remboursements; + } + + private List determinerCombinaisonsPayables(ResultatCourse resultat) { + List combinaisons = new ArrayList<>(); + + // Article 1: Le pari est payable si les deux chevaux occupent les deux premières places + // Article 3: Gestion des dead-heats + + if (resultat.isADeadHeat()) { + // Cas de dead-heat + if (resultat.getChevauxPremiers().size() >= 2) { + // Article 3a: Dead-heat à la première place + // Toutes les combinaisons des chevaux classés premiers pris deux à deux + for (int i = 0; i < resultat.getChevauxPremiers().size(); i++) { + for (int j = i + 1; j < resultat.getChevauxPremiers().size(); j++) { + combinaisons.add(new CombinaisonPayable( + resultat.getChevauxPremiers().get(i), + resultat.getChevauxPremiers().get(j) + )); + } + } + } else if (resultat.getChevauxDeuxiemes().size() >= 2) { + // Article 3b: Dead-heat à la deuxième place + // Combinaisons du premier avec chaque deuxième + for (Long chevalPremier : resultat.getChevauxPremiers()) { + for (Long chevalDeuxieme : resultat.getChevauxDeuxiemes()) { + combinaisons.add(new CombinaisonPayable(chevalPremier, chevalDeuxieme)); + } + } + } + } else { + // Cas normal + if (!resultat.getChevauxPremiers().isEmpty() && !resultat.getChevauxDeuxiemes().isEmpty()) { + combinaisons.add(new CombinaisonPayable( + resultat.getChevauxPremiers().get(0), + resultat.getChevauxDeuxiemes().get(0) + )); + } + } + + return combinaisons; + } + + private void calculerRapportsNormaux(Gains gains, List combinaisonsPayables, + List tousParis) { + // Article 5a: Cas d'arrivée normale + if (combinaisonsPayables.isEmpty()) { + gains.setMontantCagnotte(gains.getMasseAPartager()); + gains.setMasseAPartager(0.0); + return; + } + + // Normalement, une seule combinaison payable en cas d'arrivée normale + CombinaisonPayable combinaisonPayable = combinaisonsPayables.get(0); + + // Calculer le total des mises sur cette combinaison + double totalMises = calculerMisesSurCombinaison(combinaisonPayable, tousParis); + + if (totalMises > 0) { + double rapport = gains.getMasseAPartager() / totalMises; + gains.setRapports(Collections.singletonList(Math.max(rapport, RAPPORT_MINIMUM))); + } else { + // Article 8a: Aucune mise sur la combinaison payable + gains.setMontantCagnotte(gains.getMasseAPartager()); + gains.setMasseAPartager(0.0); + } + } + + private void calculerRapportsDeadHeat(Gains gains, List combinaisonsPayables, + List tousParis) { + // Article 5b: Cas d'arrivée "dead heat" + if (combinaisonsPayables.isEmpty()) { + gains.setMontantCagnotte(gains.getMasseAPartager()); + gains.setMasseAPartager(0.0); + return; + } + + // Calculer le total des mises sur toutes les combinaisons payables + double totalMisesPayables = 0.0; + Map misesParCombinaison = new HashMap<>(); + + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double mises = calculerMisesSurCombinaison(combinaison, tousParis); + misesParCombinaison.put(combinaison, mises); + totalMisesPayables += mises; + } + + // Calculer le bénéfice à répartir + double beneficeARepartir = gains.getMasseAPartager() - totalMisesPayables; + + if (beneficeARepartir <= 0) { + // Article 8b: Gestion des cas où il n'y a pas de bénéfice + gererCasParticuliersDeadHeat(gains, combinaisonsPayables, misesParCombinaison); + return; + } + + // Diviser le bénéfice en autant de parties qu'il y a de combinaisons payables + double partParCombinaison = beneficeARepartir / combinaisonsPayables.size(); + + // Calculer les rapports pour chaque combinaison + List rapports = new ArrayList<>(); + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double mises = misesParCombinaison.get(combinaison); + if (mises > 0) { + double rapport = (partParCombinaison / mises) + 1; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + // Article 8b1: Aucune mise sur une combinaison payable + // Répartir le bénéfice entre les autres combinaisons + double partSupplementaire = partParCombinaison / (combinaisonsPayables.size() - 1); + // Nous ajouterons cette part aux autres combinaisons plus tard + rapports.add(0.0); + } + } + + // Ajuster les rapports pour les combinaisons sans mises + ajusterRapportsSansMises(rapports, combinaisonsPayables, misesParCombinaison, partParCombinaison); + + gains.setRapports(rapports); + } + + private void gererCasParticuliersDeadHeat(Gains gains, List combinaisonsPayables, + Map misesParCombinaison) { + // Article 8b: Gestion des cas particuliers de dead-heat + boolean aucuneMise = true; + for (Double mises : misesParCombinaison.values()) { + if (mises > 0) { + aucuneMise = false; + break; + } + } + + if (aucuneMise) { + // Article 8b2, 8b3, 8b4: Aucune mise sur aucune combinaison payable + gains.setMontantCagnotte(gains.getMasseAPartager()); + gains.setMasseAPartager(0.0); + } else { + // Répartir la masse entre les combinaisons avec des mises + double totalMises = misesParCombinaison.values().stream().mapToDouble(Double::doubleValue).sum(); + List rapports = new ArrayList<>(); + + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double mises = misesParCombinaison.get(combinaison); + if (mises > 0) { + double rapport = gains.getMasseAPartager() / totalMises; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + rapports.add(0.0); + } + } + + gains.setRapports(rapports); + } + } + + private void ajusterRapportsSansMises(List rapports, List combinaisonsPayables, + Map misesParCombinaison, double partParCombinaison) { + // Compter le nombre de combinaisons sans mises + int combinaisonsSansMises = 0; + for (Double mises : misesParCombinaison.values()) { + if (mises == 0) { + combinaisonsSansMises++; + } + } + + if (combinaisonsSansMises > 0) { + double partSupplementaire = partParCombinaison / (combinaisonsPayables.size() - combinaisonsSansMises); + + for (int i = 0; i < rapports.size(); i++) { + if (rapports.get(i) > 0) { + rapports.set(i, rapports.get(i) + partSupplementaire / misesParCombinaison.get(combinaisonsPayables.get(i))); + } + } + } + } + + private double calculerMisesSurCombinaison(CombinaisonPayable combinaison, List tousParis) { + double totalMises = 0.0; + + for (PariJumeleGagnant pari : tousParis) { + if ((pari.getCheval1().getId().equals(combinaison.getCheval1Id()) && + pari.getCheval2().getId().equals(combinaison.getCheval2Id())) || + (pari.getCheval1().getId().equals(combinaison.getCheval2Id()) && + pari.getCheval2().getId().equals(combinaison.getCheval1Id()))) { + totalMises += pari.getMise(); + } + } + + return totalMises; + } + + private void gererCagnotte(Gains gains, List combinaisonsPayables) { + // Article 8 et 9: Gestion de la cagnotte + if (combinaisonsPayables.isEmpty()) { + gains.setMontantCagnotte(gains.getMasseAPartager()); + gains.setMasseAPartager(0.0); + } + + // Article 8c: Course annulée ou reportée + if (gains.getCourse().isEstAnnulee()) { + gains.setMontantCagnotte(gains.getMasseAPartager()); + gains.setMasseAPartager(0.0); + } + } + + // Classe interne pour représenter une combinaison payable + private static class CombinaisonPayable { + private Long cheval1Id; + private Long cheval2Id; + + public CombinaisonPayable(Long cheval1Id, Long cheval2Id) { + this.cheval1Id = cheval1Id; + this.cheval2Id = cheval2Id; + } + + public Long getCheval1Id() { return cheval1Id; } + public Long getCheval2Id() { return cheval2Id; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CombinaisonPayable that = (CombinaisonPayable) o; + return (Objects.equals(cheval1Id, that.cheval1Id) && + Objects.equals(cheval2Id, that.cheval2Id)) || + (Objects.equals(cheval1Id, that.cheval2Id) && + Objects.equals(cheval2Id, that.cheval1Id)); + } + + @Override + public int hashCode() { + // Hash code qui ne dépend pas de l'ordre des chevaux + long id1 = Math.min(cheval1Id, cheval2Id); + long id2 = Math.max(cheval1Id, cheval2Id); + return Objects.hash(id1, id2); + } + } + + public Gains obtenirGainsParCourse(Long courseId) { + return gainsRepository.findByCourseId(courseId); + } +} diff --git a/src/main/java/com/pmumali/ch2_jumelegagnant/service/PariJumeleService.java b/src/main/java/com/pmumali/ch2_jumelegagnant/service/PariJumeleService.java new file mode 100644 index 0000000..5bf9414 --- /dev/null +++ b/src/main/java/com/pmumali/ch2_jumelegagnant/service/PariJumeleService.java @@ -0,0 +1,63 @@ +package com.pmumali.ch2_jumelegagnant.service; + +import com.pmumali.ch2_jumelegagnant.model.PariJumeleGagnant; +import com.pmumali.ch2_jumelegagnant.repository.ChevalRepository; +import com.pmumali.ch2_jumelegagnant.repository.CourseRepository; +import com.pmumali.ch2_jumelegagnant.repository.PariJumeleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PariJumeleService { + + @Autowired + private PariJumeleRepository pariRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ChevalRepository chevalRepository; + + private static final double MISE_DE_BASE = 500.0; + private static final double MISE_MAXIMALE = 20 * MISE_DE_BASE; + + public PariJumeleGagnant placerPari(PariJumeleGagnant pari) { + // Vérification de la limite d'enjeu (Article 2) + if (pari.getMise() > MISE_MAXIMALE) { + pari.setMise(MISE_MAXIMALE); + // TODO: Implémenter le remboursement de la différence + } + + return pariRepository.save(pari); + } + + public List obtenirParisParCourse(Long courseId) { + return pariRepository.findByCourseId(courseId); + } + + public List obtenirParisParCheval(Long chevalId) { + return pariRepository.findByCheval1IdOrCheval2Id(chevalId, chevalId); + } + + // Méthode pour calculer le coût d'une formule combinée (Article 6a) + public double calculerCoutFormuleCombinee(int nombreChevauxSelectionnes) { + if (nombreChevauxSelectionnes < 2) { + return 0; + } + int nombreCombinaisons = (nombreChevauxSelectionnes * (nombreChevauxSelectionnes - 1)) / 2; + return nombreCombinaisons * MISE_DE_BASE; + } + + // Méthode pour calculer le coût d'une formule champ (Article 6b) + public double calculerCoutFormuleChamp(int nombreChevauxPartants, int nombreChevauxSelectionnes, boolean estChampTotal) { + if (estChampTotal) { + return (nombreChevauxPartants - 1) * MISE_DE_BASE; + } else { + return nombreChevauxSelectionnes * MISE_DE_BASE; + } + } +} + diff --git a/src/main/java/com/pmumali/simple/controller/CourseController.java b/src/main/java/com/pmumali/simple/controller/CourseController.java deleted file mode 100644 index bf2c61a..0000000 --- a/src/main/java/com/pmumali/simple/controller/CourseController.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.pmumali.simple.controller; - -import com.pmumali.simple.model.Cheval; -import com.pmumali.simple.model.Course; - -import java.util.stream.Collectors; - -public class CourseController { - - private CourseDetailsDto convertToDetailsDto(Course course) { - CourseDetailsDto dto = new CourseDetailsDto(); - dto.setId(course.getId()); - dto.setNom(course.getNom()); - dto.setDateCourse(course.getDateCourse()); - dto.setChevaux(course.getChevaux().stream() - .map(this::convertChevalDto) - .collect(Collectors.toList())); - return dto; - } - - private ChevalDto convertChevalDto(Cheval cheval) { - ChevalDto dto = new ChevalDto(); - dto.setId(cheval.getId()); - dto.setNom(cheval.getNom()); - dto.setNonPartant(cheval.isEstNonPartant()); - return dto; - } -} diff --git a/src/main/java/com/pmumali/simple/controller/PariController.java b/src/main/java/com/pmumali/simple/controller/PariController.java deleted file mode 100644 index 0b4755c..0000000 --- a/src/main/java/com/pmumali/simple/controller/PariController.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.pmumali.simple.controller; - -import com.pmu.jumele.dto.PariRequest; -import com.pmu.mali.model.ResultatCourse; -import com.pmumali.simple.dto.PariResponse; -import com.pmumali.simple.dto.ResultatCourseDto; -import com.pmumali.simple.model.Pari; -import com.pmumali.simple.service.PariService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/paris") -public class PariController { - - @Autowired - private PariService pariService; - - @PostMapping("/jumelé") - public ResponseEntity placerPari( - @RequestBody PariRequest pariRequest) { - - Pari pari = pariService.placerPariJumele( - pariRequest.getClientId(), - pariRequest.getCourseId(), - pariRequest.getChevauxIds(), - pariRequest.getMontantMise() - ); - - return ResponseEntity.ok(pari); - } - - @GetMapping("/resultats/{courseId}") - public ResponseEntity calculerResultats( - @PathVariable Long courseId) { - return ResponseEntity.ok(pariService.calculerResultats(courseId)); - } - - @PostMapping("/jumele-place") - public ResponseEntity placerPariJumelePlace( - @Valid @RequestBody PariRequest pariRequest) { - - Pari pari = pariService.placerPariJumelePlace(pariRequest); - return ResponseEntity.ok(convertToResponse(pari)); - } - - @GetMapping("/resultats/jumele-place/{courseId}") - public ResponseEntity getResultatsJumelePlace( - @PathVariable Long courseId) { -Pari - ResultatCourseDto resultat = pariService.calculerResultatsJumelePlace(courseId); - return ResponseEntity.ok(resultat); - } - - - private PariResponse convertToResponse(Pari pari) { - PariResponse response = new PariResponse(); - response.setId(pari.getId()); - response.setMontantMise(pari.getMontantMise()); - response.setDatePari(pari.getDatePari()); - response.setChevaux(pari.getChevauxJumeles().stream() - .map(Cheval::getNom) - .collect(Collectors.toList())); - response.setCourseNom(pari.getCourse().getNom()); - return response; - } -} diff --git a/src/main/java/com/pmumali/simple/dto/ChevalDto.java b/src/main/java/com/pmumali/simple/dto/ChevalDto.java deleted file mode 100644 index 7781863..0000000 --- a/src/main/java/com/pmumali/simple/dto/ChevalDto.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.pmumali.simple.dto; - -import com.pmumali.simple.model.Cheval; -import lombok.Data; - -@Data -public class ChevalDto { - private Long id; - private String nom; - private int numero; - private boolean estNonPartant; - - // Constructeurs, Getters, Setters - - public static ChevalDto fromEntity(Cheval cheval) { - ChevalDto dto = new ChevalDto(); - dto.setId(cheval.getId()); - dto.setNom(cheval.getNom()); - dto.setNumero(cheval.getNumero()); - dto.setEstNonPartant(cheval.isEstNonPartant()); - return dto; - } -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/dto/CombinaisonDto.java b/src/main/java/com/pmumali/simple/dto/CombinaisonDto.java deleted file mode 100644 index dbe232b..0000000 --- a/src/main/java/com/pmumali/simple/dto/CombinaisonDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.pmumali.simple.dto; - -import lombok.Data; - -@Data -public class CombinaisonDto { - private String cheval1; - private String cheval2; - private int nombreMises; - - // Getters, setters -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/dto/PariRequest.java b/src/main/java/com/pmumali/simple/dto/PariRequest.java deleted file mode 100644 index ef61be5..0000000 --- a/src/main/java/com/pmumali/simple/dto/PariRequest.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.pmumali.simple.dto; - -import lombok.Data; - -import java.util.List; - -@Data -public class PariRequest { - private Long clientId; - private Long courseId; - private List chevauxIds; - private double montantMise; - - // Getters, setters -} diff --git a/src/main/java/com/pmumali/simple/dto/PariResponse.java b/src/main/java/com/pmumali/simple/dto/PariResponse.java deleted file mode 100644 index a7c691f..0000000 --- a/src/main/java/com/pmumali/simple/dto/PariResponse.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.pmumali.simple.dto; - -import com.pmumali.simple.model.Cheval; -import com.pmumali.simple.model.Pari; -import com.pmumali.simple.model.enums.TypePari; -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.time.LocalDateTime; - -/** - * DTO pour la réponse API des paris - * Contient toutes les informations à exposer au client - */ -public class PariResponse { - private Long id; - private String numeroPari; - private TypePari typePari; - private double montantMise; - - @JsonFormat(pattern = "dd/MM/yyyy HH:mm:ss") - private LocalDateTime datePari; - - private String statut; // EN_COURS, GAGNANT, PERDANT, REMBOURSE - private Double gainsPotentiels; - private boolean estPaye; - - // Informations course - private Long courseId; - private String courseNom; - @JsonFormat(pattern = "dd/MM/yyyy HH:mm") - private LocalDateTime dateCourse; - - // Chevaux sélectionnés - private List chevaux; - - // Informations client (simplifiées) - private String clientNomComplet; - private String clientNumero; - - // Constructeurs - public PariResponse() {} - - public PariResponse(Long id, String numeroPari, TypePari typePari, double montantMise, - LocalDateTime datePari, String statut, Double gainsPotentiels, - boolean estPaye, Long courseId, String courseNom, - LocalDateTime dateCourse) { - this.id = id; - this.numeroPari = numeroPari; - this.typePari = typePari; - this.montantMise = montantMise; - this.datePari = datePari; - this.statut = statut; - this.gainsPotentiels = gainsPotentiels; - this.estPaye = estPaye; - this.courseId = courseId; - this.courseNom = courseNom; - this.dateCourse = dateCourse; - } - - // Getters et Setters - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getNumeroPari() { - return numeroPari; - } - - public void setNumeroPari(String numeroPari) { - this.numeroPari = numeroPari; - } - - public TypePari getTypePari() { - return typePari; - } - - public void setTypePari(TypePari typePari) { - this.typePari = typePari; - } - - public double getMontantMise() { - return montantMise; - } - - public void setMontantMise(double montantMise) { - this.montantMise = montantMise; - } - - public LocalDateTime getDatePari() { - return datePari; - } - - public void setDatePari(LocalDateTime datePari) { - this.datePari = datePari; - } - - public String getStatut() { - return statut; - } - - public void setStatut(String statut) { - this.statut = statut; - } - - public Double getGainsPotentiels() { - return gainsPotentiels; - } - - public void setGainsPotentiels(Double gainsPotentiels) { - this.gainsPotentiels = gainsPotentiels; - } - - public boolean isEstPaye() { - return estPaye; - } - - public void setEstPaye(boolean estPaye) { - this.estPaye = estPaye; - } - - public Long getCourseId() { - return courseId; - } - - public void setCourseId(Long courseId) { - this.courseId = courseId; - } - - public String getCourseNom() { - return courseNom; - } - - public void setCourseNom(String courseNom) { - this.courseNom = courseNom; - } - - public LocalDateTime getDateCourse() { - return dateCourse; - } - - public void setDateCourse(LocalDateTime dateCourse) { - this.dateCourse = dateCourse; - } - - public List getChevaux() { - return chevaux; - } - - public void setChevaux(List chevaux) { - this.chevaux = chevaux; - } - - public String getClientNomComplet() { - return clientNomComplet; - } - - public void setClientNomComplet(String clientNomComplet) { - this.clientNomComplet = clientNomComplet; - } - - public String getClientNumero() { - return clientNumero; - } - - public void setClientNumero(String clientNumero) { - this.clientNumero = clientNumero; - } - - // Méthode utilitaire de conversion depuis l'entité - public static PariResponse fromEntity(Pari pari) { - PariResponse response = new PariResponse( - pari.getId(), - "PMU-" + pari.getId(), - pari.getTypePari(), - pari.getMontantMise(), - pari.getDatePari(), - determinerStatut(pari), - pari.getGains(), - pari.isEstPaye(), - pari.getCourse().getId(), - pari.getCourse().getNom(), - pari.getCourse().getDateCourse() - ); - - response.setChevaux(pari.getChevauxJumeles().stream() - .map(ChevalDto::fromEntity) - .collect(Collectors.toList())); - - response.setClientNomComplet(pari.getClient().getPrenom() + " " + pari.getClient().getNom()); - response.setClientNumero(pari.getClient().getNumeroClient()); - - return response; - } - - private static String determinerStatut(Pari pari) { - if (pari.getChevauxJumeles().stream().anyMatch(Cheval::isEstNonPartant)) { - return "REMBOURSE"; - } - if (pari.isEstPaye()) { - return "GAGNANT"; - } - if (pari.getCourse().isTerminee() && !pari.isEstPaye()) { - return "PERDANT"; - } - return "EN_COURS"; - } -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/dto/ResultatCourseDto.java b/src/main/java/com/pmumali/simple/dto/ResultatCourseDto.java deleted file mode 100644 index 9104cd5..0000000 --- a/src/main/java/com/pmumali/simple/dto/ResultatCourseDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.pmumali.simple.dto; - -import lombok.Data; - -import java.util.List; -import java.util.Map; - -@Data -public class ResultatCourseDto { - private Long courseId; - private List combinaisonsPayables; - private Map rapports; - private boolean tirelire; - - // Getters, setters -} diff --git a/src/main/java/com/pmumali/simple/exception/PariException.java b/src/main/java/com/pmumali/simple/exception/PariException.java deleted file mode 100644 index 3d72909..0000000 --- a/src/main/java/com/pmumali/simple/exception/PariException.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.pmumali.simple.exception; - - -/** - * Exception métier pour les erreurs spécifiques aux paris PMU Mali - * conforme aux règles du "Jumelé Placé" - */ -public class PariException extends RuntimeException { - - private final ErrorCode errorCode; - private final String details; - - // Codes d'erreur standardisés - public enum ErrorCode { - // Article 1 - Règles de base - MISE_MINIMALE_NON_ATTEINTE("La mise minimale est de 500 FCFA"), - - // Article 2 - Limitation des enjeux - LIMITE_MISE_DEPASSEE("Limite de mise dépassée (20x500 FCFA maximum)"), - - // Article 3 - Dead Heat - CALCUL_RAPPORT_IMPOSSIBLE("Impossible de calculer les rapports pour ce Dead Heat"), - - // Article 4 - Non-partants - CHEVAL_NON_PARTANT("Pari invalide : cheval non-partant"), - - // Article 5 - Calcul des rapports - RAPPORT_INVALIDE("Rapport calculé invalide (<1.1)"), - - // Article 6 - Formules - FORMULE_INVALIDE("Formule de pari invalide"), - - // Article 8 - Cas particuliers - COURSE_ANNULEE("Course annulée - paris remboursés"), - - // Validations générales - PARI_INVALIDE("Pari invalide"), - SOLDE_INSUFFISANT("Solde insuffisant pour placer ce pari"), - CLIENT_BLOQUE("Compte client bloqué"); - - private final String message; - - ErrorCode(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - } - - // Constructeurs - public PariException(ErrorCode errorCode) { - super(errorCode.getMessage()); - this.errorCode = errorCode; - this.details = null; - } - - public PariException(ErrorCode errorCode, String details) { - super(errorCode.getMessage() + " : " + details); - this.errorCode = errorCode; - this.details = details; - } - - public PariException(ErrorCode errorCode, Throwable cause) { - super(errorCode.getMessage(), cause); - this.errorCode = errorCode; - this.details = null; - } - - // Getters - public ErrorCode getErrorCode() { - return errorCode; - } - - public String getDetails() { - return details; - } - - // Méthode utilitaire pour construire les messages - public static String buildLimiteMiseMessage(double limite) { - return String.format("Limite de mise dépassée (max %,.0f FCFA par course selon Article 2)", limite); - } -} diff --git a/src/main/java/com/pmumali/simple/model/Cheval.java b/src/main/java/com/pmumali/simple/model/Cheval.java deleted file mode 100644 index fbd5822..0000000 --- a/src/main/java/com/pmumali/simple/model/Cheval.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.pmumali.simple.model; - -import jakarta.persistence.*; - -@Entity -public class Cheval { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String nom; - private int numero; - - private boolean estNonPartant; - private Integer positionArrivee; - - @ManyToOne(fetch = FetchType.LAZY) - private Course course; - - - public int getNumero() { - return numero; - } - - public void setNumero(int numero) { - this.numero = numero; - } - - 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 isEstNonPartant() { - return estNonPartant; - } - - public void setEstNonPartant(boolean estNonPartant) { - this.estNonPartant = estNonPartant; - } - - public Integer getPositionArrivee() { - return positionArrivee; - } - - public void setPositionArrivee(Integer positionArrivee) { - this.positionArrivee = positionArrivee; - } - - public Course getCourse() { - return course; - } - - public void setCourse(Course course) { - this.course = course; - } -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/model/Client.java b/src/main/java/com/pmumali/simple/model/Client.java deleted file mode 100644 index 7a4f85f..0000000 --- a/src/main/java/com/pmumali/simple/model/Client.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.pmumali.simple.model; - - - -import jakarta.persistence.*; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; - -@Entity -@Table(name = "clients") -public class Client { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false, length = 50) - private String nom; - - @Column(nullable = false, length = 50) - private String prenom; - - @Column(nullable = false, unique = true, length = 30) - private String numeroClient; - - @Column(nullable = false, unique = true, length = 50) - private String email; - - @Column(nullable = false, length = 20) - private String telephone; - - @Column(name = "date_naissance") - private LocalDate dateNaissance; - - @Column(nullable = false, length = 1) - private String sexe; // M ou F - - @Column(name = "piece_identite", nullable = false, length = 50) - private String pieceIdentite; // Numéro de CNI/Passeport - - @Column(name = "type_piece", length = 20) - private String typePieceIdentite; // CNI, PASSEPORT, PERMIS - - @Column(name = "adresse_postale", length = 100) - private String adressePostale; - - @Column(name = "code_postal", length = 10) - private String codePostal; - - @Column(length = 50) - private String ville; - - @Column(length = 50) - private String pays = "Mali"; - - @Column(name = "date_inscription", nullable = false) - private LocalDate dateInscription = LocalDate.now(); - - @Column(name = "est_verifie", nullable = false) - private boolean estVerifie = false; - - @Column(name = "est_bloque", nullable = false) - private boolean estBloque = false; - - @Column(name = "solde_compte", nullable = false) - private double soldeCompte = 0.0; - - @Column(name = "limite_mise", nullable = false) - private double limiteMise = 10000.0; // 20 x 500 FCFA (Article 2) - - @OneToMany(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true) - private List paris = new ArrayList<>(); - - @OneToMany(mappedBy = "client", cascade = CascadeType.ALL) - private List transactions = new ArrayList<>(); - - // Constructeurs - public Client() { - } - - public Client(String nom, String prenom, String numeroClient, String email, String telephone) { - this.nom = nom; - this.prenom = prenom; - this.numeroClient = numeroClient; - this.email = email; - this.telephone = telephone; - } - - // Getters et Setters - public Long getId() { - return 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 getNumeroClient() { - return numeroClient; - } - - public void setNumeroClient(String numeroClient) { - this.numeroClient = numeroClient; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getTelephone() { - return telephone; - } - - public void setTelephone(String telephone) { - this.telephone = telephone; - } - - public LocalDate getDateNaissance() { - return dateNaissance; - } - - public void setDateNaissance(LocalDate dateNaissance) { - this.dateNaissance = dateNaissance; - } - - public String getSexe() { - return sexe; - } - - public void setSexe(String sexe) { - this.sexe = sexe; - } - - public String getPieceIdentite() { - return pieceIdentite; - } - - public void setPieceIdentite(String pieceIdentite) { - this.pieceIdentite = pieceIdentite; - } - - public String getTypePieceIdentite() { - return typePieceIdentite; - } - - public void setTypePieceIdentite(String typePieceIdentite) { - this.typePieceIdentite = typePieceIdentite; - } - - public String getAdressePostale() { - return adressePostale; - } - - public void setAdressePostale(String adressePostale) { - this.adressePostale = adressePostale; - } - - public String getCodePostal() { - return codePostal; - } - - public void setCodePostal(String codePostal) { - this.codePostal = codePostal; - } - - public String getVille() { - return ville; - } - - public void setVille(String ville) { - this.ville = ville; - } - - public String getPays() { - return pays; - } - - public void setPays(String pays) { - this.pays = pays; - } - - public LocalDate getDateInscription() { - return dateInscription; - } - - public void setDateInscription(LocalDate dateInscription) { - this.dateInscription = dateInscription; - } - - public boolean isEstVerifie() { - return estVerifie; - } - - public void setEstVerifie(boolean estVerifie) { - this.estVerifie = estVerifie; - } - - public boolean isEstBloque() { - return estBloque; - } - - public void setEstBloque(boolean estBloque) { - this.estBloque = estBloque; - } - - public double getSoldeCompte() { - return soldeCompte; - } - - public void setSoldeCompte(double soldeCompte) { - this.soldeCompte = soldeCompte; - } - - public double getLimiteMise() { - return limiteMise; - } - - public void setLimiteMise(double limiteMise) { - this.limiteMise = limiteMise; - } - - public List getParis() { - return paris; - } - - public void setParis(List paris) { - this.paris = paris; - } - - public List getTransactions() { - return transactions; - } - - public void setTransactions(List transactions) { - this.transactions = transactions; - } - - // Méthodes utilitaires - public void ajouterPari(Pari pari) { - paris.add(pari); - pari.setClient(this); - } - - public void retirerPari(Pari pari) { - paris.remove(pari); - pari.setClient(null); - } - - public void crediterCompte(double montant) { - this.soldeCompte += montant; - } - - public void debiterCompte(double montant) { - if (this.soldeCompte < montant) { - throw new IllegalStateException("Solde insuffisant"); - } - this.soldeCompte -= montant; - } - - @Override - public String toString() { - return "Client{" + - "id=" + id + - ", nom='" + nom + '\'' + - ", prenom='" + prenom + '\'' + - ", numeroClient='" + numeroClient + '\'' + - '}'; - } -} diff --git a/src/main/java/com/pmumali/simple/model/Combinaison.java b/src/main/java/com/pmumali/simple/model/Combinaison.java deleted file mode 100644 index bf1c8e6..0000000 --- a/src/main/java/com/pmumali/simple/model/Combinaison.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.pmumali.simple.model; - -public class Combinaison { - private final Cheval cheval1; - private final Cheval cheval2; - private int nombreMises; - - public Combinaison(Cheval cheval1, Cheval cheval2) { - this.cheval1 = cheval1; - this.cheval2 = cheval2; - } - - // Getters - public Cheval getCheval1() { return cheval1; } - public Cheval getCheval2() { return cheval2; } - public int getNombreMises() { return nombreMises; } - - public void setNombreMises(int nombreMises) { - this.nombreMises = nombreMises; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Combinaison)) return false; - Combinaison that = (Combinaison) o; - return (cheval1.equals(that.cheval1) && cheval2.equals(that.cheval2)) || - (cheval1.equals(that.cheval2) && cheval2.equals(that.cheval1)); - } - - @Override - public int hashCode() { - return cheval1.hashCode() + cheval2.hashCode(); // Ordre non important - } -} diff --git a/src/main/java/com/pmumali/simple/model/Course.java b/src/main/java/com/pmumali/simple/model/Course.java deleted file mode 100644 index f957f0c..0000000 --- a/src/main/java/com/pmumali/simple/model/Course.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.pmumali.simple.model; - -import jakarta.persistence.*; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -@Entity - -public class Course { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String nom; - private LocalDateTime dateCourse; - private boolean estAnnulee; - private boolean deadHeat; - - private boolean isTerminee=false; - - public boolean isTerminee() { - return isTerminee; - } - - public void setTerminee(boolean terminee) { - isTerminee = terminee; - } - - @OneToMany(mappedBy = "course", cascade = CascadeType.ALL) - private List chevaux = new ArrayList<>(); - - @OneToMany(mappedBy = "course") - private List paris = new ArrayList<>(); - - 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 LocalDateTime getDateCourse() { - return dateCourse; - } - - public void setDateCourse(LocalDateTime dateCourse) { - this.dateCourse = dateCourse; - } - - public boolean isEstAnnulee() { - return estAnnulee; - } - - public void setEstAnnulee(boolean estAnnulee) { - this.estAnnulee = estAnnulee; - } - - public boolean isDeadHeat() { - return deadHeat; - } - - public void setDeadHeat(boolean deadHeat) { - this.deadHeat = deadHeat; - } - - public List getChevaux() { - return chevaux; - } - - public void setChevaux(List chevaux) { - this.chevaux = chevaux; - } - - public List getParis() { - return paris; - } - - public void setParis(List paris) { - this.paris = paris; - } -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/model/Pari.java b/src/main/java/com/pmumali/simple/model/Pari.java deleted file mode 100644 index 86642f6..0000000 --- a/src/main/java/com/pmumali/simple/model/Pari.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.pmumali.simple.model; - -import com.pmumali.simple.model.enums.TypePari; -import jakarta.persistence.*; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -@Entity -public class Pari { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private double montantMise; - private LocalDateTime datePari; - private boolean estPaye; - private double gains; - - @ManyToOne(fetch = FetchType.LAZY) - private Client client; - - @ManyToOne(fetch = FetchType.LAZY) - private Course course; - - @ManyToMany - @JoinTable( - name = "pari_cheval", - joinColumns = @JoinColumn(name = "pari_id"), - inverseJoinColumns = @JoinColumn(name = "cheval_id")) - private List chevauxJumeles = new ArrayList<>(); - - public TypePari getTypePari() { - return typePari; - } - - public void setTypePari(TypePari typePari) { - this.typePari = typePari; - } - - @Enumerated(EnumType.STRING) - private TypePari typePari; // JUMELEC_GAGNANT ou JUMELEC_PLACE - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public double getMontantMise() { - return montantMise; - } - - public void setMontantMise(double montantMise) { - this.montantMise = montantMise; - } - - public LocalDateTime getDatePari() { - return datePari; - } - - public void setDatePari(LocalDateTime datePari) { - this.datePari = datePari; - } - - public boolean isEstPaye() { - return estPaye; - } - - public void setEstPaye(boolean estPaye) { - this.estPaye = estPaye; - } - - public double getGains() { - return gains; - } - - public void setGains(double gains) { - this.gains = gains; - } - - public Client getClient() { - return client; - } - - public void setClient(Client client) { - this.client = client; - } - - public Course getCourse() { - return course; - } - - public void setCourse(Course course) { - this.course = course; - } - - public List getChevauxJumeles() { - return chevauxJumeles; - } - - public void setChevauxJumeles(List chevauxJumeles) { - this.chevauxJumeles = chevauxJumeles; - } -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/model/ResultatCourse.java b/src/main/java/com/pmumali/simple/model/ResultatCourse.java deleted file mode 100644 index 2854c87..0000000 --- a/src/main/java/com/pmumali/simple/model/ResultatCourse.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.pmumali.simple.model; - - -import jakarta.persistence.*; - -import java.time.LocalDateTime; -import java.util.*; - -@Entity -@Table(name = "resultats_courses") -public class ResultatCourse { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @OneToOne - @JoinColumn(name = "course_id", nullable = false, unique = true) - private Course course; - - @Column(name = "date_publication", nullable = false) - private LocalDateTime datePublication = LocalDateTime.now(); - - @Column(name = "est_officiel", nullable = false) - private boolean estOfficiel = false; - - @Column(name = "masse_a_partager", nullable = false) - private double masseAPartager; - - @Column(name = "tirelire_active", nullable = false) - private boolean tirelireActive = false; - - @Column(name = "montant_tirelire") - private Double montantTirelire; - - @ElementCollection - @CollectionTable(name = "resultats_combinaisons", joinColumns = @JoinColumn(name = "resultat_id")) - @MapKeyColumn(name = "combinaison") - @Column(name = "rapport") - private Map rapports = new HashMap<>(); - - @ElementCollection - @CollectionTable(name = "resultats_non_partants", joinColumns = @JoinColumn(name = "resultat_id")) - @Column(name = "cheval_id") - private Set chevauxNonPartants = new HashSet<>(); - - @Enumerated(EnumType.STRING) - @Column(name = "type_resultat", nullable = false) - private TypeResultat typeResultat; - - @Version - private Long version; - - // Enumération pour les types de résultats - public enum TypeResultat { - NORMAL, - DEAD_HEAT_PREMIERS, - DEAD_HEAT_DEUXIEMES, - DEAD_HEAT_TROISIEMES, - COURSE_ANNULEE - } - - // Constructeurs - public ResultatCourse() {} - - public ResultatCourse(Course course) { - this.course = course; - } - - // Getters et Setters - public Long getId() { - return id; - } - - public Course getCourse() { - return course; - } - - public void setCourse(Course course) { - this.course = course; - } - - public LocalDateTime getDatePublication() { - return datePublication; - } - - public void setDatePublication(LocalDateTime datePublication) { - this.datePublication = datePublication; - } - - public boolean isEstOfficiel() { - return estOfficiel; - } - - public void setEstOfficiel(boolean estOfficiel) { - this.estOfficiel = estOfficiel; - } - - public double getMasseAPartager() { - return masseAPartager; - } - - public void setMasseAPartager(double masseAPartager) { - this.masseAPartager = masseAPartager; - } - - public boolean isTirelireActive() { - return tirelireActive; - } - - public void setTirelireActive(boolean tirelireActive) { - this.tirelireActive = tirelireActive; - } - - public Double getMontantTirelire() { - return montantTirelire; - } - - public void setMontantTirelire(Double montantTirelire) { - this.montantTirelire = montantTirelire; - } - - public Map getRapports() { - return rapports; - } - - public void setRapports(Map rapports) { - this.rapports = rapports; - } - - public Set getChevauxNonPartants() { - return chevauxNonPartants; - } - - public void setChevauxNonPartants(Set chevauxNonPartants) { - this.chevauxNonPartants = chevauxNonPartants; - } - - public TypeResultat getTypeResultat() { - return typeResultat; - } - - public void setTypeResultat(TypeResultat typeResultat) { - this.typeResultat = typeResultat; - } - - public Long getVersion() { - return version; - } - - // Méthodes métiers - public void ajouterRapport(String combinaison, double rapport) { - this.rapports.put(combinaison, rapport); - } - - public void marquerNonPartant(Long chevalId) { - this.chevauxNonPartants.add(chevalId); - } - - public boolean estCombinaisonPayable(String combinaison) { - return this.rapports.containsKey(combinaison); - } - - public void activerTirelire(double montant) { - this.tirelireActive = true; - this.montantTirelire = montant; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ResultatCourse)) return false; - ResultatCourse that = (ResultatCourse) o; - return Objects.equals(id, that.id) && - Objects.equals(course, that.course); - } - - @Override - public int hashCode() { - return Objects.hash(id, course); - } - - @Override - public String toString() { - return "ResultatCourse{" + - "id=" + id + - ", course=" + course.getId() + - ", typeResultat=" + typeResultat + - ", rapports=" + rapports.size() + - '}'; - } -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/model/Transaction.java b/src/main/java/com/pmumali/simple/model/Transaction.java deleted file mode 100644 index a56eacf..0000000 --- a/src/main/java/com/pmumali/simple/model/Transaction.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pmumali.simple.model; - - -import jakarta.persistence.*; - -import java.time.LocalDateTime; - -@Entity -@Table(name = "transactions") -public class Transaction { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private double montant; - - @Column(nullable = false) - private LocalDateTime dateHeure = LocalDateTime.now(); - - @Column(nullable = false, length = 20) - private String type; // DÉPÔT, RETRAIT, GAIN, REMBOURSEMENT - - @Column(length = 100) - private String description; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "client_id") - private Client client; - - // Getters, setters et constructeurs -} \ No newline at end of file diff --git a/src/main/java/com/pmumali/simple/model/enums/TypePari.java b/src/main/java/com/pmumali/simple/model/enums/TypePari.java deleted file mode 100644 index cb2a077..0000000 --- a/src/main/java/com/pmumali/simple/model/enums/TypePari.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.pmumali.simple.model.enums; - -public enum TypePari { - JUMELEC_GAGNANT, - JUMELEC_PLACE -} diff --git a/src/main/java/com/pmumali/simple/repository/ChevalRepository.java b/src/main/java/com/pmumali/simple/repository/ChevalRepository.java deleted file mode 100644 index ba6f510..0000000 --- a/src/main/java/com/pmumali/simple/repository/ChevalRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pmumali.simple.repository; - -import com.pmumali.simple.model.Cheval; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ChevalRepository extends JpaRepository { -} diff --git a/src/main/java/com/pmumali/simple/repository/CourseRepository.java b/src/main/java/com/pmumali/simple/repository/CourseRepository.java deleted file mode 100644 index 1b74d4f..0000000 --- a/src/main/java/com/pmumali/simple/repository/CourseRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pmumali.simple.repository; - -import com.pmumali.simple.model.Course; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface CourseRepository extends JpaRepository { -} diff --git a/src/main/java/com/pmumali/simple/repository/PariRepository.java b/src/main/java/com/pmumali/simple/repository/PariRepository.java deleted file mode 100644 index fe26e48..0000000 --- a/src/main/java/com/pmumali/simple/repository/PariRepository.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.pmumali.simple.repository; - -import com.pmumali.simple.model.Pari; -import com.pmumali.simple.model.Client; -import com.pmumali.simple.model.Course; -import com.pmumali.simple.model.enums.TypePari; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - -public interface PariRepository extends JpaRepository { - -double sumByClientAndCourse(Long clientID, Long courseId); - - // Trouver tous les paris d'un client - List findByClient(Client client); - - // Trouver les paris par course - List findByCourse(Course course); - - // Trouver les paris par type (JUMELEC_PLACE ou JUMELEC_GAGNANT) - List findByTypePari(TypePari typePari); - - // Somme des mises d'un client pour une course (Article 2 - Limitation des enjeux) - @Query("SELECT COALESCE(SUM(p.montantMise), 0) FROM Pari p WHERE p.client = :client AND p.course = :course") - double sumMisesByClientAndCourse(@Param("client") Client client, @Param("course") Course course); - - // Trouver les paris gagnants pour une combinaison donnée - @Query("SELECT p FROM Pari p JOIN p.chevauxJumeles c WHERE p.course = :course " + - "AND c.id IN (:cheval1Id, :cheval2Id) GROUP BY p HAVING COUNT(c) = 2") - List findParisGagnantsForCombinaison( - @Param("course") Course course, - @Param("cheval1Id") Long cheval1Id, - @Param("cheval2Id") Long cheval2Id - ); - - // Nombre de mises pour une combinaison spécifique - @Query("SELECT COUNT(p) FROM Pari p JOIN p.chevauxJumeles c WHERE p.course = :course " + - "AND c.id IN (:cheval1Id, :cheval2Id) GROUP BY p HAVING COUNT(c) = 2") - long countMisesForCombinaison( - @Param("course") Course course, - @Param("cheval1Id") Long cheval1Id, - @Param("cheval2Id") Long cheval2Id - ); - - // Trouver les paris contenant un cheval non-partant (Article 4) - @Query("SELECT DISTINCT p FROM Pari p JOIN p.chevauxJumeles c WHERE p.course = :course AND c.estNonPartant = true") - List findParisAvecNonPartants(@Param("course") Course course); - - // Statistiques pour le dashboard - @Query("SELECT NEW map(p.typePari as type, COUNT(p) as nombre, SUM(p.montantMise) as totalMises) " + - "FROM Pari p WHERE p.datePari BETWEEN :start AND :end GROUP BY p.typePari") - List> getStatistiquesParType( - @Param("start") LocalDateTime startDate, - @Param("end") LocalDateTime endDate - ); - - // Trouver les paris non payés pour une course - List findByCourseAndEstPayeFalse(Course course); - - // Méthode optimisée pour le calcul des rapports - @Query("SELECT NEW map(c1.id as cheval1Id, c2.id as cheval2Id, COUNT(p) as mises) " + - "FROM Pari p JOIN p.chevauxJumeles c1 JOIN p.chevauxJumeles c2 " + - "WHERE p.course = :course AND c1.id < c2.id " + - "GROUP BY c1.id, c2.id") - List> getMisesParCombinaison(@Param("course") Course course); - - - } diff --git a/src/main/java/com/pmumali/simple/service/CalculRapportService.java b/src/main/java/com/pmumali/simple/service/CalculRapportService.java deleted file mode 100644 index 0f25399..0000000 --- a/src/main/java/com/pmumali/simple/service/CalculRapportService.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.pmumali.simple.service; - -import com.pmumali.simple.model.Cheval; -import com.pmumali.simple.model.Combinaison; -import com.pmumali.simple.model.Course; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -public class CalculRapportService { - - public Map calculerRapports( - List combinaisonsPayables, - double masseAPartager) { - - Map rapports = new HashMap<>(); - - if (combinaisonsPayables.size() == 1) { - // Cas arrivée normale - double rapport = masseAPartager / combinaisonsPayables.get(0).getNombreMises(); - rapports.put(combinaisonsPayables.get(0), Math.max(1.1, rapport)); - } else { - // Cas Dead-Heat - double beneficeParCombinaison = masseAPartager / combinaisonsPayables.size(); - - for (Combinaison combinaison : combinaisonsPayables) { - double rapport = beneficeParCombinaison / combinaison.getNombreMises(); - rapports.put(combinaison, Math.max(1.1, rapport)); - } - } - - return rapports; - } - - /** - * Vérifie si une combinaison est gagnante selon les positions d'arrivée - */ - public boolean isCombinaisonGagnante(Combinaison combinaison, List classement) { - if (classement.size() < 2) return false; - - Cheval c1 = combinaison.getCheval1(); - Cheval c2 = combinaison.getCheval2(); - - // Les deux chevaux doivent être dans les 2 premiers (ordre quelconque) - return classement.subList(0, 2).contains(c1) && - classement.subList(0, 2).contains(c2); - } - - /** - * Calcule le nombre de mises pour une combinaison donnée - */ - public long compterMisesCombinaison(Course course, Combinaison combinaison) { - return course.getParis().stream() - .filter(p -> p.getChevauxJumeles().containsAll( - List.of(combinaison.getCheval1(), combinaison.getCheval2()) - )) - .count(); - } - - - public Map calculerRapportsJumelePlace( - List combinaisonsPayables, - double masseAPartager) { - - Map rapports = new HashMap<>(); - - if (combinaisonsPayables.isEmpty()) { - return rapports; - } - - // Article 5a: Arrivée normale - division en 3 parts égales - if (!combinaisonsPayables.get(0).getCourse().isDeadHeat()) { - double part = masseAPartager / 3; - - for (Combinaison combinaison : combinaisonsPayables) { - double rapport = part / compterMisesCombinaison(combinaison); - rapports.put(combinaison, Math.max(RAPPORT_MINIMUM, rapport)); - } - - return rapports; - } - - // Article 5b: Dead-Heat - Course course = combinaisonsPayables.get(0).getCourse(); - Map> parPosition = course.getChevaux().stream() - .filter(c -> !c.isEstNonPartant()) - .collect(Collectors.groupingBy(Cheval::getPositionArrivee)); - - List premiers = parPosition.getOrDefault(1, Collections.emptyList()); - List deuxiemes = parPosition.getOrDefault(2, Collections.emptyList()); - List troisiemes = parPosition.getOrDefault(3, Collections.emptyList()); - - // Article 5b1: Dead-Heat 3+ premiers - if (premiers.size() >= 3) { - double part = masseAPartager / combinaisonsPayables.size(); - for (Combinaison combinaison : combinaisonsPayables) { - double rapport = part / compterMisesCombinaison(combinaison); - rapports.put(combinaison, Math.max(RAPPORT_MINIMUM, rapport)); - } - return rapports; - } - - // Article 5b2: Dead-Heat 2 premiers + 1+ troisième - if (premiers.size() == 2 && !troisiemes.isEmpty()) { - // Répartition en 3 tiers - double tiers = masseAPartager / 3; - - // 1er tiers: combinaison des 2 premiers - Combinaison combinaisonPremiers = new Combinaison(premiers.get(0), premiers.get(1)); - double rapportPremiers = tiers / compterMisesCombinaison(combinaisonPremiers); - rapports.put(combinaisonPremiers, Math.max(RAPPORT_MINIMUM, rapportPremiers)); - - // 2ème tiers: premier1 avec troisièmes - double partParCombinaison = tiers / troisiemes.size(); - for (Cheval troisieme : troisiemes) { - Combinaison combinaison = new Combinaison(premiers.get(0), troisieme); - double rapport = partParCombinaison / compterMisesCombinaison(combinaison); - rapports.put(combinaison, Math.max(RAPPORT_MINIMUM, rapport)); - } - - // 3ème tiers: premier2 avec troisièmes - for (Cheval troisieme : troisiemes) { - Combinaison combinaison = new Combinaison(premiers.get(1), troisieme); - double rapport = partParCombinaison / compterMisesCombinaison(combinaison); - rapports.put(combinaison, Math.max(RAPPORT_MINIMUM, rapport)); - } - - return rapports; - } - - // ... autres cas Dead-Heat (implémenter de manière similaire) - - return rapports; - } -} diff --git a/src/main/java/com/pmumali/simple/service/FormulaireService.java b/src/main/java/com/pmumali/simple/service/FormulaireService.java deleted file mode 100644 index 357fcd0..0000000 --- a/src/main/java/com/pmumali/simple/service/FormulaireService.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.pmumali.simple.service; - -import com.pmumali.simple.model.Cheval; -import com.pmumali.simple.model.Combinaison; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; - -@Service -public class FormulaireService { - - public double calculerCoutFormule(int nombreChevaux, boolean formuleComplete) { - // Article 7: Tableaux des combinaisons - int nbCombinaisons = formuleComplete ? - nombreChevaux * (nombreChevaux - 1) / 2 : - nombreChevaux; - - return nbCombinaisons * 500; // 500 FCFA par combinaison - } - - public List genererCombinaisonsFormule( - List chevauxSelectionnes, - boolean formuleComplete) { - - List combinaisons = new ArrayList<>(); - - if (formuleComplete) { - // Toutes les combinaisons 2 à 2 - for (int i = 0; i < chevauxSelectionnes.size(); i++) { - for (int j = i + 1; j < chevauxSelectionnes.size(); j++) { - combinaisons.add(new Combinaison( - chevauxSelectionnes.get(i), - chevauxSelectionnes.get(j) - )); - } - } - } else { - // Formule simplifiée (champ total/partiel) - Cheval base = chevauxSelectionnes.get(0); - for (int i = 1; i < chevauxSelectionnes.size(); i++) { - combinaisons.add(new Combinaison(base, chevauxSelectionnes.get(i))); - } - } - - return combinaisons; - } -} diff --git a/src/main/java/com/pmumali/simple/service/PariService.java b/src/main/java/com/pmumali/simple/service/PariService.java deleted file mode 100644 index 4386fc0..0000000 --- a/src/main/java/com/pmumali/simple/service/PariService.java +++ /dev/null @@ -1,309 +0,0 @@ -package com.pmumali.simple.service; - -import com.pmumali.simple.dto.CombinaisonDto; -import com.pmumali.model.*; -import com.pmumali.simple.repository.ChevalRepository; -import com.pmumali.simple.repository.CourseRepository; -import com.pmumali.simple.repository.PariRepository; -import com.pmumali.simple.model.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.*; -import java.util.stream.Collectors; - -@Service -public class PariService { - - @Autowired - private PariRepository pariRepository; - - @Autowired - private CourseRepository courseRepository; - - @Autowired - private ChevalRepository chevalRepository; - - - public Pari placerPariJumele(Long clientId, Long courseId, - List chevauxIds, double montant) { - // Vérification mise minimum - if (montant < 500) { - throw new IllegalArgumentException("La mise minimale est de 500 FCFA"); - } - - // Vérification limite de paris (20x mise min = 10 000 FCFA) - double totalParisClient = pariRepository - .sumByClientAndCourse(clientId, courseId); - - if (totalParisClient + montant > 10000) { - throw new IllegalArgumentException("Limite de mise dépassée"); - } - - // Création du pari - Pari pari = new Pari(); - // ... initialisation - - return pariRepository.save(pari); - } - - public ResultatCourse calculerResultats(Long courseId) throws Exception { - Course course = courseRepository.findById(courseId) - .orElseThrow(() -> new Exception("Course non trouvée")); - - // Implémentation des règles de calcul - return calculerResultatsSelonReglement(course); - } - - private ResultatCourse calculerResultatsSelonReglement(Course course) { - ResultatCourse resultat = new ResultatCourse(); - - // 1. Vérifier les non-partants (Article 4) - List nonPartants = course.getChevaux().stream() - .filter(Cheval::isEstNonPartant) - .collect(Collectors.toList()); - - // 2. Calcul selon Dead-Heat (Article 3) - if (course.isDeadHeat()) { - calculerDeadHeat(resultat, course); - } else { - calculerArriveeNormale(resultat, course); - } - - // 3. Appliquer tirelire si nécessaire (Article 9) - if (resultat.getCombinaisonsPayables().isEmpty()) { - resultat.setTirelire(true); - } - - return resultat; - } - - - /** - * Détermine les combinaisons payables selon les règles du PMU Mali - */ - private List determinerCombinaisonsPayables(Course course) { - List chevauxArrives = course.getChevaux().stream() - .filter(c -> !c.isEstNonPartant()) - .sorted(Comparator.comparingInt(Cheval::getPositionArrivee)) - .collect(Collectors.toList()); - - // Article 4: Remboursement si non-partant - if (course.getChevaux().stream().anyMatch(Cheval::isEstNonPartant)) { - return Collections.emptyList(); - } - - // Article 3: Gestion Dead-Heat - if (course.isDeadHeat()) { - return calculerCombinaisonsDeadHeat(chevauxArrives); - } - - // Article 5: Arrivée normale - return calculerCombinaisonsNormales(chevauxArrives); - } - - /** - * Implémentation de l'article 3 - Cas Dead-Heat - */ - private List calculerCombinaisonsDeadHeat(List chevauxArrives) { - List combinaisons = new ArrayList<>(); - - // Groupes par position d'arrivée - Map> parPosition = chevauxArrives.stream() - .collect(Collectors.groupingBy(Cheval::getPositionArrivee)); - - List premiers = parPosition.getOrDefault(1, Collections.emptyList()); - List deuxiemes = parPosition.getOrDefault(2, Collections.emptyList()); - - // Cas Dead-Heat premier place (Article 3a) - if (premiers.size() >= 2) { - for (int i = 0; i < premiers.size(); i++) { - for (int j = i + 1; j < premiers.size(); j++) { - combinaisons.add(new Combinaison(premiers.get(i), premiers.get(j))); - } - } - } - // Cas Dead-Heat deuxième place (Article 3b) - else if (deuxiemes.size() >= 2) { - Cheval premier = premiers.get(0); - for (Cheval deuxieme : deuxiemes) { - combinaisons.add(new Combinaison(premier, deuxieme)); - } - } - - return combinaisons; - } - - /** - * Implémentation de l'article 5 - Arrivée normale - */ - private List calculerCombinaisonsNormales(List chevauxArrives) { - if (chevauxArrives.size() < 2) { - return Collections.emptyList(); - } - - Cheval premier = chevauxArrives.get(0); - Cheval deuxieme = chevauxArrives.get(1); - - return List.of(new Combinaison(premier, deuxieme)); - } - - /** - * Calcule la masse à partager selon l'article 5 - */ - private double calculerMasseAPartager(Course course, List combinaisonsPayables) { - double totalEnjeux = course.getParis().stream() - .mapToDouble(Pari::getMontantMise) - .sum(); - - double montantRembourse = course.getParis().stream() - .filter(p -> p.getChevauxJumeles().stream().anyMatch(Cheval::isEstNonPartant)) - .mapToDouble(Pari::getMontantMise) - .sum(); - - // Article 5: MAP = RNET - MREMB - PRELEV - double prelevementsLegaux = totalEnjeux * 0.15; // Exemple: 15% de prélèvement - return totalEnjeux - montantRembourse - prelevementsLegaux; - } - - /** - * Convertit les combinaisons en DTO pour la réponse API - */ - private List convertToDto(List combinaisons) { - return combinaisons.stream() - .map(c -> new CombinaisonDto( - c.getCheval1().getNom(), - c.getCheval2().getNom(), - c.getNombreMises() - )) - .collect(Collectors.toList()); - } - - /** - * Convertit les rapports en format lisible - */ - private Map convertRapports(Map rapports) { - return rapports.entrySet().stream() - .collect(Collectors.toMap( - e -> e.getKey().getCheval1().getNom() + "-" + e.getKey().getCheval2().getNom(), - Map.Entry::getValue - )); - } - - private List determinerCombinaisonsPayablesJumelePlace(Course course) { - List chevauxArrives = course.getChevaux().stream() - .filter(c -> !c.isEstNonPartant()) - .sorted(Comparator.comparingInt(Cheval::getPositionArrivee)) - .collect(Collectors.toList()); - - // Article 4: Remboursement si non-partant - if (course.getChevaux().stream().anyMatch(Cheval::isEstNonPartant)) { - return Collections.emptyList(); - } - - // Article 8: Moins de 3 chevaux arrivés - if (chevauxArrives.size() < 3) { - return Collections.emptyList(); - } - - // Article 3: Gestion Dead-Heat - if (course.isDeadHeat()) { - return calculerCombinaisonsDeadHeatJumelePlace(chevauxArrives); - } - - // Cas normal - Article 1 - return calculerCombinaisonsNormalesJumelePlace(chevauxArrives); - } - - private List calculerCombinaisonsNormalesJumelePlace(List chevauxArrives) { - List combinaisons = new ArrayList<>(); - Cheval premier = chevauxArrives.get(0); - Cheval deuxieme = chevauxArrives.get(1); - Cheval troisieme = chevauxArrives.get(2); - - // Toutes les combinaisons 2 parmi 3 - combinaisons.add(new Combinaison(premier, deuxieme)); - combinaisons.add(new Combinaison(premier, troisieme)); - combinaisons.add(new Combinaison(deuxieme, troisieme)); - - return combinaisons; - } - - private List calculerCombinaisonsDeadHeatJumelePlace(List chevauxArrives) { - List combinaisons = new ArrayList<>(); - Map> parPosition = chevauxArrives.stream() - .collect(Collectors.groupingBy(Cheval::getPositionArrivee)); - - List premiers = parPosition.getOrDefault(1, Collections.emptyList()); - List deuxiemes = parPosition.getOrDefault(2, Collections.emptyList()); - List troisiemes = parPosition.getOrDefault(3, Collections.emptyList()); - - // Article 3a: Dead-Heat à la première place (3+ chevaux) - if (premiers.size() >= 3) { - for (int i = 0; i < premiers.size(); i++) { - for (int j = i + 1; j < premiers.size(); j++) { - combinaisons.add(new Combinaison(premiers.get(i), premiers.get(j))); - } - } - return combinaisons; - } - - // Article 3b: Dead-Heat 2 premiers + 1+ troisième - if (premiers.size() == 2 && !troisiemes.isEmpty()) { - // Combinaison des deux premiers - combinaisons.add(new Combinaison(premiers.get(0), premiers.get(1))); - - // Combinaisons premier1 avec troisièmes - for (Cheval troisieme : troisiemes) { - combinaisons.add(new Combinaison(premiers.get(0), troisieme)); - } - - // Combinaisons premier2 avec troisièmes - for (Cheval troisieme : troisiemes) { - combinaisons.add(new Combinaison(premiers.get(1), troisieme)); - } - return combinaisons; - } - - // Article 3c: Dead-Heat à la deuxième place - if (!deuxiemes.isEmpty() && deuxiemes.size() >= 2) { - Cheval premier = premiers.get(0); - - // Combinaisons premier avec deuxièmes - for (Cheval deuxieme : deuxiemes) { - combinaisons.add(new Combinaison(premier, deuxieme)); - } - - // Combinaisons deuxièmes entre eux - for (int i = 0; i < deuxiemes.size(); i++) { - for (int j = i + 1; j < deuxiemes.size(); j++) { - combinaisons.add(new Combinaison(deuxiemes.get(i), deuxiemes.get(j))); - } - } - return combinaisons; - } - - // Article 3d: Dead-Heat à la troisième place - if (!troisiemes.isEmpty() && troisiemes.size() >= 2) { - Cheval premier = premiers.get(0); - Cheval deuxieme = deuxiemes.get(0); - - // Combinaison premier-deuxième - combinaisons.add(new Combinaison(premier, deuxieme)); - - // Combinaisons premier avec troisièmes - for (Cheval troisieme : troisiemes) { - combinaisons.add(new Combinaison(premier, troisieme)); - } - - // Combinaisons deuxième avec troisièmes - for (Cheval troisieme : troisiemes) { - combinaisons.add(new Combinaison(deuxieme, troisieme)); - } - return combinaisons; - } - - return Collections.emptyList(); - } - -} diff --git a/src/main/java/com/pmumali/simple/service/PariServiceTest.java b/src/main/java/com/pmumali/simple/service/PariServiceTest.java deleted file mode 100644 index e09c5c0..0000000 --- a/src/main/java/com/pmumali/simple/service/PariServiceTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.pmumali.simple.service; - -import com.pmumali.simple.model.Cheval; -import com.pmumali.simple.model.Combinaison; -import com.pmumali.simple.model.Course; - -import java.util.List; - -public class PariServiceTest { - - @Test - public void testCombinaisonsPayables_Normal() { - Course course = new Course(); - course.setDeadHeat(false); - - Cheval c1 = new Cheval(); c1.setPositionArrivee(1); - Cheval c2 = new Cheval(); c2.setPositionArrivee(2); - Cheval c3 = new Cheval(); c3.setPositionArrivee(3); - course.setChevaux(List.of(c1, c2, c3)); - - List result = pariService.determinerCombinaisonsPayablesJumelePlace(course); - - assertEquals(3, result.size()); - assertTrue(result.contains(new Combinaison(c1, c2))); - assertTrue(result.contains(new Combinaison(c1, c3))); - assertTrue(result.contains(new Combinaison(c2, c3))); - } - - @Test - public void testDeadHeat_TroisPremiers() { - Course course = new Course(); - course.setDeadHeat(true); - - Cheval c1 = new Cheval(); c1.setPositionArrivee(1); - Cheval c2 = new Cheval(); c2.setPositionArrivee(1); - Cheval c3 = new Cheval(); c3.setPositionArrivee(1); - course.setChevaux(List.of(c1, c2, c3)); - - List result = pariService.determinerCombinaisonsPayablesJumelePlace(course); - - assertEquals(3, result.size()); // C(3,2) = 3 combinaisons - } -} diff --git a/src/main/java/com/pmumali/simple/service/ValidationPariService.java b/src/main/java/com/pmumali/simple/service/ValidationPariService.java deleted file mode 100644 index b3212ee..0000000 --- a/src/main/java/com/pmumali/simple/service/ValidationPariService.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.pmumali.simple.service; - -import com.pmumali.simple.dto.PariRequest; -import com.pmumali.simple.exception.PariException; -import com.pmumali.simple.model.Cheval; -import com.pmumali.simple.model.Client; -import com.pmumali.simple.model.Course; -import com.pmumali.simple.model.Pari; -import com.pmumali.simple.model.enums.TypePari; -import com.pmumali.simple.repository.PariRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class ValidationPariService { - @Autowired - private PariRepository pariRepository; - - public void validerPari(Pari pari) { - // Article 2: Limitation des enjeux - validerLimiteEnjeux(pari); - - // Article 4: Chevaux non-partants - validerChevauxPartants(pari.getCourse(), pari.getChevauxJumeles()); - - // Article 6: Formules combinées - validerFormule(pari); - } - - private void validerLimiteEnjeux(Pari pari) { - double totalMises = pariRepository - .sumByClientAndCourse(pari.getClient().getId(), pari.getCourse().getId()); - - if (totalMises + pari.getMontantMise() > 10000) { - throw new PariException(PariException.ErrorCode.LIMITE_MISE_DEPASSEE, "Limite de mise dépassée (20x500 FCFA maximum)"); - } - } - - /** - * Valide la requête de pari selon les règles métier - */ - public void validerPariRequest(PariRequest request) { - if (request.getMontantMise() < 500) { - throw new PariException(PariException.ErrorCode.MISE_MINIMALE_NON_ATTEINTE,"La mise minimale est de 500 FCFA (Article 1)"); - } - - if (request.getChevauxIds() == null || request.getChevauxIds().size() != 2) { - throw new PariException(PariException.ErrorCode.PARI_INVALIDE,"Un pari Jumelé Gagnant doit porter sur exactement 2 chevaux"); - } - } - - /** - * Valide le pari selon toutes les règles du règlement - */ - public void validerPari(Client client, Course course, List chevaux, double montantMise) { - // Article 2: Limitation des enjeux - validerLimiteEnjeux(client, course, montantMise); - - // Article 4: Chevaux non-partants - validerChevauxPartants(course, chevaux); - - // Article 10: Course non annulée - if (course.isEstAnnulee()) { - throw new PariException(PariException.ErrorCode.COURSE_ANNULEE,"Course annulée - tous les paris seront remboursés (Article 8)"); - } - - // Vérifie que les chevaux appartiennent bien à la course - if (chevaux.stream().anyMatch(c -> !c.getCourse().equals(course))) { - throw new PariException(PariException.ErrorCode.CHEVAL_NON_PARTANT,"Un ou plusieurs chevaux ne font pas partie de cette course"); - } - } - - /** - * Implémentation de l'article 2 - Limitation des enjeux - */ - private void validerLimiteEnjeux(Client client, Course course, double nouvelleMise) { - double totalMises = pariRepository.sumByClientAndCourse(client.getId(), course.getId()); - double limite = 20 * 500; // 20 fois la mise de base (500 FCFA) - - if (totalMises + nouvelleMise > limite) { - throw new PariException( PariException.ErrorCode.LIMITE_MISE_DEPASSEE, - String.format("Limite de mise dépassée (max %,.0f FCFA par course selon Article 2)", limite) - ); - } - } - - /** - * Implémentation de l'article 4 - Chevaux non-partants - */ - private void validerChevauxPartants(Course course, List chevaux) { - if (chevaux.stream().anyMatch(Cheval::isEstNonPartant)) { - throw new PariException(PariException.ErrorCode.CHEVAL_NON_PARTANT, - "Pari non valide : un ou plusieurs chevaux sont non-partants (Article 4)" - ); - } - } - - public void validerPariJumelePlace(Pari pari) { - // Article 1: Vérification que c'est bien un Jumelé Placé - if (pari.getTypePari() != TypePari.JUMELEC_PLACE) { - throw new PariException(PariException.ErrorCode.FORMULE_INVALIDE ,"Ce n'est pas un pari Jumelé Placé"); - } - - // Article 2: Limitation des enjeux (identique) - validerLimiteEnjeux(pari.getClient(), pari.getCourse(), pari.getMontantMise()); - - // Article 4: Chevaux non-partants - if (pari.getChevauxJumeles().stream().anyMatch(Cheval::isEstNonPartant)) { - throw new PariException(PariException.ErrorCode.CHEVAL_NON_PARTANT,"Pari non valide: cheval non-partant (Article 4)"); - } - } - - -}