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 @@ -107,8 +107,10 @@ public static BaseEvent buildCustomCheckoutPayEvent(
String apiPath,
EventType eventName) {

// Extracting the instrument from the PgPaymentFlow
PgPaymentFlow pgPaymentFlow = (PgPaymentFlow) pgPaymentRequest.getPaymentFlow();
// Extracting the instrument from the PgPaymentFlow (null-safe: non-PG flows bind to null)
PgPaymentFlow pgPaymentFlow = pgPaymentRequest.getPaymentFlow() instanceof PgPaymentFlow flow
? flow
: null;

// Extracting the targetApp from the paymentMode in PgPaymentFlow
String targetApp = Optional.ofNullable(pgPaymentFlow)
Expand Down
11 changes: 11 additions & 0 deletions src/test/CallbackTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1274,4 +1274,15 @@ void testNotifyValidate() {
jsonString);
Assertions.assertEquals(expected, actual);
}

@Test
void testValidateCallbackStandardCheckoutMalformedJsonThrows() {
org.junit.jupiter.api.Assertions.assertThrows(
Exception.class,
() -> standardCheckoutClient.validateCallback(
"username",
"password",
"bc842c31a9e54efe320d30d948be61291f3ceee4766e36ab25fa65243cd76e0e",
"{not valid json"));
}
}
19 changes: 19 additions & 0 deletions src/test/OrderStatusTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -765,4 +765,23 @@ void testSubscriptionOrderStatus() {

Assertions.assertEquals(responseObject, actual);
}

@Test
void testGetOrderStatusWithoutDetailsFlagDefaultsToFalse() {
String url = String.format(StandardCheckoutConstants.ORDER_STATUS_API, merchantOrderId);
OrderStatusResponse orderStatusResponse =
OrderStatusResponse.builder().orderId("Order_DefaultFlag").state("COMPLETED").build();

addStubForGetRequest(
url,
ImmutableMap.of(StandardCheckoutConstants.ORDER_DETAILS, "false"),
getHeaders(),
HttpStatus.SC_OK,
ImmutableMap.of(),
orderStatusResponse);

// 1-arg overload must delegate to getOrderStatus(id, false)
OrderStatusResponse actual = standardCheckoutClient.getOrderStatus(merchantOrderId);
Assertions.assertEquals(actual, orderStatusResponse);
}
}
28 changes: 28 additions & 0 deletions src/test/RefundTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,32 @@ void testRefundSubscriptionThrows404() {
Assertions.assertEquals(404, phonePeException.getHttpStatusCode());
Assertions.assertEquals("Not Found", phonePeException.getMessage());
}

@Test
void testGetRefundStatusStandardCheckoutFails() {
String refundId = "RefundIdNotFound";
String url = String.format(StandardCheckoutConstants.REFUND_STATUS_API, refundId);

PhonePeResponse errorResponse =
PhonePeResponse.<Map<String, String>>builder()
.code("REFUND_NOT_FOUND")
.message("Refund does not exist")
.data(Collections.emptyMap())
.build();

addStubForGetRequest(
url,
ImmutableMap.of(),
getHeaders(),
HttpStatus.SC_NOT_FOUND,
ImmutableMap.of(),
errorResponse);

PhonePeException exception =
assertThrows(
PhonePeException.class,
() -> standardCheckoutClient.getRefundStatus(refundId));
Assertions.assertEquals(404, exception.getHttpStatusCode());
Assertions.assertEquals("REFUND_NOT_FOUND", exception.getCode());
}
}
52 changes: 52 additions & 0 deletions src/test/TransactionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,56 @@ void testTransactionSubscriptionClient() {
OrderStatusResponse actual = subscriptionClient.getTransactionStatus(transactionId);
Assertions.assertEquals(actual, transactionCheckStatusResponse);
}

@Test
void testTransactionStatusStandardCheckoutFails() {
String url = String.format(StandardCheckoutConstants.TRANSACTION_STATUS_API, transactionId);

com.phonepe.sdk.pg.common.http.PhonePeResponse errorResponse =
com.phonepe.sdk.pg.common.http.PhonePeResponse.<java.util.Map<String, String>>builder()
.code("TRANSACTION_NOT_FOUND")
.message("Transaction not found")
.data(java.util.Collections.emptyMap())
.build();

addStubForGetRequest(
url,
ImmutableMap.of(),
getHeaders(),
HttpStatus.SC_NOT_FOUND,
ImmutableMap.of(),
errorResponse);

com.phonepe.sdk.pg.common.exception.PhonePeException exception =
org.junit.jupiter.api.Assertions.assertThrows(
com.phonepe.sdk.pg.common.exception.PhonePeException.class,
() -> standardCheckoutClient.getTransactionStatus(transactionId));
Assertions.assertEquals(404, exception.getHttpStatusCode());
}

@Test
void testTransactionStatusCustomCheckoutFails() {
String url = String.format(CustomCheckoutConstants.TRANSACTION_STATUS_API, transactionId);

com.phonepe.sdk.pg.common.http.PhonePeResponse errorResponse =
com.phonepe.sdk.pg.common.http.PhonePeResponse.<java.util.Map<String, String>>builder()
.code("TRANSACTION_NOT_FOUND")
.message("Transaction not found")
.data(java.util.Collections.emptyMap())
.build();

addStubForGetRequest(
url,
ImmutableMap.of(),
getHeaders(),
HttpStatus.SC_NOT_FOUND,
ImmutableMap.of(),
errorResponse);

com.phonepe.sdk.pg.common.exception.PhonePeException exception =
org.junit.jupiter.api.Assertions.assertThrows(
com.phonepe.sdk.pg.common.exception.PhonePeException.class,
() -> customCheckoutClient.getTransactionStatus(transactionId));
Assertions.assertEquals(404, exception.getHttpStatusCode());
}
}
81 changes: 81 additions & 0 deletions src/test/customCheckoutTests/CustomCheckoutClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,85 @@ void testGetRefundStatusNotFound() {
Assertions.assertEquals(404, exception.getHttpStatusCode());
Assertions.assertEquals("REFUND_NOT_FOUND", exception.getCode());
}

