ParticipationController.java
package com.archiweb.api;
import com.archiweb.dto.*;
import com.archiweb.model.Code;
import com.archiweb.model.Participation;
import com.archiweb.model.User;
import com.archiweb.model.Win;
import com.archiweb.repository.CodeRepository;
import com.archiweb.repository.ParticipationRepository;
import com.archiweb.repository.UserRepository;
import com.archiweb.repository.WinRepository;
import com.archiweb.service.EmailService;
import com.archiweb.service.ParticipationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.*;
@RestController
@RequestMapping("/api/participations")
@Tag(
name = "Participations",
description = """
Gestion complète des participations au jeu concours :
- Enregistrement d'une nouvelle participation via un code
- Consultation des participations d’un utilisateur
- Validation de la remise d’un lot (claim)
- Suppression d’une participation
"""
)
public class ParticipationController {
private final EmailService emailService;
private final ParticipationService participationService;
private final UserRepository userRepository;
private final CodeRepository codeRepository;
private final ParticipationRepository participationRepository;
private final WinRepository winRepository;
public ParticipationController(EmailService emailService,
ParticipationService participationService,
UserRepository userRepository,
CodeRepository codeRepository,
ParticipationRepository participationRepository,
WinRepository winRepository) {
this.emailService = emailService;
this.participationService = participationService;
this.userRepository = userRepository;
this.codeRepository = codeRepository;
this.participationRepository = participationRepository;
this.winRepository = winRepository;
}
// ================================================================
// 1️⃣ Participer au jeu concours
// ================================================================
@PostMapping
public ResponseEntity<?> participate(@RequestBody ParticipationRequest request) {
String codeValeur = request.getCodeValeur();
if (codeValeur == null || codeValeur.trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("status", "error", "message", "Code vide ou invalide."));
}
User user = userRepository.findById(request.getUserId()).orElse(null);
if (user == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of("status", "error", "message", "Utilisateur introuvable."));
}
Code code = codeRepository.findByValeur(codeValeur.trim().toUpperCase()).orElse(null);
if (code == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of("status", "error", "message", "Code inconnu."));
}
if (code.getExpiresAt() != null && code.getExpiresAt().isBefore(LocalDateTime.now())) {
return ResponseEntity.status(HttpStatus.GONE)
.body(Map.of("status", "expired", "message", "Ce code est expiré."));
}
if (code.isUsed()) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(Map.of("status", "used", "message", "Ce code a déjà été utilisé."));
}
if (participationRepository.findByUserAndCode(user, code).isPresent()) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(Map.of("status", "duplicate", "message", "Vous avez déjà utilisé ce code avec ce compte."));
}
// 🔥 MARQUER COMME UTILISÉ
code.setUsed(true);
code.setUsedAt(LocalDateTime.now());
codeRepository.save(code);
// 🔥 CRÉER UNE PARTICIPATION
Participation participation = new Participation();
participation.setUser(user);
participation.setCode(code);
participation.setPrizeName(code.getPrizeType().name());
participation = participationRepository.save(participation);
// 🔥 CRÉER UN WIN (gain) pour que l'employé puisse le scanner
Win win = new Win();
win.setUser(user);
win.setPrizeName(code.getPrizeType().name());
win.setClaimed(false);
win.setCreatedAt(LocalDateTime.now());
winRepository.save(win);
// ⚠️ NE PAS ENVOYER L'EMAIL ICI - L'email sera envoyé après le choix de livraison par le frontend
// L'email sera envoyé uniquement après que l'utilisateur ait choisi son mode de réception
// (livraison à domicile ou récupération en boutique)
// 🔥 RÉPONSE
return ResponseEntity.ok(new ParticipationResponse(
"success",
participation.getId(),
user.getEmail(),
code.getValeur(),
code.getPrizeType().name(),
participation.isClaimed(),
"Félicitations, participation enregistrée !"
));
}
// ================================================================
// 2️⃣ Lister les participations d’un utilisateur
// ================================================================
@GetMapping
public ResponseEntity<?> getParticipationsByUser(@RequestParam Long userId) {
return userRepository.findById(userId)
.map(user -> {
List<Participation> participations = participationRepository.findByUser(user);
return ResponseEntity.ok(Map.of("status", "success", "data", participations));
})
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of("status", "error", "message", "Utilisateur introuvable")));
}
// ================================================================
// 3️⃣ Valider remise d’un lot
// ================================================================
@PostMapping("/{id}/claim")
public ResponseEntity<?> claimPrize(@PathVariable Long id, @RequestBody ClaimPrizeRequest request) {
return participationRepository.findById(id)
.map(p -> {
if (p.isClaimed()) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(Map.of("status", "already_claimed", "message", "Ce gain a déjà été remis"));
}
p.setClaimed(true);
p.setClaimedAt(LocalDateTime.now());
p.setStoreId(request.getStoreId());
p.setClaimedBy(request.getClaimedBy());
p.setClaimChannel(request.getChannel() != null ? request.getChannel() : "boutique");
participationRepository.save(p);
return ResponseEntity.ok(Map.of(
"status", "success",
"message", "Lot marqué comme remis",
"participationId", p.getId(),
"code", p.getCode().getValeur(),
"prizeType", p.getCode().getPrizeType().name()
));
})
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of("status", "error", "message", "Participation introuvable")));
}
// ================================================================
// 4️⃣ Supprimer une participation
// ================================================================
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteParticipation(@PathVariable Long id) {
return participationRepository.findById(id)
.map(p -> {
participationRepository.delete(p);
return ResponseEntity.ok(Map.of("status", "success", "message", "Participation supprimée avec succès"));
})
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of("status", "error", "message", "Participation introuvable")));
}
}