Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,24 @@

/**
* Response returned when enrolling an entity in Google Pay.
*
* <p>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.</p>
*/
@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.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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 = "{"
Expand Down
Loading