From b44e971dc1ee749766a68744fa2a1ce29d6ebfd1 Mon Sep 17 00:00:00 2001 From: Ilya Egoshin Date: Sat, 24 Feb 2018 14:19:21 -0600 Subject: [PATCH 01/14] small fixes to compile and pass unit tests --- .../beanstream/connection/HttpsConnector.java | 36 ++++++++++--------- .../beanstream/api/test/PaymentAPITest.java | 4 +-- .../beanstream/api/test/ReportsAPITest.java | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/beanstream/connection/HttpsConnector.java b/src/main/java/com/beanstream/connection/HttpsConnector.java index 5d0046c..4a095eb 100644 --- a/src/main/java/com/beanstream/connection/HttpsConnector.java +++ b/src/main/java/com/beanstream/connection/HttpsConnector.java @@ -23,29 +23,31 @@ package com.beanstream.connection; -import com.beanstream.exceptions.BeanstreamApiException; -import com.beanstream.responses.BeanstreamResponse; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.HttpsURLConnection; + +import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; -import org.apache.http.client.methods.*; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; -import javax.net.ssl.HttpsURLConnection; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.config.ConnectionConfig; -import org.apache.http.impl.client.DefaultHttpClient; +import com.beanstream.exceptions.BeanstreamApiException; +import com.beanstream.responses.BeanstreamResponse; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; /** * Performs the connection to the API. @@ -164,7 +166,7 @@ private BeanstreamResponse process(HttpUriRequest http, httpclient = HttpClients.createDefault(); // Remove newlines from base64 since they can bork the header. // Some base64 encoders will append a newline to the end - String auth = Base64.encode((merchantId + ":" + apiPasscode).trim().getBytes()); + String auth = Base64.encodeBase64String((merchantId + ":" + apiPasscode).trim().getBytes()); http.addHeader("Content-Type", "application/json"); http.addHeader("Authorization", "Passcode " + auth); diff --git a/src/test/java/com/beanstream/api/test/PaymentAPITest.java b/src/test/java/com/beanstream/api/test/PaymentAPITest.java index fca606f..aa66505 100644 --- a/src/test/java/com/beanstream/api/test/PaymentAPITest.java +++ b/src/test/java/com/beanstream/api/test/PaymentAPITest.java @@ -42,8 +42,8 @@ public void preAuthCompletionGreaterAmount() throws BeanstreamApiException { } } } catch (BeanstreamApiException ex) { - Assert.assertEquals("Http status code did not match expected.", 400, ex.getHttpStatusCode()); - Assert.assertEquals("Error category did not match expected", 2, ex.getCategory()); + Assert.assertEquals("Http status code did not match expected.", 402, ex.getHttpStatusCode()); + Assert.assertEquals("Completion greater than remaining reserve amount., details: ", 2, ex.getCategory()); Assert.assertEquals("Error code did not match expected", 208, ex.getCode()); } } diff --git a/src/test/java/com/beanstream/api/test/ReportsAPITest.java b/src/test/java/com/beanstream/api/test/ReportsAPITest.java index 9111265..f8104bc 100644 --- a/src/test/java/com/beanstream/api/test/ReportsAPITest.java +++ b/src/test/java/com/beanstream/api/test/ReportsAPITest.java @@ -117,7 +117,7 @@ public void testGetSingleTransactionRecordById() { Transaction transaction = beanstream.reports().getTransaction(payment.id); Assert.assertNotNull(transaction); - Assert.assertEquals("Amounts did not match", "90.0", transaction.getAmount()); + Assert.assertEquals("Amounts did not match", "90.00", transaction.getAmount()); } catch (BeanstreamApiException ex) { Logger.getLogger(ReportsAPITest.class.getName()).log(Level.SEVERE, "Error accessing Beanstream API "+ex.getCode()+", "+ex.getCategory()+", "+ex.getMessage(), ex); From 8dae07218d9964d26fa0aee1b3fcf93e77428be0 Mon Sep 17 00:00:00 2001 From: Ilya Egoshin Date: Sat, 24 Feb 2018 17:17:17 -0600 Subject: [PATCH 02/14] interac payment API added (more testing needed) --- .../java/com/beanstream/api/PaymentsAPI.java | 73 ++++++++++++++++--- .../beanstream/connection/BeanstreamUrls.java | 7 ++ .../beanstream/connection/HttpsConnector.java | 2 +- .../responses/BeanstreamResponse.java | 2 +- .../beanstream/responses/PaymentResponse.java | 3 + .../api/test/SampleTransactions.java | 54 ++++++++++---- 6 files changed, 114 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/beanstream/api/PaymentsAPI.java b/src/main/java/com/beanstream/api/PaymentsAPI.java index eff4d06..b2b1608 100644 --- a/src/main/java/com/beanstream/api/PaymentsAPI.java +++ b/src/main/java/com/beanstream/api/PaymentsAPI.java @@ -22,6 +22,17 @@ */ package com.beanstream.api; +import static com.beanstream.connection.BeanstreamUrls.getPaymentUrl; +import static com.beanstream.connection.BeanstreamUrls.getPreAuthCompletionsUrl; +import static com.beanstream.connection.BeanstreamUrls.getReturnUrl; +import static com.beanstream.connection.BeanstreamUrls.getUnreferencedReturnUrl; +import static com.beanstream.connection.BeanstreamUrls.getVoidPaymentUrl; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import org.apache.http.HttpStatus; + import com.beanstream.Configuration; import com.beanstream.Gateway; import com.beanstream.connection.BeanstreamUrls; @@ -31,23 +42,19 @@ import com.beanstream.requests.CardPaymentRequest; import com.beanstream.requests.CashPaymentRequest; import com.beanstream.requests.ChequePaymentRequest; -import com.beanstream.requests.TokenPaymentRequest; +import com.beanstream.requests.InteracPaymentRequest; +import com.beanstream.requests.PaymentRequest; +import com.beanstream.requests.ProfilePaymentRequest; import com.beanstream.requests.ReturnRequest; +import com.beanstream.requests.TokenPaymentRequest; import com.beanstream.requests.UnreferencedCardReturnRequest; import com.beanstream.requests.UnreferencedSwipeReturnRequest; import com.beanstream.responses.BeanstreamResponse; +import com.beanstream.responses.InteracPaymentResponse; import com.beanstream.responses.PaymentResponse; import com.google.gson.Gson; import com.google.gson.JsonObject; -import org.apache.http.HttpStatus; - - - -import static com.beanstream.connection.BeanstreamUrls.*; -import com.beanstream.requests.PaymentRequest; -import com.beanstream.requests.ProfilePaymentRequest; - /** * The entry point for processing payments. * @@ -149,6 +156,54 @@ public PaymentResponse makePayment(ProfilePaymentRequest paymentRequest) throws return gson.fromJson(response, PaymentResponse.class); } + /** + * Make an interac payment request. + * + * @author ilya + * @param paymentRequest the interac payment request + * @return InteracPaymentResponse the result of the interac payment request + * @throws BeanstreamApiException as a result of a business logic validation + * or any other error @see + */ + public InteracPaymentResponse interacPayment(InteracPaymentRequest paymentRequest) throws BeanstreamApiException { + + // build the URL + String url = BeanstreamUrls.getPaymentUrl( config.getPlatform(), config.getVersion()); + + // process the transaction using the REST API + String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + + // parse the output and return a InteracPaymentResponse + InteracPaymentResponse res = gson.fromJson(response, InteracPaymentResponse.class); + try { + // contents is URL-encoded for some reason + res.contents = URLDecoder.decode( res.contents, "UTF-8" ); + } catch (UnsupportedEncodingException e) {} + return res; + } + + /** + * Complete the interac payment. + * + * @author ilya + * @param merchantData - this value should be stored in session while client is redirected to financial institution website + * @param paymentRequest the interac payment request should have InteracResponse object populated (important!) + * @return PaymentResponse the result of the interac payment transaction + * @throws BeanstreamApiException as a result of a business logic validation + * or any other error @see + */ + public PaymentResponse interacPaymentCompletion(String merchantData, InteracPaymentRequest paymentRequest) throws BeanstreamApiException { + + // build the URL + String url = BeanstreamUrls.getPaymentContinuationsUrl( config.getPlatform(), config.getVersion(), merchantData); + + // process the transaction using the REST API + String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + + // parse the output and return a PaymentResponse + return gson.fromJson(response, PaymentResponse.class); + } + /** * Make a cash payment. * diff --git a/src/main/java/com/beanstream/connection/BeanstreamUrls.java b/src/main/java/com/beanstream/connection/BeanstreamUrls.java index 69e8bf7..bcaa08e 100644 --- a/src/main/java/com/beanstream/connection/BeanstreamUrls.java +++ b/src/main/java/com/beanstream/connection/BeanstreamUrls.java @@ -101,4 +101,11 @@ public static String getPaymentUrl(String platform, String version, return MessageFormat.format(BeanstreamUrls.GetPaymentUrl, platform, version, paymentId); } + + public static String getPaymentContinuationsUrl(String platform, + String version, String merchantData) { + return MessageFormat.format(ContinuationsUrl, platform, version, + merchantData); + } + } diff --git a/src/main/java/com/beanstream/connection/HttpsConnector.java b/src/main/java/com/beanstream/connection/HttpsConnector.java index 4a095eb..d536f02 100644 --- a/src/main/java/com/beanstream/connection/HttpsConnector.java +++ b/src/main/java/com/beanstream/connection/HttpsConnector.java @@ -141,7 +141,7 @@ public BeanstreamResponse handleResponse(final HttpResponse http) BeanstreamResponse bsRes = process(http, responseHandler); int httpStatus = bsRes.getHttpStatusCode(); - if (httpStatus >= 200 && httpStatus < 300) { + if ((httpStatus >= 200 && httpStatus < 300) || httpStatus == 302 /* interac payment */) { return bsRes.getResponseBody(); } else { throw mappedException(httpStatus, bsRes); diff --git a/src/main/java/com/beanstream/responses/BeanstreamResponse.java b/src/main/java/com/beanstream/responses/BeanstreamResponse.java index 48dab07..56c9ae9 100644 --- a/src/main/java/com/beanstream/responses/BeanstreamResponse.java +++ b/src/main/java/com/beanstream/responses/BeanstreamResponse.java @@ -73,7 +73,7 @@ public static BeanstreamResponse fromHttpResponse(HttpResponse http) { MediaType responseType = contentType != null ? MediaType.parse(contentType) : null; // If the payload isn't json, or we got a 2XX response, just populate the responseBody field with the payload - if (responseType == null || responseType != MediaType.JSON_UTF_8 || (httpStatusCode >= 200 && httpStatusCode < 300)) { + if (responseType == null || responseType != MediaType.JSON_UTF_8 || (httpStatusCode >= 200 && httpStatusCode < 300) || httpStatusCode == 302 /* for interac */) { return new BeanstreamResponseBuilder() .withHttpStatusCode(httpStatusCode) .withResponseBody(jsonPayload) diff --git a/src/main/java/com/beanstream/responses/PaymentResponse.java b/src/main/java/com/beanstream/responses/PaymentResponse.java index 5a25955..457ed6e 100644 --- a/src/main/java/com/beanstream/responses/PaymentResponse.java +++ b/src/main/java/com/beanstream/responses/PaymentResponse.java @@ -55,6 +55,9 @@ public class PaymentResponse { public CardResponse card; + @SerializedName("interac_online") + public InteracOnline interacOnline; + public Link[] links; public boolean isApproved() { diff --git a/src/test/java/com/beanstream/api/test/SampleTransactions.java b/src/test/java/com/beanstream/api/test/SampleTransactions.java index da09369..c33d806 100644 --- a/src/test/java/com/beanstream/api/test/SampleTransactions.java +++ b/src/test/java/com/beanstream/api/test/SampleTransactions.java @@ -1,5 +1,19 @@ package com.beanstream.api.test; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.HttpClients; +import org.junit.Assert; +import org.junit.Test; + import com.beanstream.Gateway; import com.beanstream.connection.HttpMethod; import com.beanstream.connection.HttpsConnector; @@ -14,6 +28,7 @@ import com.beanstream.requests.CashPaymentRequest; import com.beanstream.requests.ChequePaymentRequest; import com.beanstream.requests.Criteria; +import com.beanstream.requests.InteracPaymentRequest; import com.beanstream.requests.LegatoTokenRequest; import com.beanstream.requests.Operators; import com.beanstream.requests.ProfilePaymentRequest; @@ -21,6 +36,7 @@ import com.beanstream.requests.QueryFields; import com.beanstream.requests.TokenPaymentRequest; import com.beanstream.responses.BeanstreamResponse; +import com.beanstream.responses.InteracPaymentResponse; import com.beanstream.responses.LegatoTokenResponse; import com.beanstream.responses.PaymentResponse; import com.beanstream.responses.ProfileResponse; @@ -28,20 +44,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.impl.client.HttpClients; - -import org.junit.Assert; -import org.junit.Test; - /* The MIT License (MIT) * * Copyright (c) 2014 Beanstream Internet Commerce Corp, Digital River, Inc. @@ -73,8 +75,8 @@ public class SampleTransactions { public static void main(String[] args) { SampleTransactions t = new SampleTransactions(); - /*t.testPayment(); - t.testTokenPayment(); + t.testPayment(); + /*t.testTokenPayment(); t.testVoidPayment(); t.testPreAuthorization(); t.testGetTransaction(); @@ -132,6 +134,26 @@ public void testPayment() { Assert.fail(ex.getMessage()); } + /* Test Interac Payment Request Initialization */ + InteracPaymentRequest interacReq = new InteracPaymentRequest(); + interacReq.setAmount(123.45); + interacReq.setOrderNumber(getRandomOrderId("interac")); + + try { + + InteracPaymentResponse response = beanstream.payments().interacPayment(interacReq); + Assert.assertNotNull( "Merchant data is missing", response.merchantData ); + System.out.println("Merchant data:\n"+ response.merchantData); + Assert.assertNotNull( "Redirect link is missing", response.links ); + Assert.assertEquals( "Redirect link is missing", 1, response.links.length ); + System.out.println("Redirect link to complete payment: "+response.links[0].getHref()); + Assert.assertNotNull( "HTML form is missing", response.contents ); + System.out.println("Interac Form to submit:\n"+ response.contents); + } catch (BeanstreamApiException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,"An error occurred", ex); + Assert.fail(ex.getMessage()); + } + /* Test Cash Payment */ CashPaymentRequest cashReq = new CashPaymentRequest(); cashReq.setAmount(123.45); From a36109df3c1c08358b4d859ebb83f4deda964507 Mon Sep 17 00:00:00 2001 From: Ilya Egoshin Date: Sat, 24 Feb 2018 17:18:22 -0600 Subject: [PATCH 03/14] interac payment API added (more testing needed) --- .../requests/InteracPaymentRequest.java | 49 +++++++++++++++++ .../beanstream/requests/InteracResponse.java | 52 +++++++++++++++++++ .../beanstream/responses/InteracOnline.java | 38 ++++++++++++++ .../responses/InteracPaymentResponse.java | 47 +++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 src/main/java/com/beanstream/requests/InteracPaymentRequest.java create mode 100644 src/main/java/com/beanstream/requests/InteracResponse.java create mode 100644 src/main/java/com/beanstream/responses/InteracOnline.java create mode 100644 src/main/java/com/beanstream/responses/InteracPaymentResponse.java diff --git a/src/main/java/com/beanstream/requests/InteracPaymentRequest.java b/src/main/java/com/beanstream/requests/InteracPaymentRequest.java new file mode 100644 index 0000000..37a933a --- /dev/null +++ b/src/main/java/com/beanstream/requests/InteracPaymentRequest.java @@ -0,0 +1,49 @@ +/* The MIT License (MIT) + * + * Copyright (c) 2014 Beanstream Internet Commerce Corp, Digital River, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.beanstream.requests; + +import com.google.gson.annotations.SerializedName; + +/** + * Process a Interac payment. + * NOTE: You will need to have these payment options ACTIVATED by calling Beanstream + * support at 1-888-472-0811 + * @author ilya + */ +public class InteracPaymentRequest extends PaymentRequest { + @SerializedName("payment_method") + public final String paymentMethod = "interac"; + + @SerializedName("interac_response") + private InteracResponse interacResponse; + + public InteracResponse getInteracResponse() { + if (interacResponse == null) + interacResponse = new InteracResponse(); + return interacResponse; + } + + public void setInteracResponse(InteracResponse interacResponse) { + this.interacResponse = interacResponse; + } +} diff --git a/src/main/java/com/beanstream/requests/InteracResponse.java b/src/main/java/com/beanstream/requests/InteracResponse.java new file mode 100644 index 0000000..e72741c --- /dev/null +++ b/src/main/java/com/beanstream/requests/InteracResponse.java @@ -0,0 +1,52 @@ +/* The MIT License (MIT) + * + * Copyright (c) 2014 Beanstream Internet Commerce Corp, Digital River, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.beanstream.requests; + +import com.google.gson.annotations.SerializedName; + +/** + * Parameters to complete Interac payment. + * @author ilya + */ +public class InteracResponse { + @SerializedName("idebit_track2") + public String idebitTrack2; + + @SerializedName("idebit_isslang") + public String idebitIsslang; + + @SerializedName("idebit_version") + public String idebitVersion; + + @SerializedName("idebit_issconf") + public String idebitIssconf; + + @SerializedName("idebit_issname") + public String idebitIssname; + + @SerializedName("idebit_amount") + public String idebitAmount; + + @SerializedName("idebit_invoice") + public String idebitInvoice; +} diff --git a/src/main/java/com/beanstream/responses/InteracOnline.java b/src/main/java/com/beanstream/responses/InteracOnline.java new file mode 100644 index 0000000..38c9507 --- /dev/null +++ b/src/main/java/com/beanstream/responses/InteracOnline.java @@ -0,0 +1,38 @@ +/* The MIT License (MIT) + * + * Copyright (c) 2014 Beanstream Internet Commerce Corp, Digital River, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.beanstream.responses; + +import com.google.gson.annotations.SerializedName; + +/** + * Interac Online payment result. + * + * @author ilya + */ +public class InteracOnline { + @SerializedName("idebit_issconf") + private String idebitIssconf; + + @SerializedName("idebit_issname") + private String idebitIssname; +} diff --git a/src/main/java/com/beanstream/responses/InteracPaymentResponse.java b/src/main/java/com/beanstream/responses/InteracPaymentResponse.java new file mode 100644 index 0000000..3a72ad6 --- /dev/null +++ b/src/main/java/com/beanstream/responses/InteracPaymentResponse.java @@ -0,0 +1,47 @@ +/* The MIT License (MIT) + * + * Copyright (c) 2014 Beanstream Internet Commerce Corp, Digital River, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.beanstream.responses; + +import com.google.gson.annotations.SerializedName; + +/** + * The response for interac payment request. + * Before returning the response to your users HTML client, you will need to save + * the merchant_data string in the users session. This value can be used as the {id} value + * when creating your 'continue' endpoint URL for the final request in step 3. + * The response will have HTML in the contents. This should be embedded in the user's + * browser client and this needs to be displayed to the customer to redirect them to the + * Interac login page. Here the customer will log onto their bank account and approve the payment. + * An approved or declined payment will forward the customer back to the + * Funded or Non-funded URLs (respectively) on your website. + * + * @author ilya + */ +public class InteracPaymentResponse { + @SerializedName("merchant_data") + public String merchantData; + + public String contents; + + public Link[] links; +} From 5b83acc33cf316ba3f39370f918b4a53b9631e2e Mon Sep 17 00:00:00 2001 From: Ilya Egoshin Date: Sat, 24 Feb 2018 17:37:10 -0600 Subject: [PATCH 04/14] small fixes in comments to remove warnings from java docs generator --- src/main/java/com/beanstream/api/ProfilesAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/beanstream/api/ProfilesAPI.java b/src/main/java/com/beanstream/api/ProfilesAPI.java index 2b34aad..b4fbd9f 100644 --- a/src/main/java/com/beanstream/api/ProfilesAPI.java +++ b/src/main/java/com/beanstream/api/ProfilesAPI.java @@ -276,7 +276,7 @@ public ProfileResponse updateProfile(PaymentProfile profile) * * @param profileId * of the profile containing the cards - * @return List with all the cards for that profile + * @return List<Card> with all the cards for that profile * @throws BeanstreamApiException * if any validation fails or any error occur */ @@ -365,7 +365,7 @@ public ProfileResponse updateCard(String profileId, Card card) * cards. Make sure your Merchant account can support more cards. The * default amount is 1. You can change this limit in the online Members area * for Merchants located at: https://www.beanstream.com/admin/sDefault.asp - * and heading to Configuration -> Payment Profile Configuration + * and heading to Configuration -> Payment Profile Configuration * * @param profileId * @param card From 04c0b09faa61d77e978c80cc3ea0906ef5b7d93c Mon Sep 17 00:00:00 2001 From: iegoshin Date: Sun, 25 Feb 2018 13:08:34 -0600 Subject: [PATCH 05/14] getters/setters added for interac payment response --- .../beanstream/requests/InteracResponse.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/main/java/com/beanstream/requests/InteracResponse.java b/src/main/java/com/beanstream/requests/InteracResponse.java index e72741c..d538b9f 100644 --- a/src/main/java/com/beanstream/requests/InteracResponse.java +++ b/src/main/java/com/beanstream/requests/InteracResponse.java @@ -49,4 +49,60 @@ public class InteracResponse { @SerializedName("idebit_invoice") public String idebitInvoice; + + public String getIdebitTrack2() { + return idebitTrack2; + } + + public void setIdebitTrack2( String idebitTrack2 ) { + this.idebitTrack2 = idebitTrack2; + } + + public String getIdebitIsslang() { + return idebitIsslang; + } + + public void setIdebitIsslang( String idebitIsslang ) { + this.idebitIsslang = idebitIsslang; + } + + public String getIdebitVersion() { + return idebitVersion; + } + + public void setIdebitVersion( String idebitVersion ) { + this.idebitVersion = idebitVersion; + } + + public String getIdebitIssconf() { + return idebitIssconf; + } + + public void setIdebitIssconf( String idebitIssconf ) { + this.idebitIssconf = idebitIssconf; + } + + public String getIdebitIssname() { + return idebitIssname; + } + + public void setIdebitIssname( String idebitIssname ) { + this.idebitIssname = idebitIssname; + } + + public String getIdebitAmount() { + return idebitAmount; + } + + public void setIdebitAmount( String idebitAmount ) { + this.idebitAmount = idebitAmount; + } + + public String getIdebitInvoice() { + return idebitInvoice; + } + + public void setIdebitInvoice( String idebitInvoice ) { + this.idebitInvoice = idebitInvoice; + } } From b495c9a4e3e1c6e850831f2d9f7490fd137d3686 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Sun, 25 Feb 2018 13:29:37 -0600 Subject: [PATCH 06/14] validation added to Interac Response object --- .../beanstream/requests/InteracResponse.java | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/beanstream/requests/InteracResponse.java b/src/main/java/com/beanstream/requests/InteracResponse.java index d538b9f..e874f89 100644 --- a/src/main/java/com/beanstream/requests/InteracResponse.java +++ b/src/main/java/com/beanstream/requests/InteracResponse.java @@ -29,32 +29,46 @@ * @author ilya */ public class InteracResponse { + private String funded; + @SerializedName("idebit_track2") - public String idebitTrack2; + private String idebitTrack2; @SerializedName("idebit_isslang") - public String idebitIsslang; + private String idebitIsslang; @SerializedName("idebit_version") - public String idebitVersion; + private String idebitVersion; @SerializedName("idebit_issconf") - public String idebitIssconf; + private String idebitIssconf; @SerializedName("idebit_issname") - public String idebitIssname; + private String idebitIssname; @SerializedName("idebit_amount") - public String idebitAmount; + private String idebitAmount; @SerializedName("idebit_invoice") - public String idebitInvoice; + private String idebitInvoice; + + public String getFunded() { + return funded; + } + + public void setFunded( String funded ) { + if (funded != null && funded.length() > 20) + throw new IllegalArgumentException("Funded cannot be longer than 20 characters!"); + this.funded = funded; + } public String getIdebitTrack2() { return idebitTrack2; } public void setIdebitTrack2( String idebitTrack2 ) { + if (idebitTrack2 != null && idebitTrack2.length() > 256) + throw new IllegalArgumentException("IdebitTrack2 cannot be longer than 256 characters!"); this.idebitTrack2 = idebitTrack2; } @@ -63,6 +77,8 @@ public String getIdebitIsslang() { } public void setIdebitIsslang( String idebitIsslang ) { + if (idebitIsslang != null && idebitIsslang.length() > 2) + throw new IllegalArgumentException("IdebitIsslang cannot be longer than 2 characters!"); this.idebitIsslang = idebitIsslang; } @@ -71,6 +87,8 @@ public String getIdebitVersion() { } public void setIdebitVersion( String idebitVersion ) { + if (idebitVersion != null && idebitVersion.length() > 1) + throw new IllegalArgumentException("IdebitVersion cannot be longer than 1 character!"); this.idebitVersion = idebitVersion; } @@ -79,6 +97,8 @@ public String getIdebitIssconf() { } public void setIdebitIssconf( String idebitIssconf ) { + if (idebitIssconf != null && idebitIssconf.length() > 32) + throw new IllegalArgumentException("IdebitIssconf cannot be longer than 32 characters!"); this.idebitIssconf = idebitIssconf; } @@ -87,6 +107,8 @@ public String getIdebitIssname() { } public void setIdebitIssname( String idebitIssname ) { + if (idebitIssname != null && idebitIssname.length() > 32) + throw new IllegalArgumentException("IdebitIssname cannot be longer than 32 characters!"); this.idebitIssname = idebitIssname; } @@ -95,6 +117,8 @@ public String getIdebitAmount() { } public void setIdebitAmount( String idebitAmount ) { + if (idebitAmount != null && idebitAmount.length() > 9) + throw new IllegalArgumentException("IdebitAmount cannot be longer than 9 characters!"); this.idebitAmount = idebitAmount; } @@ -103,6 +127,8 @@ public String getIdebitInvoice() { } public void setIdebitInvoice( String idebitInvoice ) { + if (idebitInvoice != null && idebitInvoice.length() > 20) + throw new IllegalArgumentException("IdebitInvoice cannot be longer than 20 characters!"); this.idebitInvoice = idebitInvoice; } } From 02e677ce9fc535d4c3ace9bfb27e668fc1dfe9f5 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Sun, 25 Feb 2018 13:43:24 -0600 Subject: [PATCH 07/14] InteracOnline fields should be public --- src/main/java/com/beanstream/responses/InteracOnline.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/beanstream/responses/InteracOnline.java b/src/main/java/com/beanstream/responses/InteracOnline.java index 38c9507..0cd5189 100644 --- a/src/main/java/com/beanstream/responses/InteracOnline.java +++ b/src/main/java/com/beanstream/responses/InteracOnline.java @@ -31,8 +31,8 @@ */ public class InteracOnline { @SerializedName("idebit_issconf") - private String idebitIssconf; + public String idebitIssconf; @SerializedName("idebit_issname") - private String idebitIssname; + public String idebitIssname; } From cf7b79eeff1853993d42dd38cca4a9a656a74cc0 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Mon, 26 Feb 2018 21:29:19 -0600 Subject: [PATCH 08/14] create objects in payment request on first access --- src/main/java/com/beanstream/requests/PaymentRequest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/beanstream/requests/PaymentRequest.java b/src/main/java/com/beanstream/requests/PaymentRequest.java index 10f0976..a508332 100644 --- a/src/main/java/com/beanstream/requests/PaymentRequest.java +++ b/src/main/java/com/beanstream/requests/PaymentRequest.java @@ -119,6 +119,8 @@ public PaymentRequest setComments(String comments) { } public Address getBilling() { + if (billing==null) + billing = new Address(); return billing; } @@ -127,6 +129,8 @@ public void setBilling(Address billing) { } public Address getShipping() { + if (shipping==null) + shipping = new Address(); return shipping; } @@ -135,6 +139,8 @@ public void setShipping(Address shipping) { } public CustomFields getCustom() { + if (custom==null) + custom = new CustomFields(); return custom; } From 7e118f63cf28cedc19295f951c94a5769bd527bb Mon Sep 17 00:00:00 2001 From: iegoshin Date: Wed, 9 Dec 2020 17:59:18 -0600 Subject: [PATCH 09/14] Better handling for the 'details' array in the ErrorResponse --- .../exceptions/BeanstreamApiException.java | 14 ++++-- .../responses/BeanstreamResponse.java | 44 ++++++++++++++----- .../responses/BeanstreamResponseBuilder.java | 4 +- .../java/com/beanstream/responses/Detail.java | 16 +++++++ 4 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/beanstream/responses/Detail.java diff --git a/src/main/java/com/beanstream/exceptions/BeanstreamApiException.java b/src/main/java/com/beanstream/exceptions/BeanstreamApiException.java index 7c7aaa1..33d9530 100644 --- a/src/main/java/com/beanstream/exceptions/BeanstreamApiException.java +++ b/src/main/java/com/beanstream/exceptions/BeanstreamApiException.java @@ -46,9 +46,12 @@ /// in the 500+ range. Card holders should wait a minute and try the transaction again. /// /// -import com.beanstream.responses.BeanstreamResponse; import org.apache.http.HttpStatus; +import com.beanstream.Gateway; +import com.beanstream.responses.BeanstreamResponse; +import com.beanstream.responses.Detail; + /** * * @author bowens @@ -88,8 +91,13 @@ public static BeanstreamApiException getMappedException(int httpStatusCode, Bean int code = response.getCode(); int category = response.getCategory(); String message = response.getMessage(); - String details = response.getDetails(); - message = message + ", details: " + details; + Detail[] details = response.getDetails(); + if (details!=null && details.length>0) { + message += ", details: "; + for (Detail detail: details) { + message += "\n" + detail.getField() + ": " + detail.getMessage(); + } + } switch (httpStatusCode) { case HttpStatus.SC_MOVED_TEMPORARILY: { // 302 diff --git a/src/main/java/com/beanstream/responses/BeanstreamResponse.java b/src/main/java/com/beanstream/responses/BeanstreamResponse.java index 56c9ae9..f4fd498 100644 --- a/src/main/java/com/beanstream/responses/BeanstreamResponse.java +++ b/src/main/java/com/beanstream/responses/BeanstreamResponse.java @@ -1,13 +1,18 @@ package com.beanstream.responses; -import com.beanstream.exceptions.BeanstreamApiException; -import com.google.common.net.MediaType; -import com.google.gson.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; -import java.io.IOException; +import com.beanstream.exceptions.BeanstreamApiException; +import com.google.common.net.MediaType; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; public class BeanstreamResponse { @@ -15,14 +20,12 @@ public class BeanstreamResponse { private final int category; private final String message; private final String reference; - private final String details; + private final Detail[] details; private final int httpStatusCode; private final String responseBody; private final MediaType mediaType; - private static final Gson gson = new Gson(); - - BeanstreamResponse(int code, int category, String message, String reference, String details, int httpStatusCode, + BeanstreamResponse(int code, int category, String message, String reference, Detail[] details, int httpStatusCode, String responseBody, MediaType mediaType) { this.code = code; this.category = category; @@ -116,8 +119,27 @@ private static BeanstreamResponse fromJson(int httpStatusCode, String jsonPayloa } element = json.get("details"); - if (element != null && !element.isJsonNull()) { - builder.withDetails(element.toString()); + if (element != null && element.isJsonArray()) { + List details = new ArrayList<>(); + for (JsonElement elem: element.getAsJsonArray()) { + if (elem != null && elem.isJsonObject()) { + JsonObject obj = elem.getAsJsonObject(); + String field = null; + String message = null; + element = obj.get( "field" ); + if (element != null && !element.isJsonNull()) { + field = element.getAsString(); + } + element = obj.get( "message" ); + if (element != null && !element.isJsonNull()) { + message = element.getAsString(); + } + if (field!=null && message!=null) { + details.add( new Detail(field, message) ); + } + } + } + builder.withDetails(details.toArray(new Detail[details.size()])); } builder.withHttpStatusCode(httpStatusCode); @@ -140,7 +162,7 @@ public String getReference() { return reference; } - public String getDetails() { + public Detail[] getDetails() { return details; } diff --git a/src/main/java/com/beanstream/responses/BeanstreamResponseBuilder.java b/src/main/java/com/beanstream/responses/BeanstreamResponseBuilder.java index 54a34f9..d37aff3 100644 --- a/src/main/java/com/beanstream/responses/BeanstreamResponseBuilder.java +++ b/src/main/java/com/beanstream/responses/BeanstreamResponseBuilder.java @@ -8,7 +8,7 @@ public class BeanstreamResponseBuilder { private int category = -1; private String message = ""; private String reference = ""; - private String details = ""; + private Detail[] details = new Detail[0]; private int httpStatusCode = -1; private String responseBody = ""; private MediaType mediaType = null; @@ -43,7 +43,7 @@ public BeanstreamResponseBuilder withResponseBody(String responseBody) { return this; } - public BeanstreamResponseBuilder withDetails(String details) { + public BeanstreamResponseBuilder withDetails(Detail[] details) { this.details = details; return this; } diff --git a/src/main/java/com/beanstream/responses/Detail.java b/src/main/java/com/beanstream/responses/Detail.java new file mode 100644 index 0000000..17b24f6 --- /dev/null +++ b/src/main/java/com/beanstream/responses/Detail.java @@ -0,0 +1,16 @@ +package com.beanstream.responses; + +public class Detail { + private final String field; + private final String message; + public Detail(String field, String message) { + this.field = field; + this.message = message; + } + public String getField() { + return field; + } + public String getMessage() { + return message; + } +} From 0ab07f74a159d1815a3738479111e69f0fd50ea1 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Tue, 1 Jun 2021 21:04:16 -0500 Subject: [PATCH 10/14] add logs --- build.gradle | 3 +- .../java/com/beanstream/api/PaymentsAPI.java | 140 +++++++++++++++++- 2 files changed, 138 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index ef29e02..729e760 100644 --- a/build.gradle +++ b/build.gradle @@ -17,8 +17,7 @@ if (!hasProperty('mainClass')) { apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' -apply plugin: 'osgi' - +//apply plugin: 'osgi' sourceCompatibility = '1.7' group = "com.beanstream.api" diff --git a/src/main/java/com/beanstream/api/PaymentsAPI.java b/src/main/java/com/beanstream/api/PaymentsAPI.java index b2b1608..8427ff6 100644 --- a/src/main/java/com/beanstream/api/PaymentsAPI.java +++ b/src/main/java/com/beanstream/api/PaymentsAPI.java @@ -64,6 +64,7 @@ public class PaymentsAPI { private static final String AMOUNT_PARAM = "amount"; private static final String MERCHANT_ID_PARAM = "merchant_id"; + private static ThreadLocal communicationLog = new ThreadLocal<>(); private Configuration config; private HttpsConnector connector; private final Gson gson = new Gson(); @@ -74,6 +75,36 @@ public PaymentsAPI(Configuration config) { config.getPaymentsApiPasscode()); connector.setCustomHttpClient(config.getCustomHttpClient()); } + + public static String getLog() { + StringBuffer sb = communicationLog.get(); + if (sb!=null) { + return sb.toString(); + } + return null; + } + + private static StringBuffer getLogInternal() { + StringBuffer sb = communicationLog.get(); + if (sb==null) { + sb = new StringBuffer(); + communicationLog.set( sb ); + } + return sb; + } + + public static void addLog(String str) { + if (str!=null && str.length()>0) { + StringBuffer sb = getLogInternal(); + if (sb.length()>0) + sb.append( "\n\n" ); + sb.append( str ); + } + } + + public static void clearLog() { + communicationLog.remove(); + } public void setConfig(Configuration config) { this.config = config; @@ -95,16 +126,23 @@ public void setConfig(Configuration config) { */ public PaymentResponse makePayment(CardPaymentRequest paymentRequest) throws BeanstreamApiException { - paymentRequest.setMerchantId("" + config.getMerchantId()); + clearLog(); + + paymentRequest.setMerchantId("" + config.getMerchantId()); paymentRequest.getCard().setComplete(true); // false for pre-auth // build the URL String url = BeanstreamUrls.getPaymentUrl(config.getPlatform(), config.getVersion()); + + addLog(url); + addLog(gson.toJson( paymentRequest )); // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); } @@ -120,15 +158,22 @@ public PaymentResponse makePayment(CardPaymentRequest paymentRequest) * or any other error */ public PaymentResponse makePayment(TokenPaymentRequest paymentRequest) throws BeanstreamApiException { - paymentRequest.setMerchantId("" + config.getMerchantId()); + clearLog(); + + paymentRequest.setMerchantId("" + config.getMerchantId()); paymentRequest.getToken().setComplete(true); // true to make the payment // build the URL String url = BeanstreamUrls.getPaymentUrl( config.getPlatform(), config.getVersion()); + addLog(url); + addLog(gson.toJson( paymentRequest )); + // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); } @@ -143,15 +188,22 @@ public PaymentResponse makePayment(TokenPaymentRequest paymentRequest) throws Be * or any other error */ public PaymentResponse makePayment(ProfilePaymentRequest paymentRequest) throws BeanstreamApiException { - paymentRequest.setMerchantId("" + config.getMerchantId()); + clearLog(); + + paymentRequest.setMerchantId("" + config.getMerchantId()); paymentRequest.getProfile().setComplete(true); // true to make the payment // build the URL String url = BeanstreamUrls.getPaymentUrl( config.getPlatform(), config.getVersion()); + addLog(url); + addLog(gson.toJson( paymentRequest )); + // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); } @@ -166,13 +218,19 @@ public PaymentResponse makePayment(ProfilePaymentRequest paymentRequest) throws * or any other error @see */ public InteracPaymentResponse interacPayment(InteracPaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); // build the URL String url = BeanstreamUrls.getPaymentUrl( config.getPlatform(), config.getVersion()); + addLog(url); + addLog(gson.toJson( paymentRequest )); + // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a InteracPaymentResponse InteracPaymentResponse res = gson.fromJson(response, InteracPaymentResponse.class); try { @@ -193,13 +251,19 @@ public InteracPaymentResponse interacPayment(InteracPaymentRequest paymentReques * or any other error @see */ public PaymentResponse interacPaymentCompletion(String merchantData, InteracPaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); // build the URL String url = BeanstreamUrls.getPaymentContinuationsUrl( config.getPlatform(), config.getVersion(), merchantData); + addLog(url); + addLog(gson.toJson( paymentRequest )); + // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); } @@ -214,13 +278,19 @@ public PaymentResponse interacPaymentCompletion(String merchantData, InteracPaym * or any other error @see */ public PaymentResponse makePayment(CashPaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); // build the URL String url = BeanstreamUrls.getPaymentUrl( config.getPlatform(), config.getVersion()); + addLog(url); + addLog(gson.toJson( paymentRequest )); + // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); } @@ -235,13 +305,19 @@ public PaymentResponse makePayment(CashPaymentRequest paymentRequest) throws Bea * or any other error @see */ public PaymentResponse makePayment(ChequePaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); // build the URL String url = BeanstreamUrls.getPaymentUrl( config.getPlatform(), config.getVersion()); + addLog(url); + addLog(gson.toJson( paymentRequest )); + // process the transaction using the REST API String response = connector.ProcessTransaction(HttpMethod.post, url, paymentRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); } @@ -266,6 +342,7 @@ public PaymentResponse makePayment(ChequePaymentRequest paymentRequest) throws B */ public PaymentResponse voidPayment(String paymentId, double amount) throws BeanstreamApiException { + clearLog(); Gateway.assertNotEmpty(paymentId, "invalid paymentId"); String url = getVoidPaymentUrl(config.getPlatform(), @@ -276,9 +353,14 @@ public PaymentResponse voidPayment(String paymentId, double amount) String.valueOf(config.getMerchantId())); voidRequest.addProperty(AMOUNT_PARAM, String.valueOf(amount)); + addLog(url); + addLog(gson.toJson( voidRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, url, voidRequest); + addLog(response); + // parse the output and return a PaymentResponse return gson.fromJson(response, PaymentResponse.class); @@ -301,6 +383,7 @@ public PaymentResponse voidPayment(String paymentId, double amount) */ public PaymentResponse preAuth(CardPaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); if (paymentRequest == null || paymentRequest.getCard() == null) { // TODO - do we need to supply category and code ids here? @@ -313,8 +396,14 @@ public PaymentResponse preAuth(CardPaymentRequest paymentRequest) String preAuthUrl = getPaymentUrl(config.getPlatform(), config.getVersion()); + addLog(preAuthUrl); + addLog(gson.toJson( paymentRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, preAuthUrl, paymentRequest); + + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -335,6 +424,7 @@ public PaymentResponse preAuth(CardPaymentRequest paymentRequest) */ public PaymentResponse preAuth(ProfilePaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); if (paymentRequest == null || paymentRequest.getProfile() == null) { // TODO - do we need to supply category and code ids here? @@ -347,8 +437,14 @@ public PaymentResponse preAuth(ProfilePaymentRequest paymentRequest) String preAuthUrl = getPaymentUrl(config.getPlatform(), config.getVersion()); + addLog(preAuthUrl); + addLog(gson.toJson( paymentRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, preAuthUrl, paymentRequest); + + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -369,6 +465,7 @@ public PaymentResponse preAuth(ProfilePaymentRequest paymentRequest) */ public PaymentResponse preAuth(TokenPaymentRequest paymentRequest) throws BeanstreamApiException { + clearLog(); if (paymentRequest == null || paymentRequest.getToken() == null) { BeanstreamResponse response = BeanstreamResponse.fromMessage("invalid payment request"); @@ -379,7 +476,13 @@ public PaymentResponse preAuth(TokenPaymentRequest paymentRequest) String preAuthUrl = getPaymentUrl(config.getPlatform(), config.getVersion()); + addLog(preAuthUrl); + addLog(gson.toJson( paymentRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, preAuthUrl, paymentRequest); + + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -393,6 +496,7 @@ public PaymentResponse preAuth(TokenPaymentRequest paymentRequest) * @throws BeanstreamApiException */ public PaymentResponse preAuthCompletion(String paymentId, double amount) throws BeanstreamApiException { + clearLog(); Gateway.assertNotEmpty(paymentId, "Invalid Payment Id"); @@ -404,9 +508,14 @@ public PaymentResponse preAuthCompletion(String paymentId, double amount) throws String.valueOf(config.getMerchantId())); authorizeRequest.addProperty(AMOUNT_PARAM, String.valueOf(amount)); + addLog(authorizePaymentUrl); + addLog(gson.toJson( authorizeRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, authorizePaymentUrl, authorizeRequest); + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -420,12 +529,19 @@ public PaymentResponse preAuthCompletion(String paymentId, double amount) throws * @throws BeanstreamApiException if the transaction was declined */ public PaymentResponse preAuthCompletion(String paymentId, PaymentRequest request) throws BeanstreamApiException { + clearLog(); Gateway.assertNotEmpty(paymentId, "Invalid Payment Id"); String authorizePaymentUrl = getPreAuthCompletionsUrl( config.getPlatform(), config.getVersion(), paymentId); + addLog(authorizePaymentUrl); + addLog(gson.toJson( request )); + String response = connector.ProcessTransaction(HttpMethod.post, authorizePaymentUrl, request); + + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -438,6 +554,7 @@ public PaymentResponse preAuthCompletion(String paymentId, PaymentRequest reques * @throws BeanstreamApiException */ public PaymentResponse returnPayment(String paymentId, double amount) throws BeanstreamApiException { + clearLog(); Gateway.assertNotEmpty(paymentId, "Invalid Payment Id"); @@ -447,8 +564,13 @@ public PaymentResponse returnPayment(String paymentId, double amount) throws Bea returnRequest.setMerchantId( String.valueOf(config.getMerchantId()) ); returnRequest.setAmount( amount ); + addLog(returnPaymentUrl); + addLog(gson.toJson( returnRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, returnPaymentUrl, returnRequest); + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -463,14 +585,20 @@ public PaymentResponse returnPayment(String paymentId, double amount) throws Bea * @throws BeanstreamApiException */ public PaymentResponse unreferencedReturn(UnreferencedCardReturnRequest returnRequest) throws BeanstreamApiException { + clearLog(); String unreferencedReturnUrl = getUnreferencedReturnUrl( config.getPlatform(), config.getVersion()); returnRequest.setMerchantId( String.valueOf(config.getMerchantId()) ); + addLog(unreferencedReturnUrl); + addLog(gson.toJson( returnRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, unreferencedReturnUrl, returnRequest); + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } @@ -485,14 +613,20 @@ public PaymentResponse unreferencedReturn(UnreferencedCardReturnRequest returnRe * @throws BeanstreamApiException */ public PaymentResponse unreferencedReturn(UnreferencedSwipeReturnRequest returnRequest) throws BeanstreamApiException { + clearLog(); String unreferencedReturnUrl = getUnreferencedReturnUrl( config.getPlatform(), config.getVersion()); returnRequest.setMerchantId( String.valueOf(config.getMerchantId()) ); + addLog(unreferencedReturnUrl); + addLog(gson.toJson( returnRequest )); + String response = connector.ProcessTransaction(HttpMethod.post, unreferencedReturnUrl, returnRequest); + addLog(response); + return gson.fromJson(response, PaymentResponse.class); } From 25c72407d923fb4364fba2b2985f3ae3d1a6afde Mon Sep 17 00:00:00 2001 From: iegoshin Date: Tue, 1 Jun 2021 21:21:46 -0500 Subject: [PATCH 11/14] plugin osgi deprecated --- build.gradle | 6 +++++- settings.gradle | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 729e760..9ee7eaf 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,10 @@ import org.gradle.api.XmlProvider import org.gradle.api.artifacts.maven.MavenDeployment +plugins { + id 'biz.aQute.bnd.builder' +} + // NetBeans will automatically add "run" and "debug" tasks relying on the // "mainClass" property. You may however define the property prior executing // tasks by passing a "-PmainClass=" argument. @@ -13,12 +17,12 @@ if (!hasProperty('mainClass')) { ext.mainClass = 'com.beanstream.api.test.SampleTransactions' } - apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' //apply plugin: 'osgi' + sourceCompatibility = '1.7' group = "com.beanstream.api" version = "1.0.0" diff --git a/settings.gradle b/settings.gradle index 0492399..760957e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,7 @@ +pluginManagement { + plugins { + id 'biz.aQute.bnd.builder' version '5.3.0' + } +} + rootProject.name='beanstream' From 70f3832f2838f3a3476afc0531cfecc1c6c259c8 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Tue, 1 Jun 2021 21:24:01 -0500 Subject: [PATCH 12/14] version changed --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9ee7eaf..d2331a4 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'signing' sourceCompatibility = '1.7' group = "com.beanstream.api" -version = "1.0.0" +version = "1.0.0-modified" From 9ca298c8bf63aa6fa8e97b7dad9d77b367432320 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Tue, 1 Jun 2021 21:27:23 -0500 Subject: [PATCH 13/14] clear logs after returning --- src/main/java/com/beanstream/api/PaymentsAPI.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/beanstream/api/PaymentsAPI.java b/src/main/java/com/beanstream/api/PaymentsAPI.java index 8427ff6..1e8157d 100644 --- a/src/main/java/com/beanstream/api/PaymentsAPI.java +++ b/src/main/java/com/beanstream/api/PaymentsAPI.java @@ -79,7 +79,11 @@ public PaymentsAPI(Configuration config) { public static String getLog() { StringBuffer sb = communicationLog.get(); if (sb!=null) { - return sb.toString(); + try { + return sb.toString(); + } finally { + clearLog(); + } } return null; } From 71260b4fb147f3a77c721a41737167804fd60144 Mon Sep 17 00:00:00 2001 From: iegoshin Date: Wed, 9 Jun 2021 18:22:17 -0500 Subject: [PATCH 14/14] logging error response --- src/main/java/com/beanstream/connection/HttpsConnector.java | 4 ++++ .../java/com/beanstream/responses/BeanstreamResponse.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/beanstream/connection/HttpsConnector.java b/src/main/java/com/beanstream/connection/HttpsConnector.java index d536f02..9830d84 100644 --- a/src/main/java/com/beanstream/connection/HttpsConnector.java +++ b/src/main/java/com/beanstream/connection/HttpsConnector.java @@ -44,6 +44,7 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; +import com.beanstream.api.PaymentsAPI; import com.beanstream.exceptions.BeanstreamApiException; import com.beanstream.responses.BeanstreamResponse; import com.google.gson.Gson; @@ -210,6 +211,7 @@ private BeanstreamApiException handleException(Exception ex, HttpsURLConnection } else { message = "Connection error"; } + PaymentsAPI.addLog( message ); return new BeanstreamApiException(ex, message); } @@ -220,6 +222,8 @@ private BeanstreamApiException handleException(Exception ex, HttpsURLConnection private BeanstreamApiException mappedException(int status, BeanstreamResponse bsRes) { if (bsRes != null) { + if (bsRes.getResponseBody()!=null) + PaymentsAPI.addLog( bsRes.getResponseBody() ); return BeanstreamApiException.getMappedException(status, bsRes); } diff --git a/src/main/java/com/beanstream/responses/BeanstreamResponse.java b/src/main/java/com/beanstream/responses/BeanstreamResponse.java index f4fd498..67586cd 100644 --- a/src/main/java/com/beanstream/responses/BeanstreamResponse.java +++ b/src/main/java/com/beanstream/responses/BeanstreamResponse.java @@ -92,7 +92,8 @@ private static BeanstreamResponse fromJson(int httpStatusCode, String jsonPayloa JsonParser parser = new JsonParser(); JsonObject json = parser.parse(jsonPayload).getAsJsonObject(); - BeanstreamResponseBuilder builder = new BeanstreamResponseBuilder(); + BeanstreamResponseBuilder builder = new BeanstreamResponseBuilder() + .withResponseBody( jsonPayload ); builder.setMediaType(responseType);