From 2299ba2371490166a537726994b7d3d9133add4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Pinet?= Date: Tue, 27 Aug 2024 16:44:14 +0200 Subject: [PATCH] Extract Payment method to another client - update dependencies --- build.gradle | 24 +-- .../hopper/cloud/airlines/HopperClient.java | 35 ++-- .../cloud/airlines/HopperPaymentClient.java | 69 ++++++++ .../airlines/auth/OAuthOkHttpClient.java | 1 + .../airlines/model/PaymentCardDetail.java | 157 ++++++++++++++++++ .../tokenization/TokenizationRequest.java | 21 +++ 6 files changed, 272 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/hopper/cloud/airlines/HopperPaymentClient.java create mode 100644 src/main/java/com/hopper/cloud/airlines/model/PaymentCardDetail.java diff --git a/build.gradle b/build.gradle index 52a2fbb..ac232b2 100644 --- a/build.gradle +++ b/build.gradle @@ -20,20 +20,20 @@ repositories { mavenCentral() } dependencies { - swaggerCodegen 'org.openapitools:openapi-generator-cli:6.0.0' - implementation 'com.google.code.gson:gson:2.9.0' - implementation 'io.swagger:swagger-annotations:1.6.6' + swaggerCodegen 'org.openapitools:openapi-generator-cli:7.8.0' + implementation 'com.google.code.gson:gson:2.11.0' + implementation 'io.swagger:swagger-annotations:1.6.14' implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'javax.ws.rs:javax.ws.rs-api:2.1.1' - implementation 'com.squareup.okhttp3:okhttp:4.10.0' - implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0' - implementation 'com.squareup.okio:okio:3.2.0' - implementation 'org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.1' - implementation 'org.apache.oltu.oauth2:org.apache.oltu.oauth2.common:1.0.1' - implementation 'io.gsonfire:gson-fire:1.8.5' - implementation 'com.google.code.findbugs:jsr305:3.0.2' - implementation 'com.konghq:unirest-java:3.13.10' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' + implementation 'com.squareup.okhttp3:okhttp:4.12.0' + implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0' + implementation 'com.squareup.okio:okio:3.9.0' + implementation 'org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2' + implementation 'org.apache.oltu.oauth2:org.apache.oltu.oauth2.common:1.0.2' + implementation 'io.gsonfire:gson-fire:1.9.0' + implementation 'com.github.spotbugs:spotbugs-annotations:4.8.6' + implementation 'com.konghq:unirest-java:3.14.5' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' } task printVersionName { diff --git a/src/main/java/com/hopper/cloud/airlines/HopperClient.java b/src/main/java/com/hopper/cloud/airlines/HopperClient.java index c8d8fda..0319ffc 100644 --- a/src/main/java/com/hopper/cloud/airlines/HopperClient.java +++ b/src/main/java/com/hopper/cloud/airlines/HopperClient.java @@ -18,22 +18,19 @@ public class HopperClient { private CancelForAnyReasonCfarApi cfarApi; private SessionsApi sessionsApi; private AnalyticsApi analyticsApi; - private String paymentUrl; - private String paymentUsername; - private String paymentPassword; + private HopperPaymentClient hopperPaymentClient; public HopperClient(String url, String clientId, String clientSecret, Boolean debugging) { - this.initHopperClient(url, clientId, clientSecret, null, null, null, debugging); + this.initHopperClient(url, clientId, clientSecret, debugging); } public HopperClient(String url, String clientId, String clientSecret, String paymentUrl, String paymentUsername, String paymentPassword, Boolean debugging) { - this.initHopperClient(url, clientId, clientSecret, paymentUrl, paymentUsername, paymentPassword, debugging); + this(url, clientId, clientSecret, debugging); + hopperPaymentClient = new HopperPaymentClient(paymentUrl, paymentUsername, paymentPassword); } - private void initHopperClient(String url, String clientId, String clientSecret, String paymentUrl, String paymentUsername, String paymentPassword, Boolean debugging) { - this.paymentUrl = paymentUrl; - this.paymentUsername = paymentUsername; - this.paymentPassword = paymentPassword; + + private void initHopperClient(String url, String clientId, String clientSecret, Boolean debugging) { Map params = new HashMap<>(); params.put("audience", String.join("/", Arrays.asList(url.split("/")).subList(0, 3))); params.put("grant_type", "client_credentials"); @@ -78,7 +75,7 @@ public T readValue(String value, Class valueType) { throw new RuntimeException(e); } } - }).connectTimeout(60000).socketTimeout(60000); + }).connectTimeout(60000); } @@ -113,7 +110,7 @@ public CreateSessionOffersContractsResponse createSessionOffersAndContracts(Crea // Create offers List cfarOffers = createOffers(sessionId, createCfarOfferRequest); - // Create a contract for each offers created + // Create a contract for each offer created List cfarContracts = new ArrayList<>(); if (cfarOffers != null && !cfarOffers.isEmpty()) { for (CfarOffer offer : cfarOffers) { @@ -170,6 +167,9 @@ public CfarContract getContract(String sessionId, String contractId) throws ApiE public boolean processCfarPayment(String sessionId, String contractId, ProcessCfarPaymentRequest processCfarPaymentRequest) throws ApiException { try { + if (hopperPaymentClient == null) { + throw new ApiException("Missing credentials for payment"); + } TokenizationRequest tokenizationRequest = new TokenizationRequest(); tokenizationRequest.setPaymentMethod(new PaymentMethod()); tokenizationRequest.getPaymentMethod().setCreditCard(new CreditCard()); @@ -193,7 +193,7 @@ public boolean processCfarPayment(String sessionId, String contractId, ProcessCf tokenizationRequest.getPaymentMethod().getCreditCard().setZip(processCfarPaymentRequest.getPostalCode()); tokenizationRequest.getPaymentMethod().getCreditCard().setCountry(processCfarPaymentRequest.getCountry()); tokenizationRequest.getPaymentMethod().setEmail(processCfarPaymentRequest.getEmailAddress()); - HttpResponse response = getTokenizedPaymentHttpResponse(tokenizationRequest); + HttpResponse response = hopperPaymentClient.getTokenizedPaymentHttpResponse(tokenizationRequest); if (response.getStatus() == 201) { ProcessCfarPaymentTokenRequest processCfarPaymentTokenRequest = new ProcessCfarPaymentTokenRequest(); @@ -218,17 +218,6 @@ public boolean processCfarPayment(String sessionId, String contractId, ProcessCf } } - private HttpResponse getTokenizedPaymentHttpResponse(TokenizationRequest tokenizationRequest) throws ApiException { - if (StringUtil.isEmpty(paymentUrl) || StringUtil.isEmpty(paymentUsername) || StringUtil.isEmpty(paymentPassword)) { - throw new ApiException("Missing credentials for payment"); - } - return Unirest.post(paymentUrl) - .basicAuth(paymentUsername, paymentPassword) - .header("Content-Type", "application/json") - .body(tokenizationRequest) - .asObject(TokenizationResponse.class); - } - public CfarContractExercise createCfarContractExercise(String sessionId, CreateCfarContractExerciseRequest createCfarContractExerciseRequest) throws ApiException { return cfarApi.postCfarContractExercises(createCfarContractExerciseRequest, sessionId); } diff --git a/src/main/java/com/hopper/cloud/airlines/HopperPaymentClient.java b/src/main/java/com/hopper/cloud/airlines/HopperPaymentClient.java new file mode 100644 index 0000000..b2cd9ad --- /dev/null +++ b/src/main/java/com/hopper/cloud/airlines/HopperPaymentClient.java @@ -0,0 +1,69 @@ +package com.hopper.cloud.airlines; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.hopper.cloud.airlines.model.*; +import com.hopper.cloud.airlines.model.tokenization.TokenizationRequest; +import com.hopper.cloud.airlines.model.tokenization.TokenizationResponse; +import kong.unirest.HttpResponse; +import kong.unirest.ObjectMapper; +import kong.unirest.Unirest; + +public class HopperPaymentClient { + private String paymentUrl; + private String paymentUsername; + private String paymentPassword; + + public HopperPaymentClient(String paymentUrl, String paymentUsername, String paymentPassword) { + this.initHopperPaymentClient(paymentUrl, paymentUsername, paymentPassword); + } + + + private void initHopperPaymentClient(String paymentUrl, String paymentUsername, String paymentPassword) { + this.paymentUrl = paymentUrl; + this.paymentUsername = paymentUsername; + this.paymentPassword = paymentPassword; + + Unirest.config().setObjectMapper(new ObjectMapper() { + final com.fasterxml.jackson.databind.ObjectMapper mapper + = new com.fasterxml.jackson.databind.ObjectMapper(); + + public String writeValue(Object value) { + try { + return mapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public T readValue(String value, Class valueType) { + try { + return mapper.readValue(value, valueType); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + }).connectTimeout(60000); + + } + + + public HttpResponse getTokenizedPaymentHttpResponse(TokenizationRequest tokenizationRequest) throws ApiException { + if (StringUtil.isEmpty(paymentUrl) || StringUtil.isEmpty(paymentUsername) || StringUtil.isEmpty(paymentPassword)) { + throw new ApiException("Missing credentials for payment"); + } + return Unirest.post(paymentUrl) + .basicAuth(paymentUsername, paymentPassword) + .header("Content-Type", "application/json") + .body(tokenizationRequest) + .asObject(TokenizationResponse.class); + } + + public String tokenizePaymentCard(PaymentCardDetail paymentCardDetail) throws ApiException { + HttpResponse response = getTokenizedPaymentHttpResponse(new TokenizationRequest(paymentCardDetail)); + if (response.getStatus() == 201) { + return response.getBody().getTransaction().getPaymentMethod().getToken(); + } else { + throw new ApiException("Unable to create this specific token, response : " + response.getStatus()); + } + } +} diff --git a/src/main/java/com/hopper/cloud/airlines/auth/OAuthOkHttpClient.java b/src/main/java/com/hopper/cloud/airlines/auth/OAuthOkHttpClient.java index 9fd31c4..104a122 100644 --- a/src/main/java/com/hopper/cloud/airlines/auth/OAuthOkHttpClient.java +++ b/src/main/java/com/hopper/cloud/airlines/auth/OAuthOkHttpClient.java @@ -55,6 +55,7 @@ public T execute(OAuthClientRequest request, Map response.body().string(), response.body().contentType().toString(), response.code(), + null, responseClass); } catch (IOException e) { throw new OAuthSystemException(e); diff --git a/src/main/java/com/hopper/cloud/airlines/model/PaymentCardDetail.java b/src/main/java/com/hopper/cloud/airlines/model/PaymentCardDetail.java new file mode 100644 index 0000000..edce057 --- /dev/null +++ b/src/main/java/com/hopper/cloud/airlines/model/PaymentCardDetail.java @@ -0,0 +1,157 @@ +package com.hopper.cloud.airlines.model; + +import java.util.Objects; + +public class PaymentCardDetail { + private String number; + private String verificationValue; + private String month; + private String year; + private String firstName; + private String lastName; + private String addressLine1; + private String addressLine2; + private String city; + private String postalCode; + private String stateOrProvince; + private String country; + private String emailAddress; + + public PaymentCardDetail() { + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public String getVerificationValue() { + return verificationValue; + } + + public void setVerificationValue(String verificationValue) { + this.verificationValue = verificationValue; + } + + public String getMonth() { + return month; + } + + public void setMonth(String month) { + this.month = month; + } + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getAddressLine1() { + return addressLine1; + } + + public void setAddressLine1(String addressLine1) { + this.addressLine1 = addressLine1; + } + + public String getAddressLine2() { + return addressLine2; + } + + public void setAddressLine2(String addressLine2) { + this.addressLine2 = addressLine2; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + public String getStateOrProvince() { + return stateOrProvince; + } + + public void setStateOrProvince(String stateOrProvince) { + this.stateOrProvince = stateOrProvince; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PaymentCardDetail processCfarPayment = (PaymentCardDetail) o; + return Objects.equals(this.number, processCfarPayment.number) && + Objects.equals(this.verificationValue, processCfarPayment.verificationValue) && + Objects.equals(this.month, processCfarPayment.month) && + Objects.equals(this.year, processCfarPayment.year) && + Objects.equals(this.firstName, processCfarPayment.firstName) && + Objects.equals(this.lastName, processCfarPayment.lastName) && + Objects.equals(this.addressLine1, processCfarPayment.addressLine1) && + Objects.equals(this.addressLine2, processCfarPayment.addressLine2) && + Objects.equals(this.postalCode, processCfarPayment.postalCode) && + Objects.equals(this.city, processCfarPayment.city) && + Objects.equals(this.stateOrProvince, processCfarPayment.stateOrProvince) && + Objects.equals(this.country, processCfarPayment.country) && + Objects.equals(this.emailAddress, processCfarPayment.emailAddress); + } + + @Override + public int hashCode() { + return Objects.hash(number, verificationValue, month, year, firstName, lastName, addressLine1, addressLine2, postalCode, city, stateOrProvince, country, emailAddress); + } + +} + diff --git a/src/main/java/com/hopper/cloud/airlines/model/tokenization/TokenizationRequest.java b/src/main/java/com/hopper/cloud/airlines/model/tokenization/TokenizationRequest.java index 7c71306..422e93b 100644 --- a/src/main/java/com/hopper/cloud/airlines/model/tokenization/TokenizationRequest.java +++ b/src/main/java/com/hopper/cloud/airlines/model/tokenization/TokenizationRequest.java @@ -1,6 +1,7 @@ package com.hopper.cloud.airlines.model.tokenization; import com.fasterxml.jackson.annotation.JsonProperty; +import com.hopper.cloud.airlines.model.PaymentCardDetail; import java.util.Objects; @@ -11,6 +12,26 @@ public class TokenizationRequest { public TokenizationRequest() { } + public TokenizationRequest(PaymentCardDetail paymentCardDetail) { + PaymentMethod paymentMethod = new PaymentMethod(); + paymentMethod.setEmail(paymentCardDetail.getEmailAddress()); + CreditCard creditCard = new CreditCard(); + creditCard.setVerificationValue(paymentCardDetail.getVerificationValue()); + creditCard.setMonth(paymentCardDetail.getMonth()); + creditCard.setYear(paymentCardDetail.getYear()); + creditCard.setAddress1(paymentCardDetail.getAddressLine1()); + creditCard.setAddress2(paymentCardDetail.getAddressLine2()); + creditCard.setCity(paymentCardDetail.getCity()); + creditCard.setState(paymentCardDetail.getStateOrProvince()); + creditCard.setZip(paymentCardDetail.getPostalCode()); + creditCard.setCountry(paymentCardDetail.getCountry()); + creditCard.setLastName(paymentCardDetail.getLastName()); + creditCard.setFirstName(paymentCardDetail.getFirstName()); + creditCard.setNumber(paymentCardDetail.getNumber()); + paymentMethod.setCreditCard(creditCard); + this.setPaymentMethod(paymentMethod); + } + public PaymentMethod getPaymentMethod() { return paymentMethod; }