diff --git a/src/main/java/com/checkout/handlepaymentsandpayouts/googlepay/responses/GooglePayEnrollmentResponse.java b/src/main/java/com/checkout/handlepaymentsandpayouts/googlepay/responses/GooglePayEnrollmentResponse.java index c2a92faa..16164460 100644 --- a/src/main/java/com/checkout/handlepaymentsandpayouts/googlepay/responses/GooglePayEnrollmentResponse.java +++ b/src/main/java/com/checkout/handlepaymentsandpayouts/googlepay/responses/GooglePayEnrollmentResponse.java @@ -9,12 +9,24 @@ /** * Response returned when enrolling an entity in Google Pay. + * + *
The real 201 body carries merchant_id, tos_accepted_time and state. The spec declares only + * {@code tosAcceptedTime} and {@code state}, with {@code additionalProperties false}, so + * {@code merchant_id} was missing here: this class was generated faithfully from a wrong schema. + * Reported by a merchant. The spec is being fixed separately; until then this class follows the + * live API.
*/ @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public final class GooglePayEnrollmentResponse extends HttpMetadata { + /** + * The Google Pay merchant identifier assigned to the entity, needed to initialise Google Pay + * on the client. Returned by the API but absent from the spec. + */ + private String merchantId; + /** * When the Google terms of service were accepted. *diff --git a/src/test/java/com/checkout/handlepaymentsandpayouts/googlepay/GooglePaySerializationTest.java b/src/test/java/com/checkout/handlepaymentsandpayouts/googlepay/GooglePaySerializationTest.java index 6f346d47..b97744a5 100644 --- a/src/test/java/com/checkout/handlepaymentsandpayouts/googlepay/GooglePaySerializationTest.java +++ b/src/test/java/com/checkout/handlepaymentsandpayouts/googlepay/GooglePaySerializationTest.java @@ -15,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 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.assertTrue; /** @@ -148,6 +149,65 @@ void shouldRoundTripGooglePayEnrollmentResponse() { assertEquals(original.getState(), deserialized.getState()); } + /** + * The body a real POST /googlepay/enrollments returns in sandbox, which is not what the + * swagger example below says: it also carries merchant_id, and the spec omits it while + * setting additionalProperties false. A merchant reported the field as missing. + */ + @Test + void shouldDeserializeTheRealGooglePayEnrollmentResponse() { + String json = "{" + + "\"merchant_id\":\"12345678901234567890\"," + + "\"tos_accepted_time\":\"2026-08-13T09:12:41Z\"," + + "\"state\":\"ACTIVE\"" + + "}"; + + GooglePayEnrollmentResponse response = serializer.fromJson(json, GooglePayEnrollmentResponse.class); + + assertNotNull(response); + assertEquals("12345678901234567890", response.getMerchantId()); + assertEquals(Instant.parse("2026-08-13T09:12:41Z"), response.getTosAcceptedTime()); + assertEquals(GooglePayEnrollmentState.ACTIVE, response.getState()); + } + + /** + * merchant_id is what the caller needs to initialise Google Pay on the client, so losing it + * is the whole defect. Asserted on its own to make that unmissable. + */ + @Test + void shouldNotSilentlyDropMerchantId() { + String json = "{" + + "\"merchant_id\":\"12345678901234567890\"," + + "\"tos_accepted_time\":\"2026-08-13T09:12:41Z\"," + + "\"state\":\"ACTIVE\"" + + "}"; + + assertNotNull(serializer.fromJson(json, GooglePayEnrollmentResponse.class).getMerchantId()); + } + + /** + * A missing merchant_id has to come back null rather than empty: a caller must be able to + * tell "not returned" from "returned blank". + */ + @Test + void shouldLeaveMerchantIdNullWhenAbsent() { + String json = "{\"tos_accepted_time\":\"2026-08-13T09:12:41Z\",\"state\":\"ACTIVE\"}"; + + GooglePayEnrollmentResponse response = serializer.fromJson(json, GooglePayEnrollmentResponse.class); + + assertNull(response.getMerchantId()); + assertEquals(GooglePayEnrollmentState.ACTIVE, response.getState()); + } + + @Test + void shouldSerializeMerchantIdAsSnakeCase() { + GooglePayEnrollmentResponse response = new GooglePayEnrollmentResponse(); + response.setMerchantId("12345678901234567890"); + response.setState(GooglePayEnrollmentState.ACTIVE); + + assertTrue(serializer.toJson(response).contains("\"merchant_id\":\"12345678901234567890\"")); + } + @Test void shouldDeserializeSwaggerExampleGooglePayEnrollmentResponse() { String swaggerJson = "{"