package in.juspay;
import in.juspay.model.Promotion;
import in.juspay.model.PromotionCondition;
import in.juspay.model.PromotionStatus;
import in.juspay.request.*;
import in.juspay.response.*;
import in.juspay.util.ISO8601DateParser;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.*;
public class PaymentService {
private static final Logger LOG = Logger.getLogger(PaymentService.class);
private int connectionTimeout = 5 * 1000;
private int readTimeout = 5 * 1000;
//private static final Logger log = Logger.getLogger(PaymentService.class);
private String baseUrl;
private String key;
private String merchantId;
private Environment environment;
public void setKey(String key) {
this.key = key;
}
public PaymentService withKey(String key) {
this.key = key;
return this;
}
public void setMerchantId(String merchantId) {
this.merchantId = merchantId;
}
public PaymentService withMerchantId(String merchantId) {
this.merchantId = merchantId;
return this;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
this.baseUrl = environment.getBaseUrl();
}
public PaymentService withEnvironment(Environment environment) {
this.environment = environment;
this.baseUrl = environment.getBaseUrl();
return this;
}
private String serializeParams(Map<String, String> parameters) {
StringBuilder bufferUrl = new StringBuilder();
try {
for (Map.Entry<String, String> entry : parameters.entrySet()) {
bufferUrl.append(entry.getKey());
bufferUrl.append("=");
bufferUrl.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
bufferUrl.append("&");
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Encoding exception while trying to construct payload", e);
}
return bufferUrl.toString();
}
/**
* It opens the connection to the given endPoint and
* returns the http response as String.
*
* @param endPoint - The HTTP URL of the request
* @return HTTP response as string
*/
private String makeServiceCall(String endPoint, String encodedParams) {
HttpsURLConnection connection = null;
StringBuilder buffer = new StringBuilder();
try {
URL url = new URL(endPoint);
connection = (HttpsURLConnection) url.openConnection();
String encodedKey = new String(Base64.encodeBase64(this.key.getBytes()));
encodedKey = encodedKey.replaceAll("\n", "");
connection.setRequestProperty("Authorization", "Basic " + encodedKey);
connection.setConnectTimeout(connectionTimeout);
connection.setReadTimeout(readTimeout);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" + Integer.toString(encodedParams.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
// Setup the POST payload
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(encodedParams);
wr.flush();
wr.close();
// Read the response
InputStream inputStream = connection.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
String line;
while ((line = in.readLine()) != null)
buffer.append(line);
return buffer.toString();
} catch (Exception e) {
//log.warn("Exception while trying to make service call to Juspay", e);
throw new RuntimeException("Exception while trying to make service call to Juspay", e);
}
}
/**
* Creates a new order and returns the InitOrderResponse associated with
* that.
*
* @param initOrderRequest - InitOrderRequest with all required params
* @return InitOrderResponse for the given request
*/
public InitOrderResponse initOrder(InitOrderRequest initOrderRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("amount", String.valueOf(initOrderRequest.getAmount()));
params.put("customer_id", initOrderRequest.getCustomerId());
params.put("customer_email", initOrderRequest.getCustomerEmail());
params.put("order_id", initOrderRequest.getOrderId());
// Optional parameters
params.put("udf1", initOrderRequest.getUdf1() == null ? "" : initOrderRequest.getUdf1());
params.put("udf2", initOrderRequest.getUdf2() == null ? "" : initOrderRequest.getUdf2());
params.put("udf3", initOrderRequest.getUdf3() == null ? "" : initOrderRequest.getUdf3());
params.put("udf4", initOrderRequest.getUdf4() == null ? "" : initOrderRequest.getUdf4());
params.put("udf5", initOrderRequest.getUdf5() == null ? "" : initOrderRequest.getUdf5());
params.put("udf6", initOrderRequest.getUdf6() == null ? "" : initOrderRequest.getUdf6());
params.put("udf7", initOrderRequest.getUdf7() == null ? "" : initOrderRequest.getUdf7());
params.put("udf8", initOrderRequest.getUdf8() == null ? "" : initOrderRequest.getUdf8());
params.put("udf9", initOrderRequest.getUdf9() == null ? "" : initOrderRequest.getUdf9());
params.put("udf10", initOrderRequest.getUdf10() == null ? "" : initOrderRequest.getUdf10());
params.put("return_url", initOrderRequest.getReturnUrl() == null ? "" : initOrderRequest.getReturnUrl());
String serializedParams = serializeParams(params);
String url = baseUrl + "/init_order";
//log.info("Sending init_order to " + url);
//log.debug("Payload (init_order): " + serializedParams);
String response = makeServiceCall(url, serializedParams);
//log.debug("Init order response received: " + response);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
String merchantId = (String) jsonResponse.get("merchant_id");
Long statusId = (Long) jsonResponse.get("status_id");
String status = (String) jsonResponse.get("status");
String orderId = (String) jsonResponse.get("order_id");
InitOrderResponse initOrderResponse = new InitOrderResponse();
initOrderResponse.setStatus(status);
initOrderResponse.setOrderId(orderId);
initOrderResponse.setStatusId(statusId);
initOrderResponse.setMerchantId(merchantId);
return initOrderResponse;
}
/**
* Returns the card details associated with a token. The token information is encapsulated in the
* GetCardRequest instance. This method will throw an Exception if the call is made with an API Key
* that does not have the required privileges. If the token is invalid and the API Key is privileged,
* then the card related fields in the response would be null.
*/
public GetCardResponse getCard(GetCardRequest getCardRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("card_token", getCardRequest.getCardToken());
String serializedParams = serializeParams(params);
String url = baseUrl + "/card/get";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
GetCardResponse cardResponse = new GetCardResponse();
StoredCard card = new StoredCard();
if (null != jsonResponse.get("card_number")) {
card.withCardToken((String) jsonResponse.get("card_token"))
.withCardReference((String) jsonResponse.get("card_reference"))
.withCardNumber((String) jsonResponse.get("card_number"))
.withCardExpYear((String) jsonResponse.get("card_exp_year"))
.withCardExpMonth((String) jsonResponse.get("card_exp_month"))
.withCardIsin((String) jsonResponse.get("card_isin"))
.withCardBrand((String) jsonResponse.get("card_brand"))
.withCardIssuer((String) jsonResponse.get("card_issuer"))
.withCardType((String) jsonResponse.get("card_type"))
.withNickname((String) jsonResponse.get("nickname"))
.withNameOnCard((String) jsonResponse.get("name_on_card"));
cardResponse.setCard(card);
}
cardResponse.setCardToken((String) jsonResponse.get("card_token"));
cardResponse.setMerchantId((String) jsonResponse.get("merchantId"));
return cardResponse;
}
public GetOrderStatusResponse getOrderStatus(GetOrderStatusRequest orderStatusRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("order_id", orderStatusRequest.getOrderId());
String serializedParams = serializeParams(params);
String url = baseUrl + "/order_status";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
return assembleOrderStatusResponse(jsonResponse, new GetOrderStatusResponse());
}
protected Double getDoubleValue(Object inputObject) {
if(inputObject instanceof Long) {
return ((Long) inputObject).doubleValue();
}
else if(inputObject instanceof Double) {
return ((Double) inputObject);
}
else {
System.out.println("Can't seem to understand the input");
return null;
}
}
protected GetOrderStatusResponse assembleOrderStatusResponse(JSONObject jsonResponse,
GetOrderStatusResponse target) {
GetOrderStatusResponse orderStatusResponse = target;
orderStatusResponse.setMerchantId((String) jsonResponse.get("merchant_id"));
orderStatusResponse.setOrderId((String) jsonResponse.get("order_id"));
orderStatusResponse.setStatus((String) jsonResponse.get("status"));
orderStatusResponse.setStatusId((Long) jsonResponse.get("status_id"));
orderStatusResponse.setTxnId((String) jsonResponse.get("txn_id"));
orderStatusResponse.setGatewayId((Long) jsonResponse.get("gateway_id"));
orderStatusResponse.setAmount(getDoubleValue(jsonResponse.get("amount")));
orderStatusResponse.setBankErrorCode((String) jsonResponse.get("bank_error_code"));
orderStatusResponse.setBankErrorMessage((String) jsonResponse.get("bank_error_message"));
orderStatusResponse.setUdf1((String) jsonResponse.get("udf1"));
orderStatusResponse.setUdf2((String) jsonResponse.get("udf2"));
orderStatusResponse.setUdf3((String) jsonResponse.get("udf3"));
orderStatusResponse.setUdf4((String) jsonResponse.get("udf4"));
orderStatusResponse.setUdf5((String) jsonResponse.get("udf5"));
orderStatusResponse.setUdf6((String) jsonResponse.get("udf6"));
orderStatusResponse.setUdf7((String) jsonResponse.get("udf7"));
orderStatusResponse.setUdf8((String) jsonResponse.get("udf8"));
orderStatusResponse.setUdf9((String) jsonResponse.get("udf9"));
orderStatusResponse.setUdf10((String) jsonResponse.get("udf10"));
orderStatusResponse.setAmountRefunded(getDoubleValue(jsonResponse.get("amount_refunded")));
orderStatusResponse.setRefunded((Boolean) jsonResponse.get("refunded"));
JSONObject gatewayResponse = (JSONObject) jsonResponse.get("payment_gateway_response");
if (gatewayResponse != null) {
PaymentGatewayResponse paymentGatewayResponse = new PaymentGatewayResponse();
paymentGatewayResponse.setRootReferenceNumber((String) gatewayResponse.get("rrn"));
paymentGatewayResponse.setResponseCode((String) gatewayResponse.get("resp_code"));
paymentGatewayResponse.setResponseMessage((String) gatewayResponse.get("resp_message"));
paymentGatewayResponse.setTxnId((String) gatewayResponse.get("txn_id"));
paymentGatewayResponse.setExternalGatewayTxnId((String) gatewayResponse.get("epg_txn_id"));
paymentGatewayResponse.setAuthIdCode((String) gatewayResponse.get("auth_id_code"));
orderStatusResponse.setPaymentGatewayResponse(paymentGatewayResponse);
}
JSONObject promotionResponse = (JSONObject) jsonResponse.get("promotion");
if(promotionResponse != null) {
Promotion promotion = assemblePromotionObjectFromJSON(promotionResponse);
orderStatusResponse.setPromotion(promotion);
}
JSONArray refunds = (JSONArray) jsonResponse.get("refunds");
if(refunds != null && refunds.size() > 0) {
List<Refund> refundList = new ArrayList<Refund>(refunds.size());
for(Iterator refundIter = refunds.iterator();refundIter.hasNext();) {
JSONObject refundEntry = (JSONObject) refundIter.next();
Refund refund = new Refund();
refund.setId((String) refundEntry.get("id"));
refund.setReference((String) refundEntry.get("ref"));
refund.setAmount(getDoubleValue(refundEntry.get("amount")));
try {
refund.setCreated(ISO8601DateParser.parse((String) refundEntry.get("created")));
} catch (ParseException e) {
LOG.error("Exception while trying to parse date created. Skipping the field", e);
}
refundList.add(refund);
}
orderStatusResponse.setRefunds(refundList);
}
return orderStatusResponse;
}
/**
* Creates a new card
*
* @param addCardRequest - AddCardRequest with all the required params
* @return AddCardResponse for the given request.
*/
public AddCardResponse addCard(AddCardRequest addCardRequest) {
//Get the required params
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("customer_id", addCardRequest.customerId);
params.put("customer_email", addCardRequest.customerEmail);
params.put("card_number", String.valueOf(addCardRequest.cardNumber));
params.put("card_exp_year", String.valueOf(addCardRequest.cardExpYear));
params.put("card_exp_month", String.valueOf(addCardRequest.cardExpMonth));
params.put("name_on_card", addCardRequest.nameOnCard != null ? addCardRequest.nameOnCard : "");
params.put("nickname", addCardRequest.nickname != null ? addCardRequest.nickname : "");
String serializedParams = serializeParams(params);
String url = baseUrl + "/card/add";
String response = makeServiceCall(url, serializedParams);
JSONObject json = (JSONObject) JSONValue.parse(response);
String cardToken = (String) json.get("card_token");
String cardReference = (String) json.get("card_reference");
AddCardResponse addCardResponse = new AddCardResponse();
addCardResponse.setCardToken(cardToken);
addCardResponse.setCardReference(cardReference);
return addCardResponse;
}
/**
* Deletes the card (if present) and returns the DeleteCardResponse associated with the request
*
* @param deleteCardRequest - DeleteCardRequest request with all required params.
* @return DeleteCardResponse for the given request.
*/
public DeleteCardResponse deleteCard(DeleteCardRequest deleteCardRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("card_token", deleteCardRequest.cardToken);
String serializedParams = serializeParams(params);
String url = baseUrl + "/card/delete";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
String card_token = (String) jsonResponse.get("card_token");
Boolean deleted = (Boolean) jsonResponse.get("deleted");
String card_reference = null;
if (null != jsonResponse.get("card_reference")) {
card_reference = (String) jsonResponse.get("card_reference");
}
return new DeleteCardResponse().withCardToken(card_token).
withDeleted(deleted).
withCardReference(card_reference);
}
/**
* Initiates the payment call and returns the response of Payment
*
* @param paymentRequest - PaymentRequest with all required params
* @return PaymentResponse for the given request
*/
public PaymentResponse makePayment(PaymentRequest paymentRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
//String merchantId, String orderId,String cardNumber,String cardExpYear,String cardExpMonth,String cardSecurityCode
params.put("merchantId", paymentRequest.getMerchantId());
params.put("orderId", paymentRequest.getOrderId());
params.put("cardNumber", paymentRequest.getCardNumber());
params.put("cardExpYear", paymentRequest.getCardExpYear());
params.put("cardExpMonth", paymentRequest.getCardExpMonth());
params.put("cardSecurityCode", paymentRequest.getCardSecurityCode());
String serializedParams = serializeParams(params);
String url = baseUrl + "/payment/handlePay";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
String status = (String) jsonResponse.get("status");
String txnId = (String) jsonResponse.get("txnId");
String merchantId = (String) jsonResponse.get("merchantId");
String purchaseId = (String) jsonResponse.get("purchaseId");
String vbvUrl = (String) jsonResponse.get("vbv_url");
PaymentResponse paymentResponse = new PaymentResponse();
paymentResponse.status = status;
paymentResponse.txnId = txnId;
paymentResponse.merchantId = merchantId;
paymentResponse.purchaseId = purchaseId;
paymentResponse.vbvUrl = vbvUrl;
return paymentResponse;
}
/**
* List the cards for the user (if already present) for the given request
*
* @param listCardsRequest - ListCardsRequest with all required params.
* @return ListCardsResponse for the given request.
*/
public ListCardsResponse listCards(ListCardsRequest listCardsRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("customer_id", listCardsRequest.customerId);
String serializedParams = serializeParams(params);
String url = baseUrl + "/card/list";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
String customerId = (String) jsonResponse.get("customer_id");
String merchantId = (String) jsonResponse.get("merchantId");
ArrayList<JSONObject> tempCards = (ArrayList<JSONObject>) jsonResponse.get("cards");
ListCardsResponse listCardsResponse = new ListCardsResponse();
listCardsResponse.customerId = customerId;
listCardsResponse.merchantId = merchantId;
ArrayList<StoredCard> cards = new ArrayList<StoredCard>();
if (tempCards != null) {
for (JSONObject cardObject : tempCards) {
StoredCard card = new StoredCard();
card.withCardToken((String) cardObject.get("card_token"))
.withCardReference((String) cardObject.get("card_reference"))
.withCardNumber((String) cardObject.get("card_number"))
.withCardExpYear((String) cardObject.get("card_exp_year"))
.withCardExpMonth((String) cardObject.get("card_exp_month"))
.withCardIsin((String) cardObject.get("card_isin"))
.withNameOnCard(cardObject.get("name_on_card") != null ?
cardObject.get("name_on_card").toString() : "")
.withCardToken((String) cardObject.get("card_token"))
.withCardBrand((String) cardObject.get("card_brand"))
.withCardIssuer((String) cardObject.get("card_issuer"))
.withCardType((String) cardObject.get("card_type"))
.withNickname((String) cardObject.get("nickname"));
cards.add(card);
}
}
listCardsResponse.cards = cards;
return listCardsResponse;
}
public RefundResponse refund(RefundRequest refundRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("order_id", refundRequest.getOrderId());
params.put("amount", refundRequest.getAmount().toString());
String serializedParams = serializeParams(params);
String url = baseUrl + "/order/refund";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
RefundResponse refundResponse = (RefundResponse) assembleOrderStatusResponse(jsonResponse, new RefundResponse());
refundResponse.setSuccess(true);
return refundResponse;
}
/**
* Assembles a complete Promotion object from the given JSONObject.
* @param jsonObject
* - An instance of JSONObject that contains promotion information.
* @return
* - Promotion object that corresponds to the json input.
*/
private Promotion assemblePromotionObjectFromJSON(JSONObject jsonObject) {
Promotion promotion = new Promotion();
promotion.setId((String) jsonObject.get("id"));
promotion.setOrderId((String) jsonObject.get("order_id"));
promotion.setDiscountAmount(Double.valueOf(jsonObject.get("discount_amount").toString()));
String status = (String) jsonObject.get("status");
promotion.setStatus(PromotionStatus.valueOf(status));
ArrayList<JSONObject> conditions = (ArrayList<JSONObject>) jsonObject.get("conditions");
ArrayList<JSONObject> rules = (ArrayList<JSONObject>) jsonObject.get("rules");
List<PromotionCondition> promotionConditions = new ArrayList<PromotionCondition>();
for(JSONObject jsonCondition : (conditions != null ? conditions : rules)) {
PromotionCondition promotionCondition = new PromotionCondition();
promotionCondition.setDimension((String) jsonCondition.get("dimension"));
promotionCondition.setValue((String) jsonCondition.get("value"));
promotionConditions.add(promotionCondition);
}
promotion.setPromotionConditions(promotionConditions);
return promotion;
}
/**
* Create a promotion for an order given all the inputs.
* @param createPromotionRequest
* - An instance of CreatePromotionRequest that encapsulates all the information pertaining to the promotion.
* @return
* - An instance of CreatePromotionResponse that contains the response status of the API call and the Promotion
* object itself.
*/
public CreatePromotionResponse createPromotion(CreatePromotionRequest createPromotionRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("order_id", createPromotionRequest.getOrderId());
params.put("discount_amount", Double.valueOf(createPromotionRequest.getDiscountAmount()).toString());
for(int i=0; i < createPromotionRequest.getPromotionConditions().size(); i++) {
PromotionCondition condition = createPromotionRequest.getPromotionConditions().get(i);
params.put("dimensions[" + i + "]", condition.getDimension());
params.put("values[" + i + "]", condition.getValue());
}
String serializedParams = serializeParams(params);
String url = baseUrl + "/promotions";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
CreatePromotionResponse promotionResponse = new CreatePromotionResponse();
promotionResponse.setSuccess(true);
Promotion promotion = assemblePromotionObjectFromJSON(jsonResponse);
promotionResponse.setPromotion(promotion);
return promotionResponse;
}
/**
* Deactivates a promotion.
* @param deactivatePromotionRequest
* - request object representing the promotion using the id.
* @return
* - returns an object containing the status and the promotion object itself.
*/
public DeactivatePromotionResponse deactivatePromotion(DeactivatePromotionRequest deactivatePromotionRequest) {
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("promotion_id", deactivatePromotionRequest.getPromotionId());
String serializedParams = serializeParams(params);
String url = baseUrl + "/promotions/" + deactivatePromotionRequest.getPromotionId() + "/deactivate";
String response = makeServiceCall(url, serializedParams);
JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
DeactivatePromotionResponse deactivatePromotionResponse = new DeactivatePromotionResponse();
deactivatePromotionResponse.setSuccess(true);
Promotion promotion = assemblePromotionObjectFromJSON(jsonResponse);
deactivatePromotionResponse.setPromotion(promotion);
return deactivatePromotionResponse;
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
}