diff --git a/src/main/java/co/dapi/ACH.java b/src/main/java/co/dapi/ACH.java new file mode 100644 index 0000000..98ae917 --- /dev/null +++ b/src/main/java/co/dapi/ACH.java @@ -0,0 +1,145 @@ +package co.dapi; + +import co.dapi.response.CreateACHPullResponse; +import co.dapi.response.GetACHPullResponse; +import co.dapi.types.UserInput; +import com.google.gson.JsonSyntaxException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Optional; + + +public class ACH { + private final Config config; + + public ACH(Config config) { + this.config = config; + } + + public CreateACHPullResponse createPull(PullTransfer transfer, String accessToken, String userSecret, String operationID, UserInput[] userInputs) throws IOException { + + // Create the request body of this call + CreatePullRequest bodyObj = new CreatePullRequest(transfer, this.config.getAppSecret(), userSecret, + operationID, userInputs); + + // Convert the request body to a JSON string + String bodyJson = DapiRequest.jsonAgent.toJson(bodyObj, CreatePullRequest.class); + + // Construct the headers needed for this request + HashMap headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + accessToken); + + // Make the request and get the response + String respJson = DapiRequest.Do(bodyJson, DapiRequest.Dapi_URL + "/v2" + bodyObj.action, headers); + + + // Convert the got response to the wanted response type + CreateACHPullResponse resp = null; + try { + resp = DapiRequest.jsonAgent.fromJson(respJson, CreateACHPullResponse.class); + } catch (JsonSyntaxException e) { + // Empty catch, cause the handling code is below + } + + // Check if the got response was of unexpected format, and return a suitable response + if (resp == null || (resp.getStatus() == null && !resp.getType().isPresent())) { + // If the got response wasn't a JSON string, resp will be null, and if + // it didn't have the 'status' field, getStatus() will return null. + return new CreateACHPullResponse("UNEXPECTED_RESPONSE", "Unexpected response body"); + } + + return resp; + } + + public GetACHPullResponse getPull(String accessToken, String userSecret, String operationID, UserInput[] userInputs) throws IOException { + + // Create the request body of this call + GetPullRequest bodyObj = new GetPullRequest(this.config.getAppSecret(), userSecret, operationID, userInputs); + + // Convert the request body to a JSON string + String bodyJson = DapiRequest.jsonAgent.toJson(bodyObj, GetPullRequest.class); + + // Construct the headers needed for this request + HashMap headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + accessToken); + + // Make the request and get the response + String respJson = DapiRequest.Do(bodyJson, DapiRequest.Dapi_URL + "/v2" + bodyObj.action, headers); + + // Convert the got response to the wanted response type + GetACHPullResponse resp = null; + try { + resp = DapiRequest.jsonAgent.fromJson(respJson, GetACHPullResponse.class); + } catch (JsonSyntaxException e) { + // Empty catch, cause the handling code is below + } + + // Check if the got response was of unexpected format, and return a suitable response + if (resp == null || (resp.getStatus() == null && !resp.getType().isPresent())) { + // If the got response wasn't a JSON string, resp will be null, and if + // it didn't have the 'status' field, getStatus() will return null. + return new GetACHPullResponse("UNEXPECTED_RESPONSE", "Unexpected response body"); + } + + return resp; + } + + public static class PullTransfer { + private final String senderID; + private final float amount; + private final String description; + + /** + * Create an object that holds the info for an ACH create pull + * + * @param senderID the id of the account which the money should be pulled from. + * retrieved from one of the accounts array returned from the getAccounts method. + * @param amount the amount of money which should be pulled. + * @param description description for the ACH pull. + */ + public PullTransfer(String senderID, float amount, String description) { + this.senderID = senderID; + this.amount = amount; + this.description = description; + } + + public String getSenderID() { + return senderID; + } + + public float getAmount() { + return amount; + } + + public Optional getDescription() { + return Optional.ofNullable(description); + } + } + + private static class CreatePullRequest extends DapiRequest.BaseRequest { + private final String action = "/ach/pull/create"; + + private final PullTransfer transfer; + + public CreatePullRequest(PullTransfer transfer, + String appSecret, + String userSecret, + String operationID, + UserInput[] userInputs) { + super(appSecret, userSecret, operationID, userInputs); + this.transfer = transfer; + } + } + + private static class GetPullRequest extends DapiRequest.BaseRequest { + private final String action = "/ach/pull/get"; + + public GetPullRequest(String appSecret, + String userSecret, + String operationID, + UserInput[] userInputs) { + super(appSecret, userSecret, operationID, userInputs); + } + } +} diff --git a/src/main/java/co/dapi/DapiApp.java b/src/main/java/co/dapi/DapiApp.java index eb8880e..feec40d 100644 --- a/src/main/java/co/dapi/DapiApp.java +++ b/src/main/java/co/dapi/DapiApp.java @@ -19,6 +19,7 @@ public class DapiApp { private final Auth a; private final Data d; private final Payment p; + private final ACH ach; private final Metadata m; public DapiApp(Config config) { @@ -27,6 +28,7 @@ public DapiApp(Config config) { this.d = new Data(config); this.p = new Payment(config); this.m = new Metadata(config); + this.ach = new ACH(config); } /** @@ -297,6 +299,65 @@ public GetAccountsMetadataResponse getAccountsMetadata(String accessToken, Strin return this.m.getAccountsMetadata(accessToken, userSecret, operationID, userInputs); } + /** + * createACHPull talks to the CreatePull endpoint of Dapi, with this {@link DapiApp}'s appSecret, + * + * @param transfer the transfer details that we want to initiate. + * @param accessToken retrieved from the ExchangeToken process. + * @param userSecret retrieved from the user login. + * @return an {@link CreateACHPullResponse}. + * @throws IOException in case of trouble happened while executing the request or reading the response. + */ + public CreateACHPullResponse createACHPull(ACH.PullTransfer transfer, String accessToken, String userSecret) throws IOException { + return this.ach.createPull(transfer, accessToken, userSecret, "", null); + } + + /** + * createACHPull talks to the CreatePull endpoint of Dapi, with this {@link DapiApp}'s appSecret, + * to continue a previous operation that required to provide some userInputs. + * + * @param transfer the transfer details that we want to initiate. + * @param accessToken retrieved from the ExchangeToken process. + * @param userSecret retrieved from the user login. + * @param operationID retrieved from the previous call's response. + * @param userInputs built from the previous call's response, and the required user input. + * @return an {@link CreateACHPullResponse}. + * @throws IOException in case of trouble happened while executing the request or reading the response. + */ + + public CreateACHPullResponse createACHPull(ACH.PullTransfer transfer, String accessToken, String userSecret, String operationID, UserInput[] userInputs) throws IOException { + return this.ach.createPull(transfer, accessToken, userSecret, operationID, userInputs); + } + + /** + * getACHPull talks to the GetPull endpoint of Dapi, with this {@link DapiApp}'s appSecret, + * + * @param accessToken retrieved from the ExchangeToken process. + * @param userSecret retrieved from the user login. + * @param operationID OperationID of the createACHPull request + * @param userInputs built from the previous call's response, and the required user input. + * @return an {@link GetACHPullResponse}. + * @throws IOException in case of trouble happened while executing the request or reading the response. + */ + public GetACHPullResponse getACHPull(String accessToken, String userSecret, String operationID) throws IOException { + return this.ach.getPull(accessToken, userSecret, operationID, null); + } + + /** + * getACHPull talks to the GetPull endpoint of Dapi, with this {@link DapiApp}'s appSecret, + * to continue a previous operation that required to provide some userInputs. + * + * @param accessToken retrieved from the ExchangeToken process. + * @param userSecret retrieved from the user login. + * @param operationID OperationID of the createACHPull request + * @param userInputs built from the previous call's response, and the required user input. + * @return an {@link GetACHPullResponse}. + * @throws IOException in case of trouble happened while executing the request or reading the response. + */ + public GetACHPullResponse getACHPull(String accessToken, String userSecret, String operationID, UserInput[] userInputs) throws IOException { + return this.ach.getPull(accessToken, userSecret, operationID, userInputs); + } + /** * handleSDKRequest injects this {@link DapiApp}'s appSecret in the provided request body, bodyJson, and then * forwards the request to Dapi, with the passed headers, headersMap, and returns the RAW response got. diff --git a/src/main/java/co/dapi/response/CreateACHPullResponse.java b/src/main/java/co/dapi/response/CreateACHPullResponse.java new file mode 100644 index 0000000..00bbd9b --- /dev/null +++ b/src/main/java/co/dapi/response/CreateACHPullResponse.java @@ -0,0 +1,11 @@ +package co.dapi.response; + +public class CreateACHPullResponse extends BaseResponse { + CreateACHPullResponse() { + super(); + } + + public CreateACHPullResponse(String errType, String errMsg) { + super(errType, errMsg); + } +} diff --git a/src/main/java/co/dapi/response/GetACHPullResponse.java b/src/main/java/co/dapi/response/GetACHPullResponse.java new file mode 100644 index 0000000..135d576 --- /dev/null +++ b/src/main/java/co/dapi/response/GetACHPullResponse.java @@ -0,0 +1,21 @@ +package co.dapi.response; + +import co.dapi.types.ACHPullTransferInfo; + +import java.util.Optional; + +public class GetACHPullResponse extends BaseResponse { + private ACHPullTransferInfo transfer; + + GetACHPullResponse() { + super(); + } + + public GetACHPullResponse(String errType, String errMsg) { + super(errType, errMsg); + } + + public Optional getTransfer() { + return Optional.ofNullable(transfer); + } +} diff --git a/src/main/java/co/dapi/types/ACHPullTransferInfo.java b/src/main/java/co/dapi/types/ACHPullTransferInfo.java new file mode 100644 index 0000000..b5006d1 --- /dev/null +++ b/src/main/java/co/dapi/types/ACHPullTransferInfo.java @@ -0,0 +1,26 @@ +package co.dapi.types; + +public class ACHPullTransferInfo { + private final Float amount; + private final String status; + private final Currency currency; + + public ACHPullTransferInfo(Float amount, String status, Currency currency) { + this.amount = amount; + this.status = status; + this.currency = currency; + } + + public Float getAmount() { + return amount; + } + + public String getStatus() { + return status; + } + + public Currency getCurrency() { + return currency; + } + +}