diff --git a/src/main/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/risk/Risk.java b/src/main/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/risk/Risk.java index 1c7830ab7..f392e056d 100644 --- a/src/main/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/risk/Risk.java +++ b/src/main/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/risk/Risk.java @@ -26,8 +26,9 @@ public final class Risk { /** * The risk score calculated by our Fraud Detection engine. Absent if not enough data provided. * [Optional] + * Decimal number, for example 22.5 * [ 0 .. 100 ] */ - private Integer score; + private Double score; } diff --git a/src/main/java/com/checkout/payments/RiskAssessment.java b/src/main/java/com/checkout/payments/RiskAssessment.java index 7349e2b4b..fb8923de7 100644 --- a/src/main/java/com/checkout/payments/RiskAssessment.java +++ b/src/main/java/com/checkout/payments/RiskAssessment.java @@ -2,10 +2,24 @@ import lombok.Data; +/** + * Returns the payment's risk assessment results. + */ @Data public final class RiskAssessment { + /** + * Whether or not the payment was flagged by a risk check. + * [Optional] + * Default: false + */ private Boolean flagged; - private Integer score; + /** + * The risk score calculated by our Fraud Detection engine. Absent if not enough data provided. + * [Optional] + * Decimal number, for example 22.5 + * [ 0 .. 100 ] + */ + private Double score; } diff --git a/src/test/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/RequestAPaymentOrPayoutResponseCreatedSerializationTest.java b/src/test/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/RequestAPaymentOrPayoutResponseCreatedSerializationTest.java index dd3fe6796..ee3fe6f09 100644 --- a/src/test/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/RequestAPaymentOrPayoutResponseCreatedSerializationTest.java +++ b/src/test/java/com/checkout/handlepaymentsandpayouts/payments/postpayments/responses/requestapaymentorpayoutresponsecreated/RequestAPaymentOrPayoutResponseCreatedSerializationTest.java @@ -1,8 +1,11 @@ package com.checkout.handlepaymentsandpayouts.payments.postpayments.responses.requestapaymentorpayoutresponsecreated; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -18,6 +21,7 @@ import com.checkout.handlepaymentsandpayouts.payments.common.source.paypalsource.PaypalSource; import com.checkout.handlepaymentsandpayouts.payments.common.source.sepasource.SepaSource; import com.checkout.handlepaymentsandpayouts.payments.postpayments.responses.requestapaymentorpayoutresponsecreated.processing.Processing; +import com.checkout.handlepaymentsandpayouts.payments.postpayments.responses.requestapaymentorpayoutresponsecreated.risk.Risk; public final class RequestAPaymentOrPayoutResponseCreatedSerializationTest { @@ -244,4 +248,57 @@ void shouldDeserializeProcessingSchemeTransactionLinkId() { assertEquals("MTL-XYZ-789", processing.getSchemeTransactionLinkId()); } + // ------------------------------------------------------------------------ + // Risk + // Returns the payment's risk assessment results. score is type number, + // min 0, max 100, so a fractional value must deserialize without error + // and without rounding. + // ------------------------------------------------------------------------ + + @Test + void shouldDeserializeRiskWithFractionalScore() { + String json = "{\"id\":\"pay_123\",\"risk\":{\"flagged\":true,\"score\":22.5}}"; + + RequestAPaymentOrPayoutResponseCreated response = serializer.fromJson(json, RequestAPaymentOrPayoutResponseCreated.class); + + Risk risk = response.getRisk(); + assertNotNull(risk); + assertTrue(risk.getFlagged()); + assertEquals(22.5, risk.getScore()); + } + + @Test + void shouldDeserializeRiskSwaggerExample() { + String json = "{\"id\":\"pay_123\",\"risk\":{\"flagged\":true,\"score\":22}}"; + + RequestAPaymentOrPayoutResponseCreated response = serializer.fromJson(json, RequestAPaymentOrPayoutResponseCreated.class); + + assertEquals(22.0, response.getRisk().getScore()); + } + + @Test + void shouldDeserializeRiskBoundaryScores() { + assertEquals(0.0, serializer.fromJson("{\"score\":0}", Risk.class).getScore()); + assertEquals(100.0, serializer.fromJson("{\"score\":100}", Risk.class).getScore()); + } + + @Test + void shouldDeserializeRiskWithNullScore() { + Risk risk = serializer.fromJson("{\"flagged\":false}", Risk.class); + + assertFalse(risk.getFlagged()); + assertNull(risk.getScore()); + } + + @Test + void shouldRoundTripRiskAllProperties() { + Risk original = Risk.builder().flagged(true).score(22.5).build(); + + String json = serializer.toJson(original); + Risk deserialized = serializer.fromJson(json, Risk.class); + + assertTrue(json.contains("\"score\":22.5"), json); + assertEquals(original, deserialized); + } + } diff --git a/src/test/java/com/checkout/payments/RiskAssessmentSerializationTest.java b/src/test/java/com/checkout/payments/RiskAssessmentSerializationTest.java new file mode 100644 index 000000000..7cc217f88 --- /dev/null +++ b/src/test/java/com/checkout/payments/RiskAssessmentSerializationTest.java @@ -0,0 +1,107 @@ +package com.checkout.payments; + +import com.checkout.GsonSerializer; +import com.checkout.payments.response.GetPaymentResponse; +import com.checkout.payments.response.PaymentResponse; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class RiskAssessmentSerializationTest { + + private final GsonSerializer serializer = new GsonSerializer(); + + // ------------------------------------------------------------------------ + // RiskAssessment + // Returns the payment's risk assessment results. Covers both properties + // (flagged, score) against the risk object of the PaymentResponse and + // PaymentDetails schemas, where score is type number, min 0, max 100. + // ------------------------------------------------------------------------ + + @Test + void shouldDeserializeFractionalScoreWithoutRounding() { + final RiskAssessment risk = serializer.fromJson("{\"flagged\":true,\"score\":22.5}", RiskAssessment.class); + + assertTrue(risk.getFlagged()); + assertEquals(22.5, risk.getScore()); + } + + @Test + void shouldDeserializeWholeNumberScore() { + final RiskAssessment risk = serializer.fromJson("{\"flagged\":false,\"score\":22}", RiskAssessment.class); + + assertFalse(risk.getFlagged()); + assertEquals(22.0, risk.getScore()); + } + + @Test + void shouldDeserializeBoundaryScores() { + assertEquals(0.0, serializer.fromJson("{\"score\":0}", RiskAssessment.class).getScore()); + assertEquals(100.0, serializer.fromJson("{\"score\":100}", RiskAssessment.class).getScore()); + } + + @Test + void shouldDeserializeWithNullOptionalProperties() { + final RiskAssessment risk = serializer.fromJson("{}", RiskAssessment.class); + + assertNull(risk.getFlagged()); + assertNull(risk.getScore()); + } + + @Test + void shouldSerializeFractionalScore() { + final RiskAssessment risk = new RiskAssessment(); + risk.setFlagged(true); + risk.setScore(22.5); + + final String json = serializer.toJson(risk); + + assertTrue(json.contains("\"flagged\":true"), json); + assertTrue(json.contains("\"score\":22.5"), json); + } + + @Test + void shouldRoundTripAllProperties() { + final RiskAssessment original = new RiskAssessment(); + original.setFlagged(true); + original.setScore(22.5); + + final RiskAssessment deserialized = serializer.fromJson(serializer.toJson(original), RiskAssessment.class); + + assertEquals(original, deserialized); + assertEquals(22.5, deserialized.getScore()); + } + + @Test + void shouldDeserializeSwaggerExampleInGetPaymentResponse() { + final String json = "{\"id\":\"pay_mbabizu24mvu3mela5njyhpit4\",\"risk\":{\"flagged\":true,\"score\":22}}"; + + final GetPaymentResponse response = serializer.fromJson(json, GetPaymentResponse.class); + + assertNotNull(response.getRisk()); + assertTrue(response.getRisk().getFlagged()); + assertEquals(22.0, response.getRisk().getScore()); + } + + @Test + void shouldDeserializeFractionalScoreInGetPaymentResponse() { + final String json = "{\"id\":\"pay_123\",\"risk\":{\"flagged\":true,\"score\":22.5}}"; + + final GetPaymentResponse response = serializer.fromJson(json, GetPaymentResponse.class); + + assertEquals(22.5, response.getRisk().getScore()); + } + + @Test + void shouldDeserializeFractionalScoreInPaymentResponse() { + final String json = "{\"id\":\"pay_123\",\"risk\":{\"flagged\":false,\"score\":22.7}}"; + + final PaymentResponse response = serializer.fromJson(json, PaymentResponse.class); + + assertEquals(22.7, response.getRisk().getScore()); + } +}