From 56238b2cc6e706a5e7512d798b6b2e2790813f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20Rodr=C3=ADguez?= <127134616+armando-rodriguez-cko@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:50:45 +0100 Subject: [PATCH] Update Product.type to be a string value or enum --- .../java/com/checkout/GsonSerializer.java | 26 ++++ .../java/com/checkout/payments/Product.java | 10 +- .../java/com/checkout/GsonSerializerTest.java | 34 +++++ .../checkout/payments/GetPaymentsTestIT.java | 122 ++++++++++++++++++ 4 files changed, 191 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/checkout/GsonSerializer.java b/src/main/java/com/checkout/GsonSerializer.java index 40a90956..3990aeaf 100644 --- a/src/main/java/com/checkout/GsonSerializer.java +++ b/src/main/java/com/checkout/GsonSerializer.java @@ -18,6 +18,8 @@ import com.checkout.issuing.controls.responses.create.MccCardControlResponse; import com.checkout.issuing.controls.responses.create.VelocityCardControlResponse; import com.checkout.payments.PaymentDestinationType; +import com.checkout.payments.Product; +import com.checkout.payments.ProductType; import com.checkout.payments.previous.PaymentAction; import com.checkout.payments.sender.Sender; import com.checkout.payments.sender.SenderType; @@ -149,6 +151,7 @@ public class GsonSerializer implements Serializer { .registerTypeAdapter(WEBHOOKS_TYPE, webhooksResponseDeserializer()) .registerTypeAdapter(PREVIOUS_PAYMENT_ACTIONS_TYPE, paymentActionsResponsePreviousDeserializer()) .registerTypeAdapter(PAYMENT_ACTIONS_TYPE, paymentActionsResponseDeserializer()) + .registerTypeAdapter(Product.class, getProductDeserializer()) .create(); private final Gson gson; @@ -320,4 +323,27 @@ private static JsonDeserializer<Instant> getInstantJsonDeserializer() { } }; } + + private static JsonDeserializer<Product> getProductDeserializer() { + return (json, typeOfT, context) -> { + JsonObject jsonObject = json.getAsJsonObject(); + + JsonElement typeElement = jsonObject.get("type"); + Object typeValue = null; + + if (typeElement != null && typeElement.isJsonPrimitive()) { + String typeAsString = typeElement.getAsString(); + if (EnumUtils.isValidEnumIgnoreCase(ProductType.class, typeAsString)) { + typeValue = ProductType.valueOf(typeAsString.toUpperCase()); + } else { + typeValue = typeAsString; + } + } + + Product product = new Gson().fromJson(jsonObject, Product.class); + product.setType(typeValue); + + return product; + }; + } } diff --git a/src/main/java/com/checkout/payments/Product.java b/src/main/java/com/checkout/payments/Product.java index 967dc27a..9aedd555 100644 --- a/src/main/java/com/checkout/payments/Product.java +++ b/src/main/java/com/checkout/payments/Product.java @@ -12,7 +12,7 @@ @AllArgsConstructor public final class Product { - private ProductType type; + private Object type; private String name; @@ -54,4 +54,12 @@ public final class Product { @SerializedName("service_ends_on") private Instant serviceEndsOn; + public ProductType getTypeAsEnum() { + return type instanceof ProductType ? (ProductType) type : null; + } + + public String getTypeAsString() { + return type instanceof String ? (String) type : null; + } + } diff --git a/src/test/java/com/checkout/GsonSerializerTest.java b/src/test/java/com/checkout/GsonSerializerTest.java index 86230b2f..3bfd2bee 100644 --- a/src/test/java/com/checkout/GsonSerializerTest.java +++ b/src/test/java/com/checkout/GsonSerializerTest.java @@ -5,6 +5,8 @@ import com.checkout.issuing.cardholders.CardholderCardsResponse; import com.checkout.issuing.cards.responses.PhysicalCardDetailsResponse; import com.checkout.issuing.cards.responses.VirtualCardDetailsResponse; +import com.checkout.payments.Product; +import com.checkout.payments.ProductType; import com.checkout.payments.contexts.PaymentContextDetailsResponse; import com.checkout.payments.previous.response.GetPaymentResponse; import com.checkout.payments.previous.response.PaymentResponse; @@ -171,6 +173,38 @@ void shouldSerializePaymentDetailsResponseFromJson() { assertNotNull(paymentDetailsResponse.getPaymentPlan()); } + @Test + void shouldDeserializeProductWithEnumType() { + String json = "{ \"type\": \"DIGITAL\", \"name\": \"Product Name\" }"; + + Product product = serializer.fromJson(json, Product.class); + + assertNotNull(product); + assertEquals(ProductType.DIGITAL, product.getTypeAsEnum()); + assertNull(product.getTypeAsString()); + } + + @Test + void shouldDeserializeProductWithUnknownEnumValue() { + String json = "{ \"type\": \"UNKNOWN_VALUE\", \"name\": \"Product Name\", \"quantity\": 1, \"unit_price\": 1000 }"; + + Product product = serializer.fromJson(json, Product.class); + + assertNotNull(product); + assertEquals("UNKNOWN_VALUE", product.getTypeAsString()); + assertNull(product.getTypeAsEnum()); + } + + @Test + void shouldDeserializeProductWithNullType() { + String json = "{ \"type\": null, \"name\": \"Product Name\" }"; + + Product product = serializer.fromJson(json, Product.class); + + assertNotNull(product); + assertNull(product.getType()); + } + @Test void shouldDeserializeMultipleDateFormats() { Instant instant = Instant.parse("2021-06-08T00:00:00Z"); diff --git a/src/test/java/com/checkout/payments/GetPaymentsTestIT.java b/src/test/java/com/checkout/payments/GetPaymentsTestIT.java index 7fcc8204..017f430d 100644 --- a/src/test/java/com/checkout/payments/GetPaymentsTestIT.java +++ b/src/test/java/com/checkout/payments/GetPaymentsTestIT.java @@ -12,6 +12,8 @@ import com.checkout.payments.sender.PaymentIndividualSender; import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -21,6 +23,7 @@ import static com.checkout.CardSourceHelper.getRequestCardSource; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -48,6 +51,125 @@ void shouldGetCardPayment() { } + @Test + void shouldGetPaymentWithItemsUsingEnumType() { + + Product product = Product.builder() + .type(ProductType.DIGITAL) + .name("Test Product") + .quantity(1L) + .unitPrice(1000L) + .build(); + + PaymentRequest request = PaymentRequest.builder() + .source(getRequestCardSource()) + .reference(UUID.randomUUID().toString()) + .amount(1000L) + .currency(Currency.EUR) + .processingChannelId(System.getenv("CHECKOUT_PROCESSING_CHANNEL_ID")) + .items(Collections.singletonList(product)) + .build(); + + PaymentResponse payment = blocking(() -> paymentsClient.requestPayment(request)); + + GetPaymentResponse paymentReturned = blocking(() -> paymentsClient.getPayment(payment.getId())); + + assertNotNull(paymentReturned); + assertNotNull(paymentReturned.getItems()); + assertEquals(1, paymentReturned.getItems().size()); + + Product returnedProduct = paymentReturned.getItems().get(0); + assertEquals(ProductType.DIGITAL, returnedProduct.getTypeAsEnum()); + assertNull(returnedProduct.getTypeAsString()); + assertEquals("Test Product", returnedProduct.getName()); + assertEquals(1L, returnedProduct.getQuantity()); + assertEquals(1000L, returnedProduct.getUnitPrice()); + } + + @Test + void shouldGetPaymentWithItemsUsingStringType() { + + Product product = Product.builder() + .type("CustomType") + .name("Custom Product") + .quantity(2L) + .unitPrice(2000L) + .build(); + + PaymentRequest request = PaymentRequest.builder() + .source(getRequestCardSource()) + .reference(UUID.randomUUID().toString()) + .amount(2000L) + .currency(Currency.EUR) + .processingChannelId(System.getenv("CHECKOUT_PROCESSING_CHANNEL_ID")) + .items(Collections.singletonList(product)) + .build(); + + PaymentResponse payment = blocking(() -> paymentsClient.requestPayment(request)); + + GetPaymentResponse paymentReturned = blocking(() -> paymentsClient.getPayment(payment.getId())); + + assertNotNull(paymentReturned); + assertNotNull(paymentReturned.getItems()); + assertEquals(1, paymentReturned.getItems().size()); + + Product returnedProduct = paymentReturned.getItems().get(0); + assertEquals("CustomType", returnedProduct.getTypeAsString()); + assertNull(returnedProduct.getTypeAsEnum()); + assertEquals("Custom Product", returnedProduct.getName()); + assertEquals(2L, returnedProduct.getQuantity()); + assertEquals(2000L, returnedProduct.getUnitPrice()); + } + + @Test + void shouldGetPaymentWithMultipleItems() { + + Product enumProduct = Product.builder() + .type(ProductType.PHYSICAL) + .name("Physical Product") + .quantity(1L) + .unitPrice(1500L) + .build(); + + Product stringProduct = Product.builder() + .type("CustomType") + .name("Custom Product") + .quantity(2L) + .unitPrice(3000L) + .build(); + + PaymentRequest request = PaymentRequest.builder() + .source(getRequestCardSource()) + .reference(UUID.randomUUID().toString()) + .amount(4500L) + .currency(Currency.EUR) + .processingChannelId(System.getenv("CHECKOUT_PROCESSING_CHANNEL_ID")) + .items(Arrays.asList(enumProduct, stringProduct)) + .build(); + + PaymentResponse payment = blocking(() -> paymentsClient.requestPayment(request)); + + GetPaymentResponse paymentReturned = blocking(() -> paymentsClient.getPayment(payment.getId())); + + assertNotNull(paymentReturned); + assertNotNull(paymentReturned.getItems()); + assertEquals(2, paymentReturned.getItems().size()); + + Product returnedEnumProduct = paymentReturned.getItems().get(0); + assertEquals(ProductType.PHYSICAL, returnedEnumProduct.getTypeAsEnum()); + assertNull(returnedEnumProduct.getTypeAsString()); + assertEquals("Physical Product", returnedEnumProduct.getName()); + assertEquals(1L, returnedEnumProduct.getQuantity()); + assertEquals(1500L, returnedEnumProduct.getUnitPrice()); + + Product returnedStringProduct = paymentReturned.getItems().get(1); + assertEquals("CustomType", returnedStringProduct.getTypeAsString()); + assertNull(returnedStringProduct.getTypeAsEnum()); + assertEquals("Custom Product", returnedStringProduct.getName()); + assertEquals(2L, returnedStringProduct.getQuantity()); + assertEquals(3000L, returnedStringProduct.getUnitPrice()); + } + @Test void shouldGetCardPaymentWithMetadata() {