From a2ea9141e37610a45ab36491bca392222524b1fe Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 14:32:03 +0100 Subject: [PATCH 01/15] Updates --- CHANGELOG.md | 8 +++ build.gradle | 8 +-- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../truelayer/java/entities/ResourceType.java | 6 +- .../entities/CreatePaymentRequest.java | 5 ++ .../StartAuthorizationFlowRequest.java | 71 ++++++++----------- .../acceptance/MandatesAcceptanceTests.java | 12 ++-- .../acceptance/PaymentsAcceptanceTests.java | 18 +++-- .../acceptance/SignupPlusAcceptanceTests.java | 3 +- .../integration/PaymentsIntegrationTests.java | 10 ++- .../java/payments/PaymentsHandlerTests.java | 12 ++-- 12 files changed, 92 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4689ac73..dfc08fa44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/). +## [18.0.0] - 2025-x-x +### Added +* icon to ProviderSelection object in authorization flow requests + +### Changed +* ⚠️ Breaking: replaced the withProviderSelection() flag on authorization flow request builder with a providerSelection(...) utility +that helps to set the provider icon object if needed. + ## [17.5.1] - 2025-10-31 ### Fixed * Update Sonatype Central badge url in order to show latest version diff --git a/build.gradle b/build.gradle index f4d3f6f67..51f0c430d 100644 --- a/build.gradle +++ b/build.gradle @@ -4,11 +4,11 @@ import com.vanniktech.maven.publish.JavadocJar plugins { id 'java-library' // to unleash the lombok magic - id "io.freefair.lombok" version "8.13.1" + id "io.freefair.lombok" version "9.1.0" // to make our tests output more fancy id 'com.adarshr.test-logger' version '4.0.0' // code linting - id "com.diffplug.spotless" version "7.0.3" + id "com.diffplug.spotless" version "8.1.0" // test coverage id 'jacoco' id 'com.github.kt3k.coveralls' version '2.12.2' @@ -112,8 +112,8 @@ dependencies { testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // Mocking libraries - testImplementation group: 'org.mockito', name: 'mockito-core', version: '5.17.0' - testImplementation group: 'org.wiremock', name: 'wiremock', version: '3.12.1' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '5.21.0' + testImplementation group: 'org.wiremock', name: 'wiremock', version: '3.13.2' // Wait test utility testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.3.0' diff --git a/gradle.properties b/gradle.properties index ab4e27c5b..989d9ea82 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Main properties group=com.truelayer archivesBaseName=truelayer-java -version=17.5.1 +version=18.0.0 # Artifacts properties project_name=TrueLayer Java diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b1c..23449a2b5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/com/truelayer/java/entities/ResourceType.java b/src/main/java/com/truelayer/java/entities/ResourceType.java index 7117272b1..c51bc3790 100644 --- a/src/main/java/com/truelayer/java/entities/ResourceType.java +++ b/src/main/java/com/truelayer/java/entities/ResourceType.java @@ -9,10 +9,12 @@ @RequiredArgsConstructor @Getter public enum ResourceType { + // TODO: can this be deprecated? We should leverage the HPP URI generated by the payments-gateway instead. + // note that deprecating would probably mean creating a new type for our test utils PAYMENT("payments", "payment_id", HPP), + MANDATE("mandates", "mandate_id", HPP), - PAYOUT("payouts", "payout_id", HP2), - ; + PAYOUT("payouts", "payout_id", HP2); private final String hppLinkPath; private final String hppLinkQueryParameter; diff --git a/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java b/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java index 84c1b8b8e..41711a5e5 100644 --- a/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java +++ b/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java @@ -40,4 +40,9 @@ public class CreatePaymentRequest { * Optional field for sub-merchant details */ private SubMerchants subMerchants; + + /** + * Optional field for configuring the authorization flow + */ + private StartAuthorizationFlowRequest authorizationFlow; } diff --git a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java index e70727330..a55ccb562 100644 --- a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java +++ b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java @@ -1,27 +1,55 @@ package com.truelayer.java.payments.entities; +import com.fasterxml.jackson.annotation.JsonValue; import com.truelayer.java.payments.entities.paymentdetail.forminput.Input; import java.net.URI; import java.util.List; +import java.util.Map; import lombok.*; @Getter -@RequiredArgsConstructor +@Builder @ToString @EqualsAndHashCode public class StartAuthorizationFlowRequest { private final ProviderSelection providerSelection; + private final Map schemeSelection; + private final Redirect redirect; private final Consent consent; private final Form form; + @Builder @ToString @EqualsAndHashCode - public static class ProviderSelection {} + public static class ProviderSelection { + private final Icon icon; + + @NoArgsConstructor + @AllArgsConstructor + @EqualsAndHashCode + @ToString + public static class Icon { + IconType type; + + @RequiredArgsConstructor + @Getter + public enum IconType { + DEFAULT("default"), + EXTENDED("extended"), + EXTENDED_SMALL("extended_small"), + EXTENDED_MEDIUM("extended_medium"), + EXTENDED_LARGE("extended_large"); + + @JsonValue + private final String type; + } + } + } @Builder @Getter @@ -45,43 +73,4 @@ public static class Consent {} public static class Form { List inputTypes; } - - public static StartAuthorizationFlowRequestBuilder builder() { - return new StartAuthorizationFlowRequestBuilder(); - } - - public static class StartAuthorizationFlowRequestBuilder { - private boolean withProviderSelection; - - private Redirect redirect; - - private Consent consent; - - private Form form; - - public StartAuthorizationFlowRequestBuilder withProviderSelection() { - this.withProviderSelection = true; - return this; - } - - public StartAuthorizationFlowRequestBuilder redirect(Redirect redirect) { - this.redirect = redirect; - return this; - } - - public StartAuthorizationFlowRequestBuilder consent(Consent consent) { - this.consent = consent; - return this; - } - - public StartAuthorizationFlowRequestBuilder form(Form form) { - this.form = form; - return this; - } - - public StartAuthorizationFlowRequest build() { - return new StartAuthorizationFlowRequest( - withProviderSelection ? new ProviderSelection() : null, redirect, consent, form); - } - } } diff --git a/src/test/java/com/truelayer/java/acceptance/MandatesAcceptanceTests.java b/src/test/java/com/truelayer/java/acceptance/MandatesAcceptanceTests.java index c16d04a93..40565294d 100644 --- a/src/test/java/com/truelayer/java/acceptance/MandatesAcceptanceTests.java +++ b/src/test/java/com/truelayer/java/acceptance/MandatesAcceptanceTests.java @@ -146,7 +146,8 @@ public void itShouldGetFunds(String mandatesScope, Mandate.Type mandateType) { // start auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .redirect(StartAuthorizationFlowRequest.Redirect.builder() .returnUri(URI.create(RETURN_URI)) .build()) @@ -209,7 +210,8 @@ public void itShouldGetConstraints(String mandatesScope, Mandate.Type mandateTyp // start auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .redirect(StartAuthorizationFlowRequest.Redirect.builder() .returnUri(URI.create(RETURN_URI)) .build()) @@ -323,7 +325,8 @@ public void itShouldCreateAPaymentOnMandate(String mandatesScope, Mandate.Type m // start auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .redirect(StartAuthorizationFlowRequest.Redirect.builder() .returnUri(URI.create(RETURN_URI)) .build()) @@ -449,7 +452,8 @@ private CreateMandateRequest createMandateRequest( private ApiResponse startAuthFlowForMandate(String mandateId) { // start auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .redirect(StartAuthorizationFlowRequest.Redirect.builder() .returnUri(URI.create(RETURN_URI)) .build()) diff --git a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java index 6ae14c409..2b27f13b6 100644 --- a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java +++ b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java @@ -288,7 +288,8 @@ public void shouldCompleteARedirectAuthorizationFlowForAPayment() { // start the auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() .redirect(Redirect.builder().returnUri(URI.create(RETURN_URI)).build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .consent(StartAuthorizationFlowRequest.Consent.builder().build()) .build(); ApiResponse startAuthorizationFlowResponse = tlClient.payments() @@ -332,7 +333,8 @@ public void shouldCompleteAnEmbeddedAuthorizationFlowForAPayment() { // start the auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() .redirect(Redirect.builder().returnUri(URI.create(RETURN_URI)).build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .consent(StartAuthorizationFlowRequest.Consent.builder().build()) .form(StartAuthorizationFlowRequest.Form.builder() .inputTypes(Arrays.asList(Input.Type.TEXT, Input.Type.TEXT_WITH_IMAGE, Input.Type.SELECT)) @@ -424,7 +426,8 @@ public void shouldCompleteAnAuthorizationFlowForAPaymentWithPreselectedProvider( // start the auth flow StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() .redirect(Redirect.builder().returnUri(URI.create(RETURN_URI)).build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .build(); ApiResponse startAuthorizationFlowResponse = tlClient.payments() .startAuthorizationFlow(createPaymentResponse.getData().getId(), startAuthorizationFlowRequest) @@ -464,7 +467,8 @@ public void shouldCompleteAnAuthorizationFlowForAPaymentWithProviderReturn() { .returnUri(URI.create(RETURN_URI)) .directReturnUri(URI.create(RETURN_URI)) .build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .build(); ApiResponse startAuthorizationFlowResponse = tlClient.payments() .startAuthorizationFlow(createPaymentResponse.getData().getId(), startAuthorizationFlowRequest) @@ -556,7 +560,8 @@ public void shouldCreateAPaymentRefundAndGetRefundDetails() { .returnUri(URI.create(RETURN_URI)) .directReturnUri(URI.create(RETURN_URI)) .build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .build(); ApiResponse startAuthorizationFlowResponse = tlClient.payments() .startAuthorizationFlow(paymentId, startAuthorizationFlowRequest) @@ -818,7 +823,8 @@ private static AuthorizationFlowResponse startAuthorizationFlowWithRetry(String .returnUri(URI.create(RETURN_URI)) .directReturnUri(URI.create(RETURN_URI)) .build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .build(); // serialize the base object to json and append retry object diff --git a/src/test/java/com/truelayer/java/acceptance/SignupPlusAcceptanceTests.java b/src/test/java/com/truelayer/java/acceptance/SignupPlusAcceptanceTests.java index 74b26e87e..b69f8580f 100644 --- a/src/test/java/com/truelayer/java/acceptance/SignupPlusAcceptanceTests.java +++ b/src/test/java/com/truelayer/java/acceptance/SignupPlusAcceptanceTests.java @@ -125,7 +125,8 @@ private String createAndAuthorizePayment(String providerId, CurrencyCode currenc .returnUri(returnUri) .directReturnUri(returnUri) .build()) - .withProviderSelection() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) .build(); ApiResponse startAuthorizationFlowResponse = tlClient.payments() .startAuthorizationFlow(paymentId, startAuthorizationFlowRequest) diff --git a/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java b/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java index 405b900c9..c000d4c37 100644 --- a/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java +++ b/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java @@ -319,7 +319,15 @@ public void shouldThrowARequestInvalidError() { .status(400) .bodyFile(jsonResponseFile) .build(); - CreatePaymentRequest paymentRequest = CreatePaymentRequest.builder().build(); + CreatePaymentRequest paymentRequest = CreatePaymentRequest.builder() + .authorizationFlow(StartAuthorizationFlowRequest.builder() + .schemeSelection(Collections.singletonMap("foo", "bar")) + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .icon(new StartAuthorizationFlowRequest.ProviderSelection.Icon( + StartAuthorizationFlowRequest.ProviderSelection.Icon.IconType.DEFAULT)) + .build()) + .build()) + .build(); ApiResponse paymentResponse = tlClient.payments().createPayment(paymentRequest).get(); diff --git a/src/test/java/com/truelayer/java/payments/PaymentsHandlerTests.java b/src/test/java/com/truelayer/java/payments/PaymentsHandlerTests.java index f1fad7b6a..f03b9d1b9 100644 --- a/src/test/java/com/truelayer/java/payments/PaymentsHandlerTests.java +++ b/src/test/java/com/truelayer/java/payments/PaymentsHandlerTests.java @@ -83,8 +83,10 @@ public void shouldCallGetPaymentById() { @Test @DisplayName("It should call the start authorization flow endpoint") public void shouldCallStartAuthorizationFlow() { - StartAuthorizationFlowRequest request = - StartAuthorizationFlowRequest.builder().withProviderSelection().build(); + StartAuthorizationFlowRequest request = StartAuthorizationFlowRequest.builder() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) + .build(); sut.startAuthorizationFlow(A_PAYMENT_ID, request); @@ -95,8 +97,10 @@ public void shouldCallStartAuthorizationFlow() { @DisplayName("It should call the start authorization flow endpoint with additional headers") public void shouldCallStartAuthorizationFlowWithCustomHeaders() { Headers customHeaders = buildTestHeaders(); - StartAuthorizationFlowRequest request = - StartAuthorizationFlowRequest.builder().withProviderSelection().build(); + StartAuthorizationFlowRequest request = StartAuthorizationFlowRequest.builder() + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .build()) + .build(); sut.startAuthorizationFlow(customHeaders, A_PAYMENT_ID, request); From 30ce115f463cf8dbd9e4d4fb958f771827b8e496 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 14:57:03 +0100 Subject: [PATCH 02/15] fixes test output --- build.gradle | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 51f0c430d..e4f2ececf 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,17 @@ testlogger { theme 'mocha' } +tasks.withType(Test) { + testlogger { + theme 'mocha' + } +} + tasks.register('unit-tests', Test) { + testClassesDirs = sourceSets.test.output.classesDirs + classpath = sourceSets.test.runtimeClasspath + + dependsOn testClasses outputs.upToDateWhen { false } useJUnitPlatform{ excludeTags "integration" @@ -67,6 +77,10 @@ tasks.register('unit-tests', Test) { } tasks.register('integration-tests', Test) { + testClassesDirs = sourceSets.test.output.classesDirs + classpath = sourceSets.test.runtimeClasspath + + dependsOn testClasses outputs.upToDateWhen { false } useJUnitPlatform{ includeTags "integration" @@ -74,6 +88,10 @@ tasks.register('integration-tests', Test) { } tasks.register('acceptance-tests', Test) { + testClassesDirs = sourceSets.test.output.classesDirs + classpath = sourceSets.test.runtimeClasspath + + dependsOn testClasses outputs.upToDateWhen { false } useJUnitPlatform{ includeTags "acceptance" @@ -95,12 +113,13 @@ dependencies { implementation group: 'com.truelayer', name: 'truelayer-signing', version: '0.2.6' // Serialization - def jacksonVersion = '2.14.1' - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jacksonVersion - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion - implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: jacksonVersion - implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: jacksonVersion - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion + def jacksonVersion = '3.0.3' + implementation group: 'tools.jackson.core', name: 'jackson-core', version: jacksonVersion + implementation group: 'tools.jackson.core', name: 'jackson-databind', version: jacksonVersion + def jacksonDatatypeVersion = '2.20.1' + implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: jacksonDatatypeVersion + implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: jacksonDatatypeVersion + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.20' // Logging def tinyLogVersion = '2.5.0' From dcd008de4c69caae81d247a5d5491da7dff9787c Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:06:36 +0100 Subject: [PATCH 03/15] build simplification --- build.gradle | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index e4f2ececf..dd63b5185 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ testlogger { theme 'mocha' } -tasks.withType(Test) { +tasks.withType(Test).configureEach { testlogger { theme 'mocha' } @@ -102,10 +102,10 @@ tasks.register('acceptance-tests', Test) { dependencies { // Utilities - implementation group: 'org.apache.commons', name: 'commons-configuration2', version: '2.11.0' + implementation group: 'org.apache.commons', name: 'commons-configuration2', version: '2.13.0' // HTTP client - def retrofitVersion = '2.9.0' + def retrofitVersion = '3.0.0' implementation group: 'com.squareup.retrofit2', name: 'retrofit', version: retrofitVersion implementation group: 'com.squareup.retrofit2', name: 'converter-jackson', version: retrofitVersion @@ -136,13 +136,6 @@ dependencies { // Wait test utility testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.3.0' - - // Transitive dependencies constraints - constraints { - implementation('com.squareup.okhttp3:okhttp:4.12.0') { - because 'version 3.14.9 used by com.squareup.retrofit2:retrofit:2.9.0 has known vulnerabilities' - } - } } jacocoTestReport { @@ -151,7 +144,7 @@ jacocoTestReport { xml.required = true html.required = true } - getExecutionData().setFrom(fileTree(buildDir).include("/jacoco/unit-tests.exec")) + getExecutionData().setFrom(fileTree(rootProject.layout.buildDirectory).include("/jacoco/unit-tests.exec")) afterEvaluate { classDirectories.setFrom(files(classDirectories.files.collect { fileTree(dir: it, exclude: [ From 5b79a382c8ded6e28fc6a726af22a5e49755b0f5 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:10:31 +0100 Subject: [PATCH 04/15] update junit --- build.gradle | 2 +- .../com/truelayer/java/acceptance/PaymentsAcceptanceTests.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dd63b5185..0f9cb4513 100644 --- a/build.gradle +++ b/build.gradle @@ -127,7 +127,7 @@ dependencies { implementation group: 'org.tinylog', name: 'tinylog-impl', version: tinyLogVersion // JUnit test framework. - testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.12.2' + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '6.0.1' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // Mocking libraries diff --git a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java index 2b27f13b6..255594336 100644 --- a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java +++ b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java @@ -50,6 +50,7 @@ import java.util.stream.Stream; import lombok.*; import okhttp3.*; +import okhttp3.MediaType; import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; From a748e67f9e46e5b3ebbbf3db70c3478b44582f68 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:12:19 +0100 Subject: [PATCH 05/15] update tinylog --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0f9cb4513..d2ee3d792 100644 --- a/build.gradle +++ b/build.gradle @@ -122,7 +122,7 @@ dependencies { implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.20' // Logging - def tinyLogVersion = '2.5.0' + def tinyLogVersion = '2.7.0' implementation group: 'org.tinylog', name: 'tinylog-api', version: tinyLogVersion implementation group: 'org.tinylog', name: 'tinylog-impl', version: tinyLogVersion From e04cf71c62afe335eb0a0be530572232db6123d9 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:15:23 +0100 Subject: [PATCH 06/15] update changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfc08fa44..7722f4b49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [18.0.0] - 2025-x-x ### Added -* icon to ProviderSelection object in authorization flow requests +* icon object to ProviderSelection in authorization flow requests ### Changed -* ⚠️ Breaking: replaced the withProviderSelection() flag on authorization flow request builder with a providerSelection(...) utility +* ⚠️ Breaking: replaced the `withProviderSelection()` flag on authorization flow request builder with a `providerSelection(...)` utility that helps to set the provider icon object if needed. +* Various dependency updates ## [17.5.1] - 2025-10-31 ### Fixed From 5bef95a0eaefa399eae80a778745c729c01bebdd Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:16:42 +0100 Subject: [PATCH 07/15] updates target java version on CI --- .github/workflows/acceptance-tests.yml | 2 +- .github/workflows/build-test-coverage.yml | 2 +- .github/workflows/release-snapshot.yml | 2 +- .github/workflows/workflow-examples.yml | 2 +- .github/workflows/workflow-main.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 234b6d83a..f36927830 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -35,7 +35,7 @@ jobs: - name: Setup JDK uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper diff --git a/.github/workflows/build-test-coverage.yml b/.github/workflows/build-test-coverage.yml index 6126207d8..968d72f4e 100644 --- a/.github/workflows/build-test-coverage.yml +++ b/.github/workflows/build-test-coverage.yml @@ -70,7 +70,7 @@ jobs: - name: Setup JDK uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper diff --git a/.github/workflows/release-snapshot.yml b/.github/workflows/release-snapshot.yml index b5ed93a8f..d369c7aa6 100644 --- a/.github/workflows/release-snapshot.yml +++ b/.github/workflows/release-snapshot.yml @@ -35,7 +35,7 @@ jobs: - name: Setup JDK uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper diff --git a/.github/workflows/workflow-examples.yml b/.github/workflows/workflow-examples.yml index 2a244fe0d..522e8cc29 100644 --- a/.github/workflows/workflow-examples.yml +++ b/.github/workflows/workflow-examples.yml @@ -23,7 +23,7 @@ jobs: - name: Setup JDK uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper diff --git a/.github/workflows/workflow-main.yml b/.github/workflows/workflow-main.yml index b295b5076..71d824e31 100644 --- a/.github/workflows/workflow-main.yml +++ b/.github/workflows/workflow-main.yml @@ -38,7 +38,7 @@ jobs: - name: Setup JDK uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper From ff9ee8d7764303b875031fe4416293144ff727e7 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:17:28 +0100 Subject: [PATCH 08/15] updates target java version on CI --- .github/workflows/build-test-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test-coverage.yml b/.github/workflows/build-test-coverage.yml index 968d72f4e..5d79a357d 100644 --- a/.github/workflows/build-test-coverage.yml +++ b/.github/workflows/build-test-coverage.yml @@ -24,7 +24,7 @@ jobs: matrix: os: [ ubuntu-latest ] java-distribution: [ temurin ] - java-version: [ 11, 17, 20, 21, 22, 23 ] + java-version: [ 11, 17, 20, 23, 25 ] runs-on: ${{ matrix.os }} outputs: project_version: ${{ steps.get_project_version.outputs.project_version }} From ceec6745458e5bc0a8f20ae78b19ec38f9c83e79 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 15:21:23 +0100 Subject: [PATCH 09/15] ci update --- .github/workflows/build-test-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test-coverage.yml b/.github/workflows/build-test-coverage.yml index 5d79a357d..47ba9389e 100644 --- a/.github/workflows/build-test-coverage.yml +++ b/.github/workflows/build-test-coverage.yml @@ -24,7 +24,7 @@ jobs: matrix: os: [ ubuntu-latest ] java-distribution: [ temurin ] - java-version: [ 11, 17, 20, 23, 25 ] + java-version: [ 17, 20, 23, 25 ] runs-on: ${{ matrix.os }} outputs: project_version: ${{ steps.get_project_version.outputs.project_version }} From 637fd178d5362132d20b01bc83e021ac9242f3ef Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 16:11:33 +0100 Subject: [PATCH 10/15] todos --- CHANGELOG.md | 5 +- .../entities/CreatePaymentRequest.java | 4 ++ .../StartAuthorizationFlowRequest.java | 47 +++++++++++++++++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7722f4b49..a25c12ddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [18.0.0] - 2025-x-x ### Added -* icon object to ProviderSelection in authorization flow requests +* New Icon object to ProviderSelection in authorization flow requests +* New Consent type properties within the authorization flow request ### Changed * ⚠️ Breaking: replaced the `withProviderSelection()` flag on authorization flow request builder with a `providerSelection(...)` utility -that helps to set the provider icon object if needed. +that helps to set the provider icon object if needed * Various dependency updates ## [17.5.1] - 2025-10-31 diff --git a/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java b/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java index 41711a5e5..f6ebe8c63 100644 --- a/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java +++ b/src/main/java/com/truelayer/java/payments/entities/CreatePaymentRequest.java @@ -45,4 +45,8 @@ public class CreatePaymentRequest { * Optional field for configuring the authorization flow */ private StartAuthorizationFlowRequest authorizationFlow; + + // TODO: hosted page + + // TODO: user consent } diff --git a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java index a55ccb562..304cec3f7 100644 --- a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java +++ b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java @@ -23,6 +23,8 @@ public class StartAuthorizationFlowRequest { private final Form form; + private final Map userAccountSelection; + @Builder @ToString @EqualsAndHashCode @@ -34,7 +36,7 @@ public static class ProviderSelection { @EqualsAndHashCode @ToString public static class Icon { - IconType type; + private IconType type; @RequiredArgsConstructor @Getter @@ -56,15 +58,52 @@ public enum IconType { @ToString @EqualsAndHashCode public static class Redirect { - URI returnUri; + private final URI returnUri; - URI directReturnUri; + private final URI directReturnUri; } @Builder @ToString @EqualsAndHashCode - public static class Consent {} + public static class Consent { + private final ActionType actionType; + private final Requirements requirements; + + @RequiredArgsConstructor + @Getter + public enum ActionType { + EXPLICIT("explicit"), + ADJACENT("adjacent"); + + @JsonValue + private final String type; + } + + @ToString + @EqualsAndHashCode + @Builder + public static class Requirements { + private final Map pis; + + @Builder + @ToString + @EqualsAndHashCode + public static class AisRequirements { + + @RequiredArgsConstructor + @Getter + public enum Scope { + ACCOUNTS("accounts"), + BALANCE("balance"), + ; + + @JsonValue + private final String value; + } + } + } + } @Builder @Getter From 6166374769f633b0ac1383db6cd62dcde8060947 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 16:13:04 +0100 Subject: [PATCH 11/15] ci improvements --- .github/workflows/acceptance-tests.yml | 2 +- .github/workflows/build-test-coverage.yml | 4 ++-- .github/workflows/release-snapshot.yml | 2 +- .github/workflows/workflow-examples.yml | 2 +- .github/workflows/workflow-main.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index f36927830..719d94a91 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -29,7 +29,7 @@ jobs: acceptance-tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK diff --git a/.github/workflows/build-test-coverage.yml b/.github/workflows/build-test-coverage.yml index 47ba9389e..c6f358a7a 100644 --- a/.github/workflows/build-test-coverage.yml +++ b/.github/workflows/build-test-coverage.yml @@ -29,7 +29,7 @@ jobs: outputs: project_version: ${{ steps.get_project_version.outputs.project_version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK ${{ matrix.java }} @@ -64,7 +64,7 @@ jobs: name: Test coverage analysis runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK diff --git a/.github/workflows/release-snapshot.yml b/.github/workflows/release-snapshot.yml index d369c7aa6..46f9e74f7 100644 --- a/.github/workflows/release-snapshot.yml +++ b/.github/workflows/release-snapshot.yml @@ -29,7 +29,7 @@ jobs: name: Release to Maven Central runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK diff --git a/.github/workflows/workflow-examples.yml b/.github/workflows/workflow-examples.yml index 522e8cc29..f9abf742d 100644 --- a/.github/workflows/workflow-examples.yml +++ b/.github/workflows/workflow-examples.yml @@ -19,7 +19,7 @@ jobs: run: working-directory: ./examples/${{ matrix.project-working-dir }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup JDK uses: actions/setup-java@v4 with: diff --git a/.github/workflows/workflow-main.yml b/.github/workflows/workflow-main.yml index 71d824e31..67b595a24 100644 --- a/.github/workflows/workflow-main.yml +++ b/.github/workflows/workflow-main.yml @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest needs: [build-test-coverage, acceptance-tests] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: ref: ${{ github.ref }} - name: Setup JDK From 7b9db9113e0eb0823f2f6a0fdce9dd2d4e399ddd Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 16:16:06 +0100 Subject: [PATCH 12/15] CI dependabot --- .github/dependabot.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fa0077fd9..0d90c652b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,6 @@ version: 2 updates: + # Java dependencies - package-ecosystem: gradle directory: "/" schedule: @@ -8,4 +9,17 @@ updates: prefix: "[Dependabot]" labels: - "skip-release" - - "dependencies" \ No newline at end of file + - "dependencies" + - "java" + + # GitHub Actions dependencies + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "skip-release" + - "dependencies" + - "ci" \ No newline at end of file From b4020b1fe2e0347733fe9b8f1371cf5b78911b6c Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 19 Dec 2025 16:19:35 +0100 Subject: [PATCH 13/15] ci updates --- .github/workflows/acceptance-tests.yml | 4 ++-- .github/workflows/build-test-coverage.yml | 8 ++++---- .github/workflows/release-snapshot.yml | 4 ++-- .github/workflows/workflow-examples.yml | 4 ++-- .github/workflows/workflow-main.yml | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 719d94a91..88233e205 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -33,13 +33,13 @@ jobs: with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v5 - name: Acceptance tests in sandbox env: TL_CLIENT_ID: ${{ secrets.tl_client_id }} diff --git a/.github/workflows/build-test-coverage.yml b/.github/workflows/build-test-coverage.yml index c6f358a7a..a9b34b78f 100644 --- a/.github/workflows/build-test-coverage.yml +++ b/.github/workflows/build-test-coverage.yml @@ -33,13 +33,13 @@ jobs: with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: ${{ matrix.java-version }} distribution: ${{ matrix.java-distribution }} cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v5 - name: Get project version id: get_project_version run: | @@ -68,13 +68,13 @@ jobs: with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v5 - name: Test coverage run: ./gradlew unit-tests jacocoTestReport coveralls env: diff --git a/.github/workflows/release-snapshot.yml b/.github/workflows/release-snapshot.yml index 46f9e74f7..139de5ee2 100644 --- a/.github/workflows/release-snapshot.yml +++ b/.github/workflows/release-snapshot.yml @@ -33,13 +33,13 @@ jobs: with: ref: ${{ inputs.checkout_ref }} - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v5 - name: Create Snapshot version run: | CHECKOUT_REF=${{inputs.checkout_ref}} diff --git a/.github/workflows/workflow-examples.yml b/.github/workflows/workflow-examples.yml index f9abf742d..70464d54b 100644 --- a/.github/workflows/workflow-examples.yml +++ b/.github/workflows/workflow-examples.yml @@ -21,13 +21,13 @@ jobs: steps: - uses: actions/checkout@v6 - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v5 - name: Lint run: ./gradlew spotlessJavaCheck - name: Build diff --git a/.github/workflows/workflow-main.yml b/.github/workflows/workflow-main.yml index 67b595a24..9e3476ca0 100644 --- a/.github/workflows/workflow-main.yml +++ b/.github/workflows/workflow-main.yml @@ -36,13 +36,13 @@ jobs: with: ref: ${{ github.ref }} - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v5 - name: Create tag id: create_tag uses: mathieudutour/github-tag-action@v6.1 From 5d87394257e4f7a89d637d1877ed7b972e8fc3ee Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Mon, 22 Dec 2025 14:01:11 +0100 Subject: [PATCH 14/15] deprecated start auth flow request method as opposed to breaking change --- CHANGELOG.md | 6 +- .../StartAuthorizationFlowRequest.java | 78 ++++++++++++++++++- .../acceptance/PaymentsAcceptanceTests.java | 39 ++++++++++ 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a25c12ddd..f3ca2d7f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/). -## [18.0.0] - 2025-x-x +## [17.6.0] - 2025-x-x ### Added +* New ProviderSelection builder method on the StartAuthorizationFlowRequest builder * New Icon object to ProviderSelection in authorization flow requests * New Consent type properties within the authorization flow request ### Changed -* ⚠️ Breaking: replaced the `withProviderSelection()` flag on authorization flow request builder with a `providerSelection(...)` utility -that helps to set the provider icon object if needed +* ⚠️ Deprecated `withProviderSelection()` flag on authorization flow request builder * Various dependency updates ## [17.5.1] - 2025-10-31 diff --git a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java index 304cec3f7..78f215adf 100644 --- a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java +++ b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java @@ -8,7 +8,7 @@ import lombok.*; @Getter -@Builder +@RequiredArgsConstructor @ToString @EqualsAndHashCode public class StartAuthorizationFlowRequest { @@ -25,11 +25,85 @@ public class StartAuthorizationFlowRequest { private final Map userAccountSelection; + public static StartAuthorizationFlowRequestBuilder builder() { + return new StartAuthorizationFlowRequestBuilder(); + } + + // TODO: remove in future major version, as we will no longer support empty provider selection + public static class StartAuthorizationFlowRequestBuilder { + private boolean withProviderSelection; + + private ProviderSelection providerSelection; + + private Map schemeSelection; + + private Redirect redirect; + + private Consent consent; + + private Form form; + + private Map userAccountSelection; + + /** + * Include an empty provider selection object in the request + * @deprecated use providerSelection(ProviderSelection) instead + * @return the builder object + */ + @Deprecated + public StartAuthorizationFlowRequestBuilder withProviderSelection() { + this.withProviderSelection = true; + return this; + } + + public StartAuthorizationFlowRequestBuilder providerSelection(ProviderSelection providerSelection) { + this.providerSelection = providerSelection; + return this; + } + + public StartAuthorizationFlowRequestBuilder schemeSelection(Map schemeSelection) { + this.schemeSelection = schemeSelection; + return this; + } + + public StartAuthorizationFlowRequestBuilder redirect(Redirect redirect) { + this.redirect = redirect; + return this; + } + + public StartAuthorizationFlowRequestBuilder consent(Consent consent) { + this.consent = consent; + return this; + } + + public StartAuthorizationFlowRequestBuilder form(Form form) { + this.form = form; + return this; + } + + public StartAuthorizationFlowRequestBuilder userAccountSelection(Map userAccountSelection) { + this.userAccountSelection = userAccountSelection; + return this; + } + + public StartAuthorizationFlowRequest build() { + if (withProviderSelection && providerSelection == null) { + providerSelection = new ProviderSelection(); + } + + return new StartAuthorizationFlowRequest( + providerSelection, schemeSelection, redirect, consent, form, userAccountSelection); + } + } + @Builder @ToString @EqualsAndHashCode + @AllArgsConstructor public static class ProviderSelection { - private final Icon icon; + private Icon icon; + + public ProviderSelection() {} @NoArgsConstructor @AllArgsConstructor diff --git a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java index 255594336..bd878edbf 100644 --- a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java +++ b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java @@ -448,6 +448,45 @@ public void shouldCompleteAnAuthorizationFlowForAPaymentWithPreselectedProvider( assertCanBrowseLink(bankPage); } + @SneakyThrows + @Test + @Deprecated + @DisplayName( + "It should complete an authorization flow for a payment with a preselected provider with deprecated provider selection method") + public void shouldCompleteAnAuthorizationFlowForAPaymentWithPreselectedProviderDeprecatedProviderSelection() { + // create payment + CreatePaymentRequest paymentRequest = + buildPaymentRequestWithProviderSelection(buildPreselectedProviderSelection(), CurrencyCode.GBP); + + ApiResponse createPaymentResponse = + tlClient.payments().createPayment(paymentRequest).get(); + + assertNotError(createPaymentResponse); + assertTrue(createPaymentResponse.getData().isAuthorizationRequired()); + + // start the auth flow + StartAuthorizationFlowRequest startAuthorizationFlowRequest = StartAuthorizationFlowRequest.builder() + .redirect(Redirect.builder().returnUri(URI.create(RETURN_URI)).build()) + .withProviderSelection() + .build(); + ApiResponse startAuthorizationFlowResponse = tlClient.payments() + .startAuthorizationFlow(createPaymentResponse.getData().getId(), startAuthorizationFlowRequest) + .get(); + + assertNotError(startAuthorizationFlowResponse); + + // assert that the link returned is good to be browsed + URI bankPage = startAuthorizationFlowResponse + .getData() + .asAuthorizing() + .getAuthorizationFlow() + .getActions() + .getNext() + .asRedirect() + .getUri(); + assertCanBrowseLink(bankPage); + } + @SneakyThrows @Test @DisplayName("It should complete an authorization flow for a payment with provider return") From 32e3068e12348fcb046405aa1a6352bbfeeec5e0 Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Mon, 22 Dec 2025 16:21:05 +0100 Subject: [PATCH 15/15] integration test --- .../StartAuthorizationFlowRequest.java | 9 ++ .../integration/PaymentsIntegrationTests.java | 111 +++++++++++++++++- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java index 78f215adf..468061c9e 100644 --- a/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java +++ b/src/main/java/com/truelayer/java/payments/entities/StartAuthorizationFlowRequest.java @@ -100,11 +100,13 @@ public StartAuthorizationFlowRequest build() { @ToString @EqualsAndHashCode @AllArgsConstructor + @Getter public static class ProviderSelection { private Icon icon; public ProviderSelection() {} + @Getter @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @@ -140,6 +142,7 @@ public static class Redirect { @Builder @ToString @EqualsAndHashCode + @Getter public static class Consent { private final ActionType actionType; private final Requirements requirements; @@ -157,14 +160,20 @@ public enum ActionType { @ToString @EqualsAndHashCode @Builder + @Getter public static class Requirements { private final Map pis; + private final AisRequirements ais; + @Builder @ToString @EqualsAndHashCode + @Getter public static class AisRequirements { + private final List scopes; + @RequiredArgsConstructor @Getter public enum Scope { diff --git a/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java b/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java index c000d4c37..6053e3a7a 100644 --- a/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java +++ b/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java @@ -19,6 +19,8 @@ import com.truelayer.java.http.entities.Headers; import com.truelayer.java.http.entities.ProblemDetails; import com.truelayer.java.payments.entities.*; +import com.truelayer.java.payments.entities.StartAuthorizationFlowRequest.ProviderSelection.Icon; +import com.truelayer.java.payments.entities.StartAuthorizationFlowRequest.ProviderSelection.Icon.IconType; import com.truelayer.java.payments.entities.beneficiary.MerchantAccount; import com.truelayer.java.payments.entities.paymentdetail.PaymentDetail; import com.truelayer.java.payments.entities.paymentdetail.Status; @@ -28,8 +30,8 @@ import com.truelayer.java.payments.entities.providerselection.UserSelectedProviderSelection; import com.truelayer.java.payments.entities.schemeselection.userselected.SchemeSelection; import com.truelayer.java.payments.entities.verification.AutomatedVerification; -import java.util.Collections; -import java.util.UUID; +import java.net.URI; +import java.util.*; import java.util.stream.Stream; import lombok.SneakyThrows; import org.junit.jupiter.api.*; @@ -323,8 +325,7 @@ public void shouldThrowARequestInvalidError() { .authorizationFlow(StartAuthorizationFlowRequest.builder() .schemeSelection(Collections.singletonMap("foo", "bar")) .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() - .icon(new StartAuthorizationFlowRequest.ProviderSelection.Icon( - StartAuthorizationFlowRequest.ProviderSelection.Icon.IconType.DEFAULT)) + .icon(new Icon(IconType.DEFAULT)) .build()) .build()) .build(); @@ -594,4 +595,106 @@ private static Stream provideAutomatedVerifications() { .withRemitterDateOfBirth() .build())); } + + @Deprecated + @Test + @DisplayName("It should create a payment with authorization_flow with deprecated provider selection") + @SneakyThrows + public void shouldCreatePaymentWithAuthorizationFlowDeprecated() { + RequestStub.New() + .method("post") + .path(urlPathEqualTo("/connect/token")) + .status(200) + .bodyFile("auth/200.access_token.json") + .build(); + RequestStub.New() + .method("post") + .path(urlPathEqualTo("/payments")) + .withAuthorization() + .withSignature() + .withIdempotencyKey() + .status(201) + .bodyFile("payments/201.create_payment.AUTHORIZATION_REQUIRED.json") + .build(); + + CreatePaymentRequest paymentRequest = CreatePaymentRequest.builder() + .amountInMinor(100) + .currency(CurrencyCode.GBP) + .paymentMethod(PaymentMethod.bankTransfer().build()) + .authorizationFlow(StartAuthorizationFlowRequest.builder() + .withProviderSelection() + .build()) + .build(); + + tlClient.payments().createPayment(paymentRequest).get(); + + verifyGeneratedToken(Collections.singletonList(PAYMENTS)); + verify(postRequestedFor(urlPathEqualTo("/payments")) + .withRequestBody(matchingJsonPath("$.amount_in_minor", equalTo("100"))) + .withRequestBody(matchingJsonPath("$.currency", equalTo("GBP"))) + .withRequestBody(matchingJsonPath("$.payment_method.type", equalTo("bank_transfer"))) + .withRequestBody(matchingJsonPath("$.authorization_flow.provider_selection", equalToJson("{}")))); + } + + @Deprecated + @Test + @DisplayName("It should create a payment with authorization_flow") + @SneakyThrows + public void shouldCreatePaymentWithAuthorizationFlow() { + RequestStub.New() + .method("post") + .path(urlPathEqualTo("/connect/token")) + .status(200) + .bodyFile("auth/200.access_token.json") + .build(); + RequestStub.New() + .method("post") + .path(urlPathEqualTo("/payments")) + .withAuthorization() + .withSignature() + .withIdempotencyKey() + .status(201) + .bodyFile("payments/201.create_payment.AUTHORIZATION_REQUIRED.json") + .build(); + + CreatePaymentRequest paymentRequest = CreatePaymentRequest.builder() + .amountInMinor(100) + .currency(CurrencyCode.GBP) + .paymentMethod(PaymentMethod.bankTransfer().build()) + .authorizationFlow(StartAuthorizationFlowRequest.builder() + .redirect(StartAuthorizationFlowRequest.Redirect.builder() + .returnUri(URI.create("https://example.com/return")) + .directReturnUri(URI.create("http://example.com/direct-return")) + .build()) + .schemeSelection(Collections.singletonMap("foo", "bar")) + .providerSelection(StartAuthorizationFlowRequest.ProviderSelection.builder() + .icon(new Icon(IconType.EXTENDED)) + .build()) + .form(StartAuthorizationFlowRequest.Form.builder().build()) + .consent(StartAuthorizationFlowRequest.Consent.builder() + .actionType(StartAuthorizationFlowRequest.Consent.ActionType.ADJACENT) + .requirements(StartAuthorizationFlowRequest.Consent.Requirements.builder() + .pis(Collections.singletonMap("req1", "foo")) + .ais( + StartAuthorizationFlowRequest.Consent.Requirements.AisRequirements + .builder() + // scopes + .build()) + .build()) + .build()) + .build()) + .build(); + + tlClient.payments().createPayment(paymentRequest).get(); + + verifyGeneratedToken(Collections.singletonList(PAYMENTS)); + verify(postRequestedFor(urlPathEqualTo("/payments")) + .withRequestBody(matchingJsonPath("$.amount_in_minor", equalTo("100"))) + .withRequestBody(matchingJsonPath("$.currency", equalTo("GBP"))) + .withRequestBody(matchingJsonPath("$.payment_method.type", equalTo("bank_transfer"))) + .withRequestBody(matchingJsonPath( + "$.authorization_flow.redirect.return_uri", equalTo("https://example.com/return"))) + .withRequestBody( + matchingJsonPath("$.authorization_flow.provider_selection.icon.type", equalTo("extended")))); + } }