// ───────────────────────────────────────────────────────────────────────
// createSdkOrder()
// ───────────────────────────────────────────────────────────────────────

@Test
void testCreateSdkOrderSuccess() {
final String url = CustomCheckoutConstants.CREATE_ORDER_API;

com.phonepe.sdk.pg.payments.v2.models.request.CreateSdkOrderRequest sdkRequest =
com.phonepe.sdk.pg.payments.v2.models.request.CreateSdkOrderRequest
.CustomCheckoutBuilder()
.merchantOrderId("SDK_ORDER_001")
.amount(2000L)
.build();

com.phonepe.sdk.pg.payments.v2.models.response.CreateSdkOrderResponse sdkResponse =
com.phonepe.sdk.pg.payments.v2.models.response.CreateSdkOrderResponse.builder()
.orderId("OMO_SDK_001")
.state("PENDING")
.token("sdk-token-abc")
.expireAt(java.time.Instant.now().getEpochSecond() + 600)
.build();

addStubForPostRequest(
url, getHeaders(), sdkRequest, HttpStatus.SC_OK, Maps.newHashMap(), sdkResponse);

com.phonepe.sdk.pg.payments.v2.models.response.CreateSdkOrderResponse actual =
customCheckoutClient.createSdkOrder(sdkRequest);
Assertions.assertEquals(sdkResponse.getOrderId(), actual.getOrderId());
Assertions.assertEquals(sdkResponse.getToken(), actual.getToken());
}

@Test
void testCreateSdkOrderFailure() {
final String url = CustomCheckoutConstants.CREATE_ORDER_API;

com.phonepe.sdk.pg.payments.v2.models.request.CreateSdkOrderRequest sdkRequest =
com.phonepe.sdk.pg.payments.v2.models.request.CreateSdkOrderRequest
.CustomCheckoutBuilder()
.merchantOrderId("SDK_ORDER_FAIL_001")
.amount(2000L)
.build();

PhonePeResponse errorResponse =
PhonePeResponse.<Map<String, String>>builder()
.code("INTERNAL_SERVER_ERROR")
.message("Something went wrong")
.data(Collections.emptyMap())
.build();

addStubForPostRequest(
url,
getHeaders(),
sdkRequest,
HttpStatus.SC_INTERNAL_SERVER_ERROR,
Maps.newHashMap(),
errorResponse);

PhonePeException exception =
assertThrows(
PhonePeException.class,
() -> customCheckoutClient.createSdkOrder(sdkRequest));
Assertions.assertEquals(500, exception.getHttpStatusCode());
}

// ───────────────────────────────────────────────────────────────────────
// validateCallback()
// ───────────────────────────────────────────────────────────────────────

@Test
void testValidateCallbackMalformedJsonThrows() {
// sha256("username" + "password") = bc842c31a9e54efe320d30d948be61291f3ceee4766e36ab25fa65243cd76e0e
assertThrows(
Exception.class,
() -> customCheckoutClient.validateCallback(
"username",
"password",
"bc842c31a9e54efe320d30d948be61291f3ceee4766e36ab25fa65243cd76e0e",
"{not valid json"));
}
}
37 changes: 37 additions & 0 deletions src/test/customCheckoutTests/CustomCheckoutPciAndDeviceOsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,41 @@ void testPayDoesNotInjectDeviceOsHeaderWhenAbsent() {
PgPaymentResponse actual = customCheckoutClient.pay(request);
Assertions.assertEquals(response.getOrderId(), actual.getOrderId());
}

// ── Non-PgPaymentFlow uses default host (resolveInstrument returns null) ──

@Test
void testNonPgPaymentFlowUsesDefaultHost() throws Exception {
final String url = CustomCheckoutConstants.PAY_API;

// Use SubscriptionNotifyRequestBuilder which sets SubscriptionRedemptionPaymentFlow —
// definitively not a PgPaymentFlow, so resolveInstrument() returns null.
PgPaymentRequest request = PgPaymentRequest.SubscriptionNotifyRequestBuilder()
.merchantOrderId("ORDER_NON_PG_FLOW_001")
.amount(1000L)
.merchantSubscriptionId("SUB001")
.autoDebit(false)
.build();

PgPaymentResponse response = PgPaymentResponse.builder()
.orderId("OMO_NON_PG_FLOW_001")
.state("PENDING")
.expireAt(java.time.Instant.now().getEpochSecond() + 600)
.build();

// Stub by URL only (no body match) since SubscriptionRedemptionPaymentFlow has
// extra fields; we only care that the request routes to the default host, not PCI host.
wireMockServer.stubFor(
com.github.tomakehurst.wiremock.client.WireMock.post(
com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo(url))
.willReturn(
com.github.tomakehurst.wiremock.client.WireMock.aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody(new com.fasterxml.jackson.databind.ObjectMapper()
.writeValueAsString(response))));

PgPaymentResponse actual = customCheckoutClient.pay(request);
Assertions.assertEquals(response.getOrderId(), actual.getOrderId());
}
}
Loading