From e8d993aeb0ed4c4da11b8f755de41ec460578eeb Mon Sep 17 00:00:00 2001 From: sidibe Date: Thu, 28 Aug 2025 12:06:42 +0000 Subject: [PATCH] =?UTF-8?q?Fin=20int=C3=A9gration=20jumele=20place?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ChevalController.java | 32 ++ .../controller/CourseController.java | 47 ++ .../controller/GainsController.java | 27 ++ .../controller/PariJumelePlaceController.java | 47 ++ .../ch3_jumeleplace/dto/ChevalDto.java | 12 + .../ch3_jumeleplace/dto/CourseDto.java | 17 + .../pmumali/ch3_jumeleplace/dto/GainsDto.java | 16 + .../dto/PariJumelePlaceDto.java | 18 + .../dto/ResultatCourseDto.java | 15 + .../pmumali/ch3_jumeleplace/model/Cheval.java | 23 + .../pmumali/ch3_jumeleplace/model/Course.java | 33 ++ .../pmumali/ch3_jumeleplace/model/Gains.java | 30 ++ .../model/PariJumelePlace.java | 36 ++ .../ch3_jumeleplace/model/ResultatCourse.java | 32 ++ .../repository/ChevalRepository.java | 14 + .../repository/CourseRepository.java | 12 + .../repository/GainsRepository.java | 10 + .../repository/PariJumelePlaceRepository.java | 14 + .../repository/ResultatCourseRepository.java | 10 + .../service/ChevalService.java | 27 ++ .../service/CourseService.java | 40 ++ .../ch3_jumeleplace/service/GainsService.java | 415 ++++++++++++++++++ .../service/PariJumelePlaceService.java | 62 +++ 23 files changed, 989 insertions(+) create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/controller/ChevalController.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/controller/CourseController.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/controller/GainsController.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/controller/PariJumelePlaceController.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/dto/ChevalDto.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/dto/CourseDto.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/dto/GainsDto.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/dto/PariJumelePlaceDto.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/dto/ResultatCourseDto.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/model/Cheval.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/model/Course.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/model/Gains.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/model/PariJumelePlace.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/model/ResultatCourse.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/repository/ChevalRepository.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/repository/CourseRepository.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/repository/GainsRepository.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/repository/PariJumelePlaceRepository.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/repository/ResultatCourseRepository.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/service/ChevalService.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/service/CourseService.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/service/GainsService.java create mode 100644 src/main/java/com/pmumali/ch3_jumeleplace/service/PariJumelePlaceService.java diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/controller/ChevalController.java b/src/main/java/com/pmumali/ch3_jumeleplace/controller/ChevalController.java new file mode 100644 index 0000000..58c3acd --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/controller/ChevalController.java @@ -0,0 +1,32 @@ +package com.pmumali.ch3_jumeleplace.controller; + +import com.pmumali.ch3_jumeleplace.model.Cheval; +import com.pmumali.ch3_jumeleplace.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()); + } +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/controller/CourseController.java b/src/main/java/com/pmumali/ch3_jumeleplace/controller/CourseController.java new file mode 100644 index 0000000..d1125e3 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/controller/CourseController.java @@ -0,0 +1,47 @@ +package com.pmumali.ch3_jumeleplace.controller; + +import com.pmumali.ch3_jumeleplace.model.Course; +import com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/controller/GainsController.java b/src/main/java/com/pmumali/ch3_jumeleplace/controller/GainsController.java new file mode 100644 index 0000000..2abda45 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/controller/GainsController.java @@ -0,0 +1,27 @@ +package com.pmumali.ch3_jumeleplace.controller; + +import com.pmumali.ch3_jumeleplace.model.Gains; +import com.pmumali.ch3_jumeleplace.model.ResultatCourse; +import com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/controller/PariJumelePlaceController.java b/src/main/java/com/pmumali/ch3_jumeleplace/controller/PariJumelePlaceController.java new file mode 100644 index 0000000..4234c84 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/controller/PariJumelePlaceController.java @@ -0,0 +1,47 @@ +package com.pmumali.ch3_jumeleplace.controller; + +import com.pmumali.ch3_jumeleplace.model.PariJumelePlace; +import com.pmumali.ch3_jumeleplace.service.PariJumelePlaceService; +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-place") +public class PariJumelePlaceController { + + @Autowired + private PariJumelePlaceService pariService; + + @PostMapping + public ResponseEntity placerPari(@RequestBody PariJumelePlace 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)); + } +} + diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/dto/ChevalDto.java b/src/main/java/com/pmumali/ch3_jumeleplace/dto/ChevalDto.java new file mode 100644 index 0000000..1626d0c --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/dto/ChevalDto.java @@ -0,0 +1,12 @@ +package com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/dto/CourseDto.java b/src/main/java/com/pmumali/ch3_jumeleplace/dto/CourseDto.java new file mode 100644 index 0000000..5e49d3f --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/dto/CourseDto.java @@ -0,0 +1,17 @@ +package com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/dto/GainsDto.java b/src/main/java/com/pmumali/ch3_jumeleplace/dto/GainsDto.java new file mode 100644 index 0000000..c02e2c8 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/dto/GainsDto.java @@ -0,0 +1,16 @@ +package com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/dto/PariJumelePlaceDto.java b/src/main/java/com/pmumali/ch3_jumeleplace/dto/PariJumelePlaceDto.java new file mode 100644 index 0000000..460fb1f --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/dto/PariJumelePlaceDto.java @@ -0,0 +1,18 @@ +package com.pmumali.ch3_jumeleplace.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class PariJumelePlaceDto { + 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/ch3_jumeleplace/dto/ResultatCourseDto.java b/src/main/java/com/pmumali/ch3_jumeleplace/dto/ResultatCourseDto.java new file mode 100644 index 0000000..9317ad0 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/dto/ResultatCourseDto.java @@ -0,0 +1,15 @@ +package com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/model/Cheval.java b/src/main/java/com/pmumali/ch3_jumeleplace/model/Cheval.java new file mode 100644 index 0000000..7f5eba8 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/model/Cheval.java @@ -0,0 +1,23 @@ +package com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/model/Course.java b/src/main/java/com/pmumali/ch3_jumeleplace/model/Course.java new file mode 100644 index 0000000..35fb2f3 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/model/Course.java @@ -0,0 +1,33 @@ +package com.pmumali.ch3_jumeleplace.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; + 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/ch3_jumeleplace/model/Gains.java b/src/main/java/com/pmumali/ch3_jumeleplace/model/Gains.java new file mode 100644 index 0000000..1e951e8 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/model/Gains.java @@ -0,0 +1,30 @@ +package com.pmumali.ch3_jumeleplace.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; + + private LocalDateTime dateCalcul; +} diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/model/PariJumelePlace.java b/src/main/java/com/pmumali/ch3_jumeleplace/model/PariJumelePlace.java new file mode 100644 index 0000000..4ddba46 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/model/PariJumelePlace.java @@ -0,0 +1,36 @@ +package com.pmumali.ch3_jumeleplace.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "pari_jumele_place") +public class PariJumelePlace { + @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/ch3_jumeleplace/model/ResultatCourse.java b/src/main/java/com/pmumali/ch3_jumeleplace/model/ResultatCourse.java new file mode 100644 index 0000000..6240782 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/model/ResultatCourse.java @@ -0,0 +1,32 @@ +package com.pmumali.ch3_jumeleplace.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; + + @ElementCollection + private List chevauxDeuxiemes; + + @ElementCollection + private List chevauxTroisiemes; + + private boolean aDeadHeat; +} diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/repository/ChevalRepository.java b/src/main/java/com/pmumali/ch3_jumeleplace/repository/ChevalRepository.java new file mode 100644 index 0000000..069eccf --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/repository/ChevalRepository.java @@ -0,0 +1,14 @@ +package com.pmumali.ch3_jumeleplace.repository; + + +import com.pmumali.ch3_jumeleplace.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); +} diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/repository/CourseRepository.java b/src/main/java/com/pmumali/ch3_jumeleplace/repository/CourseRepository.java new file mode 100644 index 0000000..f5e663f --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/repository/CourseRepository.java @@ -0,0 +1,12 @@ +package com.pmumali.ch3_jumeleplace.repository; + +import com.pmumali.ch3_jumeleplace.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); +} \ No newline at end of file diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/repository/GainsRepository.java b/src/main/java/com/pmumali/ch3_jumeleplace/repository/GainsRepository.java new file mode 100644 index 0000000..e357c6f --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/repository/GainsRepository.java @@ -0,0 +1,10 @@ +package com.pmumali.ch3_jumeleplace.repository; + +import com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/repository/PariJumelePlaceRepository.java b/src/main/java/com/pmumali/ch3_jumeleplace/repository/PariJumelePlaceRepository.java new file mode 100644 index 0000000..de500b0 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/repository/PariJumelePlaceRepository.java @@ -0,0 +1,14 @@ +package com.pmumali.ch3_jumeleplace.repository; + +import com.pmumali.ch3_jumeleplace.model.PariJumelePlace; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PariJumelePlaceRepository extends JpaRepository { + List findByCourseId(Long courseId); + List findByCheval1IdOrCheval2Id(Long cheval1Id, Long cheval2Id); + List findByEstRembourse(boolean estRembourse); +} diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/repository/ResultatCourseRepository.java b/src/main/java/com/pmumali/ch3_jumeleplace/repository/ResultatCourseRepository.java new file mode 100644 index 0000000..6546834 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/repository/ResultatCourseRepository.java @@ -0,0 +1,10 @@ +package com.pmumali.ch3_jumeleplace.repository; + +import com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/service/ChevalService.java b/src/main/java/com/pmumali/ch3_jumeleplace/service/ChevalService.java new file mode 100644 index 0000000..a7223bf --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/service/ChevalService.java @@ -0,0 +1,27 @@ +package com.pmumali.ch3_jumeleplace.service; + +import com.pmumali.ch3_jumeleplace.model.Cheval; +import com.pmumali.ch3_jumeleplace.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/ch3_jumeleplace/service/CourseService.java b/src/main/java/com/pmumali/ch3_jumeleplace/service/CourseService.java new file mode 100644 index 0000000..ab34f19 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/service/CourseService.java @@ -0,0 +1,40 @@ +package com.pmumali.ch3_jumeleplace.service; + +import com.pmumali.ch3_jumeleplace.model.Course; +import com.pmumali.ch3_jumeleplace.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); + } +} diff --git a/src/main/java/com/pmumali/ch3_jumeleplace/service/GainsService.java b/src/main/java/com/pmumali/ch3_jumeleplace/service/GainsService.java new file mode 100644 index 0000000..2bb3a10 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/service/GainsService.java @@ -0,0 +1,415 @@ +package com.pmumali.ch3_jumeleplace.service; + +import com.pmumali.ch3_jumeleplace.model.Course; +import com.pmumali.ch3_jumeleplace.model.Gains; +import com.pmumali.ch3_jumeleplace.model.PariJumelePlace; +import com.pmumali.ch3_jumeleplace.model.ResultatCourse; +import com.pmumali.ch3_jumeleplace.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.List; +import java.util.Objects; + +@Service +@Transactional +public class GainsService { + + @Autowired + private PariJumelePlaceRepository 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(PariJumelePlace::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 (PariJumelePlace 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 deux des trois premières places + // Article 3: Gestion des dead-heats + + if (resultat.isADeadHeat()) { + // Cas de dead-heat + if (resultat.getChevauxPremiers().size() >= 3) { + // Article 3a: Dead-heat de trois chevaux ou plus à la première place + // Toutes les combinaisons deux à deux des chevaux classés premiers + 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.getChevauxPremiers().size() == 2 && + !resultat.getChevauxTroisiemes().isEmpty()) { + // Article 3b: Dead-heat de deux chevaux à la première place et un ou plusieurs à la troisième + // Combinaison des deux premiers + combinaisons de chaque premier avec chaque troisième + combinaisons.add(new CombinaisonPayable( + resultat.getChevauxPremiers().get(0), + resultat.getChevauxPremiers().get(1) + )); + + for (Long chevalPremier : resultat.getChevauxPremiers()) { + for (Long chevalTroisieme : resultat.getChevauxTroisiemes()) { + combinaisons.add(new CombinaisonPayable(chevalPremier, chevalTroisieme)); + } + } + } else if (resultat.getChevauxTroisiemes().size() >= 2) { + // Article 3c: Dead-heat de deux chevaux ou plus à la troisième place + // Combinaison premier + deuxième + combinaisons premier avec chaque troisième + deuxième avec chaque troisième + if (!resultat.getChevauxPremiers().isEmpty() && !resultat.getChevauxDeuxiemes().isEmpty()) { + combinaisons.add(new CombinaisonPayable( + resultat.getChevauxPremiers().get(0), + resultat.getChevauxDeuxiemes().get(0) + )); + + for (Long chevalTroisieme : resultat.getChevauxTroisiemes()) { + combinaisons.add(new CombinaisonPayable( + resultat.getChevauxPremiers().get(0), + chevalTroisieme + )); + + combinaisons.add(new CombinaisonPayable( + resultat.getChevauxDeuxiemes().get(0), + chevalTroisieme + )); + } + } + } + } else { + // Cas normal - Article 1: Les deux chevaux doivent occuper deux des trois premières places + List chevauxPayables = new ArrayList<>(); + chevauxPayables.addAll(resultat.getChevauxPremiers()); + chevauxPayables.addAll(resultat.getChevauxDeuxiemes()); + chevauxPayables.addAll(resultat.getChevauxTroisiemes()); + + // Générer toutes les combinaisons deux à deux + for (int i = 0; i < chevauxPayables.size(); i++) { + for (int j = i + 1; j < chevauxPayables.size(); j++) { + combinaisons.add(new CombinaisonPayable( + chevauxPayables.get(i), + chevauxPayables.get(j) + )); + } + } + } + + 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; + } + + // Article 5a: Le bénéfice à répartir est divisé en trois parties égales + double beneficeARepartir = gains.getMasseAPartager(); + double part = beneficeARepartir / 3; + + List rapports = new ArrayList<>(); + + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double totalMises = calculerMisesSurCombinaison(combinaison, tousParis); + + if (totalMises > 0) { + double rapport = (part / totalMises) + 1; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + rapports.add(0.0); + } + } + + gains.setRapports(rapports); + } + + 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; + } + + double beneficeARepartir = gains.getMasseAPartager(); + List rapports = new ArrayList<>(); + + // Déterminer le type de dead-heat pour appliquer les règles spécifiques + ResultatCourse resultat = gains.getCourse().getResultat(); + + if (resultat.getChevauxPremiers().size() >= 3) { + // Article 5b1: Dead-heat de trois chevaux ou plus à la première place + double partParCombinaison = beneficeARepartir / combinaisonsPayables.size(); + + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double totalMises = calculerMisesSurCombinaison(combinaison, tousParis); + + if (totalMises > 0) { + double rapport = (partParCombinaison / totalMises) + 1; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + rapports.add(0.0); + } + } + } else if (resultat.getChevauxPremiers().size() == 2 && + !resultat.getChevauxTroisiemes().isEmpty()) { + // Article 5b2: Dead-heat de deux chevaux à la première place et un ou plusieurs à la troisième + double part = beneficeARepartir / 3; + + // Trouver la combinaison des deux premiers + CombinaisonPayable combinaisonPremiers = null; + for (CombinaisonPayable combinaison : combinaisonsPayables) { + if (resultat.getChevauxPremiers().contains(combinaison.getCheval1Id()) && + resultat.getChevauxPremiers().contains(combinaison.getCheval2Id())) { + combinaisonPremiers = combinaison; + break; + } + } + + // Calculer les rapports + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double totalMises = calculerMisesSurCombinaison(combinaison, tousParis); + + if (totalMises > 0) { + double rapportPart = part; + if (combinaison.equals(combinaisonPremiers)) { + // Combinaison des deux premiers - 1/3 du bénéfice + rapportPart = part; + } else { + // Combinaisons premier-troisième - 1/3 du bénéfice divisé par le nombre de ces combinaisons + int nbCombinaisonsPremierTroisieme = combinaisonsPayables.size() - 1; + rapportPart = part / nbCombinaisonsPremierTroisieme; + } + + double rapport = (rapportPart / totalMises) + 1; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + rapports.add(0.0); + } + } + } else if (resultat.getChevauxDeuxiemes().size() >= 2) { + // Article 5b3: Dead-heat de deux chevaux ou plus à la deuxième place + double deuxTiers = beneficeARepartir * 2 / 3; + double unTiers = beneficeARepartir / 3; + + // Compter les types de combinaisons + int nbCombinaisonsPremierDeuxieme = 0; + int nbCombinaisonsDeuxiemeDeuxieme = 0; + + for (CombinaisonPayable combinaison : combinaisonsPayables) { + if (resultat.getChevauxPremiers().contains(combinaison.getCheval1Id()) || + resultat.getChevauxPremiers().contains(combinaison.getCheval2Id())) { + nbCombinaisonsPremierDeuxieme++; + } else { + nbCombinaisonsDeuxiemeDeuxieme++; + } + } + + // Calculer les rapports + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double totalMises = calculerMisesSurCombinaison(combinaison, tousParis); + + if (totalMises > 0) { + double rapportPart; + if (resultat.getChevauxPremiers().contains(combinaison.getCheval1Id()) || + resultat.getChevauxPremiers().contains(combinaison.getCheval2Id())) { + // Combinaisons premier-deuxième - 2/3 du bénéfice divisé par le nombre de ces combinaisons + rapportPart = deuxTiers / nbCombinaisonsPremierDeuxieme; + } else { + // Combinaisons deuxième-deuxième - 1/3 du bénéfice divisé par le nombre de ces combinaisons + rapportPart = unTiers / nbCombinaisonsDeuxiemeDeuxieme; + } + + double rapport = (rapportPart / totalMises) + 1; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + rapports.add(0.0); + } + } + } else if (resultat.getChevauxTroisiemes().size() >= 2) { + // Article 5b4: Dead-heat de deux chevaux ou plus à la troisième place + double part = beneficeARepartir / 3; + + // Compter les types de combinaisons + int nbCombinaisonsPremierTroisieme = 0; + int nbCombinaisonsDeuxiemeTroisieme = 0; + + for (CombinaisonPayable combinaison : combinaisonsPayables) { + if (resultat.getChevauxPremiers().contains(combinaison.getCheval1Id()) || + resultat.getChevauxPremiers().contains(combinaison.getCheval2Id())) { + nbCombinaisonsPremierTroisieme++; + } else if (resultat.getChevauxDeuxiemes().contains(combinaison.getCheval1Id()) || + resultat.getChevauxDeuxiemes().contains(combinaison.getCheval2Id())) { + nbCombinaisonsDeuxiemeTroisieme++; + } + } + + // Calculer les rapports + for (CombinaisonPayable combinaison : combinaisonsPayables) { + double totalMises = calculerMisesSurCombinaison(combinaison, tousParis); + + if (totalMises > 0) { + double rapportPart; + if (resultat.getChevauxPremiers().contains(combinaison.getCheval1Id()) && + resultat.getChevauxDeuxiemes().contains(combinaison.getCheval2Id()) || + resultat.getChevauxPremiers().contains(combinaison.getCheval2Id()) && + resultat.getChevauxDeuxiemes().contains(combinaison.getCheval1Id())) { + // Combinaison premier-deuxième - 1/3 du bénéfice + rapportPart = part; + } else if (resultat.getChevauxPremiers().contains(combinaison.getCheval1Id()) || + resultat.getChevauxPremiers().contains(combinaison.getCheval2Id())) { + // Combinaisons premier-troisième - 1/3 du bénéfice divisé par le nombre de ces combinaisons + rapportPart = part / nbCombinaisonsPremierTroisieme; + } else { + // Combinaisons deuxième-troisième - 1/3 du bénéfice divisé par le nombre de ces combinaisons + rapportPart = part / nbCombinaisonsDeuxiemeTroisieme; + } + + double rapport = (rapportPart / totalMises) + 1; + rapports.add(Math.max(rapport, RAPPORT_MINIMUM)); + } else { + rapports.add(0.0); + } + } + } + + gains.setRapports(rapports); + } + + private double calculerMisesSurCombinaison(CombinaisonPayable combinaison, List tousParis) { + double totalMises = 0.0; + + for (PariJumelePlace 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 8d: 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() { + 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/ch3_jumeleplace/service/PariJumelePlaceService.java b/src/main/java/com/pmumali/ch3_jumeleplace/service/PariJumelePlaceService.java new file mode 100644 index 0000000..c055db0 --- /dev/null +++ b/src/main/java/com/pmumali/ch3_jumeleplace/service/PariJumelePlaceService.java @@ -0,0 +1,62 @@ +package com.pmumali.ch3_jumeleplace.service; + +import com.pmumali.ch3_jumeleplace.model.PariJumelePlace; +import com.pmumali.ch3_jumeleplace.repository.ChevalRepository; +import com.pmumali.ch3_jumeleplace.repository.CourseRepository; +import com.pmumali.ch3_jumeleplace.repository.PariJumelePlaceRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PariJumelePlaceService { + + @Autowired + private PariJumelePlaceRepository 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 PariJumelePlace placerPari(PariJumelePlace 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; + } + } +}