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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,10 @@ Contributions to PG Java SDK are welcome! Here's how you can contribute:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
3. Make sure to set up the pre-commit hook by running the command `pre-commit install`
4. Commit your changes (`git commit -m 'Add some amazing feature'`)
5. Push to the branch (`git push origin feature/amazing-feature`)
6. Open a Pull Request

Please ensure your code follows the project's coding standards and includes appropriate tests.

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.phonepe</groupId>
<artifactId>pg-sdk-java</artifactId>
<version>2.2.1</version>
<version>2.2.2</version>
<name>B2B JAVA SDK</name>
<url>https://github.com/PhonePe/phonepe-pg-sdk-java</url>
<description>Phonepe PG JAVA SDK</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ public class Headers {
public static final String OAUTH_AUTHORIZATION = "Authorization";
public static final String CONTENT_TYPE = "Content-Type";
public static final String ACCEPT = "Accept";
public static final String X_DEVICE_OS = "x-device-os";
}

Large diffs are not rendered by default.

156 changes: 82 additions & 74 deletions src/main/java/com/phonepe/sdk/pg/payments/v2/CustomCheckoutClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,40 +64,37 @@ private CustomCheckoutClient(
/**
* Generates a CustomCheckout Client for interacting with the PhonePe APIs
*
* @param clientId Unique client-id assigned to merchant by PhonePe
* @param clientSecret Secret provided by PhonePe
* @param clientId Unique client-id assigned to merchant by PhonePe
* @param clientSecret Secret provided by PhonePe
* @param clientVersion The client version used for secure transactions
* @param env Set to `Env.SANDBOX` for the SANDBOX environment or `Env.PRODUCTION` for the
* production environment.
* @param env Set to `Env.SANDBOX` for the SANDBOX environment or `Env.PRODUCTION` for the production
* environment.
* @return CustomCheckoutClient object for interacting with the PhonePe APIs
*/
public static CustomCheckoutClient getInstance(
final String clientId,
final String clientSecret,
final Integer clientVersion,
final Env env)
throws PhonePeException {
final Env env) throws PhonePeException {
return getInstance(clientId, clientSecret, clientVersion, env, true);
}

/**
* Generates a CustomCheckout Client for interacting with the PhonePe APIs
*
* @param clientId received at the time of onboarding
* @param clientSecret received at the time of onboarding
* @param clientVersion received at the time of onboarding
* @param env environment to be used by the merchant
* @param shouldPublishEvents When true, events are sent to PhonePe providing smoother
* experience
* @param clientId received at the time of onboarding
* @param clientSecret received at the time of onboarding
* @param clientVersion received at the time of onboarding
* @param env environment to be used by the merchant
* @param shouldPublishEvents When true, events are sent to PhonePe providing smoother experience
* @return CustomCheckoutClient object for interacting with the PhonePe APIs
*/
public static CustomCheckoutClient getInstance(
final String clientId,
final String clientSecret,
final Integer clientVersion,
final Env env,
boolean shouldPublishEvents)
throws PhonePeException {
boolean shouldPublishEvents) throws PhonePeException {
final boolean shouldPublishInProd = shouldPublishEvents && env == Env.PRODUCTION;
return new CustomCheckoutClient(
clientId, clientSecret, clientVersion, env, shouldPublishInProd);
Expand All @@ -113,14 +110,23 @@ public static CustomCheckoutClient getInstance(
public PgPaymentResponse pay(PgPaymentRequest pgPaymentRequest) {
String url = CustomCheckoutConstants.PAY_API;
try {
PgPaymentResponse pgPaymentResponse =
requestViaAuthRefresh(
HttpMethodType.POST,
pgPaymentRequest,
url,
null,
new TypeReference<PgPaymentResponse>() {},
headers);
List<HttpHeaderPair> requestHeaders = headers;
if (pgPaymentRequest.getDeviceOS() != null && !pgPaymentRequest.getDeviceOS()
.isBlank()) {
requestHeaders = new ArrayList<>(headers);
requestHeaders.add(
HttpHeaderPair.builder()
.key(Headers.X_DEVICE_OS)
.value(pgPaymentRequest.getDeviceOS())
.build());
}
PgPaymentResponse pgPaymentResponse = requestViaAuthRefresh(
HttpMethodType.POST,
pgPaymentRequest,
url,
null,
new TypeReference<PgPaymentResponse>() {},
requestHeaders);
this.eventPublisher.send(
BaseEvent.buildCustomCheckoutPayEvent(
EventState.SUCCESS, pgPaymentRequest, url, EventType.PAY_SUCCESS));
Expand Down Expand Up @@ -152,24 +158,23 @@ public OrderStatusResponse getOrderStatus(String merchantOrderId) {
* Gets status of an order
*
* @param merchantOrderId Order id generated by merchant
* @param details true -> order status has all attempt details under paymentDetails list false
* -> order status has only latest attempt details under paymentDetails list
* @param details true -> order status has all attempt details under paymentDetails list false -> order
* status has only latest attempt details under paymentDetails list
* @return OrderStatusResponse Response with order and transaction details
*/
@SneakyThrows
public OrderStatusResponse getOrderStatus(String merchantOrderId, boolean details) {
String url = String.format(CustomCheckoutConstants.ORDER_STATUS_API, merchantOrderId);
try {
OrderStatusResponse orderStatusResponse =
requestViaAuthRefresh(
HttpMethodType.GET,
null,
url,
Collections.singletonMap(
CustomCheckoutConstants.ORDER_DETAILS,
Boolean.toString(details)),
new TypeReference<OrderStatusResponse>() {},
headers);
OrderStatusResponse orderStatusResponse = requestViaAuthRefresh(
HttpMethodType.GET,
null,
url,
Collections.singletonMap(
CustomCheckoutConstants.ORDER_DETAILS,
Boolean.toString(details)),
new TypeReference<OrderStatusResponse>() {},
headers);
this.eventPublisher.send(
BaseEvent.buildOrderStatusEvent(
EventState.SUCCESS,
Expand Down Expand Up @@ -201,14 +206,13 @@ public OrderStatusResponse getOrderStatus(String merchantOrderId, boolean detail
public RefundResponse refund(RefundRequest refundRequest) {
String url = CustomCheckoutConstants.REFUND_API;
try {
RefundResponse refundResponse =
requestViaAuthRefresh(
HttpMethodType.POST,
refundRequest,
url,
null,
new TypeReference<RefundResponse>() {},
headers);
RefundResponse refundResponse = requestViaAuthRefresh(
HttpMethodType.POST,
refundRequest,
url,
null,
new TypeReference<RefundResponse>() {},
headers);
this.eventPublisher.send(
BaseEvent.buildRefundEvent(
EventState.SUCCESS,
Expand Down Expand Up @@ -240,14 +244,13 @@ public RefundResponse refund(RefundRequest refundRequest) {
public CreateSdkOrderResponse createSdkOrder(CreateSdkOrderRequest createSdkOrderRequest) {
String url = CustomCheckoutConstants.CREATE_ORDER_API;
try {
CreateSdkOrderResponse createSdkOrderResponse =
requestViaAuthRefresh(
HttpMethodType.POST,
createSdkOrderRequest,
url,
null,
new TypeReference<CreateSdkOrderResponse>() {},
headers);
CreateSdkOrderResponse createSdkOrderResponse = requestViaAuthRefresh(
HttpMethodType.POST,
createSdkOrderRequest,
url,
null,
new TypeReference<CreateSdkOrderResponse>() {},
headers);
this.eventPublisher.send(
BaseEvent.buildCreateSdkOrderEvent(
EventState.SUCCESS,
Expand Down Expand Up @@ -278,17 +281,15 @@ public CreateSdkOrderResponse createSdkOrder(CreateSdkOrderRequest createSdkOrde
*/
@SneakyThrows
public OrderStatusResponse getTransactionStatus(String transactionId) {
final String url =
String.format(CustomCheckoutConstants.TRANSACTION_STATUS_API, transactionId);
final String url = String.format(CustomCheckoutConstants.TRANSACTION_STATUS_API, transactionId);
try {
OrderStatusResponse orderStatusResponse =
requestViaAuthRefresh(
HttpMethodType.GET,
null,
url,
null,
new TypeReference<OrderStatusResponse>() {},
headers);
OrderStatusResponse orderStatusResponse = requestViaAuthRefresh(
HttpMethodType.GET,
null,
url,
null,
new TypeReference<OrderStatusResponse>() {},
headers);
this.eventPublisher.send(
BaseEvent.buildTransactionStatusEvent(
EventState.SUCCESS,
Expand Down Expand Up @@ -321,14 +322,13 @@ public OrderStatusResponse getTransactionStatus(String transactionId) {
public RefundStatusResponse getRefundStatus(String refundId) {
final String url = String.format(CustomCheckoutConstants.REFUND_STATUS_API, refundId);
try {
RefundStatusResponse refundStatusResponse =
requestViaAuthRefresh(
HttpMethodType.GET,
null,
url,
null,
new TypeReference<RefundStatusResponse>() {},
headers);
RefundStatusResponse refundStatusResponse = requestViaAuthRefresh(
HttpMethodType.GET,
null,
url,
null,
new TypeReference<RefundStatusResponse>() {},
headers);
this.eventPublisher.send(
BaseEvent.buildRefundStatusEvent(
EventState.SUCCESS,
Expand All @@ -353,10 +353,10 @@ public RefundStatusResponse getRefundStatus(String refundId) {
/**
* Validate if the callback is valid
*
* @param username username set by the merchant on the dashboard
* @param password password set by the merchant on the dashboard
* @param username username set by the merchant on the dashboard
* @param password password set by the merchant on the dashboard
* @param authorization String data under `authorization` key of response headers
* @param responseBody Callback response body
* @param responseBody Callback response body
* @return CallbackResponse Deserialized callback body
* @throws PhonePeException when callback is not valid
*/
Expand All @@ -379,13 +379,21 @@ public CallbackResponse validateCallback(
}
}

/** Prepares the headers for CustomCheckout Client */
/**
* Prepares the headers for CustomCheckout Client
*/
private void prepareHeaders() {
this.headers = new ArrayList<>();
headers.add(
HttpHeaderPair.builder().key(Headers.CONTENT_TYPE).value(APPLICATION_JSON).build());
HttpHeaderPair.builder()
.key(Headers.CONTENT_TYPE)
.value(APPLICATION_JSON)
.build());
headers.add(
HttpHeaderPair.builder().key(Headers.SOURCE).value(Headers.INTEGRATION).build());
HttpHeaderPair.builder()
.key(Headers.SOURCE)
.value(Headers.INTEGRATION)
.build());
headers.add(
HttpHeaderPair.builder()
.key(Headers.SOURCE_VERSION)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2025 Original Author(s), PhonePe India Pvt. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.phonepe.sdk.pg.payments.v2.models.request;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
@JsonInclude(Include.NON_NULL)
public class PrefillUserLoginDetails {

private String phoneNumber;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ public class StandardCheckoutPayRequest {
private PaymentFlow paymentFlow;
private Long expireAfter;
private Boolean disablePaymentRetry;
private PrefillUserLoginDetails prefillUserLoginDetails;

/**
* Builds Standard Checkout Pay Request
*
* @param merchantOrderId The unique order ID generated by the merchant
* @param amount Order amount in paisa
* @param redirectUrl URL where user will be redirected after success/failed payment
* @param metaInfo Merchant defined meta info to store additional information
* @param message Payment message shown in APP for collect requests
* @param amount Order amount in paisa
* @param redirectUrl URL where user will be redirected after success/failed payment
* @param metaInfo Merchant defined meta info to store additional information
* @param message Payment message shown in APP for collect requests
*/
@Builder
public StandardCheckoutPayRequest(
Expand All @@ -51,18 +52,22 @@ public StandardCheckoutPayRequest(
String message,
Long expireAfter,
PaymentModeConfig paymentModeConfig,
Boolean disablePaymentRetry) {
Boolean disablePaymentRetry,
PrefillUserLoginDetails prefillUserLoginDetails) {
this.merchantOrderId = merchantOrderId;
this.amount = amount;
this.metaInfo = metaInfo;
this.expireAfter = expireAfter;
MerchantUrls merchantUrls = MerchantUrls.builder().redirectUrl(redirectUrl).build();
MerchantUrls merchantUrls = MerchantUrls.builder()
.redirectUrl(redirectUrl)
.build();
this.setPaymentFlow(
PgCheckoutPaymentFlow.builder()
.message(message)
.merchantUrls(merchantUrls)
.paymentModeConfig(paymentModeConfig)
.build());
this.disablePaymentRetry = disablePaymentRetry;
this.prefillUserLoginDetails = prefillUserLoginDetails;
}
}
Loading