start
23
.editorconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
|
||||
# We recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
# Change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{ts,tsx,js,jsx,json,css,scss,yml,html}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
24
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Java CI with Gradle
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
# cache: gradle
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build --debug
|
||||
35
.gitignore
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
env.tmp
|
||||
15
.gitpod.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
tasks:
|
||||
- init: ./gradlew bootJar
|
||||
command: ./gradlew bootRun
|
||||
|
||||
# exposed ports
|
||||
ports:
|
||||
- port: 8080
|
||||
onOpen: open-preview
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- redhat.java
|
||||
- vscjava.vscode-java-debug
|
||||
- vscjava.vscode-java-test
|
||||
- pivotal.vscode-spring-boot
|
||||
1
.vagrant/bundler/global.sol
Normal file
@@ -0,0 +1 @@
|
||||
{"dependencies":[["racc",["~> 1.4"]],["nokogiri",[">= 0"]],["vagrant-parallels",["= 2.3.1"]]],"checksum":"306cc775b2e3e42f6683a775882841f765b492aba52a9466599f24190c03f6c4","vagrant_version":"2.3.4"}
|
||||
1
.vagrant/machines/default/parallels/action_provision
Normal file
@@ -0,0 +1 @@
|
||||
1.5:8c33c12b-0476-4308-a4eb-0a0e3f6e7c04
|
||||
1
.vagrant/machines/default/parallels/action_set_name
Normal file
@@ -0,0 +1 @@
|
||||
1684332805
|
||||
1
.vagrant/machines/default/parallels/box_meta
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"jeffnoxon/ubuntu-20.04-arm64","version":"1.0.1","provider":"parallels","directory":"boxes/jeffnoxon-VAGRANTSLASH-ubuntu-20.04-arm64/1.0.1/parallels"}
|
||||
1
.vagrant/machines/default/parallels/creator_uid
Normal file
@@ -0,0 +1 @@
|
||||
502
|
||||
1
.vagrant/machines/default/parallels/id
Normal file
@@ -0,0 +1 @@
|
||||
8c33c12b-0476-4308-a4eb-0a0e3f6e7c04
|
||||
1
.vagrant/machines/default/parallels/index_uuid
Normal file
@@ -0,0 +1 @@
|
||||
f8191b6c631844249c51d3efa644d6e5
|
||||
27
.vagrant/machines/default/parallels/private_key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAuC1nYsYLVfRM8SqObjVwqawSmMVWdauwghkDpiw1DmCfKG2C
|
||||
OkGuMOkCfEpiP86IpJEf1gZbVoBncKg3u5NKHF44BcaMPAunCde6sf68fUs8RHA3
|
||||
QyaOwmRC8rdpzXAeVycoV1gxqN4t/wwRuK73/4YVNmVxYbD6TXh1YGKjRpZ8qV6b
|
||||
WDLaX0PanhAFdfXvKEViZi+Scm/9m/bBxgJVcCxV30KRQGFqT6QWHgIRoDHhFVSN
|
||||
ISPFsd0yOnNH4UQDAtBUiKmAroXvYubdpot5JqmlnsHVE8SXSEIwR0Ma6PLLYBnJ
|
||||
0V0KURu4JXMKu+Bc7FL18BrwhXz7ejz6tx586QIDAQABAoIBAEjt+bVcFJsJrPoG
|
||||
TvYHBUC6mXaTFcRsou0xOIexk6TIz90zV9D3tyE48zoCPltjzinUKZYXWE2tdMhg
|
||||
ZAlLrpoDGQ34bAlO1+sG2K+o3jyC8S9sfAWEHB2PlA8GX8fwsKL0J35GtwtWR0Jq
|
||||
Jg5KgntVPcsXakkzyjmpDFmJVXwaaIn0DAxjdbxRtczyaqztBf/uzmZC0gAR1go+
|
||||
d/eAMnVEIaKkQjPGzWo5y6u4SDDf3Ec1bFw0o+tKuQmRLC111/kHHSZUm1yVE2Nt
|
||||
E1a6nb1KqUof/gx6IU59HyMcyFb2cdGNzJdpIQ8JAMsN0kwGxT4wD57qy8bnBbgS
|
||||
DTLTFQECgYEA6NmZ1JySpE43o8BneqJcK75CtTZxfjW3UFpRZvd1Wk1ocJ85cmzq
|
||||
PwKZHcSwGFL+bY+jfQK9r5/1utnSJ6AHOl8lM1k4AKaTrJSJcSYK8/a+nF9Db6Al
|
||||
cdyDcpa6dWVkghTGY3ra0ASTE+C3ROmlqFLjNvigZ1vraglUdt0iLokCgYEAyn0B
|
||||
7YbTHzZP9E/SJ8+MmDoHvmPTgLD4GyOXx1vaCPEeuJ/QQG9UFA8wVrrN2KhXQj9F
|
||||
KqiYD02rF0ClVLWU//jR8hYuoUsIOuO/Q8MysVKtcd2h94Oo9DCP77srNAXDQJVs
|
||||
dGw2wf8sfy0uJqexHoR9m5oQtbbsK3BMhWvVQ2ECgYBoXjh8Ot3jtYds5226YxHL
|
||||
LZF65fdC6dLLul/oNhysqCua51N5fWYVbhWxaRrBHFocQ5i1DMh28szSvpVa23jB
|
||||
6imjdWcLq55faYidZb7dEQjo0C5K105RVdS5ROQ4gITnZWZy6nsvaA2AiGW9BrkQ
|
||||
1G4xkolbKrE/KwVn7cBHeQKBgDo7LvW/AzIDrYSl+9rlDhqs/ZMcJDPrML6lQr3b
|
||||
RV2y8dHIa9xL59MI9y7J8+6tosJzbZGyAGDORjiep60vtxTR2paTGH/cExbUbimv
|
||||
lgF2tFh9k1mZ7FmlKY+YtPj1+0u0bQciI7Ewj/xW4uHM8dvD4FeCO/H2E/7+AZOR
|
||||
CjihAoGBAJiPAtv19G9R6i/rhnZMYD/vbc4enNPyit3SIBiZ5kXG+VxJ4opeQWqc
|
||||
Khk2LcwG+VdPoIchhM5RJYPU+14v19XL1X/bGEWXJ+jmY5vNVErYkT2QBhZvb0Md
|
||||
jFTCAMpgJawlQ6lGcl3JXoo0cX0LRtvs50Ap61oSra9nFpY9eT1R
|
||||
-----END RSA PRIVATE KEY-----
|
||||
1
.vagrant/machines/default/parallels/synced_folders
Normal file
@@ -0,0 +1 @@
|
||||
{"parallels":{"/home/vagrant/adyen-java-spring":{"disabled":false,"guestpath":"/home/vagrant/adyen-java-spring","hostpath":"/Users/jilling/Downloads/adyen-java-spring-online-payments-8984812cc775f66ebb8e2b8a3e14794cabe57a0e","__vagrantfile":true}}}
|
||||
1
.vagrant/machines/default/parallels/vagrant_cwd
Normal file
@@ -0,0 +1 @@
|
||||
/Users/jilling/Downloads/adyen-java-spring-online-payments-8984812cc775f66ebb8e2b8a3e14794cabe57a0e
|
||||
9
.vagrant/rgloader/loader.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
# This file loads the proper rgloader/loader.rb file that comes packaged
|
||||
# with Vagrant so that encoded files can properly run with Vagrant.
|
||||
|
||||
if ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"]
|
||||
require File.expand_path(
|
||||
"rgloader/loader", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"])
|
||||
else
|
||||
raise "Encoded files can't be read outside of the Vagrant installer."
|
||||
end
|
||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Adyen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
75
README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Adyen [online payment](https://docs.adyen.com/checkout) integration demos
|
||||
|
||||
[](https://gitpod.io/#https://github.com/adyen-examples/adyen-java-spring-online-payments)
|
||||
|
||||
|
||||
This repository includes examples of PCI-compliant UI integrations for online payments with Adyen. Within this demo app, you'll find a simplified version of an e-commerce website, complete with commented code to highlight key features and concepts of Adyen's API. Check out the underlying code to see how you can integrate Adyen to give your shoppers the option to pay with their preferred payment methods, all in a seamless checkout experience.
|
||||
|
||||

|
||||
|
||||
## Supported Integrations
|
||||
|
||||
**Java + Spring Boot + Thymeleaf** demos of the following client-side integrations are currently available in this repository:
|
||||
|
||||
- [Drop-in](https://docs.adyen.com/checkout/drop-in-web)
|
||||
- [Component](https://docs.adyen.com/checkout/components-web)
|
||||
- ACH
|
||||
- Alipay
|
||||
- Card (3DS2)
|
||||
- Dotpay
|
||||
- giropay
|
||||
- iDEAL
|
||||
- Klarna (Pay now, Pay later, Slice it)
|
||||
- SOFORT
|
||||
- PayPal
|
||||
|
||||
The Demo leverages Adyen's API Library for Java ([GitHub](https://github.com/Adyen/adyen-java-api-library) | [Docs](https://docs.adyen.com/development-resources/libraries#java)).
|
||||
|
||||
## Requirements
|
||||
|
||||
- Java 11
|
||||
- Network access to maven central
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone this repo:
|
||||
|
||||
```
|
||||
git clone https://github.com/adyen-examples/adyen-java-spring-online-payments.git
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. Set environment variables for your [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) - Remember to add `http://localhost:8080` as an origin for client key, and merchant account name:
|
||||
|
||||
```shell
|
||||
export ADYEN_API_KEY=yourAdyenApiKey
|
||||
export ADYEN_MERCHANT_ACCOUNT=yourAdyenMerchantAccount
|
||||
export ADYEN_CLIENT_KEY=yourAdyenClientKey
|
||||
```
|
||||
|
||||
On Windows CMD you can use below commands instead
|
||||
|
||||
```shell
|
||||
set ADYEN_API_KEY=yourAdyenApiKey
|
||||
set ADYEN_MERCHANT_ACCOUNT=yourAdyenMerchantAccount
|
||||
set ADYEN_CLIENT_KEY=yourAdyenClientKey
|
||||
```
|
||||
|
||||
2. Start the server:
|
||||
|
||||
```
|
||||
./gradlew bootRun
|
||||
```
|
||||
|
||||
3. Visit [http://localhost:8080/](http://localhost:8080/) to select an integration type.
|
||||
|
||||
To try out integrations with test card numbers and payment method details, see [Test card numbers](https://docs.adyen.com/development-resources/test-cards/test-card-numbers).
|
||||
|
||||
## Contributing
|
||||
|
||||
We commit all our new features directly into our GitHub repository. Feel free to request or suggest new features or code changes yourself as well!
|
||||
|
||||
## License
|
||||
|
||||
MIT license. For more information, see the **LICENSE** file in the root directory.
|
||||
11
Vagrantfile
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "jeffnoxon/ubuntu-20.04-arm64"
|
||||
config.vm.provider :parallels do |v|
|
||||
v.memory = "4096"
|
||||
v.cpus = 4
|
||||
v.update_guest_tools = true
|
||||
end
|
||||
config.vm.synced_folder '.', '/home/vagrant/adyen-java-spring', disabled: false
|
||||
config.vm.network :forwarded_port, guest:3000, host: 3000
|
||||
config.vm.network :forwarded_port, guest:8080, host: 8080
|
||||
end
|
||||
28
build.gradle
Normal file
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.3.5.RELEASE'
|
||||
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'com.adyen'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = '11'
|
||||
|
||||
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:20.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()
|
||||
}
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
185
gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or 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 UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$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 "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 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
|
||||
;;
|
||||
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" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
gradlew.bat
vendored
Normal file
@@ -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
|
||||
1
settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'online-payments'
|
||||
12
src/main/java/com/adyen/checkout/Config.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.adyen.checkout;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import nz.net.ultraq.thymeleaf.LayoutDialect;
|
||||
|
||||
public class Config {
|
||||
@Bean
|
||||
public LayoutDialect layoutDialect() {
|
||||
return new LayoutDialect();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.adyen.checkout;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class OnlinePaymentsApplication {
|
||||
private static final Logger log = LoggerFactory.getLogger(OnlinePaymentsApplication.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OnlinePaymentsApplication.class, args);
|
||||
log.info("\n----------------------------------------------------------\n\t" +
|
||||
"Application is running! Access URLs:\n\t" +
|
||||
"Local: \t\thttp://localhost:8080\n\t" +
|
||||
"\n----------------------------------------------------------");
|
||||
}
|
||||
|
||||
}
|
||||
191
src/main/java/com/adyen/checkout/api/CheckoutResource.java
Normal file
@@ -0,0 +1,191 @@
|
||||
package com.adyen.checkout.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
import com.adyen.Client;
|
||||
import com.adyen.enums.Environment;
|
||||
import com.adyen.model.checkout.*;
|
||||
import com.adyen.service.Checkout;
|
||||
import com.adyen.service.exception.ApiException;
|
||||
|
||||
/**
|
||||
* REST controller for using Adyen checkout API
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class CheckoutResource {
|
||||
private final Logger log = LoggerFactory.getLogger(CheckoutResource.class);
|
||||
|
||||
@Value("${ADYEN_MERCHANT_ACCOUNT}")
|
||||
private String merchantAccount;
|
||||
|
||||
private final Checkout checkout;
|
||||
|
||||
public CheckoutResource(@Value("${ADYEN_API_KEY}") String apiKey) {
|
||||
var client = new Client(apiKey, Environment.TEST);
|
||||
this.checkout = new Checkout(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code POST /getPaymentMethods} : Get valid payment methods.
|
||||
*
|
||||
* @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("/getPaymentMethods")
|
||||
public ResponseEntity<PaymentMethodsResponse> paymentMethods() throws IOException, ApiException {
|
||||
var paymentMethodsRequest = new PaymentMethodsRequest();
|
||||
paymentMethodsRequest.setMerchantAccount(merchantAccount);
|
||||
paymentMethodsRequest.setChannel(PaymentMethodsRequest.ChannelEnum.WEB);
|
||||
|
||||
log.info("REST request to get Adyen payment methods {}", paymentMethodsRequest);
|
||||
var response = checkout.paymentMethods(paymentMethodsRequest);
|
||||
return ResponseEntity.ok()
|
||||
.body(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code POST /initiatePayment} : Make a payment.
|
||||
*
|
||||
* @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("/initiatePayment")
|
||||
public ResponseEntity<PaymentsResponse> payments(@RequestBody PaymentsRequest body, HttpServletRequest request) throws IOException, ApiException {
|
||||
var paymentRequest = new PaymentsRequest();
|
||||
paymentRequest.setMerchantAccount(merchantAccount); // required
|
||||
paymentRequest.setChannel(PaymentsRequest.ChannelEnum.WEB); // required
|
||||
|
||||
var amount = new Amount()
|
||||
.currency(findCurrency(body.getPaymentMethod().getType()))
|
||||
.value(1000L); // value is 10€ in minor units
|
||||
paymentRequest.setAmount(amount);
|
||||
|
||||
var orderRef = UUID.randomUUID().toString();
|
||||
paymentRequest.setReference(orderRef); // required
|
||||
// required for 3ds2 redirect flow
|
||||
paymentRequest.setReturnUrl("http://localhost:8080/api/handleShopperRedirect?orderRef=" + orderRef);
|
||||
|
||||
// required for 3ds2 native flow
|
||||
paymentRequest.setAdditionalData(Collections.singletonMap("allow3DS2", "true"));
|
||||
// required for 3ds2 native flow
|
||||
paymentRequest.setOrigin("http://localhost:8080");
|
||||
// required for 3ds2
|
||||
paymentRequest.setBrowserInfo(body.getBrowserInfo());
|
||||
// required by some issuers for 3ds2
|
||||
paymentRequest.setShopperIP(request.getRemoteAddr());
|
||||
|
||||
paymentRequest.setPaymentMethod(body.getPaymentMethod());
|
||||
|
||||
var type = body.getPaymentMethod().getType();
|
||||
// required for Klarna
|
||||
if (type.contains("klarna")) {
|
||||
paymentRequest.setCountryCode("DE");
|
||||
paymentRequest.setShopperReference("1234");
|
||||
paymentRequest.setShopperEmail("youremail@email.com");
|
||||
paymentRequest.setShopperLocale("en_US");
|
||||
var lineItems = new ArrayList<LineItem>();
|
||||
lineItems.add(
|
||||
new LineItem().quantity(1L).amountExcludingTax(331L).taxPercentage(2100L).description("Sunglasses").id("Item 1").taxAmount(69L).amountIncludingTax(400L)
|
||||
);
|
||||
lineItems.add(
|
||||
new LineItem().quantity(2L).amountExcludingTax(248L).taxPercentage(2100L).description("Headphones").id("Item 2").taxAmount(52L).amountIncludingTax(300L)
|
||||
);
|
||||
paymentRequest.setLineItems(lineItems);
|
||||
} else if (type.contains("paypal")) {
|
||||
paymentRequest.setCountryCode("US");
|
||||
}
|
||||
|
||||
log.info("REST request to make Adyen payment {}", paymentRequest);
|
||||
var response = checkout.payments(paymentRequest);
|
||||
return ResponseEntity.ok()
|
||||
.body(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code POST /submitAdditionalDetails} : Make a payment.
|
||||
*
|
||||
* @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("/submitAdditionalDetails")
|
||||
public ResponseEntity<PaymentsDetailsResponse> payments(@RequestBody PaymentsDetailsRequest detailsRequest) throws IOException, ApiException {
|
||||
log.info("REST request to make Adyen payment details {}", detailsRequest);
|
||||
var response = checkout.paymentsDetails(detailsRequest);
|
||||
return ResponseEntity.ok()
|
||||
.body(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code GET /handleShopperRedirect} : Handle redirect during payment.
|
||||
*
|
||||
* @return the {@link RedirectView} with status {@code 302}
|
||||
* @throws IOException from Adyen API.
|
||||
* @throws ApiException from Adyen API.
|
||||
*/
|
||||
@GetMapping("/handleShopperRedirect")
|
||||
public RedirectView redirect(@RequestParam(required = false) String payload, @RequestParam(required = false) String redirectResult, @RequestParam String orderRef) throws IOException, ApiException {
|
||||
var detailsRequest = new PaymentsDetailsRequest();
|
||||
if (redirectResult != null && !redirectResult.isEmpty()) {
|
||||
detailsRequest.setDetails(Collections.singletonMap("redirectResult", redirectResult));
|
||||
} else if (payload != null && !payload.isEmpty()) {
|
||||
detailsRequest.setDetails(Collections.singletonMap("payload", payload));
|
||||
}
|
||||
|
||||
return getRedirectView(detailsRequest);
|
||||
}
|
||||
|
||||
private RedirectView getRedirectView(final PaymentsDetailsRequest detailsRequest) throws ApiException, IOException {
|
||||
log.info("REST request to handle payment redirect {}", detailsRequest);
|
||||
var response = checkout.paymentsDetails(detailsRequest);
|
||||
var redirectURL = "/result/";
|
||||
switch (response.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=" + response.getResultCode());
|
||||
}
|
||||
|
||||
/* ################# UTILS ###################### */
|
||||
private String findCurrency(String type) {
|
||||
switch (type) {
|
||||
case "paypal":
|
||||
case "ach":
|
||||
return "USD";
|
||||
case "wechatpayqr":
|
||||
case "alipay":
|
||||
return "CNY";
|
||||
case "dotpay":
|
||||
return "PLN";
|
||||
case "boletobancario":
|
||||
case "boletobancario_santander":
|
||||
return "BRL";
|
||||
default:
|
||||
return "EUR";
|
||||
}
|
||||
}
|
||||
/* ################# end UTILS ###################### */
|
||||
}
|
||||
38
src/main/java/com/adyen/checkout/web/CheckoutController.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.adyen.checkout.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
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 CheckoutController {
|
||||
@Value("${ADYEN_CLIENT_KEY}")
|
||||
private String clientKey;
|
||||
|
||||
@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", clientKey);
|
||||
return "checkout";
|
||||
}
|
||||
|
||||
@GetMapping("/result/{type}")
|
||||
public String result(@PathVariable String type, Model model) {
|
||||
model.addAttribute("type", type);
|
||||
return "result";
|
||||
}
|
||||
}
|
||||
1
src/main/resources/application.properties
Normal file
@@ -0,0 +1 @@
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
125
src/main/resources/static/adyenImplementation.js
Normal file
@@ -0,0 +1,125 @@
|
||||
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: filterUnimplemented(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: 1000,
|
||||
currency: "EUR",
|
||||
},
|
||||
},
|
||||
paypal: {
|
||||
amount: {
|
||||
value: 1000,
|
||||
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 = new AdyenCheckout(configuration);
|
||||
checkout.create(type).mount(document.getElementById("payment"));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert("Error occurred. Look at console for details");
|
||||
}
|
||||
}
|
||||
|
||||
function filterUnimplemented(pm) {
|
||||
pm.paymentMethods = pm.paymentMethods.filter((it) =>
|
||||
[
|
||||
"scheme",
|
||||
"ideal",
|
||||
"dotpay",
|
||||
"giropay",
|
||||
// "sepadirectdebit",
|
||||
"directEbanking",
|
||||
"ach",
|
||||
"alipay",
|
||||
"klarna_paynow",
|
||||
"klarna",
|
||||
"klarna_account",
|
||||
"paypal",
|
||||
].includes(it.type)
|
||||
);
|
||||
return pm;
|
||||
}
|
||||
|
||||
// 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();
|
||||
413
src/main/resources/static/css/application.css
Normal file
@@ -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 */
|
||||
0
src/main/resources/static/images/.keep
Normal file
BIN
src/main/resources/static/images/cardcheckout.gif
Normal file
|
After Width: | Height: | Size: 3.7 MiB |
4
src/main/resources/static/images/error.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="88" height="88" viewBox="0 0 88 88" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 44C2 20.9046 20.9046 2 44 2C67.0954 2 86 20.9046 86 44C86 67.0954 67.0954 86 44 86C20.9046 86 2 67.0954 2 44Z" stroke="#D10244" stroke-width="4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.5 41.0339L55.8744 28.7009C56.6554 27.9225 57.9218 27.9225 58.7028 28.7009C59.4839 29.4793 59.4839 30.7414 58.7028 31.5199L46.3284 43.8529L58.7028 56.1858C59.4838 56.9643 59.4838 58.2264 58.7028 59.0048C57.9218 59.7832 56.6554 59.7832 55.8744 59.0048L43.5 46.6718L31.1257 59.0048C30.3446 59.7832 29.0783 59.7832 28.2972 59.0048C27.5162 58.2264 27.5162 56.9643 28.2972 56.1858L40.6716 43.8529L28.2972 31.5199C27.5162 30.7414 27.5162 29.4793 28.2972 28.7009C29.0783 27.9225 30.3446 27.9225 31.1256 28.7009L43.5 41.0339Z" fill="#D10244"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 850 B |
4
src/main/resources/static/images/failed.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="88" height="88" viewBox="0 0 88 88" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 44C2 20.9046 20.9046 2 44 2C67.0954 2 86 20.9046 86 44C86 67.0954 67.0954 86 44 86C20.9046 86 2 67.0954 2 44Z" stroke="#D10244" stroke-width="4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.5 41.0339L55.8744 28.7009C56.6554 27.9225 57.9218 27.9225 58.7028 28.7009C59.4839 29.4793 59.4839 30.7414 58.7028 31.5199L46.3284 43.8529L58.7028 56.1858C59.4838 56.9643 59.4838 58.2264 58.7028 59.0048C57.9218 59.7832 56.6554 59.7832 55.8744 59.0048L43.5 46.6718L31.1257 59.0048C30.3446 59.7832 29.0783 59.7832 28.2972 59.0048C27.5162 58.2264 27.5162 56.9643 28.2972 56.1858L40.6716 43.8529L28.2972 31.5199C27.5162 30.7414 27.5162 29.4793 28.2972 28.7009C29.0783 27.9225 30.3446 27.9225 31.1256 28.7009L43.5 41.0339Z" fill="#D10244"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 850 B |
BIN
src/main/resources/static/images/headphones.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
10
src/main/resources/static/images/mystore-logo.svg
Normal file
|
After Width: | Height: | Size: 83 KiB |
24
src/main/resources/static/images/pending.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<path d="M67.7975,34.25 C68.3735,34.25 68.948375,34.469375 69.38825,34.90925 C70.266875,35.787875 70.266875,37.21325 69.38825,38.091875 L43.136375,64.342625 C42.917,64.562 42.629,64.67225 42.341,64.67225 C42.053,64.67225 41.765,64.562 41.545625,64.342625 L30.40925,53.20625 C29.5295,52.3265 29.5295,50.903375 30.40925,50.023625 C30.848,49.584875 31.424,49.364375 32,49.364375 C32.574875,49.364375 33.152,49.584875 33.59075,50.023625 L42.341,58.775 L66.20675,34.90925 C66.646625,34.469375 67.2215,34.25 67.7975,34.25" id="path-1"></path>
|
||||
</defs>
|
||||
<g id="Layouts" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Chanel---04---Checkout" transform="translate(-669.000000, -275.000000)">
|
||||
<g id="Group-5" transform="translate(524.000000, 100.000000)">
|
||||
<g id="Group-4" transform="translate(115.000000, 175.000000)">
|
||||
<g id="Icon" transform="translate(30.000000, 0.000000)">
|
||||
<path d="M50,4 C24.709139,4 4,24.709139 4,50 C4,75.290861 24.709139,96 50,96 C75.290861,96 96,75.290861 96,50 C96,24.709139 75.290861,4 50,4 Z M50,0 C77.5,0 100,22.5 100,50 C100,77.5 77.5,100 50,100 C22.5,100 0,77.5 0,50 C0,22.5 22.5,0 50,0 Z" id="Path" fill="#0ABF53" fill-rule="nonzero"></path>
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<use id="Mask" fill="#0ABF53" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
24
src/main/resources/static/images/success.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<path d="M67.7975,34.25 C68.3735,34.25 68.948375,34.469375 69.38825,34.90925 C70.266875,35.787875 70.266875,37.21325 69.38825,38.091875 L43.136375,64.342625 C42.917,64.562 42.629,64.67225 42.341,64.67225 C42.053,64.67225 41.765,64.562 41.545625,64.342625 L30.40925,53.20625 C29.5295,52.3265 29.5295,50.903375 30.40925,50.023625 C30.848,49.584875 31.424,49.364375 32,49.364375 C32.574875,49.364375 33.152,49.584875 33.59075,50.023625 L42.341,58.775 L66.20675,34.90925 C66.646625,34.469375 67.2215,34.25 67.7975,34.25" id="path-1"></path>
|
||||
</defs>
|
||||
<g id="Layouts" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Chanel---04---Checkout" transform="translate(-669.000000, -275.000000)">
|
||||
<g id="Group-5" transform="translate(524.000000, 100.000000)">
|
||||
<g id="Group-4" transform="translate(115.000000, 175.000000)">
|
||||
<g id="Icon" transform="translate(30.000000, 0.000000)">
|
||||
<path d="M50,4 C24.709139,4 4,24.709139 4,50 C4,75.290861 24.709139,96 50,96 C75.290861,96 96,75.290861 96,50 C96,24.709139 75.290861,4 50,4 Z M50,0 C77.5,0 100,22.5 100,50 C100,77.5 77.5,100 50,100 C22.5,100 0,77.5 0,50 C0,22.5 22.5,0 50,0 Z" id="Path" fill="#0ABF53" fill-rule="nonzero"></path>
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<use id="Mask" fill="#0ABF53" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/main/resources/static/images/sunglasses.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
11
src/main/resources/static/images/thank-you.svg
Normal file
|
After Width: | Height: | Size: 70 KiB |
24
src/main/resources/templates/checkout.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<html lang="en"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Checkout</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" id="payment-page">
|
||||
<!-- Hidden divs with data passed from the Express server -->
|
||||
<div id="clientKey" class="hidden" th:text="${clientKey}"></div>
|
||||
<div id="type" class="hidden" th:text="${type}"></div>
|
||||
|
||||
<div class="container">
|
||||
<!-- The Checkout integration type will be rendered below.-->
|
||||
<!-- Drop-in includes styling out-of-the-box, so no additional styling is needed. -->
|
||||
<div class="payment-container">
|
||||
<div id="payment" class="payment"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Adyen Component client code -->
|
||||
<script type="text/javascript" src="/adyenImplementation.js"></script>
|
||||
</div>
|
||||
</body>
|
||||
118
src/main/resources/templates/index.html
Normal file
@@ -0,0 +1,118 @@
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Select type</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<div class='main-container'>
|
||||
<div class="info">
|
||||
<h1>Select a demo</h1>
|
||||
<p>Click to view an interactive example of a PCI-compliant UI integration for online payments.</p>
|
||||
<p>
|
||||
Make sure the payment method you want to use are enabled for your account.
|
||||
Refer <a href="https://docs.adyen.com/payment-methods#add-payment-methods-to-your-account">the documentation</a>
|
||||
to add missing
|
||||
payment methods.
|
||||
</p>
|
||||
<p>To learn more about client-side integration solutions, check out <a href="https://docs.adyen.com/checkout">Online
|
||||
payments.</a></p>
|
||||
</div>
|
||||
<ul class="integration-list">
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=dropin" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Drop-in</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=card" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Card</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=ideal" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">iDEAL</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=dotpay" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Dotpay</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=giropay" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">giropay</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<!-- <li class="integration-list-item">-->
|
||||
<!-- <a href="/preview?type=sepadirectdebit" class="integration-list-item-link">-->
|
||||
<!-- <div class="title-container">-->
|
||||
<!-- <p class="integration-list-item-title">SEPA Direct Debit</p>-->
|
||||
<!-- </div>-->
|
||||
<!-- </a>-->
|
||||
<!-- </li>-->
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=directEbanking" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">SOFORT</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=ach" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">ACH</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=paypal" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">PayPal</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=alipay" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Alipay</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=klarna_paynow" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Klarna - Pay now</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=klarna" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Klarna - Pay later</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="integration-list-item">
|
||||
<a href="/preview?type=klarna_account" class="integration-list-item-link">
|
||||
<div class="title-container">
|
||||
<p class="integration-list-item-title">Klarna - Slice it</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
44
src/main/resources/templates/layout.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html
|
||||
lang="en"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
>
|
||||
<head>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">
|
||||
Checkout Demo
|
||||
</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
<script src="https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/4.1.0/adyen.js"
|
||||
integrity="sha384-3tEepwhhMcyxgIbL3HBe3I59BpSMNyKoNrbKWARYH1tJ7K7K6NdTDqOltKlwiVsH"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/4.1.0/adyen.css"
|
||||
integrity="sha384-+CPzBNZVkBXu4uXDECnVuVQ24Kl8vWrR61UzuuuUj5IBEP//BQ0G0KDNfz2iPcvJ"
|
||||
crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="/css/application.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header id="header">
|
||||
<a href="/">
|
||||
<img src="/images/mystore-logo.svg" alt="" />
|
||||
</a>
|
||||
</header>
|
||||
<div class="container">
|
||||
<th:block layout:fragment="content" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
34
src/main/resources/templates/preview.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Preview</title>
|
||||
</head>
|
||||
<body>
|
||||
<main layout:fragment="content" class="preview-page">
|
||||
<section class="cart">
|
||||
<h2>Cart</h2>
|
||||
<div class="order-summary">
|
||||
<ul class="order-summary-list">
|
||||
<li class="order-summary-list-list-item">
|
||||
<img src="/images/sunglasses.png" class="order-summary-list-list-item-image" alt="">
|
||||
<p class="order-summary-list-list-item-title">Sunglasses</p>
|
||||
<p class="order-summary-list-list-item-price">5.00</p>
|
||||
</li>
|
||||
<li class="order-summary-list-list-item">
|
||||
<img src="/images/headphones.png" class="order-summary-list-list-item-image" alt="">
|
||||
<p class="order-summary-list-list-item-title">Headphones</p>
|
||||
<p class="order-summary-list-list-item-price">5.00</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cart-footer"><span class="cart-footer-label">Total:</span><span
|
||||
class="cart-footer-amount">10.00</span>
|
||||
<a th:href="@{/checkout(type=${type})}">
|
||||
<p class="button">Continue to checkout</p>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
26
src/main/resources/templates/result.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<html lang="en"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title th:text="${type}"></title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="status-container">
|
||||
<div class="status">
|
||||
<img th:src="${'/images/' + type + '.svg'}" class="status-image" alt="">
|
||||
<img th:if="${type == 'success' || type == 'pending'}" src="/images/thank-you.svg" class="status-image" alt="">
|
||||
|
||||
<p class="status-message">
|
||||
<span th:if="${type == 'success' }">Your order has been successfully placed.</span>
|
||||
<span th:if="${type == 'pending' }">Your order has been received! Payment completion pending.</span>
|
||||
<span th:if="${type == 'failed' }">The payment was refused. Please try a different payment method or card.</span>
|
||||
<span th:if="${type == 'error' }">
|
||||
Error! Please review response in console and refer to
|
||||
<a href="https://docs.adyen.com/development-resources/response-handling">Response handling.</a>
|
||||
</span>
|
||||
</p>
|
||||
<a class="button" href="/">Return Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
@@ -0,0 +1,30 @@
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||