├── .github └── workflows │ └── maven.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── README.md ├── checkstyle-suppressions.xml ├── checkstyle.xml ├── circle.yml ├── doc ├── diagram.png └── diagram.uxf ├── docker ├── amd64 │ └── Dockerfile ├── arm32v7 │ └── Dockerfile └── arm64v8 │ └── Dockerfile ├── integration-testing └── pom.xml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── server ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── payneteasy │ │ └── pos │ │ └── proxy │ │ ├── Configs.java │ │ ├── IPaymentService.java │ │ ├── JsonMessages.java │ │ ├── PosProxyApplication.java │ │ ├── WebServer.java │ │ ├── impl │ │ ├── InpasNetworkClientExtended.java │ │ ├── InpasNetworkManager.java │ │ └── PaymentServiceImpl.java │ │ └── messages │ │ ├── CloseDayRequest.java │ │ ├── CloseDayResponse.java │ │ ├── PaymentRequest.java │ │ ├── PaymentResponse.java │ │ └── RefundRequest.java │ └── resources │ └── swagger-ui │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── index.html │ ├── oauth2-redirect.html │ ├── pos-proxy.json │ ├── swagger-ui-bundle.js │ ├── swagger-ui-bundle.js.map │ ├── swagger-ui-standalone-preset.js │ ├── swagger-ui-standalone-preset.js.map │ ├── swagger-ui.css │ ├── swagger-ui.css.map │ ├── swagger-ui.js │ └── swagger-ui.js.map └── swagger ├── make-bundle.sh ├── messages ├── CloseDayRequest.yaml ├── CloseDayResponse.yaml ├── PaymentRequest.yaml ├── PaymentResponse.yaml └── RefundRequest.yaml ├── pos-proxy.yaml └── run-ui.sh /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 11 20 | uses: actions/setup-java@v2 21 | with: 22 | java-version: '11' 23 | distribution: 'adopt' 24 | - name: Build with Maven 25 | run: ./mvnw -B package --file pom.xml 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | classpath 2 | .project 3 | .settings/ 4 | target/ 5 | *.iml 6 | *.ipr 7 | *.iws 8 | *~ 9 | .idea 10 | gen/ 11 | classes/ 12 | gen-external-apklibs/ 13 | .vertx 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/payneteasy/pos-proxy/4b261fc96dfaf95f2829ece62c59e3dd810c37eb/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: true # faster builds 3 | 4 | jdk: 5 | - oraclejdk8 6 | 7 | cache: 8 | directories: 9 | - $HOME/.m2 10 | 11 | script: "./mvnw clean install" 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pos-proxy 2 | 3 | ## How it works 4 | 5 | POS Proxy is a web server that redirects json requests to a POS terminal connected via USB. 6 | You can also use this example to see how to integrate the Payneteasy mPOS SDK to your java application. 7 | 8 | ![Sequence diagram](https://raw.githubusercontent.com/payneteasy/pos-proxy/master/doc/diagram.png) 9 | 10 | * Client - a client code to start a payment 11 | * POS Proxy - this application 12 | * gate.payneteasy.com - Our authorisation server 13 | * Merchant site - we can make a callback to your server with a final order status 14 | 15 | ## Swagger UI 16 | 17 | * Run the application 18 | * Go to the http://0.0.0.0:8081/pos-proxy/swagger-ui 19 | 20 | Please see the video below: 21 | 22 | [![Swagger UI](https://img.youtube.com/vi/_A6wEbFHIOI/0.jpg)](https://youtu.be/_A6wEbFHIOI) 23 | 24 | ## How to generate a client code 25 | 26 | * Install swagger-codegen from https://github.com/swagger-api/swagger-codegen 27 | * Run swagger-codegen with your language 28 | 29 | ```bash 30 | swagger-codegen generate -i http://0.0.0.0:8081/pos-proxy/swagger-ui/pos-proxy.json -l java 31 | ``` 32 | 33 | ## Run it from docker 34 | 35 | ### amd64 36 | 37 | ```bash 38 | docker run -it -p 8081:8081/tcp payneteasy/pos-proxy:amd64 39 | ``` 40 | 41 | ### arm 64 v8 (Raspberry PI 3) 42 | 43 | ```bash 44 | docker run -it -p 8081:8081/tcp payneteasy/pos-proxy:arm64v8 45 | ``` 46 | 47 | ### arm 32 v7 (Raspberry PI 1/2) 48 | 49 | ```bash 50 | docker run -it -p 8081:8081/tcp payneteasy/pos-proxy:arm32v7 51 | ``` 52 | 53 | ## Requirements 54 | 55 | * Java 1.8 (Oracle or OpenJDK) 56 | 57 | ## How to build and run 58 | 59 | ```bash 60 | ./mvnw clean package 61 | cd server/target && java -jar server-1.3-SNAPSHOT-jar-with-dependencies.jar 62 | ``` 63 | 64 | ## How to run from release page 65 | 66 | ```bash 67 | wget https://github.com/payneteasy/pos-proxy/releases/download/1.3.0/pos-proxy-1.3.0.jar 68 | java -jar server-1.0-1-SNAPSHOT-jar-with-dependencies.jar 69 | ``` 70 | 71 | ## How to change a listening port 72 | 73 | You can change the listening port by pass this via -D option or via environment variable. 74 | 75 | Via environment variable: 76 | ```bash 77 | export HTTP_SERVER_PORT=9090 78 | java -jar server-1.3-SNAPSHOT-jar-with-dependencies.jar 79 | ``` 80 | 81 | Via -D option: 82 | ```bash 83 | java -DHTTP_SERVER_PORT=9090 -jar server-1.3-SNAPSHOT-jar-with-dependencies.jar 84 | ``` 85 | 86 | ## How to connect to a Verifone terminal via USB cable 87 | 88 | Run socat program to listen 27016 tcp port and redirects all tcp packets to a tty device. 89 | 90 | ```bash 91 | socat -d -d -v -x tcp4-listen:27015,reuseaddr,fork file:/dev/ttyACM0,nonblock,echo=0,raw 92 | ``` 93 | -------------------------------------------------------------------------------- /checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/openjdk:8-jdk 6 | 7 | working_directory: ~/repo 8 | 9 | environment: 10 | MAVEN_OPTS: -Xmx3200m 11 | 12 | steps: 13 | - checkout 14 | 15 | # Download and cache dependencies 16 | - restore_cache: 17 | keys: 18 | - v1-dependencies-{{ checksum "pom.xml" }} 19 | # fallback to using the latest cache if no exact match is found 20 | - v1-dependencies- 21 | 22 | - run: mvn test 23 | 24 | - save_cache: 25 | paths: 26 | - ~/.m2 27 | key: v1-dependencies-{{ checksum "pom.xml" }} 28 | 29 | # run tests! 30 | - run: ./mvnw clean install 31 | -------------------------------------------------------------------------------- /doc/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/payneteasy/pos-proxy/4b261fc96dfaf95f2829ece62c59e3dd810c37eb/doc/diagram.png -------------------------------------------------------------------------------- /doc/diagram.uxf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 4 | 5 | UMLGeneric 6 | 7 | 60 8 | 30 9 | 100 10 | 30 11 | 12 | _:Client_ 13 | 14 | 15 | 16 | Relation 17 | 18 | 90 19 | 50 20 | 30 21 | 600 22 | 23 | lt=. 24 | 10.0;10.0;10.0;580.0 25 | 26 | 27 | UMLGeneric 28 | 29 | 260 30 | 30 31 | 100 32 | 30 33 | 34 | _:POS Proxy_ 35 | 36 | 37 | 38 | UMLGeneric 39 | 40 | 520 41 | 30 42 | 200 43 | 30 44 | 45 | _:gate.payneteasy.com_ 46 | 47 | 48 | 49 | Relation 50 | 51 | 90 52 | 110 53 | 230 54 | 40 55 | 56 | lt=<<- 57 | POST /pos-proxy/pay 58 | 210.0;20.0;10.0;20.0 59 | 60 | 61 | Relation 62 | 63 | 290 64 | 50 65 | 30 66 | 240 67 | 68 | lt=. 69 | 10.0;10.0;10.0;220.0 70 | 71 | 72 | Relation 73 | 74 | 600 75 | 50 76 | 30 77 | 590 78 | 79 | lt=. 80 | 10.0;10.0;10.0;570.0 81 | 82 | 83 | Relation 84 | 85 | 90 86 | 320 87 | 540 88 | 110 89 | 90 | lt=<<- 91 | POST https://gate.payneteasy.com/paynet/api/v2/status 92 | with Order ID 93 | 94 | see http://doc.payneteasy.com/card_payment_API/ 95 | sale-transactions.html#order-status 96 | 97 | 520.0;20.0;10.0;20.0 98 | 99 | 100 | Relation 101 | 102 | 90 103 | 470 104 | 540 105 | 40 106 | 107 | lt=<<- 108 | Responses with Order Status 109 | 10.0;20.0;520.0;20.0 110 | 111 | 112 | UMLGeneric 113 | 114 | 90 115 | 120 116 | 20 117 | 100 118 | 119 | 120 | bg=yellow 121 | 122 | 123 | 124 | UMLGeneric 125 | 126 | 290 127 | 110 128 | 20 129 | 120 130 | 131 | 132 | bg=yellow 133 | 134 | 135 | 136 | Relation 137 | 138 | 90 139 | 170 140 | 230 141 | 50 142 | 143 | lt=<<- 144 | Returns Order ID 145 | 146 | 10.0;20.0;210.0;20.0 147 | 148 | 149 | UMLGeneric 150 | 151 | 90 152 | 320 153 | 20 154 | 200 155 | 156 | 157 | bg=yellow 158 | 159 | 160 | 161 | UMLGeneric 162 | 163 | 600 164 | 320 165 | 20 166 | 190 167 | 168 | 169 | bg=yellow 170 | 171 | 172 | 173 | UMLGeneric 174 | 175 | 1100 176 | 40 177 | 100 178 | 30 179 | 180 | _:Merchant Site_ 181 | 182 | 183 | 184 | Relation 185 | 186 | 1140 187 | 60 188 | 30 189 | 560 190 | 191 | lt=. 192 | 10.0;10.0;10.0;540.0 193 | 194 | 195 | Relation 196 | 197 | 600 198 | 260 199 | 570 200 | 50 201 | 202 | lt=<- 203 | Makes a callback 204 | see http://doc.payneteasy.com/common_utilities/merchants_callbacks.html 205 | 550.0;20.0;10.0;20.0 206 | 207 | 208 | -------------------------------------------------------------------------------- /docker/amd64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-slim 2 | ADD https://github.com/payneteasy/pos-proxy/releases/download/1.3.1/pos-proxy-1.3.1.jar /opt/app.jar 3 | WORKDIR /opt 4 | EXPOSE 8081/tcp 5 | CMD ["java", "-jar", "app.jar"] 6 | -------------------------------------------------------------------------------- /docker/arm32v7/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm32v7/openjdk:8-jre-slim 2 | ADD https://github.com/payneteasy/pos-proxy/releases/download/1.3.1/pos-proxy-1.3.1.jar /opt/app.jar 3 | WORKDIR /opt 4 | EXPOSE 8081/tcp 5 | CMD ["java", "-jar", "app.jar"] 6 | -------------------------------------------------------------------------------- /docker/arm64v8/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm64v8/openjdk:8-jre-slim 2 | ADD https://github.com/payneteasy/pos-proxy/releases/download/1.3.1/pos-proxy-1.3.1.jar /opt/app.jar 3 | WORKDIR /opt 4 | EXPOSE 8081/tcp 5 | CMD ["java", "-jar", "app.jar"] 6 | -------------------------------------------------------------------------------- /integration-testing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | jar 4 | 5 | com.payneteasy.pos-proxy 6 | integration-testing 7 | 8 | Robot integration testing ${project.version} 9 | 10 | 11 | com.payneteasy 12 | pos-proxy 13 | 1.3-SNAPSHOT 14 | 15 | 16 | 17 | UTF-8 18 | true 19 | 20 | 21 | 22 | 23 | integration-test 24 | 25 | false 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | com.google.code.findbugs 35 | jsr305 36 | 37 | 38 | 39 | junit 40 | junit 41 | test 42 | 43 | 44 | 45 | ch.qos.logback 46 | logback-classic 47 | 48 | 49 | ch.qos.logback 50 | logback-core 51 | 52 | 53 | 54 | org.slf4j 55 | slf4j-api 56 | 57 | 58 | 59 | org.slf4j 60 | jcl-over-slf4j 61 | 62 | 63 | org.slf4j 64 | log4j-over-slf4j 65 | 66 | 67 | org.slf4j 68 | jul-to-slf4j 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | if [ "$MVNW_VERBOSE" = true ]; then 205 | echo $MAVEN_PROJECTBASEDIR 206 | fi 207 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 208 | 209 | # For Cygwin, switch paths to Windows format before running java 210 | if $cygwin; then 211 | [ -n "$M2_HOME" ] && 212 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 213 | [ -n "$JAVA_HOME" ] && 214 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 215 | [ -n "$CLASSPATH" ] && 216 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 217 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 218 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 219 | fi 220 | 221 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 222 | 223 | exec "$JAVACMD" \ 224 | $MAVEN_OPTS \ 225 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 226 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 227 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 228 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% 146 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | pom 4 | 5 | pos-proxy 6 | com.payneteasy 7 | 1.3-SNAPSHOT 8 | 9 | pos robot ${project.version} 10 | 11 | POS/mPOS robot for passing ceritification 12 | 13 | https://github.com/evsinev/pos-proxy 14 | 15 | 16 | server 17 | integration-testing 18 | 19 | 20 | 21 | 1.8 22 | UTF-8 23 | 24 | 1.1.11 25 | 1.7.25 26 | 1.8.0 27 | 28 | ${project.basedir}/../target/coverage 29 | 30 | 0.8.0 31 | 32 | ${project.basedir}/../target/jacoco.exec 33 | java 34 | jacoco 35 | 36 | 4.1.1.4 37 | 38 | 1.4-90 39 | 40 | 41 | 42 | scm:git:git@github.com:evsinev/pos-proxy.git 43 | scm:git:git@github.com:evsinev/pos-proxy.git 44 | https://github.com/evsinev/pos-proxy.git 45 | HEAD 46 | 47 | 48 | 49 | 50 | reader-repo 51 | reader repo 52 | http://paynet-qa.clubber.me/reader/maven 53 | 54 | 55 | 56 | jitpack.io 57 | https://jitpack.io 58 | 59 | 60 | 61 | 62 | 65 | 66 | 67 | 68 | sonatype-nexus-staging 69 | sonatype oss RELEASE repository 70 | https://oss.sonatype.org/service/local/staging/deploy/maven2 71 | 72 | 73 | 74 | sonatype-nexus-snapshots 75 | sonatype oss SNAPSHOT repository 76 | https://oss.sonatype.org/content/repositories/snapshots 77 | false 78 | 79 | 80 | 81 | local-site 82 | Store only on local disk 83 | file:///tmp/mysql-scheduler-site 84 | 85 | 86 | 87 | 88 | 89 | The Apache Software License, Version 2.0 90 | http://www.apache.org/licenses/LICENSE-2.0.txt 91 | repo 92 | 93 | 94 | 95 | 96 | 97 | esinev 98 | esinev@gmail.com 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | com.payneteasy.pos-proxy 107 | server 108 | 1.3-SNAPSHOT 109 | 110 | 111 | 112 | com.payneteasy.android.reader.readers 113 | readers-miura-rxtx 114 | ${reader.version} 115 | 116 | 117 | 118 | com.payneteasy.android.reader.readers 119 | readers-inpas 120 | ${reader.version} 121 | 122 | 123 | 124 | com.payneteasy.android.reader.readers 125 | readers-common-rxtx-network 126 | ${reader.version} 127 | 128 | 129 | 130 | com.google.android 131 | android 132 | ${android.version} 133 | provided 134 | 135 | 136 | 137 | 138 | com.google.code.gson 139 | gson 140 | 2.2.4 141 | 142 | 143 | 144 | ru.odnoklassniki 145 | one-nio 146 | 1.0.2 147 | 148 | 149 | com.sun 150 | tools 151 | 152 | 153 | 154 | 155 | 156 | com.google.code.findbugs 157 | jsr305 158 | 3.0.2 159 | 160 | 161 | 162 | 163 | ch.qos.logback 164 | logback-classic 165 | ${logback.version} 166 | 167 | 168 | ch.qos.logback 169 | logback-core 170 | ${logback.version} 171 | 172 | 173 | 174 | org.slf4j 175 | slf4j-api 176 | ${slf4j.version} 177 | 178 | 179 | org.slf4j 180 | jcl-over-slf4j 181 | ${slf4j.version} 182 | 183 | 184 | org.slf4j 185 | log4j-over-slf4j 186 | ${slf4j.version} 187 | 188 | 189 | org.slf4j 190 | jul-to-slf4j 191 | ${slf4j.version} 192 | 193 | 194 | 195 | junit 196 | junit 197 | 4.13.2 198 | test 199 | 200 | 201 | 202 | org.jetbrains 203 | annotations 204 | 15.0 205 | 206 | 207 | 208 | org.mockito 209 | mockito-core 210 | 1.10.19 211 | test 212 | 213 | 214 | 215 | org.projectlombok 216 | lombok 217 | 1.18.12 218 | provided 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | org.apache.maven.plugins 228 | maven-release-plugin 229 | 2.5.3 230 | 231 | 232 | 233 | org.apache.maven.plugins 234 | maven-compiler-plugin 235 | 3.1 236 | 237 | ${java.version} 238 | ${java.version} 239 | true 240 | true 241 | 242 | 243 | 244 | 245 | org.codehaus.mojo 246 | cobertura-maven-plugin 247 | 2.7 248 | 249 | 250 | html 251 | xml 252 | 253 | true 254 | 255 | 256 | 257 | 258 | 259 | org.jacoco 260 | jacoco-maven-plugin 261 | ${jacoco.version} 262 | 263 | ${sonar.jacoco.reportPaths} 264 | ${sonar.jacoco.reportPaths} 265 | true 266 | 267 | 268 | 269 | agent-for-ut 270 | 271 | prepare-agent 272 | 273 | 274 | 275 | 276 | 277 | 278 | org.apache.maven.plugins 279 | maven-checkstyle-plugin 280 | 3.0.0 281 | 282 | 283 | validate 284 | validate 285 | 286 | checkstyle.xml 287 | UTF-8 288 | true 289 | true 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | org.sonatype.plugins 300 | nexus-staging-maven-plugin 301 | 1.6.3 302 | true 303 | 304 | sonatype-nexus-staging 305 | https://oss.sonatype.org/ 306 | true 307 | 308 | 309 | 310 | 311 | org.apache.maven.plugins 312 | maven-site-plugin 313 | 3.3 314 | 315 | true 316 | true 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | org.apache.maven.plugins 328 | maven-project-info-reports-plugin 329 | 2.7 330 | 331 | 332 | 333 | summary 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | release-profile 345 | 346 | 347 | performRelease 348 | true 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | org.apache.maven.plugins 357 | maven-gpg-plugin 358 | 1.1 359 | 360 | 361 | sign-artifacts 362 | verify 363 | 364 | sign 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | -------------------------------------------------------------------------------- /server/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | jar 5 | 6 | com.payneteasy.pos-proxy 7 | server 8 | 9 | Robot server ${project.version} 10 | 11 | 12 | com.payneteasy 13 | pos-proxy 14 | 1.3-SNAPSHOT 15 | 16 | 17 | 18 | UTF-8 19 | true 20 | 21 | 22 | 23 | 24 | integration-test 25 | 26 | false 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | com.payneteasy.android.reader.readers 36 | readers-miura-rxtx 37 | 38 | 39 | 40 | com.payneteasy.android.reader.readers 41 | readers-common-rxtx-network 42 | 43 | 44 | 45 | com.payneteasy.android.reader.readers 46 | readers-inpas 47 | 48 | 49 | 50 | com.google.android 51 | android 52 | provided 53 | 54 | 55 | 56 | com.google.code.findbugs 57 | jsr305 58 | 59 | 60 | 61 | junit 62 | junit 63 | test 64 | 65 | 66 | 67 | ch.qos.logback 68 | logback-classic 69 | 70 | 71 | ch.qos.logback 72 | logback-core 73 | 74 | 75 | 76 | org.slf4j 77 | slf4j-api 78 | 79 | 80 | 81 | org.slf4j 82 | jcl-over-slf4j 83 | 84 | 85 | org.slf4j 86 | log4j-over-slf4j 87 | 88 | 89 | org.slf4j 90 | jul-to-slf4j 91 | 92 | 93 | 94 | com.google.code.gson 95 | gson 96 | 97 | 98 | 99 | ru.odnoklassniki 100 | one-nio 101 | 102 | 103 | 104 | org.projectlombok 105 | lombok 106 | provided 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | maven-assembly-plugin 115 | 116 | 117 | 118 | com.payneteasy.pos.proxy.PosProxyApplication 119 | true 120 | 121 | 122 | 123 | jar-with-dependencies 124 | 125 | 126 | 127 | 128 | make-assembly 129 | package 130 | 131 | single 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/Configs.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.File; 7 | import java.util.Arrays; 8 | 9 | public enum Configs { 10 | 11 | HTTP_SERVER_ADDRESS ( "0.0.0.0" ) 12 | , HTTP_SERVER_PORT ( 8081 ) 13 | , HTTP_SERVER_SELECTORS ( 1 ) 14 | , HTTP_SERVER_MIN_WORKERS ( 2 ) 15 | , HTTP_SERVER_MAX_WORKERS ( 10 ) 16 | , API_KEY ( "56CC8E1F-85B3-404E-BB26-7671D45016D6" ) 17 | ; 18 | 19 | private static final Logger LOG = LoggerFactory.getLogger(Configs.class); 20 | 21 | static { 22 | LOG.info("Version is " + getVersion()); 23 | LOG.info("Configuration (you can change it with -D option or with env variable)"); 24 | int maxNameLength = getMaxNameLength(); 25 | for (Configs config : Configs.values()) { 26 | String value = config.name().contains("PASSWORD") ? "***" : config.asString(); 27 | LOG.info(" {} = {}", padRight(config.propertyName, maxNameLength), value); 28 | } 29 | } 30 | 31 | private static int getMaxNameLength() { 32 | return Arrays.stream(Configs.values()).mapToInt(value -> value.propertyName.length()).max().orElse(10); 33 | } 34 | 35 | 36 | private static String padRight(String aText, int aLength) { 37 | StringBuilder sb = new StringBuilder(aLength); 38 | sb.append(aText); 39 | while(sb.length() < aLength) { 40 | sb.append(" "); 41 | } 42 | return sb.toString(); 43 | } 44 | 45 | 46 | Configs(String aDefaultValue) { 47 | propertyName = name(); 48 | defaultValue = aDefaultValue; 49 | } 50 | 51 | Configs(long aDefaultValue) { 52 | this(String.valueOf(aDefaultValue)); 53 | } 54 | 55 | private final String propertyName; 56 | private final String defaultValue; 57 | 58 | public static String getVersion() { 59 | String version = Configs.class.getPackage().getImplementationVersion(); 60 | return version != null ? version : "unknown"; 61 | } 62 | 63 | public String asString() { 64 | String value = System.getProperty(propertyName, null); 65 | if(value == null) { 66 | value = System.getenv(propertyName); 67 | } 68 | if(value == null) { 69 | value = defaultValue; 70 | } 71 | return value; 72 | } 73 | 74 | public int asInt() { 75 | return Integer.parseInt(asString()); 76 | } 77 | 78 | public boolean asBoolean() { 79 | return Boolean.parseBoolean(asString()); 80 | } 81 | 82 | public int asMilliseconds() { 83 | return asInt() * 1_000; 84 | } 85 | 86 | public File asFile() { 87 | return new File(asString()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/IPaymentService.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy; 2 | 3 | import com.payneteasy.pos.proxy.messages.*; 4 | 5 | public interface IPaymentService { 6 | 7 | PaymentResponse pay(PaymentRequest aRequest); 8 | 9 | PaymentResponse refund(RefundRequest aRequest); 10 | 11 | CloseDayResponse closeDay(CloseDayRequest aRequest); 12 | } 13 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/JsonMessages.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import one.nio.http.HttpException; 6 | import one.nio.http.Request; 7 | import one.nio.http.Response; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.nio.charset.Charset; 12 | 13 | public class JsonMessages { 14 | 15 | private static final Logger LOG = LoggerFactory.getLogger(JsonMessages.class); 16 | 17 | private static final Charset UTF_8 = Charset.forName("utf-8"); 18 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 19 | 20 | private final Request request; 21 | private final String url; 22 | 23 | public JsonMessages(Request aRequest) { 24 | request = aRequest; 25 | url = aRequest.getURI(); 26 | } 27 | 28 | public T parse(Class aClass) throws HttpException { 29 | if(request.getBody() == null) { 30 | throw new HttpException("No body"); 31 | } 32 | String json = new String(request.getBody(), UTF_8); 33 | LOG.debug("IN {} = {}", url, json); 34 | return GSON.fromJson(json, aClass); 35 | } 36 | 37 | public Response response(Object aObject) { 38 | String json = GSON.toJson(aObject); 39 | LOG.debug("OUT {} = {}", url, json); 40 | Response response = new Response(Response.OK, json.getBytes(UTF_8)); 41 | response.addHeader("Content-Type: application/json"); 42 | return response; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/PosProxyApplication.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy; 2 | 3 | import com.payneteasy.pos.proxy.impl.PaymentServiceImpl; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.IOException; 8 | 9 | public class PosProxyApplication { 10 | 11 | private static final Logger LOG = LoggerFactory.getLogger(PosProxyApplication.class); 12 | 13 | public static void main(String[] args) throws IOException { 14 | LOG.info("Initialising ..."); 15 | LOG.info("Server {} starting on {}:{} ...", Configs.getVersion(), Configs.HTTP_SERVER_ADDRESS.asString(), Configs.HTTP_SERVER_PORT.asInt()); 16 | IPaymentService service = new PaymentServiceImpl(); 17 | WebServer server = new WebServer(service); 18 | server.start(); 19 | server.registerShutdownHook(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/WebServer.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy; 2 | 3 | import com.payneteasy.pos.proxy.messages.*; 4 | import one.nio.http.*; 5 | import one.nio.server.AcceptorConfig; 6 | import one.nio.util.ByteArrayBuilder; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.concurrent.Executor; 13 | import java.util.concurrent.Executors; 14 | 15 | 16 | public class WebServer extends HttpServer { 17 | 18 | private static final Logger LOG = LoggerFactory.getLogger(WebServer.class); 19 | private static final Executor PAYMENT_EXECUTOR = Executors.newSingleThreadExecutor(); 20 | 21 | private static final String EXPECTED_API_KEY = ": " + Configs.API_KEY.asString(); 22 | 23 | private final IPaymentService paymentService; 24 | 25 | public WebServer(IPaymentService aPaymentService) throws IOException { 26 | super(createConfig(Configs.HTTP_SERVER_ADDRESS.asString(), Configs.HTTP_SERVER_PORT.asInt())); 27 | paymentService = aPaymentService; 28 | } 29 | 30 | private static HttpServerConfig createConfig(String aAddress, int aPort) { 31 | AcceptorConfig acceptorConfig = new AcceptorConfig(); 32 | acceptorConfig.address = aAddress; 33 | acceptorConfig.port = aPort; 34 | 35 | HttpServerConfig config = new HttpServerConfig(); 36 | config.acceptors = new AcceptorConfig[]{acceptorConfig}; 37 | config.selectors = Configs.HTTP_SERVER_SELECTORS.asInt(); 38 | config.minWorkers = Configs.HTTP_SERVER_MIN_WORKERS.asInt(); 39 | config.maxWorkers = Configs.HTTP_SERVER_MAX_WORKERS.asInt(); 40 | return config; 41 | 42 | } 43 | 44 | @Path("/pos-proxy/management/version.txt") 45 | public Response handleVersion() { 46 | return Response.ok(Configs.getVersion()); 47 | } 48 | 49 | @Path("/pos-proxy/pay") 50 | public void pay(Request aRequest, HttpSession aSession) throws IOException { 51 | PAYMENT_EXECUTOR.execute(() -> { 52 | try { 53 | if (!checkApiKey(aRequest, aSession)) { 54 | return; 55 | } 56 | JsonMessages json = new JsonMessages(aRequest); 57 | PaymentRequest request = json.parse(PaymentRequest.class); 58 | PaymentResponse response = paymentService.pay(request); 59 | aSession.sendResponse(json.response(response)); 60 | } catch (Exception e) { 61 | sendError("Error while processing pay", aSession, e); 62 | } 63 | }); 64 | } 65 | 66 | @Path("/pos-proxy/refund") 67 | public void refund(Request aRequest, HttpSession aSession) throws IOException { 68 | PAYMENT_EXECUTOR.execute(() -> { 69 | try { 70 | if (!checkApiKey(aRequest, aSession)) { 71 | return; 72 | } 73 | JsonMessages json = new JsonMessages(aRequest); 74 | RefundRequest request = json.parse(RefundRequest.class); 75 | PaymentResponse response = paymentService.refund(request); 76 | aSession.sendResponse(json.response(response)); 77 | } catch (Exception e) { 78 | sendError("Error while processing pay", aSession, e); 79 | } 80 | }); 81 | } 82 | 83 | @Path("/pos-proxy/close-day") 84 | public void closeDay(Request aRequest, HttpSession aSession) throws IOException { 85 | PAYMENT_EXECUTOR.execute(() -> { 86 | try { 87 | if (!checkApiKey(aRequest, aSession)) { 88 | return; 89 | } 90 | JsonMessages json = new JsonMessages(aRequest); 91 | CloseDayRequest request = json.parse(CloseDayRequest.class); 92 | CloseDayResponse response = paymentService.closeDay(request); 93 | aSession.sendResponse(json.response(response)); 94 | } catch (Exception e) { 95 | sendError("Error while processing pay", aSession, e); 96 | } 97 | }); 98 | } 99 | 100 | private boolean checkApiKey(Request aRequest, HttpSession aSession) throws IOException { 101 | String apiKey = aRequest.getHeader("X-API-Key"); 102 | 103 | if(EXPECTED_API_KEY.equals(apiKey)) { 104 | return true; 105 | } else { 106 | LOG.error("Expected X-API-Key is '{}' but was '{}'", EXPECTED_API_KEY, apiKey); 107 | aSession.sendError(Response.FORBIDDEN, "Wrong X-API-Key"); 108 | return false; 109 | 110 | } 111 | } 112 | 113 | 114 | @Override 115 | public void handleDefault(Request aRequest, HttpSession aSession) throws IOException { 116 | if(aRequest.getURI().startsWith("/pos-proxy/swagger-ui")) { 117 | swagger(aRequest, aSession); 118 | } else { 119 | super.handleDefault(aRequest, aSession); 120 | } 121 | } 122 | 123 | public void swagger(Request aRequest, HttpSession aSession) { 124 | asyncExecute(() -> { 125 | try { 126 | String filename = aRequest.getURI().substring("/pos-proxy/swagger-ui".length()); 127 | if(filename.length() == 0) { 128 | aSession.sendResponse(Response.redirect("/pos-proxy/swagger-ui/")); 129 | return; 130 | } 131 | if(filename.length() == 1) { 132 | filename = "/index.html"; 133 | } 134 | String resource = "/swagger-ui" + filename; 135 | InputStream in = WebServer.class.getResourceAsStream(resource); 136 | if(in == null) { 137 | LOG.warn("Resource {} -> {} not found", aRequest.getURI(), resource); 138 | aSession.sendError(Response.NOT_FOUND, "Resource " + resource + " not found\n"); 139 | return; 140 | } 141 | ByteArrayBuilder byteArrayBuilder = readStream(in); 142 | aSession.sendResponse(new Response(Response.OK, byteArrayBuilder.toBytes())); 143 | } catch (Exception e) { 144 | sendError("Cannot process " + aRequest.getURI(), aSession, e); 145 | } 146 | }); 147 | } 148 | 149 | public String getResourceName(String aUri) { 150 | return aUri; 151 | } 152 | 153 | private void sendError(String aMessage, HttpSession aSession, Exception e) { 154 | LOG.error("Error: {}", aMessage, e); 155 | try { 156 | aSession.sendError(Response.INTERNAL_ERROR, e.getMessage()); 157 | } catch (IOException e1) { 158 | LOG.error("Cannot send error: {}", aMessage, e); 159 | } 160 | 161 | } 162 | 163 | private static ByteArrayBuilder readStream(InputStream in) throws IOException { 164 | byte[] buffer = new byte[64000]; 165 | ByteArrayBuilder builder = new ByteArrayBuilder(buffer.length); 166 | for (int bytes; (bytes = in.read(buffer)) > 0; ) { 167 | builder.append(buffer, 0, bytes); 168 | } 169 | return builder; 170 | } 171 | 172 | 173 | } 174 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/impl/InpasNetworkClientExtended.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.impl; 2 | 3 | import com.payneteasy.android.sdk.logger.ILogger; 4 | import com.payneteasy.android.sdk.reader.inpas.config.InpasTerminalConfiguration; 5 | import com.payneteasy.android.sdk.util.LoggerUtil; 6 | import com.payneteasy.inpas.sa.client.SmartAgentClient; 7 | import com.payneteasy.inpas.sa.messages.sale.*; 8 | 9 | import java.io.IOException; 10 | import java.math.BigDecimal; 11 | 12 | public class InpasNetworkClientExtended { 13 | 14 | private static final ILogger LOG = LoggerUtil.create(InpasNetworkClientExtended.class); 15 | 16 | private final SmartAgentClient delegate; 17 | private final String address; 18 | private final InpasTerminalConfiguration configuration; 19 | 20 | public InpasNetworkClientExtended(String aAddress, InpasTerminalConfiguration aConfiguration) { 21 | delegate = new SmartAgentClient(aConfiguration.createNetworkClientOptions(aAddress)); 22 | address = aAddress; 23 | configuration = aConfiguration; 24 | } 25 | 26 | public void connect() throws InterruptedException { 27 | while (!Thread.currentThread().isInterrupted()) { 28 | try { 29 | delegate.openConnection(); 30 | return; 31 | } catch (IOException e) { 32 | if(configuration.throwExceptionIfCannotConnect()) { 33 | throw new IllegalStateException("Cannot connect to " + address, e); 34 | } else { 35 | LOG.error("Cannot connect to {}. Sleeping 1 second ...", address, e); 36 | Thread.sleep(1_000); 37 | } 38 | } 39 | } 40 | 41 | } 42 | 43 | public Sa1PaymentResponse makeSale(String aCurrency, BigDecimal aAmount, String aTerminalId) throws IOException { 44 | Sa1PaymentResponse saleResponse = delegate.sale(new Sa1PaymentRequest.Builder() 45 | ._04_currencyCode(643) 46 | ._00_amount(aAmount) 47 | ._26_stan(configuration.getInvoice()) 48 | ._27_terminalId(aTerminalId) 49 | .build()); 50 | return saleResponse; 51 | } 52 | 53 | public Sa29ReversalResponse makeReversal(String aCurrency, BigDecimal aAmount, String aRrn, String aTerminalId) throws IOException { 54 | 55 | Sa29ReversalRequest request = new Sa29ReversalRequest.Builder() 56 | ._00_amount(aAmount) 57 | ._04_currencyCode(643) 58 | ._26_stan(configuration.getInvoice()) 59 | ._14_rrn(aRrn) 60 | ._27_terminalId(aTerminalId) 61 | .build(); 62 | return delegate.reversal(request); 63 | } 64 | 65 | public void makeReconciliation(String aTerminalId) { 66 | try { 67 | Sa59ReconciliationResponse reconciliation = delegate.reconciliation(new Sa59ReconciliationRequest.Builder()._27_terminalId(aTerminalId).build()); 68 | } catch (IOException e) { 69 | LOG.error("Cannot make reconciliation", e); 70 | } 71 | } 72 | 73 | public void closeConnection() { 74 | try { 75 | delegate.close(); 76 | } catch (Exception e) { 77 | LOG.error("Error while closing connection", e); 78 | } 79 | } 80 | 81 | public void sendEot() { 82 | try { 83 | delegate.sendEot(); 84 | } catch (Exception e) { 85 | LOG.error("Cannot send EOT", e); 86 | } 87 | } 88 | 89 | public Sa26TestConnectionResponse checkConnection(String aTerminalId ) { 90 | try { 91 | LOG.debug("InpasNetworkClient; checkConnection new branch"); 92 | return delegate.testConnectionToHost(aTerminalId); 93 | } catch (IOException e) { 94 | LOG.error("Error while testConnectionLocal", e); 95 | } 96 | 97 | return null; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/impl/InpasNetworkManager.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.impl; 2 | 3 | import com.payneteasy.android.sdk.reader.inpas.config.InpasTerminalConfiguration; 4 | import com.payneteasy.android.sdk.reader.inpas.network.InpasNetworkClient; 5 | import com.payneteasy.inpas.sa.client.handlers.DefaultClientPacketOptions; 6 | import com.payneteasy.pos.proxy.messages.PaymentResponse; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.io.IOException; 11 | 12 | public class InpasNetworkManager { 13 | 14 | private static final Logger LOG = LoggerFactory.getLogger(InpasNetworkManager.class); 15 | 16 | private final String amount; 17 | private final String currency; 18 | private final String posAddress; 19 | 20 | public InpasNetworkManager(String amount, String currency, String aPosAddress) { 21 | this.amount = amount; 22 | this.currency = currency; 23 | posAddress = aPosAddress; 24 | } 25 | 26 | public interface IInpasOperationHandler { 27 | PaymentResponse invokeOperation(InpasNetworkClientExtended aClient) throws IOException; 28 | } 29 | 30 | public PaymentResponse makeOperation(IInpasOperationHandler aHandler) { 31 | InpasNetworkClientExtended client = new InpasNetworkClientExtended(posAddress, new InpasTerminalConfiguration.Builder() 32 | .packetOptions(new DefaultClientPacketOptions()) 33 | .throwExceptionIfCannotConnect(true) 34 | .build() 35 | ); 36 | try { 37 | client.connect(); 38 | try { 39 | 40 | return aHandler.invokeOperation(client); 41 | 42 | } catch (Exception e) { 43 | client.sendEot(); 44 | LOG.error("Cannot process a payment", e); 45 | return error("-1"); 46 | } finally { 47 | client.closeConnection(); 48 | } 49 | } catch (InterruptedException e) { 50 | Thread.currentThread().interrupt(); 51 | throw new IllegalStateException("Interrupted"); 52 | } catch (Exception e) { 53 | LOG.error("Cannot connect", e); 54 | return error("-2"); 55 | } 56 | 57 | } 58 | 59 | private PaymentResponse error(String aErrorCode) { 60 | return PaymentResponse.builder() 61 | .amount ( amount ) 62 | .currency ( currency ) 63 | .orderId ( null ) 64 | .responseCode ( aErrorCode ) 65 | .build(); 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/impl/PaymentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.impl; 2 | 3 | import com.payneteasy.inpas.sa.messages.sale.Sa1PaymentResponse; 4 | import com.payneteasy.inpas.sa.messages.sale.Sa29ReversalResponse; 5 | import com.payneteasy.pos.proxy.IPaymentService; 6 | import com.payneteasy.pos.proxy.messages.*; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.math.BigDecimal; 11 | 12 | public class PaymentServiceImpl implements IPaymentService { 13 | 14 | private static final Logger LOG = LoggerFactory.getLogger(PaymentServiceImpl.class); 15 | 16 | @Override 17 | public PaymentResponse pay(PaymentRequest aRequest) { 18 | InpasNetworkManager manager = new InpasNetworkManager(aRequest.getAmount(), aRequest.getCurrency(), aRequest.getPosAddress()); 19 | 20 | return manager.makeOperation(aClient -> { 21 | Sa1PaymentResponse saResponse = aClient.makeSale( 22 | aRequest.getCurrency() 23 | , new BigDecimal(aRequest.getAmount()) 24 | , aRequest.getTerminalId() 25 | ); 26 | 27 | return PaymentResponse.builder() 28 | .amount ( saResponse.get_00_amount().toString() ) 29 | .currency ( aRequest.getCurrency() ) 30 | .orderId ( saResponse.get_14_rrn() ) 31 | .responseCode ( saResponse.get_15_responseCode() ) 32 | .build(); 33 | }); 34 | } 35 | 36 | @Override 37 | public PaymentResponse refund(RefundRequest aRequest) { 38 | InpasNetworkManager manager = new InpasNetworkManager(aRequest.getRefundAmount(), aRequest.getCurrency(), aRequest.getPosAddress()); 39 | 40 | return manager.makeOperation(aClient -> { 41 | Sa29ReversalResponse saResponse = aClient.makeReversal( 42 | aRequest.getCurrency() 43 | , new BigDecimal(aRequest.getRefundAmount()) 44 | , aRequest.getOrderId() 45 | , aRequest.getTerminalId() 46 | ); 47 | 48 | return PaymentResponse.builder() 49 | .amount ( saResponse.get_00_amount().toString() ) 50 | .currency ( aRequest.getCurrency() ) 51 | .orderId ( aRequest.getOrderId() ) 52 | .responseCode ( saResponse.get_15_responseCode() ) 53 | .build(); 54 | }); 55 | } 56 | 57 | @Override 58 | public CloseDayResponse closeDay(CloseDayRequest aRequest) { 59 | InpasNetworkManager manager = new InpasNetworkManager("0", "RUB", aRequest.getPosAddress()); 60 | 61 | PaymentResponse response = manager.makeOperation(aClient -> { 62 | aClient.makeReconciliation(aRequest.getTerminalId()); 63 | return PaymentResponse.builder() 64 | .responseCode("00") 65 | .currency("RUB") 66 | .amount("0") 67 | .build(); 68 | }); 69 | 70 | return new CloseDayResponse(response.getResponseCode()); 71 | } 72 | 73 | public static String toRrn(long aOrderId) { 74 | StringBuilder sb = new StringBuilder(); 75 | sb.append(aOrderId); 76 | while(sb.length() < 11) { 77 | sb.insert(0, "0"); 78 | } 79 | sb.insert(0, "P"); 80 | return sb.toString(); 81 | } 82 | 83 | private Long getPaynetOrderId(Sa1PaymentResponse saResponse) { 84 | if(saResponse.get_14_rrn() == null) { 85 | return null; 86 | } 87 | return Long.parseLong(saResponse.get_14_rrn().replace("P", "")); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/messages/CloseDayRequest.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.messages; 2 | 3 | import lombok.Data; 4 | import lombok.NonNull; 5 | 6 | @Data 7 | public class CloseDayRequest { 8 | 9 | @NonNull 10 | private final String posAddress; 11 | 12 | @NonNull 13 | private final String posType; 14 | 15 | private final String terminalId; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/messages/CloseDayResponse.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.messages; 2 | 3 | import lombok.Data; 4 | import lombok.NonNull; 5 | 6 | @Data 7 | public class CloseDayResponse { 8 | 9 | @NonNull 10 | private final String responseCode; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/messages/PaymentRequest.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.messages; 2 | 3 | import lombok.Data; 4 | import lombok.NonNull; 5 | 6 | @Data 7 | public class PaymentRequest { 8 | 9 | @NonNull 10 | private final String amount; 11 | 12 | @NonNull 13 | private final String currency; 14 | 15 | @NonNull 16 | private final String posAddress; 17 | 18 | @NonNull 19 | private final String posType; 20 | 21 | private final String terminalId; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/messages/PaymentResponse.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.messages; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | import lombok.NonNull; 6 | 7 | @Data 8 | @Builder 9 | public class PaymentResponse { 10 | 11 | 12 | @NonNull 13 | private final String amount; 14 | 15 | @NonNull 16 | private final String currency; 17 | 18 | @NonNull 19 | private final String responseCode; 20 | 21 | private final String orderId; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /server/src/main/java/com/payneteasy/pos/proxy/messages/RefundRequest.java: -------------------------------------------------------------------------------- 1 | package com.payneteasy.pos.proxy.messages; 2 | 3 | import lombok.Data; 4 | import lombok.NonNull; 5 | 6 | @Data 7 | public class RefundRequest { 8 | 9 | @NonNull 10 | private final String refundAmount; 11 | 12 | /** 13 | * Paynet order id to refund 14 | */ 15 | private final String orderId; 16 | 17 | @NonNull 18 | private final String currency; 19 | 20 | @NonNull 21 | private final String posAddress; 22 | 23 | @NonNull 24 | private final String posType; 25 | 26 | private final String terminalId; 27 | } 28 | -------------------------------------------------------------------------------- /server/src/main/resources/swagger-ui/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/payneteasy/pos-proxy/4b261fc96dfaf95f2829ece62c59e3dd810c37eb/server/src/main/resources/swagger-ui/favicon-16x16.png -------------------------------------------------------------------------------- /server/src/main/resources/swagger-ui/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/payneteasy/pos-proxy/4b261fc96dfaf95f2829ece62c59e3dd810c37eb/server/src/main/resources/swagger-ui/favicon-32x32.png -------------------------------------------------------------------------------- /server/src/main/resources/swagger-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 8 | 9 | 10 | 11 | 32 | 33 | 34 | 35 |
36 | 37 | 38 | 39 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /server/src/main/resources/swagger-ui/oauth2-redirect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 68 | -------------------------------------------------------------------------------- /server/src/main/resources/swagger-ui/pos-proxy.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Lounge Config Service", 5 | "version": "1.0.1" 6 | }, 7 | "host": "0.0.0.0:8081", 8 | "securityDefinitions": { 9 | "APIKeyHeader": { 10 | "type": "apiKey", 11 | "in": "header", 12 | "name": "X-API-Key" 13 | } 14 | }, 15 | "security": [ 16 | { 17 | "APIKeyHeader": [] 18 | } 19 | ], 20 | "schemes": [ 21 | "http", 22 | "https" 23 | ], 24 | "basePath": "/pos-proxy", 25 | "produces": [ 26 | "application/json" 27 | ], 28 | "paths": { 29 | "/pay": { 30 | "post": { 31 | "tags": [ 32 | "proxy" 33 | ], 34 | "summary": "Make a payment", 35 | "parameters": [ 36 | { 37 | "in": "body", 38 | "name": "body", 39 | "required": true, 40 | "schema": { 41 | "title": "Payment Request", 42 | "type": "object", 43 | "additionalProperties": false, 44 | "properties": { 45 | "amount": { 46 | "type": "string", 47 | "description": "Amount", 48 | "example": "10.00" 49 | }, 50 | "currency": { 51 | "type": "string", 52 | "description": "Currency", 53 | "example": "RUB" 54 | }, 55 | "posType": { 56 | "type": "string", 57 | "enum": [ 58 | "INPAS" 59 | ], 60 | "description": "POS terminal type", 61 | "example": "INPAS" 62 | }, 63 | "posAddress": { 64 | "type": "string", 65 | "description": "POS terminal address", 66 | "example": "10.0.1.20:27015" 67 | }, 68 | "terminalId": { 69 | "type": "string", 70 | "description": "Terminal ID", 71 | "example": "3A123456" 72 | } 73 | } 74 | } 75 | } 76 | ], 77 | "responses": { 78 | "200": { 79 | "description": "Status", 80 | "schema": { 81 | "title": "Control Response", 82 | "type": "object", 83 | "additionalProperties": false, 84 | "properties": { 85 | "responseCode": { 86 | "type": "string", 87 | "description": "00 - Approved, other codes - errors" 88 | }, 89 | "orderId": { 90 | "type": "integer", 91 | "format": "int64" 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "/refund": { 100 | "post": { 101 | "tags": [ 102 | "proxy" 103 | ], 104 | "summary": "Make a refund", 105 | "parameters": [ 106 | { 107 | "in": "body", 108 | "name": "body", 109 | "required": true, 110 | "schema": { 111 | "title": "Refund Request", 112 | "type": "object", 113 | "additionalProperties": false, 114 | "properties": { 115 | "refundAmount": { 116 | "type": "string", 117 | "description": "Refund amount", 118 | "example": "10.00" 119 | }, 120 | "currency": { 121 | "type": "string", 122 | "description": "Currency", 123 | "example": "RUB" 124 | }, 125 | "orderId": { 126 | "type": "integer", 127 | "format": "int64" 128 | }, 129 | "posType": { 130 | "type": "string", 131 | "enum": [ 132 | "INPAS" 133 | ], 134 | "description": "POS terminal type", 135 | "example": "INPAS" 136 | }, 137 | "posAddress": { 138 | "type": "string", 139 | "description": "POS terminal address", 140 | "example": "10.0.1.20:27015" 141 | }, 142 | "terminalId": { 143 | "type": "string", 144 | "description": "Terminal ID", 145 | "example": "3A123456" 146 | } 147 | } 148 | } 149 | } 150 | ], 151 | "responses": { 152 | "200": { 153 | "description": "Status", 154 | "schema": { 155 | "title": "Control Response", 156 | "type": "object", 157 | "additionalProperties": false, 158 | "properties": { 159 | "responseCode": { 160 | "type": "string", 161 | "description": "00 - Approved, other codes - errors" 162 | }, 163 | "orderId": { 164 | "type": "integer", 165 | "format": "int64" 166 | } 167 | } 168 | } 169 | } 170 | } 171 | } 172 | }, 173 | "/close-day": { 174 | "post": { 175 | "tags": [ 176 | "proxy" 177 | ], 178 | "summary": "Close day", 179 | "parameters": [ 180 | { 181 | "in": "body", 182 | "name": "body", 183 | "required": true, 184 | "schema": { 185 | "title": "Close Day Request", 186 | "type": "object", 187 | "additionalProperties": false, 188 | "properties": { 189 | "posType": { 190 | "type": "string", 191 | "enum": [ 192 | "INPAS" 193 | ], 194 | "description": "POS terminal type", 195 | "example": "INPAS" 196 | }, 197 | "posAddress": { 198 | "type": "string", 199 | "description": "POS terminal address", 200 | "example": "10.0.1.20:27015" 201 | }, 202 | "terminalId": { 203 | "type": "string", 204 | "description": "Terminal ID", 205 | "example": "3A123456" 206 | } 207 | } 208 | } 209 | } 210 | ], 211 | "responses": { 212 | "200": { 213 | "description": "Status", 214 | "schema": { 215 | "title": "Close Day Response", 216 | "type": "object", 217 | "additionalProperties": false, 218 | "properties": { 219 | "responseCode": { 220 | "type": "string", 221 | "description": "00 - Approved, other codes - errors" 222 | } 223 | } 224 | } 225 | } 226 | } 227 | } 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /server/src/main/resources/swagger-ui/swagger-ui.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""} -------------------------------------------------------------------------------- /swagger/make-bundle.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | swagger-ui-watcher pos-proxy.yaml --bundle ../server/src/main/resources/swagger-ui/pos-proxy.json 4 | -------------------------------------------------------------------------------- /swagger/messages/CloseDayRequest.yaml: -------------------------------------------------------------------------------- 1 | title: "Close Day Request" 2 | type: "object" 3 | additionalProperties: false 4 | properties: 5 | posType: 6 | type: "string" 7 | enum: 8 | - "INPAS" 9 | description: "POS terminal type" 10 | example: "INPAS" 11 | 12 | posAddress: 13 | type: "string" 14 | description: "POS terminal address" 15 | example: "10.0.1.20:27015" 16 | 17 | terminalId: 18 | type: "string" 19 | description: "Terminal ID" 20 | example: "3A123456" 21 | -------------------------------------------------------------------------------- /swagger/messages/CloseDayResponse.yaml: -------------------------------------------------------------------------------- 1 | title: "Close Day Response" 2 | type: "object" 3 | additionalProperties: false 4 | properties: 5 | responseCode: 6 | type: "string" 7 | description: "00 - Approved, other codes - errors" 8 | 9 | -------------------------------------------------------------------------------- /swagger/messages/PaymentRequest.yaml: -------------------------------------------------------------------------------- 1 | title: "Payment Request" 2 | type: "object" 3 | additionalProperties: false 4 | properties: 5 | amount: 6 | type: "string" 7 | description: "Amount" 8 | example: "10.00" 9 | 10 | currency: 11 | type: "string" 12 | description: "Currency" 13 | example: "RUB" 14 | 15 | posType: 16 | type: "string" 17 | enum: 18 | - "INPAS" 19 | description: "POS terminal type" 20 | example: "INPAS" 21 | 22 | 23 | posAddress: 24 | type: "string" 25 | description: "POS terminal address" 26 | example: "10.0.1.20:27015" 27 | 28 | terminalId: 29 | type: "string" 30 | description: "Terminal ID" 31 | example: "3A123456" 32 | 33 | -------------------------------------------------------------------------------- /swagger/messages/PaymentResponse.yaml: -------------------------------------------------------------------------------- 1 | title: "Control Response" 2 | type: "object" 3 | additionalProperties: false 4 | properties: 5 | responseCode: 6 | type: "string" 7 | description: "00 - Approved, other codes - errors" 8 | 9 | orderId: 10 | type: "integer" 11 | format: "int64" 12 | 13 | 14 | -------------------------------------------------------------------------------- /swagger/messages/RefundRequest.yaml: -------------------------------------------------------------------------------- 1 | title: "Refund Request" 2 | type: "object" 3 | additionalProperties: false 4 | properties: 5 | refundAmount: 6 | type: "string" 7 | description: "Refund amount" 8 | example: "10.00" 9 | 10 | currency: 11 | type: "string" 12 | description: "Currency" 13 | example: "RUB" 14 | 15 | orderId: 16 | type: "integer" 17 | format: "int64" 18 | 19 | posType: 20 | type: "string" 21 | enum: 22 | - "INPAS" 23 | description: "POS terminal type" 24 | example: "INPAS" 25 | 26 | posAddress: 27 | type: "string" 28 | description: "POS terminal address" 29 | example: "10.0.1.20:27015" 30 | 31 | terminalId: 32 | type: "string" 33 | description: "Terminal ID" 34 | example: "3A123456" 35 | -------------------------------------------------------------------------------- /swagger/pos-proxy.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | title: Lounge Config Service 4 | version: "1.0.1" 5 | 6 | host: 0.0.0.0:8081 7 | 8 | securityDefinitions: 9 | APIKeyHeader: 10 | type: apiKey 11 | in: header 12 | name: X-API-Key 13 | security: 14 | - APIKeyHeader: [] 15 | 16 | schemes: 17 | - http 18 | - https 19 | basePath: /pos-proxy 20 | produces: 21 | - application/json 22 | 23 | paths: 24 | /pay: 25 | post: 26 | tags: ['proxy'] 27 | summary: Make a payment 28 | parameters: 29 | - in: body 30 | name: body 31 | required: true 32 | schema: 33 | $ref: './messages/PaymentRequest.yaml' 34 | responses: 35 | 200: 36 | description: Status 37 | schema: 38 | $ref: './messages/PaymentResponse.yaml' 39 | 40 | /refund: 41 | post: 42 | tags: ['proxy'] 43 | summary: Make a refund 44 | parameters: 45 | - in: body 46 | name: body 47 | required: true 48 | schema: 49 | $ref: './messages/RefundRequest.yaml' 50 | responses: 51 | 200: 52 | description: Status 53 | schema: 54 | $ref: './messages/PaymentResponse.yaml' 55 | 56 | /close-day: 57 | post: 58 | tags: ['proxy'] 59 | summary: Close day 60 | parameters: 61 | - in: body 62 | name: body 63 | required: true 64 | schema: 65 | $ref: './messages/CloseDayRequest.yaml' 66 | responses: 67 | 200: 68 | description: Status 69 | schema: 70 | $ref: './messages/CloseDayResponse.yaml' 71 | -------------------------------------------------------------------------------- /swagger/run-ui.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | swagger-ui-watcher pos-proxy.yaml 3 | --------------------------------------------------------------------------------