diff --git a/.github/workflows/e2e-checkout-advanced.yml b/.github/workflows/e2e-checkout-advanced.yml
index 0b14c847..0b55095b 100644
--- a/.github/workflows/e2e-checkout-advanced.yml
+++ b/.github/workflows/e2e-checkout-advanced.yml
@@ -12,8 +12,30 @@ on:
- 'checkout-example-advanced/**'
jobs:
+ # e2e testing with Adyen.Web Drop-in/Components v5 (see /_archive/v5 folder)
+ checkout-advanced-v5:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout project
+ uses: actions/checkout@v3
+ - name: Setup java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: 17
+ - name: Grant execute permission for gradlew
+ run: chmod +x checkout-example-advanced/_archive/v5/gradlew
+ - name: Build checkout-example-advanced/v5 with Gradle
+ run: cd checkout-example-advanced/_archive/v5; ./gradlew build
+ - name: Build checkout-example-advanced image
+ run: docker build -t checkout-example-advanced-v5:latest -f ./checkout-example-advanced/_archive/v5/Dockerfile ./checkout-example-advanced/_archive/v5
+ - name: Start checkout-example-advanced container
+ run: docker run --rm -d --name checkout-example-advanced-v5 -p 8080:8080 -e ADYEN_API_KEY="${{ secrets.ADYEN_API_KEY }}" -e ADYEN_MERCHANT_ACCOUNT=${{ secrets.ADYEN_MERCHANT_ACCOUNT }} -e ADYEN_CLIENT_KEY=${{ secrets.ADYEN_CLIENT_KEY }} -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} checkout-example-advanced-v5:latest
+ - name: Run testing suite
+ run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=advanced-checkout/v5 -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} --network host ghcr.io/adyen-examples/adyen-testing-suite:main
- checkout-advanced:
+ # e2e testing with Adyen.Web Drop-in/Components v6
+ checkout-advanced-v6:
runs-on: ubuntu-latest
steps:
- name: Checkout project
@@ -33,3 +55,4 @@ jobs:
run: docker run --rm -d --name checkout-example-advanced -p 8080:8080 -e ADYEN_API_KEY="${{ secrets.ADYEN_API_KEY }}" -e ADYEN_MERCHANT_ACCOUNT=${{ secrets.ADYEN_MERCHANT_ACCOUNT }} -e ADYEN_CLIENT_KEY=${{ secrets.ADYEN_CLIENT_KEY }} -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} checkout-example-advanced:latest
- name: Run testing suite
run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=advanced-checkout -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} --network host ghcr.io/adyen-examples/adyen-testing-suite:main
+
diff --git a/checkout-example-advanced/Dockerfile b/checkout-example-advanced/Dockerfile
index b9e9562c..f052365a 100644
--- a/checkout-example-advanced/Dockerfile
+++ b/checkout-example-advanced/Dockerfile
@@ -1,4 +1,3 @@
FROM amazoncorretto:17-alpine-jdk
-MAINTAINER jlengrand
-COPY build/libs/adyen-java-spring-online-payments-checkout-advanced-0.0.1-SNAPSHOT.jar adyen-java-spring-online-payments-checkout-advanced-0.0.1-SNAPSHOT.jar
-ENTRYPOINT ["java","-jar","/adyen-java-spring-online-payments-checkout-advanced-0.0.1-SNAPSHOT.jar"]
+COPY build/libs/adyen-java-spring-online-payments-checkout-advanced.jar adyen-java-spring-online-payments-checkout-advanced.jar
+ENTRYPOINT ["java","-jar","/adyen-java-spring-online-payments-checkout-advanced.jar"]
diff --git a/checkout-example-advanced/README.md b/checkout-example-advanced/README.md
index 70bfc55f..745a0014 100644
--- a/checkout-example-advanced/README.md
+++ b/checkout-example-advanced/README.md
@@ -1,5 +1,8 @@
# Adyen [Online Payments](https://docs.adyen.com/online-payments) Integration Demo - Advanced Flow
+Checkout advanced sample application using `Adyen.Web Drop-in/Components v6.x.x`, (see [folder /_archive/v5](./_archive/v5) to access the previous version using `Adyen.Web Drop-in/Components v5.x.x`).
+
+
[![Java CI with Gradle](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/build-checkout-advanced.yml/badge.svg)](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/build-checkout-advanced.yml)
[![E2E (Playwright)](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/e2e-checkout-advanced.yml/badge.svg)](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/e2e-checkout-advanced.yml)
diff --git a/checkout-example-advanced/_archive/v5/.gitignore b/checkout-example-advanced/_archive/v5/.gitignore
new file mode 100644
index 00000000..b63da455
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/checkout-example-advanced/_archive/v5/Dockerfile b/checkout-example-advanced/_archive/v5/Dockerfile
new file mode 100644
index 00000000..c01c11d1
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/Dockerfile
@@ -0,0 +1,3 @@
+FROM amazoncorretto:17-alpine-jdk
+COPY build/libs/adyen-java-spring-online-payments-checkout-advanced-0.0.1-SNAPSHOT.jar adyen-java-spring-online-payments-checkout-advanced-0.0.1-SNAPSHOT.jar
+ENTRYPOINT ["java","-jar","/adyen-java-spring-online-payments-checkout-advanced-0.0.1-SNAPSHOT.jar"]
diff --git a/checkout-example-advanced/_archive/v5/README.md b/checkout-example-advanced/_archive/v5/README.md
new file mode 100644
index 00000000..5b86f9b2
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/README.md
@@ -0,0 +1,106 @@
+# Sample app with Adyen Adyen Web 5.68.0.
+
+This folder contains the **previous version** of the sample application that uses **Adyen Web 5.68.x**.
+
+**Check the root folder of the repository to use the latest version of Adyen Web/Components 6.x.x**
+
+# Adyen [Online Payments](https://docs.adyen.com/online-payments) Integration Demo - Advanced Flow
+
+[![Java CI with Gradle](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/build-checkout-advanced.yml/badge.svg)](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/build-checkout-advanced.yml)
+[![E2E (Playwright)](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/e2e-checkout-advanced.yml/badge.svg)](https://github.com/adyen-examples/adyen-java-spring-online-payments/actions/workflows/e2e-checkout-advanced.yml)
+
+## Run demo in one-click
+
+[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/adyen-examples/adyen-java-spring-online-payments/tree/main/checkout-example-advanced)
+ [First time with Gitpod?](https://github.com/adyen-examples/.github/blob/main/pages/gitpod-get-started.md)
+
+## Description
+This repository showcases a PCI-compliant integration of the **Advanced Flow**. Explore this simplified e-commerce demo to discover the code, libraries and configuration you need to enable various payment options in your checkout experience.
+
+It includes a **Java + Spring Boot + Thymeleaf** application that supports [Adyen Drop-in and Components](https://docs.adyen.com/online-payments/build-your-integration)
+(ACH, Alipay, Cards, Dotpay, iDEAL, Klarna, PayPal, etc..) using the Adyen's API Library for Java ([GitHub](https://github.com/Adyen/adyen-java-api-library)).
+
+
+> **Note:**
+For a simpler flow using `/sessions`, check out the demo in the [`checkout-example`](../checkout-example) folder.
+
+![Card checkout demo](src/main/resources/static/images/cardcheckout.gif)
+
+
+## Requirements
+
+- [Adyen API Credentials](https://docs.adyen.com/development-resources/api-credentials/)
+- Java 17
+- Network access to Maven central
+
+## 1. Installation
+
+```
+git clone https://github.com/adyen-examples/adyen-java-spring-online-payments.git
+```
+
+## 2. Set the environment variables
+* [API key](https://docs.adyen.com/user-management/how-to-get-the-api-key)
+* [Client Key](https://docs.adyen.com/user-management/client-side-authentication)
+* [Merchant Account](https://docs.adyen.com/account/account-structure)
+* [HMAC Key](https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures)
+
+On Linux/Mac/Windows export/set the environment variables.
+```shell
+export ADYEN_API_KEY=yourAdyenApiKey
+export ADYEN_MERCHANT_ACCOUNT=yourAdyenMerchantAccount
+export ADYEN_CLIENT_KEY=yourAdyenClientKey
+export ADYEN_HMAC_KEY=yourHmacKey
+```
+
+Alternatively, it's possible to define the variables in the `application.properties`.
+```txt
+ADYEN_API_KEY=yourAdyenApiKey
+ADYEN_MERCHANT_ACCOUNT=yourAdyenMerchantAccount
+ADYEN_CLIENT_KEY=yourAdyenClientKey
+ADYEN_HMAC_KEY=yourHmacKey
+```
+
+## 3. Configure allowed origins (CORS)
+
+It is required to specify the domain or URL of the web applications that will make requests to Adyen.
+
+In the Customer Area add `http://localhost:8080` in the list of Allowed Origins associated with the Client Key.
+
+## 4. Run the application
+
+```
+cd checkout-example
+
+./gradlew bootRun
+```
+
+Visit [http://localhost:8080/](http://localhost:8080/) to choose an integration type.
+
+Try out the different payment methods with our [test card numbers](https://docs.adyen.com/development-resources/test-cards/test-card-numbers) and other payment method details.
+
+# Webhooks
+
+Webhooks deliver asynchronous notifications about the payment status and other events that are important to receive and process.
+You can find more information about webhooks in [this blog post](https://www.adyen.com/knowledge-hub/consuming-webhooks).
+
+### Webhook setup
+
+In the Customer Area under the `Developers → Webhooks` section, [create](https://docs.adyen.com/development-resources/webhooks/#set-up-webhooks-in-your-customer-area) a new `Standard webhook`.
+
+A good practice is to set up basic authentication, copy the generated HMAC Key and set it as an environment variable. The application will use this to verify the [HMAC signatures](https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures/).
+
+Make sure the webhook is **enabled**, so it can receive notifications.
+
+### Expose an endpoint
+
+This demo provides a simple webhook implementation exposed at `/api/webhooks/notifications` that shows you how to receive, validate and consume the webhook payload.
+
+### Test your webhook
+
+The following webhooks `events` should be enabled:
+* **AUTHORISATION**
+
+
+To make sure that the Adyen platform can reach your application, we have written a [Webhooks Testing Guide](https://github.com/adyen-examples/.github/blob/main/pages/webhooks-testing.md)
+that explores several options on how you can easily achieve this (e.g. running on localhost or cloud).
diff --git a/checkout-example-advanced/_archive/v5/build.gradle b/checkout-example-advanced/_archive/v5/build.gradle
new file mode 100644
index 00000000..4c02d942
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/build.gradle
@@ -0,0 +1,34 @@
+plugins {
+ id 'org.springframework.boot' version '3.3.4'
+ id 'io.spring.dependency-management' version '1.1.6'
+
+ id 'java'
+}
+
+group = 'com.adyen'
+version = '0.0.1-SNAPSHOT'
+
+sourceCompatibility = 17
+targetCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+ implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
+ implementation 'com.adyen:adyen-java-api-library:32.0.0'
+
+ developmentOnly 'org.springframework.boot:spring-boot-devtools'
+
+ testImplementation('org.springframework.boot:spring-boot-starter-test') {
+ exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
+ }
+
+}
+
+test {
+ useJUnitPlatform()
+}
diff --git a/checkout-example-advanced/_archive/v5/gradle/wrapper/gradle-wrapper.jar b/checkout-example-advanced/_archive/v5/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..249e5832
Binary files /dev/null and b/checkout-example-advanced/_archive/v5/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/checkout-example-advanced/_archive/v5/gradle/wrapper/gradle-wrapper.properties b/checkout-example-advanced/_archive/v5/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..35bff925
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon May 22 09:48:27 CEST 2023
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/checkout-example-advanced/_archive/v5/gradlew b/checkout-example-advanced/_archive/v5/gradlew
new file mode 100755
index 00000000..1b6c7873
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/checkout-example-advanced/_archive/v5/gradlew.bat b/checkout-example-advanced/_archive/v5/gradlew.bat
new file mode 100644
index 00000000..107acd32
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/checkout-example-advanced/_archive/v5/settings.gradle b/checkout-example-advanced/_archive/v5/settings.gradle
new file mode 100644
index 00000000..d6681414
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'adyen-java-spring-online-payments-checkout-advanced'
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/ApplicationProperty.java b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/ApplicationProperty.java
new file mode 100644
index 00000000..907e54eb
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/ApplicationProperty.java
@@ -0,0 +1,63 @@
+package com.adyen.checkout;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ApplicationProperty {
+
+ @Value("${server.port}")
+ private int serverPort;
+
+ @Value("${ADYEN_API_KEY:#{null}}")
+ private String apiKey;
+
+ @Value("${ADYEN_MERCHANT_ACCOUNT:#{null}}")
+ private String merchantAccount;
+
+ @Value("${ADYEN_CLIENT_KEY:#{null}}")
+ private String clientKey;
+
+ @Value("${ADYEN_HMAC_KEY:#{null}}")
+ private String hmacKey;
+
+ public int getServerPort() {
+ return serverPort;
+ }
+
+ public void setServerPort(int serverPort) {
+ this.serverPort = serverPort;
+ }
+
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public void setApiKey(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ public String getMerchantAccount() {
+ return merchantAccount;
+ }
+
+ public void setMerchantAccount(String merchantAccount) {
+ this.merchantAccount = merchantAccount;
+ }
+
+ public String getClientKey() {
+ return clientKey;
+ }
+
+ public void setClientKey(String clientKey) {
+ this.clientKey = clientKey;
+ }
+
+ public String getHmacKey() {
+ return hmacKey;
+ }
+
+ public void setHmacKey(String hmacKey) {
+ this.hmacKey = hmacKey;
+ }
+}
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/Config.java b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/Config.java
similarity index 100%
rename from checkout-example-advanced/src/main/java/com/adyen/checkout/Config.java
rename to checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/Config.java
diff --git a/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/OnlinePaymentsApplication.java b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/OnlinePaymentsApplication.java
new file mode 100644
index 00000000..bcece038
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/OnlinePaymentsApplication.java
@@ -0,0 +1,28 @@
+package com.adyen.checkout;
+
+import jakarta.annotation.PostConstruct;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class OnlinePaymentsApplication {
+ private static final Logger log = LoggerFactory.getLogger(OnlinePaymentsApplication.class);
+
+ @Autowired
+ private ApplicationProperty applicationProperty;
+
+ public static void main(String[] args) {
+ SpringApplication.run(OnlinePaymentsApplication.class, args);
+ }
+
+ @PostConstruct
+ public void init() {
+ log.info("\n----------------------------------------------------------\n\t" +
+ "Application is running on http://localhost:" + applicationProperty.getServerPort() +
+ "\n----------------------------------------------------------");
+ }
+
+}
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/api/CheckoutResource.java b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/api/CheckoutResource.java
similarity index 100%
rename from checkout-example-advanced/src/main/java/com/adyen/checkout/api/CheckoutResource.java
rename to checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/api/CheckoutResource.java
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/api/WebhookResource.java b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/api/WebhookResource.java
similarity index 100%
rename from checkout-example-advanced/src/main/java/com/adyen/checkout/api/WebhookResource.java
rename to checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/api/WebhookResource.java
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/web/CheckoutController.java b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/web/CheckoutController.java
similarity index 97%
rename from checkout-example-advanced/src/main/java/com/adyen/checkout/web/CheckoutController.java
rename to checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/web/CheckoutController.java
index e86aca75..f6846148 100644
--- a/checkout-example-advanced/src/main/java/com/adyen/checkout/web/CheckoutController.java
+++ b/checkout-example-advanced/_archive/v5/src/main/java/com/adyen/checkout/web/CheckoutController.java
@@ -1,4 +1,4 @@
-package com.adyen.checkout.web;
+package com.adyen.checkout.views;
import com.adyen.checkout.ApplicationProperty;
import org.slf4j.Logger;
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/application.properties b/checkout-example-advanced/_archive/v5/src/main/resources/application.properties
new file mode 100644
index 00000000..9e4ba1af
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.jackson.default-property-inclusion=non_null
+spring.jackson.serialization.indent_output = true
+server.port=8080
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/adyenImplementation.js b/checkout-example-advanced/_archive/v5/src/main/resources/static/adyenImplementation.js
new file mode 100644
index 00000000..1f8cac49
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/adyenImplementation.js
@@ -0,0 +1,105 @@
+const clientKey = document.getElementById("clientKey").innerHTML;
+const type = document.getElementById("type").innerHTML;
+
+async function initCheckout() {
+ try {
+ const paymentMethodsResponse = await callServer("/api/getPaymentMethods");
+ const configuration = {
+ paymentMethodsResponse: paymentMethodsResponse,
+ clientKey,
+ locale: "en_US",
+ environment: "test",
+ showPayButton: true,
+ paymentMethodsConfiguration: {
+ ideal: {
+ showImage: true,
+ },
+ card: {
+ hasHolderName: true,
+ holderNameRequired: true,
+ name: "Credit or debit card",
+ amount: {
+ value: 10000,
+ currency: "EUR",
+ },
+ },
+ paypal: {
+ amount: {
+ value: 10000,
+ currency: "USD",
+ },
+ environment: "test", // Change this to "live" when you're ready to accept live PayPal payments
+ countryCode: "US", // Only needed for test. This will be automatically retrieved when you are in production.
+ onCancel: (data, component) => {
+ component.setStatus('ready');
+ },
+ }
+ },
+ onSubmit: (state, component) => {
+ if (state.isValid) {
+ handleSubmission(state, component, "/api/initiatePayment");
+ }
+ },
+ onAdditionalDetails: (state, component) => {
+ handleSubmission(state, component, "/api/submitAdditionalDetails");
+ },
+ };
+ // `spring.jackson.default-property-inclusion=non_null` needs to set in
+ // src/main/resources/application.properties to avoid NPE here
+ const checkout = await new AdyenCheckout(configuration);
+ checkout.create(type).mount(document.getElementById("payment"));
+ } catch (error) {
+ console.error(error);
+ alert("Error occurred. Look at console for details");
+ }
+}
+
+// Event handlers called when the shopper selects the pay button,
+// or when additional information is required to complete the payment
+async function handleSubmission(state, component, url) {
+ try {
+ const res = await callServer(url, state.data);
+ handleServerResponse(res, component);
+ } catch (error) {
+ console.error(error);
+ alert("Error occurred. Look at console for details");
+ }
+}
+
+// Calls your server endpoints
+async function callServer(url, data) {
+ const res = await fetch(url, {
+ method: "POST",
+ body: data ? JSON.stringify(data) : "",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+
+ return await res.json();
+}
+
+// Handles responses sent from your server to the client
+function handleServerResponse(res, component) {
+ if (res.action) {
+ component.handleAction(res.action);
+ } else {
+ switch (res.resultCode) {
+ case "Authorised":
+ window.location.href = "/result/success";
+ break;
+ case "Pending":
+ case "Received":
+ window.location.href = "/result/pending";
+ break;
+ case "Refused":
+ window.location.href = "/result/failed";
+ break;
+ default:
+ window.location.href = "/result/error";
+ break;
+ }
+ }
+}
+
+initCheckout();
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/css/application.css b/checkout-example-advanced/_archive/v5/src/main/resources/static/css/application.css
new file mode 100644
index 00000000..0d6fda34
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/css/application.css
@@ -0,0 +1,413 @@
+/* General page body */
+
+html,
+body {
+ width: 100%;
+ margin: 0;
+ font-family: "Fakt", sans-serif, Helvetica, Arial;
+}
+
+*,
+:after,
+:before {
+ box-sizing: border-box;
+}
+
+a,
+u {
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: none;
+}
+
+.hidden {
+ display: none;
+}
+
+#header {
+ background: #fff;
+ border-bottom: 1px solid #e6e9eb;
+ height: 44px;
+ left: 0;
+ margin-bottom: 24px;
+ padding: 14px 26px;
+ position: fixed;
+ text-align: center;
+ top: 0;
+ width: 100%;
+ z-index: 2;
+ box-sizing: border-box;
+}
+
+/* Buttons */
+
+.button {
+ background: #00112c;
+ border: 0;
+ border-radius: 6px;
+ color: #fff;
+ cursor: pointer;
+ display: inline-block;
+ font-size: 1em;
+ font-weight: 500;
+ margin: 0;
+ padding: 15px;
+ text-align: center;
+ transition: background 0.3s ease-out, box-shadow 0.3s ease-out;
+ width: 100%;
+}
+
+.button:hover {
+ background: #1c3045;
+ box-shadow: 0 3px 4px rgba(0, 15, 45, 0.2);
+}
+
+.button:active {
+ background: #3a4a5c;
+}
+
+.button:disabled {
+ background: #e6e9eb;
+ box-shadow: none;
+ cursor: not-allowed;
+ -webkit-user-select: all;
+ -moz-user-select: all;
+ -ms-user-select: all;
+ user-select: all;
+}
+
+/* end General page body */
+
+/* Index page */
+
+.main-container {
+ margin: auto;
+ max-width: 1048px;
+ padding: 0 16px;
+ display: flex;
+ flex-direction: column;
+}
+
+.integration-list {
+ display: flex;
+ margin-top: 6%;
+ max-width: 1048px;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+@media (min-width: 768px) {
+ .integration-list {
+ margin-left: -8px;
+ margin-bottom: -8px;
+ margin-right: -8px;
+ }
+}
+
+@media (min-width: 1024px) {
+ .integration-list {
+ margin-left: -16px;
+ margin-bottom: -16px;
+ margin-right: -16px;
+ }
+}
+
+.integration-list-item {
+ background: #f7f8f9;
+ border-radius: 6px;
+ flex: 1 1 0;
+ margin: 4px;
+ min-width: 40%;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid #f7f8f9;
+}
+
+.integration-list-item:hover {
+ box-shadow: 0 16px 24px 0 #e5eaef;
+ text-decoration: none;
+ border: 1px solid #06f;
+}
+
+@media (min-width: 768px) {
+ .integration-list-item {
+ margin-left: 16px;
+ margin-bottom: 16px;
+ margin-right: 16px;
+ margin-top: 16px;
+ min-width: 25%;
+ }
+}
+
+.integration-list-item-link {
+ padding: 20px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+@media (min-width: 768px) {
+ .integration-list-item-link {
+ padding-left: 28px;
+ padding-bottom: 28px;
+ padding-right: 28px;
+ padding-top: 28px;
+ }
+}
+
+.integration-list-item-title {
+ margin: 0;
+ text-align: center;
+ color: #00112c;
+ font-size: 1em;
+ font-weight: 700;
+ margin: 10px 0 0;
+}
+
+@media (min-width: 768px) {
+ .integration-list-item-title {
+ font-size: 24px;
+ margin-left: 0;
+ margin-bottom: 6px;
+ margin-right: 0;
+ }
+}
+
+.integration-list-item-subtitle {
+ color: #00112c;
+ font-size: 0.67em;
+ font-weight: 700;
+ margin: 10px 0 0;
+}
+
+@media (min-width: 768px) {
+ .integration-list-item-subtitle {
+ font-size: 16px;
+ margin-left: 0;
+ margin-bottom: 6px;
+ margin-right: 0;
+ }
+}
+
+.title-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.info {
+ margin-top: 10%;
+ color: #00112c;
+}
+
+/* end Index page */
+
+/* Cart preview page */
+
+.shopping-cart {
+ float: right;
+}
+@media (min-width: 768px) {
+ .shopping-cart {
+ padding-left: 0;
+ padding-bottom: 0;
+ padding-right: 0;
+ padding-top: 3px;
+ }
+}
+.shopping-cart-link {
+ display: inline-block;
+ position: relative;
+}
+.order-summary-list {
+ border-top: 1px solid #e6e9eb;
+}
+.order-summary-list-list-item {
+ border-bottom: 1px solid #e6e9eb;
+ display: flex;
+ height: 97px;
+}
+.order-summary-list-list-item-image {
+ height: 64px;
+ margin: 16px;
+ width: 64px;
+}
+.order-summary-list-list-item-title {
+ font-weight: 700;
+ margin: auto auto auto 0;
+}
+.order-summary-list-list-item-price {
+ color: #687282;
+ margin: auto 16px;
+ text-align: right;
+ width: 80px;
+}
+@media (min-width: 768px) {
+ .order-summary-list-list-item-price {
+ margin-left: 24px;
+ margin-bottom: auto;
+ margin-right: 24px;
+ margin-top: auto;
+ }
+}
+.order-summary-list-list-item-remove-product {
+ background: none;
+ border: 0;
+ cursor: pointer;
+ height: 25px;
+ margin: auto 0;
+ padding: 0;
+ width: 25px;
+}
+.cart {
+ text-align: center;
+ margin-top: 80px;
+}
+.cart-footer {
+ font-weight: 700;
+ margin-top: 17px;
+ text-align: right;
+}
+@media (min-width: 768px) {
+ .cart-footer {
+ margin-top: 24px;
+ }
+}
+.cart-footer .button {
+ margin-top: 30px;
+ width: 100%;
+}
+@media (min-width: 768px) {
+ .cart-footer .button {
+ margin-top: 0;
+ width: 288px;
+ }
+}
+.cart-footer-amount {
+ margin-left: 16px;
+ margin-right: 24px;
+}
+.whole-preview {
+ margin: auto;
+ max-width: 1110px;
+ padding: 0 16px;
+}
+@media (min-width: 1440px) {
+ .whole-preview {
+ padding-left: 0;
+ padding-bottom: 0;
+ padding-right: 0;
+ padding-top: 0;
+ }
+}
+
+/* end of Cart preview page */
+
+/* Payment page */
+
+#payment-page {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+#payment-page .container {
+ margin-top: 100px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ width: 100%;
+ max-width: 1110px;
+ padding-left: 8px;
+ padding-right: 8px;
+}
+
+.checkout-component {
+ background: #f7f8f9;
+ border: 1px solid #e6e9eb;
+ border-radius: 12px;
+ margin: 8px 0;
+}
+
+/* Adyen Components */
+.payment {
+ width: 100%;
+ padding-top: 0px !important;
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+@media screen and (max-width: 1076px) {
+ #payment-page .container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .payment {
+ align-self: center;
+ }
+}
+
+.payment-container {
+ display: flex;
+ justify-content: center;
+ background: #f7f8f9;
+ border: 1px solid #e6e9eb;
+ border-radius: 12px;
+ padding-top: 18px;
+ padding-bottom: 18px;
+ width: 100%;
+ height: 100%;
+}
+
+/* end Payments page */
+
+
+/* Status page */
+
+.status-container {
+ height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.status {
+ margin: 100px 0 126px;
+ text-align: center;
+}
+
+.status .status-image {
+ display: block;
+ height: 100px;
+ margin: 16px auto 0;
+}
+
+.status .status-image-thank-you {
+ height: 66px;
+}
+
+.status .status-message {
+ margin: 8px 0 24px;
+}
+
+.status .button {
+ max-width: 236px;
+}
+
+@media (min-width: 768px) {
+ .status .button {
+ max-width: 200px;
+ }
+}
+
+/* end Status page */
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/.keep b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/cardcheckout.gif b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/cardcheckout.gif
new file mode 100644
index 00000000..dc3e612c
Binary files /dev/null and b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/cardcheckout.gif differ
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/error.svg b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/error.svg
new file mode 100644
index 00000000..4db9773b
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/error.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/failed.svg b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/failed.svg
new file mode 100644
index 00000000..4db9773b
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/failed.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/headphones.png b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/headphones.png
new file mode 100644
index 00000000..12d1cf44
Binary files /dev/null and b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/headphones.png differ
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/mystore-logo.svg b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/mystore-logo.svg
new file mode 100644
index 00000000..0418b242
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/mystore-logo.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/pending.svg b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/pending.svg
new file mode 100644
index 00000000..465c4b46
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/pending.svg
@@ -0,0 +1,24 @@
+
+
+
+ Icon
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/success.svg b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/success.svg
new file mode 100644
index 00000000..465c4b46
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/success.svg
@@ -0,0 +1,24 @@
+
+
+
+ Icon
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/sunglasses.png b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/sunglasses.png
new file mode 100644
index 00000000..1f280537
Binary files /dev/null and b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/sunglasses.png differ
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/static/images/thank-you.svg b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/thank-you.svg
new file mode 100644
index 00000000..587d3b5b
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/static/images/thank-you.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/templates/checkout.html b/checkout-example-advanced/_archive/v5/src/main/resources/templates/checkout.html
new file mode 100644
index 00000000..03e6907f
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/templates/checkout.html
@@ -0,0 +1,24 @@
+
+
+ Checkout
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/templates/index.html b/checkout-example-advanced/_archive/v5/src/main/resources/templates/index.html
new file mode 100644
index 00000000..d573b4f5
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/templates/index.html
@@ -0,0 +1,118 @@
+
+
+ Select type
+
+
+
+
+
+
Select a demo
+
Click to view an interactive example of a PCI-compliant UI integration for online payments.
+
+ Make sure the payment method you want to use are enabled for your account.
+ Refer the documentation
+ to add missing
+ payment methods.
+
+
To learn more about client-side integration solutions, check out Online
+ payments.
+
+
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/templates/layout.html b/checkout-example-advanced/_archive/v5/src/main/resources/templates/layout.html
new file mode 100644
index 00000000..b3895e5b
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/templates/layout.html
@@ -0,0 +1,46 @@
+
+
+
+
+ Checkout Demo Advanced
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/templates/preview.html b/checkout-example-advanced/_archive/v5/src/main/resources/templates/preview.html
new file mode 100644
index 00000000..41a09e74
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/templates/preview.html
@@ -0,0 +1,34 @@
+
+
+ Preview
+
+
+
+
+ Cart
+
+
+
+
+ Sunglasses
+ 50.00
+
+
+
+ Headphones
+ 50.00
+
+
+
+
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/main/resources/templates/result.html b/checkout-example-advanced/_archive/v5/src/main/resources/templates/result.html
new file mode 100644
index 00000000..8e145b12
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/main/resources/templates/result.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+ Your order has been successfully placed.
+ Your order has been received! Payment completion pending.
+ The payment was refused. Please try a different payment method or card.
+
+ Error! Please review response in console and refer to
+ Response handling.
+
+
+
Return Home
+
+
+
diff --git a/checkout-example-advanced/_archive/v5/src/test/java/com/adyen/checkout/OnlinePaymentsApplicationTests.java b/checkout-example-advanced/_archive/v5/src/test/java/com/adyen/checkout/OnlinePaymentsApplicationTests.java
new file mode 100644
index 00000000..e07d9e45
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/src/test/java/com/adyen/checkout/OnlinePaymentsApplicationTests.java
@@ -0,0 +1,26 @@
+package com.adyen.checkout;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.event.annotation.BeforeTestClass;
+
+@SpringBootTest
+class OnlinePaymentsApplicationTests {
+
+ @BeforeAll
+ public static void onceExecutedBeforeAll() {
+ System.setProperty("ADYEN_API_KEY", "testKey");
+ System.setProperty("ADYEN_MERCHANT_ACCOUNT", "testAccount");
+ System.setProperty("ADYEN_CLIENT_KEY", "testKey");
+ }
+
+ @AfterAll
+ public static void onceExecutedAfterAll(){
+ System.clearProperty("ADYEN_API_KEY");
+ System.clearProperty("ADYEN_MERCHANT_ACCOUNT");
+ System.clearProperty("ADYEN_CLIENT_KEY");
+ }
+
+}
diff --git a/checkout-example-advanced/_archive/v5/startDocker.sh b/checkout-example-advanced/_archive/v5/startDocker.sh
new file mode 100755
index 00000000..a61dc10f
--- /dev/null
+++ b/checkout-example-advanced/_archive/v5/startDocker.sh
@@ -0,0 +1,6 @@
+docker run \
+-e ADYEN_CLIENT_KEY \
+-e ADYEN_MERCHANT_ACCOUNT \
+-e ADYEN_HMAC_KEY \
+-e ADYEN_API_KEY \
+-p8080:8080 checkout-example-advanced:latest
diff --git a/checkout-example-advanced/build.gradle b/checkout-example-advanced/build.gradle
index 36caf9f3..ce0bd808 100644
--- a/checkout-example-advanced/build.gradle
+++ b/checkout-example-advanced/build.gradle
@@ -6,7 +6,6 @@ plugins {
}
group = 'com.adyen'
-version = '0.0.1-SNAPSHOT'
sourceCompatibility = 17
targetCompatibility = 17
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/ApplicationProperty.java b/checkout-example-advanced/src/main/java/com/adyen/checkout/ApplicationProperty.java
index 907e54eb..9227f1e6 100644
--- a/checkout-example-advanced/src/main/java/com/adyen/checkout/ApplicationProperty.java
+++ b/checkout-example-advanced/src/main/java/com/adyen/checkout/ApplicationProperty.java
@@ -60,4 +60,4 @@ public String getHmacKey() {
public void setHmacKey(String hmacKey) {
this.hmacKey = hmacKey;
}
-}
+}
\ No newline at end of file
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/api/CheckoutController.java b/checkout-example-advanced/src/main/java/com/adyen/checkout/api/CheckoutController.java
new file mode 100644
index 00000000..642b80c6
--- /dev/null
+++ b/checkout-example-advanced/src/main/java/com/adyen/checkout/api/CheckoutController.java
@@ -0,0 +1,184 @@
+package com.adyen.checkout.api;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.UUID;
+
+import com.adyen.checkout.configurations.ApplicationConfiguration;
+import com.adyen.model.RequestOptions;
+import com.adyen.service.checkout.PaymentsApi;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.view.RedirectView;
+import com.adyen.model.checkout.*;
+import com.adyen.service.exception.ApiException;
+
+/**
+ * REST controller for using Adyen checkout API
+ */
+@RestController
+public class CheckoutController {
+ private final Logger log = LoggerFactory.getLogger(CheckoutController.class);
+
+ private final ApplicationConfiguration applicationConfiguration;
+
+ private final PaymentsApi paymentsApi;
+
+ public CheckoutController(PaymentsApi paymentsApi, ApplicationConfiguration applicationConfiguration) {
+ this.applicationConfiguration = applicationConfiguration;
+ this.paymentsApi = paymentsApi;
+ }
+
+ /**
+ * {@code POST /api/paymentMethods}: Retrieves available payment methods from Adyen.
+ *
+ * @return the {@link ResponseEntity} with status {@code 200 (Ok)} and with body the paymentMethods response.
+ * @throws IOException from Adyen API.
+ * @throws ApiException from Adyen API.
+ */
+ @PostMapping("/api/paymentMethods")
+ public ResponseEntity paymentMethods() throws IOException, ApiException {
+ PaymentMethodsRequest paymentMethodsRequest = new PaymentMethodsRequest();
+ paymentMethodsRequest.setMerchantAccount(this.applicationConfiguration.getAdyenMerchantAccount());
+ paymentMethodsRequest.setChannel(PaymentMethodsRequest.ChannelEnum.WEB);
+
+ log.info("Sending request to /paymentMethods");
+ PaymentMethodsResponse response = paymentsApi.paymentMethods(paymentMethodsRequest);
+ log.info("Adyen: /paymentMethods response: {}", response);
+ return ResponseEntity.ok().body(response);
+ }
+
+ /**
+ * {@code POST /api/payments}: Make a payment request to Adyen.
+ *
+ * @return the {@link ResponseEntity} with status {@code 200 (Ok)} and with body the paymentMethods response.
+ * @throws IOException from Adyen API.
+ * @throws ApiException from Adyen API.
+ */
+ @PostMapping("/api/payments")
+ public ResponseEntity payments(@RequestHeader String host, @RequestBody PaymentRequest body, HttpServletRequest request) throws IOException, ApiException {
+ PaymentRequest paymentRequest = new PaymentRequest();
+
+ Amount amount = new Amount()
+ .currency("EUR")
+ .value(10000L); // value is 100€ in minor units, hardcoded in the example, total amount should be retrieved from a storage, e.g. database.
+
+ // Sets ADYEN_MERCHANT_ACCOUNT in the request
+ paymentRequest.setMerchantAccount(this.applicationConfiguration.getAdyenMerchantAccount());
+ paymentRequest.setChannel(PaymentRequest.ChannelEnum.WEB);
+ paymentRequest.setReference(UUID.randomUUID().toString()); // required
+ paymentRequest.setReturnUrl(request.getScheme() + "://" + host + "/api/handleShopperRedirect"); // Redirect flow
+
+ paymentRequest.setAmount(amount);
+
+ // Set countryCode and lineItems fields, which is required for some payment methods (e.g. Klarna)
+ paymentRequest.setCountryCode("NL");
+ paymentRequest.setLineItems(Arrays.asList(
+ new LineItem().quantity(1L).amountIncludingTax(5000L).description("Sunglasses"),
+ new LineItem().quantity(1L).amountIncludingTax(5000L).description("Headphones"))
+ );
+
+ AuthenticationData authenticationData = new AuthenticationData();
+ authenticationData.setAttemptAuthentication(AuthenticationData.AttemptAuthenticationEnum.ALWAYS);
+ // Add the following lines for Native 3DS2:
+ //ThreeDSRequestData threeDSRequestData = new ThreeDSRequestData();
+ //threeDSRequestData.setNativeThreeDS(ThreeDSRequestData.NativeThreeDSEnum.PREFERRED);
+ //authenticationData.setThreeDSRequestData(threeDSRequestData);
+
+ paymentRequest.setAuthenticationData(authenticationData);
+
+ // Required for authentication - 3DS2 redirect flow
+ paymentRequest.setOrigin(request.getScheme() + "://" + host);
+ paymentRequest.setBrowserInfo(body.getBrowserInfo());
+ paymentRequest.setShopperIP(request.getRemoteAddr());
+ paymentRequest.setPaymentMethod(body.getPaymentMethod());
+
+ // we strongly recommend that you the billingAddress in your request
+ // card schemes require this for channel web, iOS, and Android implementations
+ /*paymentRequest.setBillingAddress(new BillingAddress()
+ .city("Amsterdam")
+ .country("NL")
+ .postalCode("1234AA")
+ .street("Street 1")
+ .houseNumberOrName("1"));
+ */
+
+ // Sets the shopper email
+ //paymentRequest.setShopperEmail("youremail@email.com");
+
+ // https://docs.adyen.com/development-resources/api-idempotency/
+ RequestOptions requestOptions = new RequestOptions();
+ requestOptions.setIdempotencyKey(UUID.randomUUID().toString());
+
+ log.info("Sending request to /payments");
+ PaymentResponse paymentResponse = paymentsApi.payments(paymentRequest, requestOptions);
+ log.info("Adyen: /payments response: {}", paymentRequest);
+ return ResponseEntity.ok().body(paymentResponse);
+ }
+
+ /**
+ * {@code POST /api/payments/details} : Make a payments/details request to Adyen.
+ *
+ *
+ * @return the {@link ResponseEntity} with status {@code 200 (Ok)} and with body the paymentMethods response.
+ * @throws IOException from Adyen API.
+ * @throws ApiException from Adyen API.
+ */
+ @PostMapping("/api/payments/details")
+ public ResponseEntity paymentsDetails(@RequestBody PaymentDetailsRequest detailsRequest) throws IOException, ApiException {
+ log.info("Sending request to /payments/details {}", detailsRequest);
+ PaymentDetailsResponse detailsResponse = paymentsApi.paymentsDetails(detailsRequest);
+ log.info("Adyen: /payments/details response: {}", detailsResponse);
+ return ResponseEntity.ok().body(detailsResponse);
+ }
+
+ /**
+ * {@code GET /api/handleShopperRedirect} : Handle redirect during payment. This gets called during the redirect flow, you can specify this in the `returnUrl`-field when constructing the /payments request to Adyen.
+ *
+ * @return the {@link RedirectView} with status {@code 302}
+ * @throws IOException from Adyen API.
+ * @throws ApiException from Adyen API.
+ */
+ @GetMapping("/api/handleShopperRedirect")
+ public RedirectView redirect(@RequestParam(required = false) String payload, @RequestParam(required = false) String redirectResult) throws IOException, ApiException {
+ // Sends a request to /payments/completionDetails when redirect occurs
+ PaymentCompletionDetails completionDetails = new PaymentCompletionDetails();
+ if (redirectResult != null && !redirectResult.isEmpty()) {
+ // For redirect, you are redirected to an Adyen domain to complete the 3DS2 challenge
+ // After completing the 3DS2 challenge, you get the redirect result from Adyen in the returnUrl
+ // We then pass the redirectResult to the /completionDetails call to Adyen.
+ completionDetails.redirectResult(redirectResult);
+ } else if (payload != null && !payload.isEmpty()) {
+ completionDetails.payload(payload);
+ }
+
+ PaymentDetailsRequest detailsRequest = new PaymentDetailsRequest();
+ detailsRequest.setDetails(completionDetails);
+
+ log.info("Sending request to /payments/details {}", detailsRequest);
+ PaymentDetailsResponse paymentDetailsResponse = paymentsApi.paymentsDetails(detailsRequest);
+ log.info("Adyen: /payments/details response: {}", paymentDetailsResponse);
+
+ // Handle redirect after getting the /payment/completionDetails paymentDetailsResponse
+ String redirectURL = "/result/";
+ switch (paymentDetailsResponse.getResultCode()) {
+ case AUTHORISED:
+ redirectURL += "success";
+ break;
+ case PENDING:
+ case RECEIVED:
+ redirectURL += "pending";
+ break;
+ case REFUSED:
+ redirectURL += "failed";
+ break;
+ default:
+ redirectURL += "error";
+ break;
+ }
+ return new RedirectView(redirectURL + "?reason=" + paymentDetailsResponse.getResultCode());
+ }
+}
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/api/WebhookController.java b/checkout-example-advanced/src/main/java/com/adyen/checkout/api/WebhookController.java
new file mode 100644
index 00000000..b443966f
--- /dev/null
+++ b/checkout-example-advanced/src/main/java/com/adyen/checkout/api/WebhookController.java
@@ -0,0 +1,103 @@
+package com.adyen.checkout.api;
+
+import com.adyen.checkout.ApplicationProperty;
+import com.adyen.model.notification.NotificationRequest;
+import com.adyen.model.notification.NotificationRequestItem;
+import com.adyen.util.HMACValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.security.SignatureException;
+import java.util.Optional;
+
+/**
+ * REST controller for receiving Adyen webhook notifications
+ */
+@RestController
+public class WebhookController {
+ private final Logger log = LoggerFactory.getLogger(WebhookController.class);
+
+ private final ApplicationProperty applicationProperty;
+ private final HMACValidator hmacValidator;
+
+ @Autowired
+ public WebhookController(ApplicationProperty applicationProperty, HMACValidator hmacValidator) {
+ this.applicationProperty = applicationProperty;
+
+ if (this.applicationProperty.getHmacKey() == null) {
+ log.warn("ADYEN_HMAC_KEY is UNDEFINED (Webhook cannot be authenticated)");
+ //throw new RuntimeException("ADYEN_HMAC_KEY is UNDEFINED");
+ }
+ this.hmacValidator = hmacValidator;
+ }
+
+ /**
+ * Process incoming Webhook notification: get NotificationRequestItem, validate HMAC signature
+ * Consume the webhook asynchronously, send response status 202: Accepted
+ * Best practice: Add authentication to protect this endpoint, see https://docs.adyen.com/development-resources/webhooks/
+ * @param json The payload of the incoming webhook
+ * @return 202 "Accepted" - If your server has finished processing the payload (e.g. storing it).
+ */
+ @PostMapping("/api/webhooks/notifications")
+ public ResponseEntity webhooks(@RequestBody String json) throws Exception {
+ log.warn("Incoming (not validated) webhook {}", json);
+ // From JSON string to object
+ NotificationRequest notificationRequest = NotificationRequest.fromJson(json);
+
+ // Fetch first (and only) NotificationRequestItem
+ Optional notificationRequestItem = notificationRequest.getNotificationItems().stream().findFirst();
+
+ if (notificationRequestItem.isEmpty()) {
+ // Unexpected webhook with no payload
+ log.warn("Empty NotificationItem");
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Empty NotificationItem");
+ }
+
+ try {
+ NotificationRequestItem item = notificationRequestItem.get();
+ if (hmacValidator.validateHMAC(item, this.applicationProperty.getHmacKey())) {
+ log.info("""
+ Received webhook with event {} :\s
+ Merchant Reference: {}
+ Alias : {}
+ PSP reference : {}"""
+ , item.getEventCode(), item.getMerchantReference(), item.getAdditionalData().get("alias"), item.getPspReference());
+
+ // Consume event asynchronously
+ consumeEvent(item);
+
+ } else {
+ // Invalid HMAC signature
+ log.warn("Could HMAC signature did not match: {}", item);
+ throw new RuntimeException("HMAC signature did not match");
+ }
+ } catch (SignatureException e) {
+ // Unexpected error during HMAC validation
+ log.error("Error while validating HMAC Key", e);
+ throw new SignatureException(e);
+ }
+
+ // Acknowledge event has been consumed
+ return ResponseEntity.status(HttpStatus.ACCEPTED).build();
+ }
+
+ // process payload asynchronously
+ void consumeEvent(NotificationRequestItem item) {
+ log.info("Consumed webhook {}", item.toString());
+
+ // add item to DB, queue or different thread
+
+ // example: send to Kafka consumer
+
+ // producer.send(producerRecord);
+ // producer.flush();
+ // producer.close();
+ }
+}
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/configurations/ApplicationConfiguration.java b/checkout-example-advanced/src/main/java/com/adyen/checkout/configurations/ApplicationConfiguration.java
new file mode 100644
index 00000000..6180d08e
--- /dev/null
+++ b/checkout-example-advanced/src/main/java/com/adyen/checkout/configurations/ApplicationConfiguration.java
@@ -0,0 +1,62 @@
+package com.adyen.checkout.configurations;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ApplicationConfiguration {
+ @Value("${server.port}")
+ private int serverPort;
+
+ @Value("${ADYEN_API_KEY:#{null}}")
+ private String adyenApiKey;
+
+ @Value("${ADYEN_MERCHANT_ACCOUNT:#{null}}")
+ private String adyenMerchantAccount;
+
+ @Value("${ADYEN_CLIENT_KEY:#{null}}")
+ private String adyenClientKey;
+
+ @Value("${ADYEN_HMAC_KEY:#{null}}")
+ private String adyenHmacKey;
+
+ public int getServerPort() {
+ return serverPort;
+ }
+
+ public void setServerPort(int serverPort) {
+ this.serverPort = serverPort;
+ }
+
+ public String getAdyenApiKey() {
+ return adyenApiKey;
+ }
+
+ public void setAdyenApiKey(String adyenApiKey) {
+ this.adyenApiKey = adyenApiKey;
+ }
+
+ public String getAdyenMerchantAccount() {
+ return adyenMerchantAccount;
+ }
+
+ public void setAdyenMerchantAccount(String adyenMerchantAccount) {
+ this.adyenMerchantAccount = adyenMerchantAccount;
+ }
+
+ public String getAdyenClientKey() {
+ return adyenClientKey;
+ }
+
+ public void setAdyenClientKey(String adyenClientKey) {
+ this.adyenClientKey = adyenClientKey;
+ }
+
+ public String getAdyenHmacKey() {
+ return adyenHmacKey;
+ }
+
+ public void setAdyenHmacKey(String adyenHmacKey) {
+ this.adyenHmacKey = adyenHmacKey;
+ }
+}
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/configurations/DependencyInjectionConfiguration.java b/checkout-example-advanced/src/main/java/com/adyen/checkout/configurations/DependencyInjectionConfiguration.java
new file mode 100644
index 00000000..f4a59e03
--- /dev/null
+++ b/checkout-example-advanced/src/main/java/com/adyen/checkout/configurations/DependencyInjectionConfiguration.java
@@ -0,0 +1,63 @@
+package com.adyen.checkout.configurations;
+
+import com.adyen.Client;
+import com.adyen.Config;
+import com.adyen.enums.Environment;
+import com.adyen.service.checkout.PaymentsApi;
+import com.adyen.util.HMACValidator;
+import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class DependencyInjectionConfiguration {
+ private final Logger log = LoggerFactory.getLogger(DependencyInjectionConfiguration.class);
+ private final ApplicationConfiguration applicationConfiguration;
+
+ public DependencyInjectionConfiguration(ApplicationConfiguration applicationConfiguration) {
+ this.applicationConfiguration = applicationConfiguration;
+
+ // https://docs.adyen.com/development-resources/api-credentials/#generate-api-key
+ if (applicationConfiguration.getAdyenApiKey() == null) {
+ log.error("ADYEN_API_KEY is null");
+ //throw new RuntimeException("ADYEN_API_KEY is null");
+ }
+
+ // https://docs.adyen.com/account/account-structure/#merchant-accounts
+ if (applicationConfiguration.getAdyenMerchantAccount() == null) {
+ log.error("ADYEN_MERCHANT_ACCOUNT is null");
+ //throw new RuntimeException("ADYEN_MERCHANT_ACCOUNT is null");
+ }
+
+ // https://docs.adyen.com/development-resources/client-side-authentication/#get-your-client-key
+ if (applicationConfiguration.getAdyenClientKey() == null) {
+ log.error("ADYEN_CLIENT_KEY is null");
+ //throw new RuntimeException("ADYEN_CLIENT_KEY is null");
+ }
+ }
+
+ @Bean
+ Client client() {
+ Config config = new Config();
+ config.setApiKey(applicationConfiguration.getAdyenApiKey());
+ config.setEnvironment(Environment.TEST);
+ return new Client(config);
+ }
+
+ @Bean
+ PaymentsApi paymentsApi() {
+ return new PaymentsApi(client());
+ }
+
+ @Bean
+ HMACValidator hmacValidator() {
+ return new HMACValidator();
+ }
+
+ @Bean
+ public LayoutDialect layoutDialect() {
+ return new LayoutDialect();
+ }
+}
diff --git a/checkout-example-advanced/src/main/java/com/adyen/checkout/views/ViewController.java b/checkout-example-advanced/src/main/java/com/adyen/checkout/views/ViewController.java
new file mode 100644
index 00000000..65f8c076
--- /dev/null
+++ b/checkout-example-advanced/src/main/java/com/adyen/checkout/views/ViewController.java
@@ -0,0 +1,52 @@
+package com.adyen.checkout.views;
+
+import com.adyen.checkout.ApplicationProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@Controller
+public class ViewController {
+
+ @Autowired
+ private ApplicationProperty applicationProperty;
+
+ @Autowired
+ public ViewController(ApplicationProperty applicationProperty) {
+ this.applicationProperty = applicationProperty;
+
+ if (this.applicationProperty.getClientKey() == null) {
+ Logger log = LoggerFactory.getLogger(ViewController.class);
+ log.warn("ADYEN_CLIENT_KEY is undefined ");
+ }
+ }
+
+ @GetMapping("/")
+ public String index() {
+ return "index";
+ }
+
+ @GetMapping("/preview")
+ public String preview(@RequestParam String type, Model model) {
+ model.addAttribute("type", type);
+ return "preview";
+ }
+
+ @GetMapping("/checkout")
+ public String checkout(@RequestParam String type, Model model) {
+ model.addAttribute("type", type);
+ model.addAttribute("clientKey", this.applicationProperty.getClientKey());
+ return "checkout";
+ }
+
+ @GetMapping("/result/{type}")
+ public String result(@PathVariable String type, Model model) {
+ model.addAttribute("type", type);
+ return "result";
+ }
+}
\ No newline at end of file
diff --git a/checkout-example-advanced/src/main/resources/static/adyenImplementation.js b/checkout-example-advanced/src/main/resources/static/adyenImplementation.js
index 1f8cac49..dd22053c 100644
--- a/checkout-example-advanced/src/main/resources/static/adyenImplementation.js
+++ b/checkout-example-advanced/src/main/resources/static/adyenImplementation.js
@@ -1,105 +1,143 @@
const clientKey = document.getElementById("clientKey").innerHTML;
-const type = document.getElementById("type").innerHTML;
+const { AdyenCheckout, Dropin } = window.AdyenWeb;
-async function initCheckout() {
- try {
- const paymentMethodsResponse = await callServer("/api/getPaymentMethods");
- const configuration = {
- paymentMethodsResponse: paymentMethodsResponse,
- clientKey,
- locale: "en_US",
- environment: "test",
- showPayButton: true,
- paymentMethodsConfiguration: {
- ideal: {
- showImage: true,
- },
- card: {
- hasHolderName: true,
- holderNameRequired: true,
- name: "Credit or debit card",
- amount: {
- value: 10000,
- currency: "EUR",
- },
- },
- paypal: {
- amount: {
- value: 10000,
- currency: "USD",
- },
- environment: "test", // Change this to "live" when you're ready to accept live PayPal payments
- countryCode: "US", // Only needed for test. This will be automatically retrieved when you are in production.
- onCancel: (data, component) => {
- component.setStatus('ready');
- },
- }
- },
- onSubmit: (state, component) => {
- if (state.isValid) {
- handleSubmission(state, component, "/api/initiatePayment");
- }
- },
- onAdditionalDetails: (state, component) => {
- handleSubmission(state, component, "/api/submitAdditionalDetails");
- },
- };
- // `spring.jackson.default-property-inclusion=non_null` needs to set in
- // src/main/resources/application.properties to avoid NPE here
- const checkout = await new AdyenCheckout(configuration);
- checkout.create(type).mount(document.getElementById("payment"));
- } catch (error) {
- console.error(error);
- alert("Error occurred. Look at console for details");
- }
-}
+async function startCheckout() {
+ try {
+ const paymentMethodsResponse = await fetch("/api/paymentMethods", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ }
+ }).then(response => response.json());
-// Event handlers called when the shopper selects the pay button,
-// or when additional information is required to complete the payment
-async function handleSubmission(state, component, url) {
- try {
- const res = await callServer(url, state.data);
- handleServerResponse(res, component);
- } catch (error) {
- console.error(error);
- alert("Error occurred. Look at console for details");
- }
-}
+ const configuration = {
+ paymentMethodsResponse: paymentMethodsResponse,
+ clientKey,
+ locale: "en_US",
+ countryCode: 'NL',
+ environment: "test",
+ showPayButton: true,
+ translations: {
+ 'en-US': {
+ 'creditCard.securityCode.label': 'CVV/CVC'
+ }
+ },
+ onSubmit: async (state, component, actions) => {
+ console.info("onSubmit", state, component, actions);
+ try {
+ if (state.isValid) {
+ const {action, order, resultCode, donationToken} = await fetch("/api/payments", {
+ method: "POST",
+ body: state.data ? JSON.stringify(state.data) : "",
+ headers: {
+ "Content-Type": "application/json",
+ }
+ }).then(response => response.json());
+
+ if (!resultCode) {
+ actions.reject();
+ }
+
+ actions.resolve({
+ resultCode,
+ action,
+ order,
+ donationToken
+ });
+ }
+ } catch (error) {
+ console.error(error);
+ actions.reject();
+ }
+ },
+ onPaymentCompleted: (result, component) => {
+ console.info("onPaymentCompleted", result, component);
+ handleOnPaymentCompleted(result, component);
+ },
+ onPaymentFailed: (result, component) => {
+ console.info("onPaymentFailed", result, component);
+ handleOnPaymentFailed(result, component);
+ },
+ onError: (error, component) => {
+ console.error("onError", error.name, error.message, error.stack, component);
+ window.location.href = "/result/error";
+ },
+ onAdditionalDetails: async (state, component) => {
+ console.info("onAdditionalDetails", state, component);
+ const response = await fetch("/api/payments/details", {
+ method: "POST",
+ body: state.data ? JSON.stringify(state.data) : "",
+ headers: {
+ "Content-Type": "application/json",
+ }
+ }).then(response => response.json());
+
+ if (response.action) {
+ component.handleAction(response.action);
+ } else {
+ handleOnPaymentCompleted(response);
+ }
+ }
+ };
-// Calls your server endpoints
-async function callServer(url, data) {
- const res = await fetch(url, {
- method: "POST",
- body: data ? JSON.stringify(data) : "",
- headers: {
- "Content-Type": "application/json",
- },
- });
+ const paymentMethodsConfiguration = {
+ card: {
+ showBrandIcon: true,
+ hasHolderName: true,
+ holderNameRequired: true,
+ name: "Credit or debit card",
+ amount: {
+ value: 10000,
+ currency: "EUR",
+ },
+ placeholders: {
+ cardNumber: '1234 5678 9012 3456',
+ expiryDate: 'MM/YY',
+ securityCodeThreeDigits: '123',
+ securityCodeFourDigits: '1234',
+ holderName: 'J. Smith'
+ }
+ }
+ };
- return await res.json();
+ // Start the AdyenCheckout and mount the element onto the 'payment' div.
+ const adyenCheckout = await AdyenCheckout(configuration);
+ const dropin = new Dropin(adyenCheckout, {
+ paymentMethodsConfiguration: paymentMethodsConfiguration
+ }).mount(document.getElementById("payment"));
+ } catch (error) {
+ console.error(error);
+ alert("Error occurred. Look at console for details.");
+ }
+}
+
+// Function to handle payment completion redirects
+function handleOnPaymentCompleted(response) {
+ switch (response.resultCode) {
+ case "Authorised":
+ window.location.href = "/result/success";
+ break;
+ case "Pending":
+ case "Received":
+ window.location.href = "/result/pending";
+ break;
+ default:
+ window.location.href = "/result/error";
+ break;
+ }
}
-// Handles responses sent from your server to the client
-function handleServerResponse(res, component) {
- if (res.action) {
- component.handleAction(res.action);
- } else {
- switch (res.resultCode) {
- case "Authorised":
- window.location.href = "/result/success";
- break;
- case "Pending":
- case "Received":
- window.location.href = "/result/pending";
- break;
- case "Refused":
- window.location.href = "/result/failed";
- break;
- default:
- window.location.href = "/result/error";
- break;
+// Function to handle payment failure redirects
+function handleOnPaymentFailed(response) {
+ switch (response.resultCode) {
+ case "Cancelled":
+ case "Refused":
+ window.location.href = "/result/failed";
+ break;
+ default:
+ window.location.href = "/result/error";
+ break;
}
- }
}
-initCheckout();
+startCheckout();
diff --git a/checkout-example-advanced/src/main/resources/templates/layout.html b/checkout-example-advanced/src/main/resources/templates/layout.html
index b3895e5b..18d94bfa 100644
--- a/checkout-example-advanced/src/main/resources/templates/layout.html
+++ b/checkout-example-advanced/src/main/resources/templates/layout.html
@@ -20,17 +20,17 @@
crossorigin="anonymous"
/>
-
-
-
+
+
+