From cabfa1f5d59d2d9188db88f8d6d33cac429d49ec Mon Sep 17 00:00:00 2001 From: Alan Di Giovanni Date: Wed, 16 Jul 2025 15:26:37 -0300 Subject: [PATCH 1/2] feat(PC-126): User payment refactor with Mercado Pago SDK --- build.gradle | 2 + .../UserPaymentsControllerAdapter.java | 33 +++++ .../model/SubscriptionResponse.java | 4 + .../controller/model/UserPaymentResponse.java | 33 +++++ ...eUserPaymentDatabaseRepositoryAdapter.java | 39 ++++++ .../model/PaymentStatusHibernateModel.java | 38 ++++++ .../PlanConfigurationHibernateModel.java | 51 +++++++ .../hibernate/model/PlanHibernateModel.java | 8 ++ .../hibernate/model/UserHibernateModel.java | 1 - .../model/UserPaymentsHibernateModel.java | 62 +++++++++ ...UserPaymentHibernateRepositoryAdapter.java | 7 + ...rPaymentMercadoLibreRepositoryAdapter.java | 124 ++++++++++++++++++ .../port/in/CreateUserPaymentCommand.java | 7 + .../port/out/CreateUserPaymentRepository.java | 8 ++ .../usecase/CreateUserPaymentUseCase.java | 62 +++++++++ .../usecase/model/PaymentStatus.java | 13 ++ .../cuoco/application/usecase/model/Plan.java | 2 + .../usecase/model/PlanConfiguration.java | 18 +++ .../usecase/model/Subscription.java | 9 ++ .../usecase/model/UserPayment.java | 17 +++ .../MercadoPagoBrandingConfig.java | 14 ++ .../MercadoPagoCallbacksConfig.java | 15 +++ .../config/mercadopago/MercadoPagoConfig.java | 16 +++ .../cuoco/shared/model/ErrorDescription.java | 1 + .../com/cuoco/shared/utils/Constants.java | 1 + src/main/resources/application.yml | 16 ++- src/main/resources/sql/ddl/01_user_tables.sql | 38 ++++++ src/main/resources/sql/ddl/05_inserts.sql | 3 + 28 files changed, 640 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/in/controller/model/SubscriptionResponse.java create mode 100644 src/main/java/com/cuoco/adapter/in/controller/model/UserPaymentResponse.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/model/PlanConfigurationHibernateModel.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/repository/CreateUserPaymentHibernateRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/application/port/in/CreateUserPaymentCommand.java create mode 100644 src/main/java/com/cuoco/application/port/out/CreateUserPaymentRepository.java create mode 100644 src/main/java/com/cuoco/application/usecase/CreateUserPaymentUseCase.java create mode 100644 src/main/java/com/cuoco/application/usecase/model/PaymentStatus.java create mode 100644 src/main/java/com/cuoco/application/usecase/model/PlanConfiguration.java create mode 100644 src/main/java/com/cuoco/application/usecase/model/Subscription.java create mode 100644 src/main/java/com/cuoco/application/usecase/model/UserPayment.java create mode 100644 src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoBrandingConfig.java create mode 100644 src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoCallbacksConfig.java create mode 100644 src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoConfig.java diff --git a/build.gradle b/build.gradle index 6cde39d..d8e87d5 100644 --- a/build.gradle +++ b/build.gradle @@ -36,6 +36,8 @@ dependencies { implementation 'com.github.lolgab:snunit-autowire_native0.4.0-M2_2.11:0.0.4' implementation 'jakarta.validation:jakarta.validation-api:3.0.2' + implementation 'com.mercadopago:sdk-java:2.5.0' + // Swagger documentation implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' diff --git a/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java b/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java new file mode 100644 index 0000000..1cf4082 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java @@ -0,0 +1,33 @@ +package com.cuoco.adapter.in.controller; + +import com.cuoco.adapter.in.controller.model.UserPaymentResponse; +import com.cuoco.application.port.in.CreateUserPaymentCommand; +import com.cuoco.application.usecase.model.UserPayment; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/payments") +@RequiredArgsConstructor +public class UserPaymentsControllerAdapter { + + private final CreateUserPaymentCommand createUserPaymentCommand; + + @PostMapping() + public ResponseEntity subscribe() { + log.info("Executing POST for user subscription payment"); + + UserPayment userPayment = createUserPaymentCommand.execute(); + UserPaymentResponse response = UserPaymentResponse.fromDomain(userPayment); + + log.info("User subscription payment response: {}", response); + return ResponseEntity.ok(response); + } + + +} diff --git a/src/main/java/com/cuoco/adapter/in/controller/model/SubscriptionResponse.java b/src/main/java/com/cuoco/adapter/in/controller/model/SubscriptionResponse.java new file mode 100644 index 0000000..e63db28 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/in/controller/model/SubscriptionResponse.java @@ -0,0 +1,4 @@ +package com.cuoco.adapter.in.controller.model; + +public class SubscriptionResponse { +} diff --git a/src/main/java/com/cuoco/adapter/in/controller/model/UserPaymentResponse.java b/src/main/java/com/cuoco/adapter/in/controller/model/UserPaymentResponse.java new file mode 100644 index 0000000..7dbca1e --- /dev/null +++ b/src/main/java/com/cuoco/adapter/in/controller/model/UserPaymentResponse.java @@ -0,0 +1,33 @@ +package com.cuoco.adapter.in.controller.model; + +import com.cuoco.application.usecase.model.UserPayment; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserPaymentResponse { + + private String externalId; + private String externalReference; + private String checkoutUrl; + + public static UserPaymentResponse fromDomain(UserPayment userPayment) { + return UserPaymentResponse.builder() + .externalId(userPayment.getExternalId()) + .externalReference(userPayment.getExternalReference()) + .checkoutUrl(userPayment.getCheckoutUrl()) + .build(); + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java new file mode 100644 index 0000000..8e67d0e --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java @@ -0,0 +1,39 @@ +package com.cuoco.adapter.out.hibernate; + +import com.cuoco.adapter.out.hibernate.model.UserHibernateModel; +import com.cuoco.adapter.out.hibernate.model.UserPaymentsHibernateModel; +import com.cuoco.adapter.out.hibernate.repository.CreateUserPaymentHibernateRepositoryAdapter; +import com.cuoco.application.port.out.CreateUserPaymentRepository; +import com.cuoco.application.usecase.model.UserPayment; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Repository; + +@Slf4j +@Repository +@Qualifier("repository") +@RequiredArgsConstructor +public class CreateUserPaymentDatabaseRepositoryAdapter implements CreateUserPaymentRepository { + + private final CreateUserPaymentHibernateRepositoryAdapter createUserPaymentHibernateRepositoryAdapter; + + @Override + public UserPayment execute(UserPayment userPayment) { + log.info("Executing create user payment in database"); + + UserPaymentsHibernateModel userPaymentToSave = UserPaymentsHibernateModel.fromDomain(userPayment); + + userPaymentToSave.setUser(UserHibernateModel.builder().id(userPayment.getUser().getId()).build()); + + UserPaymentsHibernateModel savedUserPayment = createUserPaymentHibernateRepositoryAdapter.save(userPaymentToSave); + + log.info("Saved user payment with ID {}", savedUserPayment.getId()); + + UserPayment response = savedUserPayment.toDomain(); + + response.setUser(userPayment.getUser()); + + return response; + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java new file mode 100644 index 0000000..33496b0 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java @@ -0,0 +1,38 @@ +package com.cuoco.adapter.out.hibernate.model; + +import com.cuoco.application.usecase.model.PaymentStatus; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity(name = "payment_status") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentStatusHibernateModel { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + private String description; + + public PaymentStatusHibernateModel fromDomain(PaymentStatus paymentStatus) { + return PaymentStatusHibernateModel.builder() + .id(paymentStatus.getId()) + .description(paymentStatus.getDescription()) + .build(); + } + + public PaymentStatus toDomain() { + return PaymentStatus.builder() + .id(id) + .description(description) + .build(); + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanConfigurationHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanConfigurationHibernateModel.java new file mode 100644 index 0000000..ba7a44e --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanConfigurationHibernateModel.java @@ -0,0 +1,51 @@ +package com.cuoco.adapter.out.hibernate.model; + +import com.cuoco.application.usecase.model.PlanConfiguration; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Entity(name = "plan_configuration") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PlanConfigurationHibernateModel { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + private String title; + private String description; + private Integer quantity; + private BigDecimal price; + private String currency; + + public static PlanConfigurationHibernateModel fromDomain(PlanConfiguration planConfiguration) { + return PlanConfigurationHibernateModel.builder() + .title(planConfiguration.getTitle()) + .description(planConfiguration.getDescription()) + .quantity(planConfiguration.getQuantity()) + .price(planConfiguration.getPrice()) + .currency(planConfiguration.getCurrency()) + .build(); + } + + public PlanConfiguration toDomain() { + return PlanConfiguration.builder() + .title(title) + .description(description) + .quantity(quantity) + .price(price) + .currency(currency) + .build(); + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java index 540f1e4..931cb29 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java @@ -5,6 +5,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -22,10 +24,15 @@ public class PlanHibernateModel { private Integer id; private String description; + @OneToOne + @JoinColumn(name = "configuration_id") + private PlanConfigurationHibernateModel configuration; + public static PlanHibernateModel fromDomain(Plan plan) { return PlanHibernateModel.builder() .id(plan.getId()) .description(plan.getDescription()) + .configuration(PlanConfigurationHibernateModel.fromDomain(plan.getConfiguration())) .build(); } @@ -33,6 +40,7 @@ public Plan toDomain() { return Plan.builder() .id(id) .description(description) + .configuration(configuration != null ? configuration.toDomain() : null) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java index e5176d2..8375734 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java @@ -1,6 +1,5 @@ package com.cuoco.adapter.out.hibernate.model; -import com.cuoco.application.usecase.model.Allergy; import com.cuoco.application.usecase.model.User; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java new file mode 100644 index 0000000..e3d08d6 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java @@ -0,0 +1,62 @@ +package com.cuoco.adapter.out.hibernate.model; + +import com.cuoco.application.usecase.model.UserPayment; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Entity(name = "user_payments") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserPaymentsHibernateModel { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + @JoinColumn(name = "user_id", referencedColumnName = "id") + private UserHibernateModel user; + + @OneToOne + @JoinColumn(name = "to_plan_id") + private PlanHibernateModel toPlan; + + private String externalId; + private String externalReference; + private String checkoutUrl; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private LocalDateTime deletedAt; + + public static UserPaymentsHibernateModel fromDomain(UserPayment userPayment) { + return UserPaymentsHibernateModel.builder() + .id(userPayment.getId()) + .toPlan(PlanHibernateModel.fromDomain(userPayment.getPlan())) + .externalId(userPayment.getExternalId()) + .externalReference(userPayment.getExternalReference()) + .checkoutUrl(userPayment.getCheckoutUrl()) + .build(); + } + + public UserPayment toDomain() { + return UserPayment.builder() + .plan(toPlan.toDomain()) + .externalId(externalId) + .externalReference(externalReference) + .checkoutUrl(checkoutUrl) + .build(); + } + +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/repository/CreateUserPaymentHibernateRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/repository/CreateUserPaymentHibernateRepositoryAdapter.java new file mode 100644 index 0000000..57e6afe --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/repository/CreateUserPaymentHibernateRepositoryAdapter.java @@ -0,0 +1,7 @@ +package com.cuoco.adapter.out.hibernate.repository; + +import com.cuoco.adapter.out.hibernate.model.UserPaymentsHibernateModel; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CreateUserPaymentHibernateRepositoryAdapter extends JpaRepository { +} diff --git a/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java new file mode 100644 index 0000000..012351b --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java @@ -0,0 +1,124 @@ +package com.cuoco.adapter.out.mercadopago; + +import com.cuoco.adapter.exception.NotAvailableException; +import com.cuoco.application.port.out.CreateUserPaymentRepository; +import com.cuoco.application.usecase.model.Plan; +import com.cuoco.application.usecase.model.PlanConfiguration; +import com.cuoco.application.usecase.model.User; +import com.cuoco.application.usecase.model.UserPayment; +import com.cuoco.shared.config.mercadopago.MercadoPagoConfig; +import com.cuoco.shared.model.ErrorDescription; +import com.cuoco.shared.utils.Constants; +import com.mercadopago.client.preference.PreferenceBackUrlsRequest; +import com.mercadopago.client.preference.PreferenceClient; +import com.mercadopago.client.preference.PreferenceItemRequest; +import com.mercadopago.client.preference.PreferenceRequest; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.resources.preference.Preference; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.UUID; + +@Slf4j +@Component +@Qualifier("provider") +@RequiredArgsConstructor +public class CreateUserPaymentMercadoLibreRepositoryAdapter implements CreateUserPaymentRepository { + + private static final String EXTERNAL_REFERENCE_PREFIX = "CUOCO_PRO_UPGRADE"; + private static final String HOST_DOMAIN = "cuoco.com.ar"; + private static final String API_CONTEXT = "/api"; + + private final HttpServletRequest request; + private final MercadoPagoConfig config; + + @Override + public UserPayment execute(UserPayment userPayment) { + + com.mercadopago.MercadoPagoConfig.setAccessToken(config.getAccessToken()); + + User user = userPayment.getUser(); + Plan plan = userPayment.getPlan(); + + log.info("Executing MercadoPago preference payment for user ID {} and plan ID {}", user.getId(), plan.getId()); + + try { + PreferenceRequest request = buildPreference(userPayment); + + PreferenceClient client = new PreferenceClient(); + + Preference preference = client.create(request); + + UserPayment response = buildResponse(userPayment, preference); + + log.info("Payment created with external ID {}", response.getExternalId()); + + return response; + + } catch (MPException e) { + log.error("Error while creating preference in MercadoPago SDK", e); + throw new NotAvailableException(ErrorDescription.NOT_AVAILABLE.getValue()); + } catch (MPApiException e) { + log.error("Failed to create preference payment with MercadoPago API", e); + throw new NotAvailableException(ErrorDescription.NOT_AVAILABLE.getValue()); + } + } + + private String generateExternalReference(Long userId) { + return EXTERNAL_REFERENCE_PREFIX + .concat(Constants.UNDERSCORE.getValue()) + .concat(userId.toString()) + .concat(Constants.UNDERSCORE.getValue()) + .concat(UUID.randomUUID().toString().substring(0, 8)); + } + + private PreferenceRequest buildPreference(UserPayment userPayment) { + return PreferenceRequest.builder() + .items(List.of(buildItems(userPayment.getPlan()))) + .backUrls(buildBackUrls()) + .externalReference(generateExternalReference(userPayment.getUser().getId())) + .build(); + } + + private PreferenceBackUrlsRequest buildBackUrls() { + + String host = request.getRequestURL().toString().replace(request.getRequestURI(), Constants.EMPTY.getValue()); + String contextPath = host.contains(HOST_DOMAIN) ? API_CONTEXT : Constants.EMPTY.getValue(); + String baseUrl = host + contextPath; + + return PreferenceBackUrlsRequest.builder() + .success(baseUrl + config.getCallbacks().getSuccess()) + .pending(baseUrl + config.getCallbacks().getPending()) + .failure(baseUrl + config.getCallbacks().getFailure()) + .build(); + } + + private PreferenceItemRequest buildItems(Plan plan) { + PlanConfiguration planConfiguration = plan.getConfiguration(); + + return PreferenceItemRequest.builder() + .title(planConfiguration.getTitle()) + .description(planConfiguration.getDescription()) + .quantity(planConfiguration.getQuantity()) + .unitPrice(planConfiguration.getPrice()) + .currencyId(planConfiguration.getCurrency()) + .build(); + } + + private UserPayment buildResponse(UserPayment request, Preference preference) { + return UserPayment.builder() + .user(request.getUser()) + .plan(request.getPlan()) + .externalId(preference.getId()) + .checkoutUrl(preference.getInitPoint()) + .externalReference(preference.getExternalReference()) + .build(); + + } +} diff --git a/src/main/java/com/cuoco/application/port/in/CreateUserPaymentCommand.java b/src/main/java/com/cuoco/application/port/in/CreateUserPaymentCommand.java new file mode 100644 index 0000000..352f851 --- /dev/null +++ b/src/main/java/com/cuoco/application/port/in/CreateUserPaymentCommand.java @@ -0,0 +1,7 @@ +package com.cuoco.application.port.in; + +import com.cuoco.application.usecase.model.UserPayment; + +public interface CreateUserPaymentCommand { + UserPayment execute(); +} diff --git a/src/main/java/com/cuoco/application/port/out/CreateUserPaymentRepository.java b/src/main/java/com/cuoco/application/port/out/CreateUserPaymentRepository.java new file mode 100644 index 0000000..09e2e4b --- /dev/null +++ b/src/main/java/com/cuoco/application/port/out/CreateUserPaymentRepository.java @@ -0,0 +1,8 @@ +package com.cuoco.application.port.out; + + +import com.cuoco.application.usecase.model.UserPayment; + +public interface CreateUserPaymentRepository { + UserPayment execute(UserPayment userPayment); +} diff --git a/src/main/java/com/cuoco/application/usecase/CreateUserPaymentUseCase.java b/src/main/java/com/cuoco/application/usecase/CreateUserPaymentUseCase.java new file mode 100644 index 0000000..3c3650a --- /dev/null +++ b/src/main/java/com/cuoco/application/usecase/CreateUserPaymentUseCase.java @@ -0,0 +1,62 @@ +package com.cuoco.application.usecase; + +import com.cuoco.application.exception.BadRequestException; +import com.cuoco.application.port.in.CreateUserPaymentCommand; +import com.cuoco.application.port.out.CreateUserPaymentRepository; +import com.cuoco.application.port.out.GetPlanByIdRepository; +import com.cuoco.application.usecase.domainservice.UserDomainService; +import com.cuoco.application.usecase.model.Plan; +import com.cuoco.application.usecase.model.User; +import com.cuoco.application.usecase.model.UserPayment; +import com.cuoco.shared.model.ErrorDescription; +import com.cuoco.shared.utils.PlanConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class CreateUserPaymentUseCase implements CreateUserPaymentCommand { + + private final UserDomainService userDomainService; + private final GetPlanByIdRepository getPlanByIdRepository; + private final CreateUserPaymentRepository createUserPaymentProvider; + private final CreateUserPaymentRepository createUserPaymentRepository; + + public CreateUserPaymentUseCase( + UserDomainService userDomainService, + GetPlanByIdRepository getPlanByIdRepository, + @Qualifier("provider") CreateUserPaymentRepository createUserPaymentProvider, + @Qualifier("repository") CreateUserPaymentRepository createUserPaymentRepository + ) { + this.userDomainService = userDomainService; + this.getPlanByIdRepository = getPlanByIdRepository; + this.createUserPaymentProvider = createUserPaymentProvider; + this.createUserPaymentRepository = createUserPaymentRepository; + } + + @Override + public UserPayment execute() { + User user = userDomainService.getCurrentUser(); + + if(user.getPlan().getId() == PlanConstants.PRO.getValue()) { + log.info("User already has a PRO plan"); + throw new BadRequestException(ErrorDescription.USER_HAS_PRO_PLAN.getValue()); + } + + Plan plan = getPlanByIdRepository.execute(PlanConstants.PRO.getValue()); + + UserPayment userPayment = createUserPaymentProvider.execute(buildUserPayment(user, plan)); + + createUserPaymentRepository.execute(userPayment); + + return userPayment; + } + + private UserPayment buildUserPayment(User user, Plan plan) { + return UserPayment.builder() + .user(user) + .plan(plan) + .build(); + } +} diff --git a/src/main/java/com/cuoco/application/usecase/model/PaymentStatus.java b/src/main/java/com/cuoco/application/usecase/model/PaymentStatus.java new file mode 100644 index 0000000..1e7f702 --- /dev/null +++ b/src/main/java/com/cuoco/application/usecase/model/PaymentStatus.java @@ -0,0 +1,13 @@ +package com.cuoco.application.usecase.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@AllArgsConstructor +public class PaymentStatus implements Parametric { + private Integer id; + private String description; +} diff --git a/src/main/java/com/cuoco/application/usecase/model/Plan.java b/src/main/java/com/cuoco/application/usecase/model/Plan.java index 7ced45b..34d6821 100644 --- a/src/main/java/com/cuoco/application/usecase/model/Plan.java +++ b/src/main/java/com/cuoco/application/usecase/model/Plan.java @@ -10,4 +10,6 @@ public class Plan implements Parametric { private Integer id; private String description; + + private PlanConfiguration configuration; } diff --git a/src/main/java/com/cuoco/application/usecase/model/PlanConfiguration.java b/src/main/java/com/cuoco/application/usecase/model/PlanConfiguration.java new file mode 100644 index 0000000..35571a0 --- /dev/null +++ b/src/main/java/com/cuoco/application/usecase/model/PlanConfiguration.java @@ -0,0 +1,18 @@ +package com.cuoco.application.usecase.model; + +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class PlanConfiguration { + + private String title; + private String description; + private Integer quantity; + private BigDecimal price; + private String currency; + +} diff --git a/src/main/java/com/cuoco/application/usecase/model/Subscription.java b/src/main/java/com/cuoco/application/usecase/model/Subscription.java new file mode 100644 index 0000000..ec2f28c --- /dev/null +++ b/src/main/java/com/cuoco/application/usecase/model/Subscription.java @@ -0,0 +1,9 @@ +package com.cuoco.application.usecase.model; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class Subscription { +} diff --git a/src/main/java/com/cuoco/application/usecase/model/UserPayment.java b/src/main/java/com/cuoco/application/usecase/model/UserPayment.java new file mode 100644 index 0000000..3f312cc --- /dev/null +++ b/src/main/java/com/cuoco/application/usecase/model/UserPayment.java @@ -0,0 +1,17 @@ +package com.cuoco.application.usecase.model; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class UserPayment { + + private Long id; + private User user; + private Plan plan; + private String externalId; + private String externalReference; + private String checkoutUrl; + +} diff --git a/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoBrandingConfig.java b/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoBrandingConfig.java new file mode 100644 index 0000000..dd8bc8b --- /dev/null +++ b/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoBrandingConfig.java @@ -0,0 +1,14 @@ +package com.cuoco.shared.config.mercadopago; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "mercado-pago.branding") +public class MercadoPagoBrandingConfig { + private String primaryColor; + private String secondaryColor; + private boolean showMercadoPagoBranding; +} diff --git a/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoCallbacksConfig.java b/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoCallbacksConfig.java new file mode 100644 index 0000000..00a5b9f --- /dev/null +++ b/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoCallbacksConfig.java @@ -0,0 +1,15 @@ +package com.cuoco.shared.config.mercadopago; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "mercado-pago.callbacks") +public class MercadoPagoCallbacksConfig { + private String success; + private String pending; + private String failure; +} + diff --git a/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoConfig.java b/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoConfig.java new file mode 100644 index 0000000..13ec8a1 --- /dev/null +++ b/src/main/java/com/cuoco/shared/config/mercadopago/MercadoPagoConfig.java @@ -0,0 +1,16 @@ +package com.cuoco.shared.config.mercadopago; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "mercado-pago") +public class MercadoPagoConfig { + + private String accessToken; + private MercadoPagoCallbacksConfig callbacks; + private MercadoPagoBrandingConfig branding; + +} \ No newline at end of file diff --git a/src/main/java/com/cuoco/shared/model/ErrorDescription.java b/src/main/java/com/cuoco/shared/model/ErrorDescription.java index f992299..c14cbfa 100644 --- a/src/main/java/com/cuoco/shared/model/ErrorDescription.java +++ b/src/main/java/com/cuoco/shared/model/ErrorDescription.java @@ -26,6 +26,7 @@ public enum ErrorDescription { USER_NOT_EXISTS("El usuario ingresado no existe"), USER_DUPLICATED("El usuario ya existe"), USER_NOT_ACTIVATED("El usuario no esta activo"), + USER_HAS_PRO_PLAN("El usuario ya tiene el plan PRO"), NO_AUTH_TOKEN("El token no esta presente"), INVALID_TOKEN("El token ingresado no es válido"), INVALID_CREDENTIALS("Las credenciales no son válidas"), diff --git a/src/main/java/com/cuoco/shared/utils/Constants.java b/src/main/java/com/cuoco/shared/utils/Constants.java index 3d2e924..9cbc1a0 100644 --- a/src/main/java/com/cuoco/shared/utils/Constants.java +++ b/src/main/java/com/cuoco/shared/utils/Constants.java @@ -2,6 +2,7 @@ public enum Constants { + UNDERSCORE("_"), COMMA(","), SLASH("/"), DOT("."), diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b6eb693..d36710a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -40,6 +40,16 @@ email: connectiontimeout: 5000 timeout: 5000 writetimeout: 5000 +mercado-pago: + access-token: ${MP_ACCESS_TOKEN} + callbacks: + success: ${MP_CALLBACK_SUCCESS:/payment/success} + pending: ${MP_CALLBACK_PENDING:/payment/pending} + failure: ${MP_CALLBACK_FAILURE:/payment/failure} + branding: + primary-color: ${MP_BRANDING_PRIMARY_COLOR:#FF6B35} + secondary-color: ${MP_BRANDING_SECONDARY_COLOR:#FFA500} + show-mercado-pago-branding: ${MP_BRANDING_ENABLE_MP_BRANDING:false} shared: email: no-reply: @@ -56,4 +66,8 @@ shared: base-path: ${RECIPE_IMAGES_BASE_PATH} meal-preps: size: ${MEAL_PREP_DEFAULT_SIZE:1} - recipes-size: ${RECIPES_SIZE_PER_MEAL_PREP:3} \ No newline at end of file + recipes-size: ${RECIPES_SIZE_PER_MEAL_PREP:3} + + + + diff --git a/src/main/resources/sql/ddl/01_user_tables.sql b/src/main/resources/sql/ddl/01_user_tables.sql index d78651b..a9fc466 100644 --- a/src/main/resources/sql/ddl/01_user_tables.sql +++ b/src/main/resources/sql/ddl/01_user_tables.sql @@ -20,6 +20,26 @@ CREATE TABLE diets ); CREATE TABLE plans +( + `id` int NOT NULL AUTO_INCREMENT, + `description` varchar(255) DEFAULT NULL, + `configuration_id` int DEFAULT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_plan_configuration_id` FOREIGN KEY (`configuration_id`) REFERENCES `plans` (`id`) +); + +CREATE TABLE plan_configuration +( + `id` int NOT NULL AUTO_INCREMENT, + `title` varchar(255) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `quantity` int DEFAULT NULL, + `price` DECIMAL(10,2) DEFAULT NULL, + `currency` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE payment_status ( `id` int NOT NULL AUTO_INCREMENT, `description` varchar(255) DEFAULT NULL, @@ -79,3 +99,21 @@ CREATE TABLE user_preferences CONSTRAINT `FK_user_preferences_diet_id` FOREIGN KEY (`diet_id`) REFERENCES `diets` (`id`), CONSTRAINT `FK_user_preferences_cook_level_id` FOREIGN KEY (`cook_level_id`) REFERENCES `cook_levels` (`id`) ); + +CREATE TABLE user_payments +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `to_plan_id` int DEFAULT NULL, + `status_id` int DEFAULT NULL, + `external_id` varchar(255) DEFAULT NULL, + `external_reference` varchar(255) DEFAULT NULL, + `checkout_url` varchar(255) DEFAULT NULL, + `created_at` datetime(6) DEFAULT NULL, + `updated_at` datetime(6) DEFAULT NULL, + `deleted_at` datetime(6) DEFAULT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_user_payments_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `FK_user_payments_plan_id` FOREIGN KEY (`to_plan_id`) REFERENCES `plans` (`id`), + CONSTRAINT `FK_user_payments_status_id` FOREIGN KEY (`status_id`) REFERENCES `payment_status` (`id`) +); diff --git a/src/main/resources/sql/ddl/05_inserts.sql b/src/main/resources/sql/ddl/05_inserts.sql index 38682af..480ae98 100644 --- a/src/main/resources/sql/ddl/05_inserts.sql +++ b/src/main/resources/sql/ddl/05_inserts.sql @@ -2,6 +2,9 @@ INSERT INTO plans (id, description) VALUES (1, 'Free'), (2, 'Pro'); +INSERT INTO plan_configuration (id, title, description, quantity, price, currency) +VALUES (1, 'Cuoco Pro - Plan Premium', 'Actualiza a Pro: Recetas ilimitadas, filtros avanzados, meal preps y mucho más', 1, 500.00, 'ARS'); + INSERT INTO cook_levels (id, description) VALUES (1, 'Bajo'), (2, 'Medio'), From 38b4d23a4dea8256dcf6c2b4f655b5c633a228b1 Mon Sep 17 00:00:00 2001 From: Alan Di Giovanni Date: Wed, 16 Jul 2025 23:25:41 -0300 Subject: [PATCH 2/2] fix(PC-126): Fixes webhook from mercado pago integration --- .../UserPaymentsControllerAdapter.java | 25 +++++- .../JwtAuthenticationFilterAdapter.java | 1 + ...eUserPaymentDatabaseRepositoryAdapter.java | 2 - ...aymentStatusDatabaseRepositoryAdapter.java | 28 +++++++ ...nalReferenceDatabaseRepositoryAdapter.java | 36 +++++++++ ...eUserPaymentDatabaseRepositoryAdapter.java | 40 ++++++++++ .../model/PaymentStatusHibernateModel.java | 2 +- .../hibernate/model/PlanHibernateModel.java | 2 +- .../hibernate/model/UserHibernateModel.java | 20 +++++ .../model/UserPaymentsHibernateModel.java | 10 +++ .../model/UserPreferencesHibernateModel.java | 8 ++ ...ymentStatusHibernateRepositoryAdapter.java | 7 ++ ...alReferenceHibernateRepositoryAdapter.java | 12 +++ ...rPaymentMercadoPagoRepositoryAdapter.java} | 14 ++-- ...erPaymentMercadoPagoRepositoryAdapter.java | 46 +++++++++++ .../port/in/ProcessUserPaymentCommand.java | 17 ++++ .../out/GetAllPaymentStatusRepository.java | 9 +++ ...rPaymentByExternalReferenceRepository.java | 7 ++ .../out/ProcessUserPaymentRepository.java | 7 ++ .../port/out/UpdateUserPaymentRepository.java | 7 ++ .../usecase/ProcessUserPaymentUseCase.java | 77 +++++++++++++++++++ .../usecase/model/UserPayment.java | 1 + .../security/SecurityConfiguration.java | 1 + .../cuoco/shared/utils/PaymentConstants.java | 17 ++++ src/main/resources/sql/ddl/05_inserts.sql | 9 +++ 25 files changed, 392 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/GetAllPaymentStatusDatabaseRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/GetUserPaymentByExternalReferenceDatabaseRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/UpdateUserPaymentDatabaseRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/repository/GetAllPaymentStatusHibernateRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/adapter/out/hibernate/repository/GetUserPaymentByExternalReferenceHibernateRepositoryAdapter.java rename src/main/java/com/cuoco/adapter/out/mercadopago/{CreateUserPaymentMercadoLibreRepositoryAdapter.java => CreateUserPaymentMercadoPagoRepositoryAdapter.java} (90%) create mode 100644 src/main/java/com/cuoco/adapter/out/mercadopago/ProcessUserPaymentMercadoPagoRepositoryAdapter.java create mode 100644 src/main/java/com/cuoco/application/port/in/ProcessUserPaymentCommand.java create mode 100644 src/main/java/com/cuoco/application/port/out/GetAllPaymentStatusRepository.java create mode 100644 src/main/java/com/cuoco/application/port/out/GetUserPaymentByExternalReferenceRepository.java create mode 100644 src/main/java/com/cuoco/application/port/out/ProcessUserPaymentRepository.java create mode 100644 src/main/java/com/cuoco/application/port/out/UpdateUserPaymentRepository.java create mode 100644 src/main/java/com/cuoco/application/usecase/ProcessUserPaymentUseCase.java create mode 100644 src/main/java/com/cuoco/shared/utils/PaymentConstants.java diff --git a/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java b/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java index 1cf4082..4755b8e 100644 --- a/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java +++ b/src/main/java/com/cuoco/adapter/in/controller/UserPaymentsControllerAdapter.java @@ -2,14 +2,19 @@ import com.cuoco.adapter.in.controller.model.UserPaymentResponse; import com.cuoco.application.port.in.CreateUserPaymentCommand; +import com.cuoco.application.port.in.ProcessUserPaymentCommand; import com.cuoco.application.usecase.model.UserPayment; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; + @Slf4j @RestController @RequestMapping("/payments") @@ -17,10 +22,11 @@ public class UserPaymentsControllerAdapter { private final CreateUserPaymentCommand createUserPaymentCommand; + private final ProcessUserPaymentCommand processUserPaymentCommand; - @PostMapping() - public ResponseEntity subscribe() { - log.info("Executing POST for user subscription payment"); + @PostMapping + public ResponseEntity init() { + log.info("Executing POST for init user subscription payment"); UserPayment userPayment = createUserPaymentCommand.execute(); UserPaymentResponse response = UserPaymentResponse.fromDomain(userPayment); @@ -30,4 +36,17 @@ public ResponseEntity subscribe() { } + @PostMapping("/webhook") + public ResponseEntity processPayment(@RequestBody Map payload) { + log.info("Executing POST for payment webhook: {}", payload); + + ProcessUserPaymentCommand.Command command = ProcessUserPaymentCommand.Command.builder() + .payload(payload) + .build(); + + processUserPaymentCommand.execute(command); + + log.info("User payment webhook processed successfully"); + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/com/cuoco/adapter/in/security/JwtAuthenticationFilterAdapter.java b/src/main/java/com/cuoco/adapter/in/security/JwtAuthenticationFilterAdapter.java index 18cf56e..13d33bd 100644 --- a/src/main/java/com/cuoco/adapter/in/security/JwtAuthenticationFilterAdapter.java +++ b/src/main/java/com/cuoco/adapter/in/security/JwtAuthenticationFilterAdapter.java @@ -77,6 +77,7 @@ protected boolean shouldNotFilter(HttpServletRequest request) { || matcher.match("/cook-levels", request.getRequestURI()) || matcher.match("/meal-types", request.getRequestURI()) || matcher.match("/preparation-times", request.getRequestURI()) + || matcher.match("/payments/webhook", request.getRequestURI()) || matcher.match("/v3/api-docs/**", request.getRequestURI()) || matcher.match("/swagger-ui/**", request.getRequestURI()) || matcher.match("/swagger-ui.html", request.getRequestURI()); diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java index 8e67d0e..a7bb771 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/CreateUserPaymentDatabaseRepositoryAdapter.java @@ -24,8 +24,6 @@ public UserPayment execute(UserPayment userPayment) { UserPaymentsHibernateModel userPaymentToSave = UserPaymentsHibernateModel.fromDomain(userPayment); - userPaymentToSave.setUser(UserHibernateModel.builder().id(userPayment.getUser().getId()).build()); - UserPaymentsHibernateModel savedUserPayment = createUserPaymentHibernateRepositoryAdapter.save(userPaymentToSave); log.info("Saved user payment with ID {}", savedUserPayment.getId()); diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/GetAllPaymentStatusDatabaseRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/GetAllPaymentStatusDatabaseRepositoryAdapter.java new file mode 100644 index 0000000..42b8de5 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/GetAllPaymentStatusDatabaseRepositoryAdapter.java @@ -0,0 +1,28 @@ +package com.cuoco.adapter.out.hibernate; + +import com.cuoco.adapter.out.hibernate.model.PaymentStatusHibernateModel; +import com.cuoco.adapter.out.hibernate.repository.GetAllPaymentStatusHibernateRepositoryAdapter; +import com.cuoco.application.port.out.GetAllPaymentStatusRepository; +import com.cuoco.application.usecase.model.PaymentStatus; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class GetAllPaymentStatusDatabaseRepositoryAdapter implements GetAllPaymentStatusRepository { + + private final GetAllPaymentStatusHibernateRepositoryAdapter getAllPaymentStatusHibernateRepositoryAdapter; + + @Override + public List getAll() { + log.info("Get all payment statuses from database"); + + List response = getAllPaymentStatusHibernateRepositoryAdapter.findAll(); + + return response.stream().map(PaymentStatusHibernateModel::toDomain).toList(); + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/GetUserPaymentByExternalReferenceDatabaseRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/GetUserPaymentByExternalReferenceDatabaseRepositoryAdapter.java new file mode 100644 index 0000000..988a0c9 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/GetUserPaymentByExternalReferenceDatabaseRepositoryAdapter.java @@ -0,0 +1,36 @@ +package com.cuoco.adapter.out.hibernate; + +import com.cuoco.adapter.exception.NotFoundException; +import com.cuoco.adapter.out.hibernate.model.UserPaymentsHibernateModel; +import com.cuoco.adapter.out.hibernate.repository.GetUserPaymentByExternalReferenceHibernateRepositoryAdapter; +import com.cuoco.application.port.out.GetUserPaymentByExternalReferenceRepository; +import com.cuoco.application.usecase.model.UserPayment; +import com.cuoco.shared.model.ErrorDescription; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class GetUserPaymentByExternalReferenceDatabaseRepositoryAdapter implements GetUserPaymentByExternalReferenceRepository { + + private final GetUserPaymentByExternalReferenceHibernateRepositoryAdapter getUserPaymentByExternalReferenceHibernateRepositoryAdapter; + + @Override + public UserPayment execute(String externalReference) { + log.info("Executing get user payment by external reference {}", externalReference); + + Optional maybeResponse = getUserPaymentByExternalReferenceHibernateRepositoryAdapter.findByExternalReference(externalReference); + + if(!maybeResponse.isPresent()) { + log.info("Not found user payment with external reference {}", externalReference); + throw new NotFoundException(ErrorDescription.NOT_FOUND.getValue()); + } + + UserPaymentsHibernateModel response = maybeResponse.get(); + return response.toDomain(); + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/UpdateUserPaymentDatabaseRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/UpdateUserPaymentDatabaseRepositoryAdapter.java new file mode 100644 index 0000000..eafebc8 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/UpdateUserPaymentDatabaseRepositoryAdapter.java @@ -0,0 +1,40 @@ +package com.cuoco.adapter.out.hibernate; + +import com.cuoco.adapter.out.hibernate.model.UserHibernateModel; +import com.cuoco.adapter.out.hibernate.model.UserPaymentsHibernateModel; +import com.cuoco.adapter.out.hibernate.repository.CreateUserPaymentHibernateRepositoryAdapter; +import com.cuoco.application.port.out.CreateUserPaymentRepository; +import com.cuoco.application.port.out.UpdateUserPaymentRepository; +import com.cuoco.application.usecase.model.UserPayment; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Repository; + +@Slf4j +@Repository +@Qualifier("repository") +@RequiredArgsConstructor +public class UpdateUserPaymentDatabaseRepositoryAdapter implements UpdateUserPaymentRepository { + + private final CreateUserPaymentHibernateRepositoryAdapter createUserPaymentHibernateRepositoryAdapter; + + @Override + public UserPayment execute(UserPayment userPayment) { + log.info("Executing update user payment in database"); + + UserPaymentsHibernateModel userPaymentToUpdate = UserPaymentsHibernateModel.fromDomain(userPayment); + + userPaymentToUpdate.setUser(UserHibernateModel.builder().id(userPayment.getUser().getId()).build()); + + UserPaymentsHibernateModel updatedUserPayment = createUserPaymentHibernateRepositoryAdapter.save(userPaymentToUpdate); + + log.info("Updated user payment with ID {}", updatedUserPayment.getId()); + + UserPayment response = updatedUserPayment.toDomain(); + + response.setUser(userPayment.getUser()); + + return response; + } +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java index 33496b0..d110762 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/PaymentStatusHibernateModel.java @@ -22,7 +22,7 @@ public class PaymentStatusHibernateModel { private Integer id; private String description; - public PaymentStatusHibernateModel fromDomain(PaymentStatus paymentStatus) { + public static PaymentStatusHibernateModel fromDomain(PaymentStatus paymentStatus) { return PaymentStatusHibernateModel.builder() .id(paymentStatus.getId()) .description(paymentStatus.getDescription()) diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java index 931cb29..80e8540 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/PlanHibernateModel.java @@ -32,7 +32,7 @@ public static PlanHibernateModel fromDomain(Plan plan) { return PlanHibernateModel.builder() .id(plan.getId()) .description(plan.getDescription()) - .configuration(PlanConfigurationHibernateModel.fromDomain(plan.getConfiguration())) + .configuration(plan.getConfiguration() != null ? PlanConfigurationHibernateModel.fromDomain(plan.getConfiguration()) : null) .build(); } diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java index 8375734..d002f32 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserHibernateModel.java @@ -1,6 +1,7 @@ package com.cuoco.adapter.out.hibernate.model; import com.cuoco.application.usecase.model.User; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -40,6 +41,9 @@ public class UserHibernateModel { private LocalDateTime updatedAt; private LocalDateTime deletedAt; + @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) + private UserPreferencesHibernateModel preferences; + @ManyToMany @JoinTable( name = "user_allergies", @@ -75,6 +79,22 @@ public class UserHibernateModel { @OneToMany(mappedBy = "user") private List calendars; + public static UserHibernateModel fromDomain(User user) { + return UserHibernateModel.builder() + .id(user.getId()) + .name(user.getName()) + .email(user.getEmail()) + .password(user.getPassword()) + .plan(PlanHibernateModel.fromDomain(user.getPlan())) + .active(user.getActive()) + .preferences(UserPreferencesHibernateModel.fromDomain(user.getPreferences())) + .createdAt(LocalDateTime.now()) + .updatedAt(LocalDateTime.now()) + .dietaryNeeds(user.getDietaryNeeds().stream().map(DietaryNeedHibernateModel::fromDomain).toList()) + .allergies(user.getAllergies().stream().map(AllergyHibernateModel::fromDomain).toList()) + .build(); + } + public User toDomain() { return User.builder() .id(id) diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java index e3d08d6..7e9bc8f 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPaymentsHibernateModel.java @@ -1,5 +1,6 @@ package com.cuoco.adapter.out.hibernate.model; +import com.cuoco.application.usecase.model.User; import com.cuoco.application.usecase.model.UserPayment; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -33,6 +34,10 @@ public class UserPaymentsHibernateModel { @JoinColumn(name = "to_plan_id") private PlanHibernateModel toPlan; + @OneToOne + @JoinColumn(name = "status_id") + private PaymentStatusHibernateModel status; + private String externalId; private String externalReference; private String checkoutUrl; @@ -43,7 +48,9 @@ public class UserPaymentsHibernateModel { public static UserPaymentsHibernateModel fromDomain(UserPayment userPayment) { return UserPaymentsHibernateModel.builder() .id(userPayment.getId()) + .user(UserHibernateModel.fromDomain(userPayment.getUser())) .toPlan(PlanHibernateModel.fromDomain(userPayment.getPlan())) + .status(PaymentStatusHibernateModel.fromDomain(userPayment.getStatus())) .externalId(userPayment.getExternalId()) .externalReference(userPayment.getExternalReference()) .checkoutUrl(userPayment.getCheckoutUrl()) @@ -52,7 +59,10 @@ public static UserPaymentsHibernateModel fromDomain(UserPayment userPayment) { public UserPayment toDomain() { return UserPayment.builder() + .id(id) + .user(user.toDomain()) .plan(toPlan.toDomain()) + .status(status.toDomain()) .externalId(externalId) .externalReference(externalReference) .checkoutUrl(checkoutUrl) diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPreferencesHibernateModel.java b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPreferencesHibernateModel.java index 2ac3218..c0e9ce8 100644 --- a/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPreferencesHibernateModel.java +++ b/src/main/java/com/cuoco/adapter/out/hibernate/model/UserPreferencesHibernateModel.java @@ -36,6 +36,14 @@ public class UserPreferencesHibernateModel { @JoinColumn(name = "diet_id", referencedColumnName = "id") private DietHibernateModel diet; + public static UserPreferencesHibernateModel fromDomain(UserPreferences userPreferences) { + return UserPreferencesHibernateModel.builder() + .id(userPreferences.getId()) + .cookLevel(CookLevelHibernateModel.fromDomain(userPreferences.getCookLevel())) + .diet(DietHibernateModel.fromDomain(userPreferences.getDiet())) + .build(); + } + public UserPreferences toDomain() { return UserPreferences.builder() .id(id) diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/repository/GetAllPaymentStatusHibernateRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/repository/GetAllPaymentStatusHibernateRepositoryAdapter.java new file mode 100644 index 0000000..2183d21 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/repository/GetAllPaymentStatusHibernateRepositoryAdapter.java @@ -0,0 +1,7 @@ +package com.cuoco.adapter.out.hibernate.repository; + +import com.cuoco.adapter.out.hibernate.model.PaymentStatusHibernateModel; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface GetAllPaymentStatusHibernateRepositoryAdapter extends JpaRepository { +} diff --git a/src/main/java/com/cuoco/adapter/out/hibernate/repository/GetUserPaymentByExternalReferenceHibernateRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/hibernate/repository/GetUserPaymentByExternalReferenceHibernateRepositoryAdapter.java new file mode 100644 index 0000000..5a14ae5 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/hibernate/repository/GetUserPaymentByExternalReferenceHibernateRepositoryAdapter.java @@ -0,0 +1,12 @@ +package com.cuoco.adapter.out.hibernate.repository; + +import com.cuoco.adapter.out.hibernate.model.UserPaymentsHibernateModel; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface GetUserPaymentByExternalReferenceHibernateRepositoryAdapter extends JpaRepository { + + Optional findByExternalReference(String externalReference); + +} diff --git a/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoPagoRepositoryAdapter.java similarity index 90% rename from src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java rename to src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoPagoRepositoryAdapter.java index 012351b..d26c5ea 100644 --- a/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoLibreRepositoryAdapter.java +++ b/src/main/java/com/cuoco/adapter/out/mercadopago/CreateUserPaymentMercadoPagoRepositoryAdapter.java @@ -2,6 +2,7 @@ import com.cuoco.adapter.exception.NotAvailableException; import com.cuoco.application.port.out.CreateUserPaymentRepository; +import com.cuoco.application.usecase.model.PaymentStatus; import com.cuoco.application.usecase.model.Plan; import com.cuoco.application.usecase.model.PlanConfiguration; import com.cuoco.application.usecase.model.User; @@ -9,6 +10,7 @@ import com.cuoco.shared.config.mercadopago.MercadoPagoConfig; import com.cuoco.shared.model.ErrorDescription; import com.cuoco.shared.utils.Constants; +import com.cuoco.shared.utils.PaymentConstants; import com.mercadopago.client.preference.PreferenceBackUrlsRequest; import com.mercadopago.client.preference.PreferenceClient; import com.mercadopago.client.preference.PreferenceItemRequest; @@ -29,7 +31,7 @@ @Component @Qualifier("provider") @RequiredArgsConstructor -public class CreateUserPaymentMercadoLibreRepositoryAdapter implements CreateUserPaymentRepository { +public class CreateUserPaymentMercadoPagoRepositoryAdapter implements CreateUserPaymentRepository { private static final String EXTERNAL_REFERENCE_PREFIX = "CUOCO_PRO_UPGRADE"; private static final String HOST_DOMAIN = "cuoco.com.ar"; @@ -81,17 +83,16 @@ private String generateExternalReference(Long userId) { private PreferenceRequest buildPreference(UserPayment userPayment) { return PreferenceRequest.builder() .items(List.of(buildItems(userPayment.getPlan()))) - .backUrls(buildBackUrls()) .externalReference(generateExternalReference(userPayment.getUser().getId())) + .backUrls(buildBackUrls()) + .autoReturn("approved") .build(); } private PreferenceBackUrlsRequest buildBackUrls() { - String host = request.getRequestURL().toString().replace(request.getRequestURI(), Constants.EMPTY.getValue()); - String contextPath = host.contains(HOST_DOMAIN) ? API_CONTEXT : Constants.EMPTY.getValue(); - String baseUrl = host + contextPath; - + String baseUrl = request.getRequestURL().toString().replace(request.getRequestURI(), Constants.EMPTY.getValue()); + return PreferenceBackUrlsRequest.builder() .success(baseUrl + config.getCallbacks().getSuccess()) .pending(baseUrl + config.getCallbacks().getPending()) @@ -115,6 +116,7 @@ private UserPayment buildResponse(UserPayment request, Preference preference) { return UserPayment.builder() .user(request.getUser()) .plan(request.getPlan()) + .status(PaymentStatus.builder().id(PaymentConstants.STATUS_PENDING.getValue()).build()) .externalId(preference.getId()) .checkoutUrl(preference.getInitPoint()) .externalReference(preference.getExternalReference()) diff --git a/src/main/java/com/cuoco/adapter/out/mercadopago/ProcessUserPaymentMercadoPagoRepositoryAdapter.java b/src/main/java/com/cuoco/adapter/out/mercadopago/ProcessUserPaymentMercadoPagoRepositoryAdapter.java new file mode 100644 index 0000000..4287759 --- /dev/null +++ b/src/main/java/com/cuoco/adapter/out/mercadopago/ProcessUserPaymentMercadoPagoRepositoryAdapter.java @@ -0,0 +1,46 @@ +package com.cuoco.adapter.out.mercadopago; + +import com.cuoco.adapter.exception.UnauthorizedException; +import com.cuoco.application.port.out.ProcessUserPaymentRepository; +import com.cuoco.application.usecase.model.PaymentStatus; +import com.cuoco.application.usecase.model.UserPayment; +import com.cuoco.shared.config.mercadopago.MercadoPagoConfig; +import com.cuoco.shared.model.ErrorDescription; +import com.mercadopago.client.payment.PaymentClient; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.resources.payment.Payment; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class ProcessUserPaymentMercadoPagoRepositoryAdapter implements ProcessUserPaymentRepository { + + private final MercadoPagoConfig config; + + @Override + public UserPayment execute(String paymentId) { + + com.mercadopago.MercadoPagoConfig.setAccessToken(config.getAccessToken()); + + try { + PaymentClient client = new PaymentClient(); + Payment payment = client.get(Long.parseLong(paymentId)); + + UserPayment response = UserPayment.builder() + .status(PaymentStatus.builder().description(payment.getStatus()).build()) + .externalReference(payment.getExternalReference()) + .build(); + + log.info("Payment info received with status={} and external_reference={}", response.getStatus(), response.getExternalReference()); + + return response; + } catch (MPException | MPApiException e) { + log.error("Error fetching payment details from MercadoPago", e); + throw new UnauthorizedException(ErrorDescription.NOT_AVAILABLE.getValue()); + } + } +} diff --git a/src/main/java/com/cuoco/application/port/in/ProcessUserPaymentCommand.java b/src/main/java/com/cuoco/application/port/in/ProcessUserPaymentCommand.java new file mode 100644 index 0000000..d31a50b --- /dev/null +++ b/src/main/java/com/cuoco/application/port/in/ProcessUserPaymentCommand.java @@ -0,0 +1,17 @@ +package com.cuoco.application.port.in; + +import lombok.Builder; +import lombok.Data; + +import java.util.Map; + +public interface ProcessUserPaymentCommand { + void execute(Command command); + + @Data + @Builder + class Command { + private String secret; + private Map payload; + } +} diff --git a/src/main/java/com/cuoco/application/port/out/GetAllPaymentStatusRepository.java b/src/main/java/com/cuoco/application/port/out/GetAllPaymentStatusRepository.java new file mode 100644 index 0000000..d580ce2 --- /dev/null +++ b/src/main/java/com/cuoco/application/port/out/GetAllPaymentStatusRepository.java @@ -0,0 +1,9 @@ +package com.cuoco.application.port.out; + +import com.cuoco.application.usecase.model.PaymentStatus; + +import java.util.List; + +public interface GetAllPaymentStatusRepository { + List getAll(); +} diff --git a/src/main/java/com/cuoco/application/port/out/GetUserPaymentByExternalReferenceRepository.java b/src/main/java/com/cuoco/application/port/out/GetUserPaymentByExternalReferenceRepository.java new file mode 100644 index 0000000..6339a48 --- /dev/null +++ b/src/main/java/com/cuoco/application/port/out/GetUserPaymentByExternalReferenceRepository.java @@ -0,0 +1,7 @@ +package com.cuoco.application.port.out; + +import com.cuoco.application.usecase.model.UserPayment; + +public interface GetUserPaymentByExternalReferenceRepository { + UserPayment execute(String externalReference); +} diff --git a/src/main/java/com/cuoco/application/port/out/ProcessUserPaymentRepository.java b/src/main/java/com/cuoco/application/port/out/ProcessUserPaymentRepository.java new file mode 100644 index 0000000..1546eea --- /dev/null +++ b/src/main/java/com/cuoco/application/port/out/ProcessUserPaymentRepository.java @@ -0,0 +1,7 @@ +package com.cuoco.application.port.out; + +import com.cuoco.application.usecase.model.UserPayment; + +public interface ProcessUserPaymentRepository { + UserPayment execute(String paymentId); +} diff --git a/src/main/java/com/cuoco/application/port/out/UpdateUserPaymentRepository.java b/src/main/java/com/cuoco/application/port/out/UpdateUserPaymentRepository.java new file mode 100644 index 0000000..0cdfc75 --- /dev/null +++ b/src/main/java/com/cuoco/application/port/out/UpdateUserPaymentRepository.java @@ -0,0 +1,7 @@ +package com.cuoco.application.port.out; + +import com.cuoco.application.usecase.model.UserPayment; + +public interface UpdateUserPaymentRepository { + UserPayment execute(UserPayment userPayment); +} diff --git a/src/main/java/com/cuoco/application/usecase/ProcessUserPaymentUseCase.java b/src/main/java/com/cuoco/application/usecase/ProcessUserPaymentUseCase.java new file mode 100644 index 0000000..604e596 --- /dev/null +++ b/src/main/java/com/cuoco/application/usecase/ProcessUserPaymentUseCase.java @@ -0,0 +1,77 @@ +package com.cuoco.application.usecase; + +import com.cuoco.application.port.in.ProcessUserPaymentCommand; +import com.cuoco.application.port.out.GetAllPaymentStatusRepository; +import com.cuoco.application.port.out.GetUserByIdRepository; +import com.cuoco.application.port.out.GetUserPaymentByExternalReferenceRepository; +import com.cuoco.application.port.out.ProcessUserPaymentRepository; +import com.cuoco.application.port.out.UpdateUserPaymentRepository; +import com.cuoco.application.port.out.UpdateUserRepository; +import com.cuoco.application.usecase.model.PaymentStatus; +import com.cuoco.application.usecase.model.User; +import com.cuoco.application.usecase.model.UserPayment; +import com.cuoco.shared.utils.PaymentConstants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ProcessUserPaymentUseCase implements ProcessUserPaymentCommand { + + private static final String PAYMENT = "payment"; + private static final String APPROVED = "approved"; + + private final ProcessUserPaymentRepository processPaymentProvider; + private final GetUserPaymentByExternalReferenceRepository getUserPaymentByExternalReferenceRepository; + private final UpdateUserPaymentRepository updateUserPaymentRepository; + private final UpdateUserRepository updateUserRepository; + private final GetUserByIdRepository getUserByIdRepository; + + @Override + public void execute(Command command) { + log.info("Execute user process payment with command {}", command); + + String type = (String) command.getPayload().get("type"); + String paymentId = getPaymentId(command.getPayload()); + + if (PAYMENT.equalsIgnoreCase(type) && (paymentId != null)) { + UserPayment receivedPayment = processPaymentProvider.execute(paymentId); + + if (receivedPayment.getStatus().getDescription().equalsIgnoreCase(APPROVED)) { + + UserPayment userPayment = getUserPaymentByExternalReferenceRepository.execute(receivedPayment.getExternalReference()); + + User user = getUserByIdRepository.execute(userPayment.getUser().getId()); + + userPayment.setUser(user); + + userPayment.setStatus(PaymentStatus.builder().id(PaymentConstants.STATUS_APPROVED.getValue()).build()); + + updateUserPlan(userPayment); + + updateUserPaymentRepository.execute(userPayment); + } + } + } + + private void updateUserPlan(UserPayment userPayment) { + User user = userPayment.getUser(); + user.setPlan(userPayment.getPlan()); + + updateUserRepository.execute(user); + } + + private String getPaymentId(Map payload) { + if(payload.containsKey("data") && payload.get("data") != null) { + return String.valueOf(((Map) payload.get("data")).get("id")); + } + + return null; + } +} diff --git a/src/main/java/com/cuoco/application/usecase/model/UserPayment.java b/src/main/java/com/cuoco/application/usecase/model/UserPayment.java index 3f312cc..f4a8455 100644 --- a/src/main/java/com/cuoco/application/usecase/model/UserPayment.java +++ b/src/main/java/com/cuoco/application/usecase/model/UserPayment.java @@ -10,6 +10,7 @@ public class UserPayment { private Long id; private User user; private Plan plan; + private PaymentStatus status; private String externalId; private String externalReference; private String checkoutUrl; diff --git a/src/main/java/com/cuoco/shared/config/security/SecurityConfiguration.java b/src/main/java/com/cuoco/shared/config/security/SecurityConfiguration.java index 3c63221..e0b8fa9 100644 --- a/src/main/java/com/cuoco/shared/config/security/SecurityConfiguration.java +++ b/src/main/java/com/cuoco/shared/config/security/SecurityConfiguration.java @@ -41,6 +41,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/preparation-times", "/dietary-needs", "/allergies", + "/payments/webhook", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html" diff --git a/src/main/java/com/cuoco/shared/utils/PaymentConstants.java b/src/main/java/com/cuoco/shared/utils/PaymentConstants.java new file mode 100644 index 0000000..b3a81cf --- /dev/null +++ b/src/main/java/com/cuoco/shared/utils/PaymentConstants.java @@ -0,0 +1,17 @@ +package com.cuoco.shared.utils; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PaymentConstants { + + STATUS_PENDING(1), + STATUS_APPROVED(2), + STATUS_IN_PROCESS(3), + STATUS_REJECTED(4); + + private final int value; + +} \ No newline at end of file diff --git a/src/main/resources/sql/ddl/05_inserts.sql b/src/main/resources/sql/ddl/05_inserts.sql index 480ae98..46c4322 100644 --- a/src/main/resources/sql/ddl/05_inserts.sql +++ b/src/main/resources/sql/ddl/05_inserts.sql @@ -5,6 +5,15 @@ VALUES (1, 'Free'), INSERT INTO plan_configuration (id, title, description, quantity, price, currency) VALUES (1, 'Cuoco Pro - Plan Premium', 'Actualiza a Pro: Recetas ilimitadas, filtros avanzados, meal preps y mucho más', 1, 500.00, 'ARS'); +INSERT INTO payment_status (id, description) +VALUES (1, 'pending'), + (2, 'approved'), + (3, 'in_process'), + (4, 'rejected'), + (5, 'cancelled'), + (6, 'refunded'), + (7, 'charged_back'); + INSERT INTO cook_levels (id, description) VALUES (1, 'Bajo'), (2, 'Medio'),