1- package com .outfitlab .project .domain . service ;
1+ package com .outfitlab .project .presentation ;
22
3- import com .mercadopago .MercadoPagoConfig ;
4- import com .mercadopago .client .payment .PaymentClient ;
5- import com .mercadopago .client .preference .PreferenceClient ;
6- import com .mercadopago .client .preference .PreferenceItemRequest ;
7- import com .mercadopago .client .preference .PreferencePayerRequest ;
8- import com .mercadopago .client .preference .PreferenceRequest ;
93import com .mercadopago .exceptions .MPApiException ;
10- import com .mercadopago .resources .payment .Payment ;
11- import com .mercadopago .resources .preference .Preference ;
124import com .mercadopago .exceptions .MPException ;
13- import org .springframework .beans .factory .annotation .Value ;
14- import org .springframework .stereotype .Service ;
5+ import com .outfitlab .project .domain .service .SubscriptionService ;
6+ import org .springframework .beans .factory .annotation .Autowired ;
7+ import org .springframework .http .ResponseEntity ;
8+ import org .springframework .web .bind .annotation .*;
9+ import java .util .Map ;
10+ import java .util .HashMap ;
1511import java .math .BigDecimal ;
16- import java .util .ArrayList ;
17- import java .util .List ;
1812
19- @ Service
20- public class SubscriptionService {
13+ class SubscriptionRequest {
14+ private String planId ;
15+ private String userEmail ;
16+ private BigDecimal price ;
17+ private String currency ;
2118
22- /**
23- * Constructor para inicializar el SDK con el Access Token.
24- * Se ejecuta al iniciar Spring Boot.
25- */
26- public SubscriptionService (@ Value ("${mercadopago.access.token}" ) String accessToken ) {
27- if (accessToken == null || accessToken .trim ().isEmpty () || accessToken .equals ("${mercadopago.access.token}" )) {
28- throw new IllegalArgumentException ("ERROR: El Access Token de Mercado Pago no está configurado. Revisa la variable de entorno MP_ACCESS_TOKEN." );
29- }
30- MercadoPagoConfig .setAccessToken (accessToken );
31- System .out .println ("Mercado Pago SDK de Java inicializado (desde SubscriptionService)." );
32- }
19+ public String getPlanId () { return planId ; }
20+ public void setPlanId (String planId ) { this .planId = planId ; }
21+ public String getUserEmail () { return userEmail ; }
22+ public void setUserEmail (String userEmail ) { this .userEmail = userEmail ; }
23+ public BigDecimal getPrice () { return price ; }
24+ public void setPrice (BigDecimal price ) { this .price = price ; }
25+ public String getCurrency () { return currency ; }
26+ public void setCurrency (String currency ) { this .currency = currency ; }
27+ }
3328
34- /**
35- * Crea una Preferencia de Pago Único (para la demo).
36- */
37- public String createMercadoPagoPreference (String planId , String userEmail , BigDecimal price , String currency ) throws MPException , MPApiException {
29+ @ RestController
30+ @ RequestMapping ("/api/mp" )
31+ public class SubscriptionController {
3832
39- // 1. Definir el ítem
40- PreferenceItemRequest itemRequest = PreferenceItemRequest .builder ()
41- .id (planId )
42- .title ("Demo Premium Outfit Lab" )
43- .description ("Acceso único a funciones premium" )
44- .quantity (1 )
45- .unitPrice (price )
46- .currencyId (currency )
47- .build ();
33+ @ Autowired
34+ private SubscriptionService subscriptionService ;
4835
49- List <PreferenceItemRequest > items = new ArrayList <>();
50- items .add (itemRequest );
36+ @ PostMapping ("/crear-suscripcion" )
37+ @ CrossOrigin (origins = "http://localhost:5173" )
38+ public ResponseEntity <Map <String , String >> createPreference (@ RequestBody SubscriptionRequest request ) {
5139
52- // 2. Definir el pagador (con el email de prueba)
53- PreferencePayerRequest payer = PreferencePayerRequest .builder ()
54- .email (userEmail )
55- .build ();
40+ if (request .getPlanId () == null || request .getUserEmail () == null || request .getPrice () == null ) {
41+ return ResponseEntity .badRequest ().body (Map .of ("error" , "Faltan planId, userEmail o price." ));
42+ }
5643
57- // 3. Crear la solicitud de Preferencia
58- PreferenceRequest request = PreferenceRequest .builder ()
59- .items (items )
60- .payer (payer )
61- // --- SE ELIMINAN backUrls y autoReturn ---
62- // Esto evita el error 500 (MPApiException) al validar localhost.
63- // Mercado Pago usará las URLs configuradas en el dashboard
64- // o mostrará un botón simple de "Volver al sitio".
65- .externalReference (planId )
66- .build ();
44+ try {
45+ String initPointUrl = subscriptionService .createMercadoPagoPreference (
46+ request .getPlanId (),
47+ request .getUserEmail (),
48+ request .getPrice (),
49+ request .getCurrency () != null ? request .getCurrency () : "ARS"
50+ );
6751
68- // 4. Ejecutar la API
69- PreferenceClient client = new PreferenceClient ( );
70- Preference preference = client . create ( request );
52+ Map < String , String > response = new HashMap <>();
53+ response . put ( "initPoint" , initPointUrl );
54+ return ResponseEntity . ok ( response );
7155
72- // 5. Devolver la URL de pago
73- return preference .getInitPoint ();
56+ } catch (MPException | MPApiException e ) {
57+ e .printStackTrace ();
58+ System .err .println ("Error de API de Mercado Pago: " + e .getMessage ());
59+ return ResponseEntity .status (500 ).body (Map .of ("error" , "Error al crear la preferencia en Mercado Pago." ));
60+ } catch (Exception e ) {
61+ e .printStackTrace ();
62+ return ResponseEntity .status (500 ).body (Map .of ("error" , "Error interno del servidor." ));
63+ }
7464 }
7565
76- /**
77- * Procesa el Webhook para un Pago Único.
78- */
79- public void processPaymentNotification (Long paymentId ) throws MPException , MPApiException {
80- PaymentClient client = new PaymentClient ();
81- Payment payment = client .get (paymentId );
82-
83- String status = payment .getStatus ();
84- String externalReference = payment .getExternalReference ();
66+ @ PostMapping ("/webhooks" )
67+ public ResponseEntity <String > handleMercadoPagoWebhook (
68+ @ RequestParam (name = "id" , required = false ) String id ,
69+ @ RequestParam (name = "topic" , required = false ) String topic )
70+ {
71+ if ("payment" .equals (topic ) && id != null ) {
72+ try {
73+ Long paymentId = Long .parseLong (id );
8574
86- System .out .printf ("Procesando Webhook de PAGO. ID Pago MP: %s, ID Plan Interno: %s, Status: %s%n" ,
87- paymentId , externalReference , status );
75+ subscriptionService .processPaymentNotification (paymentId );
8876
89- if ("approved" .equals (status )) {
90- System .out .println ("Pago AUTHORIZED. Activando Premium (Demo) para: " + externalReference );
91- // TODO: Aquí iría tu lógica de base de datos para activar el servicio
92- } else if ("rejected" .equals (status ) || "cancelled" .equals (status )) {
93- System .out .println ("Pago REJECTED/CANCELLED para: " + externalReference );
77+ return ResponseEntity .ok ("Notification processed successfully." );
78+ } catch (NumberFormatException e ) {
79+ System .err .println ("Error: El ID del Webhook no es un número (Long). ID: " + id );
80+ return ResponseEntity .badRequest ().body ("ID inválido." );
81+ } catch (MPException | MPApiException e ) {
82+ System .err .println ("Error procesando Webhook de Pago: " + e .getMessage ());
83+ return ResponseEntity .status (500 ).body ("Error processing notification." );
84+ }
9485 }
86+
87+ return ResponseEntity .ok ("Notification received, not a relevant topic." );
9588 }
96- }
89+ }
0 commit comments