use of org.mifos.connector.mpesa.dto.StkCallback in project ph-ee-connector-mpesa by openMF.
the class SafaricomRoutesBuilder method configure.
@Override
public void configure() {
mpesaProps = mpesaUtils.setMpesaProperties();
logger.info("AMS Name set by configure" + mpesaProps.getName());
/*
* Use this endpoint for getting the mpesa transaction status
* The request parameter is same as the safaricom standards
*/
from("rest:POST:/buygoods/transactionstatus").id("buy-goods-transaction-status").process(exchange -> {
String body = exchange.getIn().getBody(String.class);
TransactionStatusRequestDTO transactionStatusRequestDTO = objectMapper.readValue(body, TransactionStatusRequestDTO.class);
exchange.setProperty(BUY_GOODS_TRANSACTION_STATUS_BODY, transactionStatusRequestDTO);
logger.info(body);
}).to("direct:lipana-transaction-status");
/*
Use this endpoint for receiving the callback form safaricom mpesa endpoint
*/
from("rest:POST:/buygoods/callback").id("buy-goods-callback").log(LoggingLevel.INFO, "Callback body \n\n..\n\n..\n\n.. ${body}").unmarshal().json(JsonLibrary.Jackson, JsonObject.class).to("direct:callback-handler");
from("direct:callback-handler").id("callback-handler").log(LoggingLevel.INFO, "Handling callback body").process(exchange -> {
JsonObject response = exchange.getIn().getBody(JsonObject.class);
StkCallback callback = SafaricomUtils.getStkCallback(response);
String checkoutRequestId = callback.getCheckoutRequestId();
String clientCorrelationId = correlationIDStore.getClientCorrelation(checkoutRequestId);
exchange.setProperty(TRANSACTION_ID, clientCorrelationId);
exchange.setProperty(SERVER_TRANSACTION_ID, checkoutRequestId);
logger.info("\n\n StkCallback " + callback + "\n");
logger.info("\n\n Correlation Key " + clientCorrelationId + "\n\n");
if (callback.getResultCode() == 0) {
exchange.setProperty(TRANSACTION_FAILED, false);
exchange.setProperty(SERVER_TRANSACTION_RECEIPT_NUMBER, SafaricomUtils.getTransactionId(response));
exchange.setProperty(CALLBACK_RECEIVED, true);
exchange.setProperty(CALLBACK, callback.toString());
} else {
exchange.setProperty(ERROR_CODE, callback.getResultCode().toString());
exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(String.class));
exchange.setProperty(ERROR_DESCRIPTION, callback.getResultDesc());
}
}).choice().when(exchangeProperty(ERROR_CODE).isNotNull()).to("direct:filter-by-error-code").choice().when(exchangeProperty(IS_ERROR_RECOVERABLE).isEqualTo(false)).process(exchange -> exchange.setProperty(TRANSACTION_FAILED, true)).process(collectionResponseProcessor).otherwise().log("Current resultCode is recoverable hence waiting for getting transaction status").endChoice().otherwise().process(collectionResponseProcessor);
/*
Rest endpoint to initiate payment for buy goods
Sample request body: {
"BusinessShortCode": 174379,
"Amount": 1,
"PartyA": 254708374149,
"PartyB": 174379,
"PhoneNumber": 254708374149,
"CallBackURL": "https://mydomain.com/path",
"AccountReference": "CompanyXLTD",
"TransactionDesc": "Payment of X"
}
*/
from("rest:POST:/buygoods").id("buy-goods-online").process(exchange -> {
String body = exchange.getIn().getBody(String.class);
BuyGoodsPaymentRequestDTO buyGoodsPaymentRequestDTO = objectMapper.readValue(body, BuyGoodsPaymentRequestDTO.class);
exchange.setProperty(BUY_GOODS_REQUEST_BODY, buyGoodsPaymentRequestDTO);
logger.info(buyGoodsPaymentRequestDTO.toString());
}).to("direct:buy-goods-base");
/*
* Starts the payment flow
*
* Step1: Authenticate the user by initiating [get-access-token] flow
* Step2: On successful [Step1], directs to [lipana-buy-goods] flow
*/
from("direct:buy-goods-base").id("buy-goods-base").log(LoggingLevel.INFO, "Starting buy goods flow").log(LoggingLevel.INFO, "Starting buy goods flow with retry count: " + maxRetryCount).to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())).log(LoggingLevel.INFO, "Got access token, moving on to API call.").to("direct:lipana-buy-goods").log(LoggingLevel.INFO, "Status: ${header.CamelHttpResponseCode}").log(LoggingLevel.INFO, "Transaction API response: ${body}").to("direct:transaction-response-handler");
/*
* Starts the payment flow
*
* Step1: Authenticate the user by initiating [get-access-token] flow
* Step2: On successful [Step1], directs to [lipana-buy-goods] flow
*/
from("direct:get-transaction-status-base").id("buy-goods-get-transaction-status-base").log(LoggingLevel.INFO, "Starting buy goods transaction status flow").choice().when(exchangeProperty(SERVER_TRANSACTION_STATUS_RETRY_COUNT).isLessThanOrEqualTo(maxRetryCount)).to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())).log(LoggingLevel.INFO, "Got access token, moving on to API call.").to("direct:lipana-transaction-status").log(LoggingLevel.INFO, "Status: ${header.CamelHttpResponseCode}").log(LoggingLevel.INFO, "Transaction API response: ${body}").to("direct:transaction-status-response-handler").otherwise().process(exchange -> {
exchange.setProperty(IS_RETRY_EXCEEDED, true);
exchange.setProperty(TRANSACTION_FAILED, true);
}).process(collectionResponseProcessor);
/*
* Route to handle async transaction status API responses
*/
from("direct:transaction-status-response-handler").id("transaction-status-response-handler").log(LoggingLevel.INFO, "## Staring transaction status handler route").choice().when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo("200")).log(LoggingLevel.INFO, "Transaction status request successful").process(exchange -> {
String body = exchange.getIn().getBody(String.class);
JSONObject jsonObject = new JSONObject(body);
exchange.setProperty(LAST_RESPONSE_BODY, body);
String server_id = jsonObject.getString("CheckoutRequestID");
String resultCode = jsonObject.getString("ResultCode");
String resultDescription = jsonObject.getString("ResultDesc");
Object correlationId = exchange.getProperty(CORRELATION_ID);
if (resultCode.equals("0")) {
exchange.setProperty(TRANSACTION_FAILED, false);
} else {
exchange.setProperty(ERROR_CODE, resultCode);
exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(String.class));
exchange.setProperty(ERROR_DESCRIPTION, resultDescription);
}
exchange.setProperty(SERVER_TRANSACTION_ID, server_id);
exchange.setProperty(TRANSACTION_ID, correlationId);
}).choice().when(exchange -> exchange.getProperty(ERROR_CODE) != null).to("direct:filter-by-error-code").process(exchange -> {
boolean isRecoverableError = exchange.getProperty(IS_ERROR_RECOVERABLE, Boolean.class);
if (isRecoverableError) {
exchange.setProperty(IS_TRANSACTION_PENDING, true);
} else {
exchange.setProperty(TRANSACTION_FAILED, true);
}
}).endChoice().process(collectionResponseProcessor).when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo("500")).process(exchange -> {
logger.info("Handling 500 transaction status case");
String body = exchange.getIn().getBody(String.class);
JSONObject jsonObject = new JSONObject(body);
exchange.setProperty(LAST_RESPONSE_BODY, body);
String errorCode = jsonObject.getString("errorCode");
String errorDescription = jsonObject.getString("errorMessage");
exchange.setProperty(ERROR_CODE, errorCode);
exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(String.class));
exchange.setProperty(ERROR_DESCRIPTION, errorDescription);
Object correlationId = exchange.getProperty(CORRELATION_ID);
exchange.setProperty(TRANSACTION_ID, correlationId);
exchange.setProperty(IS_TRANSACTION_PENDING, true);
}).process(collectionResponseProcessor).otherwise().log(LoggingLevel.ERROR, "Transaction status request unsuccessful").process(exchange -> {
Object correlationId = exchange.getProperty(CORRELATION_ID);
exchange.setProperty(TRANSACTION_ID, correlationId);
}).setProperty(TRANSACTION_FAILED, constant(true)).process(collectionResponseProcessor);
/*
* Route to handle async API responses
*/
from("direct:transaction-response-handler").id("transaction-response-handler").choice().when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo("200")).log(LoggingLevel.INFO, "Collection request successful").process(exchange -> {
JSONObject jsonObject = new JSONObject(exchange.getIn().getBody(String.class));
String server_id = jsonObject.getString("CheckoutRequestID");
Object correlationId = exchange.getProperty(CORRELATION_ID);
exchange.setProperty(SERVER_TRANSACTION_ID, server_id);
exchange.setProperty(TRANSACTION_ID, correlationId);
correlationIDStore.addMapping(server_id, (String) correlationId);
logger.info("Saved correlationId mapping \n\n {" + server_id + " : " + correlationId + "}");
}).process(transactionResponseProcessor).otherwise().log(LoggingLevel.ERROR, "Collection request unsuccessful").process(exchange -> {
Object correlationId = exchange.getProperty(CORRELATION_ID);
exchange.setProperty(TRANSACTION_ID, correlationId);
}).setProperty(TRANSACTION_FAILED, constant(true)).process(transactionResponseProcessor);
/*
* Takes the access toke and payment request and forwards the requests to lipana API.
* [Password] and [TransactionType] are set in runtime and request is forwarded to lipana endpoint.
*/
from("direct:lipana-buy-goods").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")).setHeader("Content-Type", constant("application/json")).setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")).setBody(exchange -> {
mpesaProps = mpesaUtils.setMpesaProperties();
logger.info("AMS Name in Route " + mpesaProps.getName());
logger.info("Values from safaricome routebuilder: Shortcode - " + mpesaProps.getBusinessShortCode() + " Till -" + mpesaProps.getTill());
BuyGoodsPaymentRequestDTO buyGoodsPaymentRequestDTO = (BuyGoodsPaymentRequestDTO) exchange.getProperty(BUY_GOODS_REQUEST_BODY);
String password = safaricomUtils.getPassword("" + buyGoodsPaymentRequestDTO.getBusinessShortCode(), mpesaProps.getPassKey(), "" + buyGoodsPaymentRequestDTO.getTimestamp());
buyGoodsPaymentRequestDTO.setPassword(password);
buyGoodsPaymentRequestDTO.setTransactionType(MPESA_BUY_GOODS_TRANSACTION_TYPE);
logger.info("BUY GOODS BODY: \n\n..\n\n..\n\n.. " + buyGoodsPaymentRequestDTO);
logger.info(MpesaUtils.maskString(accessTokenStore.getAccessToken()));
return buyGoodsPaymentRequestDTO;
}).marshal().json(JsonLibrary.Jackson).toD(mpesaProps.getApiHost() + buyGoodsLipanaUrl + "?bridgeEndpoint=true&throwExceptionOnFailure=false&" + ConnectionUtils.getConnectionTimeoutDsl(mpesaTimeout)).process(mpesaGenericProcessor).log(LoggingLevel.INFO, "MPESA API called, response: \n\n ${body}");
/*
* Takes the request for transaction status and forwards in to the lipana transaction status endpoint
*/
from("direct:lipana-transaction-status").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")).setHeader("Content-Type", constant("application/json")).setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")).setBody(exchange -> {
TransactionStatusRequestDTO transactionStatusRequestDTO = new TransactionStatusRequestDTO();
BuyGoodsPaymentRequestDTO buyGoodsPaymentRequestDTO = (BuyGoodsPaymentRequestDTO) exchange.getProperty(BUY_GOODS_REQUEST_BODY);
logger.info("BUY GOODS REQUEST: \n\n..\n\n..\n\n.." + buyGoodsPaymentRequestDTO);
transactionStatusRequestDTO.setBusinessShortCode(buyGoodsPaymentRequestDTO.getBusinessShortCode());
transactionStatusRequestDTO.setTimestamp("" + safaricomUtils.getTimestamp());
transactionStatusRequestDTO.setCheckoutRequestId(exchange.getProperty(SERVER_TRANSACTION_ID, String.class));
transactionStatusRequestDTO.setPassword(safaricomUtils.getPassword("" + transactionStatusRequestDTO.getBusinessShortCode(), mpesaProps.getPassKey(), transactionStatusRequestDTO.getTimestamp()));
logger.info("TRANSACTION STATUS REQUEST DTO \n\n..\n\n..\n\n.." + transactionStatusRequestDTO);
return transactionStatusRequestDTO;
}).marshal().json(JsonLibrary.Jackson).toD(mpesaProps.getApiHost() + transactionStatusUrl + "?bridgeEndpoint=true&throwExceptionOnFailure=false&" + ConnectionUtils.getConnectionTimeoutDsl(mpesaTimeout)).process(mpesaGenericProcessor).log(LoggingLevel.INFO, "MPESA STATUS called, response: \n\n ${body}");
}
use of org.mifos.connector.mpesa.dto.StkCallback in project ph-ee-connector-mpesa by openMF.
the class SafaricomUtils method getStkCallback.
/*
* Return the result code from the callback received from mpesa server
*/
public static StkCallback getStkCallback(JsonObject callback) {
StkCallback stkCallback = new StkCallback();
LinkedHashMap<String, Object> body = (LinkedHashMap<String, Object>) callback.get("Body");
LinkedHashMap<String, Object> stkCallbackFromServer = (LinkedHashMap<String, Object>) body.get("stkCallback");
stkCallback.setMerchantRequestId((String) stkCallbackFromServer.get("MerchantRequestID"));
stkCallback.setCheckoutRequestId((String) stkCallbackFromServer.get("CheckoutRequestID"));
stkCallback.setResultCode(Long.parseLong(String.valueOf(stkCallbackFromServer.get("ResultCode"))));
stkCallback.setResultDesc((String) stkCallbackFromServer.get("ResultDesc"));
return stkCallback;
}
Aggregations