diff --git a/yape-challenge/.gradle/6.8/executionHistory/executionHistory.bin b/yape-challenge/.gradle/6.8/executionHistory/executionHistory.bin new file mode 100644 index 0000000..3ce5805 Binary files /dev/null and b/yape-challenge/.gradle/6.8/executionHistory/executionHistory.bin differ diff --git a/yape-challenge/.gradle/6.8/executionHistory/executionHistory.lock b/yape-challenge/.gradle/6.8/executionHistory/executionHistory.lock new file mode 100644 index 0000000..a214537 Binary files /dev/null and b/yape-challenge/.gradle/6.8/executionHistory/executionHistory.lock differ diff --git a/yape-challenge/.gradle/6.8/fileChanges/last-build.bin b/yape-challenge/.gradle/6.8/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/yape-challenge/.gradle/6.8/fileChanges/last-build.bin differ diff --git a/yape-challenge/.gradle/6.8/fileHashes/fileHashes.bin b/yape-challenge/.gradle/6.8/fileHashes/fileHashes.bin new file mode 100644 index 0000000..862d81e Binary files /dev/null and b/yape-challenge/.gradle/6.8/fileHashes/fileHashes.bin differ diff --git a/yape-challenge/.gradle/6.8/fileHashes/fileHashes.lock b/yape-challenge/.gradle/6.8/fileHashes/fileHashes.lock new file mode 100644 index 0000000..32aeff3 Binary files /dev/null and b/yape-challenge/.gradle/6.8/fileHashes/fileHashes.lock differ diff --git a/yape-challenge/.gradle/6.8/gc.properties b/yape-challenge/.gradle/6.8/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/yape-challenge/.gradle/8.5/checksums/checksums.lock b/yape-challenge/.gradle/8.5/checksums/checksums.lock new file mode 100644 index 0000000..8db3239 Binary files /dev/null and b/yape-challenge/.gradle/8.5/checksums/checksums.lock differ diff --git a/yape-challenge/.gradle/8.5/checksums/md5-checksums.bin b/yape-challenge/.gradle/8.5/checksums/md5-checksums.bin new file mode 100644 index 0000000..1cc0ba6 Binary files /dev/null and b/yape-challenge/.gradle/8.5/checksums/md5-checksums.bin differ diff --git a/yape-challenge/.gradle/8.5/checksums/sha1-checksums.bin b/yape-challenge/.gradle/8.5/checksums/sha1-checksums.bin new file mode 100644 index 0000000..67f2fb0 Binary files /dev/null and b/yape-challenge/.gradle/8.5/checksums/sha1-checksums.bin differ diff --git a/yape-challenge/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock b/yape-challenge/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000..5e3ad40 Binary files /dev/null and b/yape-challenge/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock differ diff --git a/yape-challenge/.gradle/8.5/dependencies-accessors/gc.properties b/yape-challenge/.gradle/8.5/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/yape-challenge/.gradle/8.5/executionHistory/executionHistory.bin b/yape-challenge/.gradle/8.5/executionHistory/executionHistory.bin new file mode 100644 index 0000000..b99a3e4 Binary files /dev/null and b/yape-challenge/.gradle/8.5/executionHistory/executionHistory.bin differ diff --git a/yape-challenge/.gradle/8.5/executionHistory/executionHistory.lock b/yape-challenge/.gradle/8.5/executionHistory/executionHistory.lock new file mode 100644 index 0000000..f56e9a3 Binary files /dev/null and b/yape-challenge/.gradle/8.5/executionHistory/executionHistory.lock differ diff --git a/yape-challenge/.gradle/8.5/fileChanges/last-build.bin b/yape-challenge/.gradle/8.5/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/yape-challenge/.gradle/8.5/fileChanges/last-build.bin differ diff --git a/yape-challenge/.gradle/8.5/fileHashes/fileHashes.bin b/yape-challenge/.gradle/8.5/fileHashes/fileHashes.bin new file mode 100644 index 0000000..6beb20f Binary files /dev/null and b/yape-challenge/.gradle/8.5/fileHashes/fileHashes.bin differ diff --git a/yape-challenge/.gradle/8.5/fileHashes/fileHashes.lock b/yape-challenge/.gradle/8.5/fileHashes/fileHashes.lock new file mode 100644 index 0000000..2941681 Binary files /dev/null and b/yape-challenge/.gradle/8.5/fileHashes/fileHashes.lock differ diff --git a/yape-challenge/.gradle/8.5/fileHashes/resourceHashesCache.bin b/yape-challenge/.gradle/8.5/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..c0931dc Binary files /dev/null and b/yape-challenge/.gradle/8.5/fileHashes/resourceHashesCache.bin differ diff --git a/yape-challenge/.gradle/8.5/gc.properties b/yape-challenge/.gradle/8.5/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/yape-challenge/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/yape-challenge/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..17a24fb Binary files /dev/null and b/yape-challenge/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/yape-challenge/.gradle/buildOutputCleanup/cache.properties b/yape-challenge/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..05d71cb --- /dev/null +++ b/yape-challenge/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Fri May 31 01:27:20 PET 2024 +gradle.version=8.5 diff --git a/yape-challenge/.gradle/buildOutputCleanup/outputFiles.bin b/yape-challenge/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..6305d33 Binary files /dev/null and b/yape-challenge/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/yape-challenge/.gradle/checksums/checksums.lock b/yape-challenge/.gradle/checksums/checksums.lock new file mode 100644 index 0000000..627aebd Binary files /dev/null and b/yape-challenge/.gradle/checksums/checksums.lock differ diff --git a/yape-challenge/.gradle/configuration-cache/gc.properties b/yape-challenge/.gradle/configuration-cache/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/yape-challenge/.gradle/file-system.probe b/yape-challenge/.gradle/file-system.probe new file mode 100644 index 0000000..7aca2b0 Binary files /dev/null and b/yape-challenge/.gradle/file-system.probe differ diff --git a/yape-challenge/.gradle/vcs-1/gc.properties b/yape-challenge/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/yape-challenge/.idea/.gitignore b/yape-challenge/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/yape-challenge/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/yape-challenge/.idea/compiler.xml b/yape-challenge/.idea/compiler.xml new file mode 100644 index 0000000..bf60b75 --- /dev/null +++ b/yape-challenge/.idea/compiler.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yape-challenge/.idea/gradle.xml b/yape-challenge/.idea/gradle.xml new file mode 100644 index 0000000..0794f40 --- /dev/null +++ b/yape-challenge/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/yape-challenge/.idea/jarRepositories.xml b/yape-challenge/.idea/jarRepositories.xml new file mode 100644 index 0000000..fdc392f --- /dev/null +++ b/yape-challenge/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/yape-challenge/.idea/libraries-with-intellij-classes.xml b/yape-challenge/.idea/libraries-with-intellij-classes.xml new file mode 100644 index 0000000..9fa3156 --- /dev/null +++ b/yape-challenge/.idea/libraries-with-intellij-classes.xml @@ -0,0 +1,65 @@ + + + + + + \ No newline at end of file diff --git a/yape-challenge/.idea/misc.xml b/yape-challenge/.idea/misc.xml new file mode 100644 index 0000000..7134f89 --- /dev/null +++ b/yape-challenge/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/yape-challenge/.idea/uiDesigner.xml b/yape-challenge/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/yape-challenge/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yape-challenge/build.gradle b/yape-challenge/build.gradle new file mode 100644 index 0000000..35aa4f9 --- /dev/null +++ b/yape-challenge/build.gradle @@ -0,0 +1,3 @@ +group 'com.yape' +version '1.0-SNAPSHOT' + diff --git a/yape-challenge/gradle/wrapper/gradle-wrapper.jar b/yape-challenge/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/yape-challenge/gradle/wrapper/gradle-wrapper.jar differ diff --git a/yape-challenge/gradle/wrapper/gradle-wrapper.properties b/yape-challenge/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..a595206 --- /dev/null +++ b/yape-challenge/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/yape-challenge/gradlew b/yape-challenge/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/yape-challenge/gradlew @@ -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" "$@" diff --git a/yape-challenge/gradlew.bat b/yape-challenge/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/yape-challenge/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/yape-challenge/settings.gradle b/yape-challenge/settings.gradle new file mode 100644 index 0000000..a507532 --- /dev/null +++ b/yape-challenge/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = 'yape-challenge' +include 'yape-transaction-manager' +include 'yape-transaction-validator' + diff --git a/yape-challenge/yape-transaction-manager/.gitignore b/yape-challenge/yape-transaction-manager/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/yape-challenge/yape-transaction-manager/.gitignore @@ -0,0 +1,37 @@ +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 +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/yape-challenge/yape-transaction-manager/build.gradle b/yape-challenge/yape-transaction-manager/build.gradle new file mode 100644 index 0000000..7d7ad15 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/build.gradle @@ -0,0 +1,42 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.0' + id 'io.spring.dependency-management' version '1.1.5' +} + +group = 'com.yape' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '21' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + + implementation 'org.springframework.boot:spring-boot-starter-graphql' + implementation 'com.graphql-java:graphql-java-extended-scalars:21.0' + implementation 'jakarta.validation:jakarta.validation-api:3.1.0' + implementation 'org.springframework.boot:spring-boot-starter-data-cassandra' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.kafka:spring-kafka' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.graphql:spring-graphql-test' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.kafka:spring-kafka-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/yape-challenge/yape-transaction-manager/gradle/wrapper/gradle-wrapper.jar b/yape-challenge/yape-transaction-manager/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e644113 Binary files /dev/null and b/yape-challenge/yape-transaction-manager/gradle/wrapper/gradle-wrapper.jar differ diff --git a/yape-challenge/yape-transaction-manager/gradle/wrapper/gradle-wrapper.properties b/yape-challenge/yape-transaction-manager/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b82aa23 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/yape-challenge/yape-transaction-manager/gradlew b/yape-challenge/yape-transaction-manager/gradlew new file mode 100644 index 0000000..1aa94a4 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/yape-challenge/yape-transaction-manager/gradlew.bat b/yape-challenge/yape-transaction-manager/gradlew.bat new file mode 100644 index 0000000..25da30d --- /dev/null +++ b/yape-challenge/yape-transaction-manager/gradlew.bat @@ -0,0 +1,92 @@ +@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=. +@rem This is normally unused +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% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +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% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/yape-challenge/yape-transaction-manager/settings.gradle b/yape-challenge/yape-transaction-manager/settings.gradle new file mode 100644 index 0000000..aa90877 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'yape-transaction-manager' diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/YapeTransactionManagerApplication.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/YapeTransactionManagerApplication.java new file mode 100644 index 0000000..1c35408 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/YapeTransactionManagerApplication.java @@ -0,0 +1,25 @@ +package com.yape.transaction.manager; + +import com.yape.transaction.manager.infrastructure.config.DataStaxAstraProperties; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.context.annotation.Bean; + +import java.nio.file.Path; + +@ConfigurationPropertiesScan +@SpringBootApplication +public class YapeTransactionManagerApplication { + + public static void main(String[] args) { + SpringApplication.run(YapeTransactionManagerApplication.class, args); + } + + @Bean + public CqlSessionBuilderCustomizer sessionBuilderCustomizer(DataStaxAstraProperties astraProperties) { + Path bundle = astraProperties.getSecureConnectBundle().toPath(); + return builder -> builder.withCloudSecureConnectBundle(bundle); + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/graphql/TransactionController.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/graphql/TransactionController.java new file mode 100644 index 0000000..02bb3e0 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/graphql/TransactionController.java @@ -0,0 +1,21 @@ +package com.yape.transaction.manager.application.graphql; + +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.repository.TransactionRepository; +import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.stereotype.Controller; + +@Controller +public class TransactionController { + + private final TransactionRepository repository; + + public TransactionController(TransactionRepository repository) { + this.repository = repository; + } + + @QueryMapping + Iterable transactions() { + return repository.findAll(); + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/FindTransactionResponse.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/FindTransactionResponse.java new file mode 100644 index 0000000..d542416 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/FindTransactionResponse.java @@ -0,0 +1,17 @@ +package com.yape.transaction.manager.application.response; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +@Data +public class FindTransactionResponse { + + String transactionExternalId; + TransactionType transactionType; + TransactionStatus transactionStatus; + double value; + Date createAt; +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/TransactionStatus.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/TransactionStatus.java new file mode 100644 index 0000000..ecec2d5 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/TransactionStatus.java @@ -0,0 +1,12 @@ +package com.yape.transaction.manager.application.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class TransactionStatus { + + String name; +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/TransactionType.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/TransactionType.java new file mode 100644 index 0000000..be492fe --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/response/TransactionType.java @@ -0,0 +1,11 @@ +package com.yape.transaction.manager.application.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class TransactionType { + + String name; +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/rest/TransactionManagerController.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/rest/TransactionManagerController.java new file mode 100644 index 0000000..f251d49 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/application/rest/TransactionManagerController.java @@ -0,0 +1,37 @@ +package com.yape.transaction.manager.application.rest; + +import com.yape.transaction.manager.application.response.FindTransactionResponse; +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.service.TransactionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/yape/transaction/v1") +public class TransactionManagerController { + + private final TransactionService service; + + @Autowired + public TransactionManagerController(TransactionService service) { + this.service = service; + } + + @PostMapping("/create") + public ResponseEntity create(@RequestBody Transaction request) { + + return ResponseEntity.ok().body(service.createTransaction(request).toRestFindResponse()); + } + + @GetMapping("/{externalId}") + public ResponseEntity> find(@PathVariable String externalId) { + + List transaction = service.findTransactionsByExternalId(externalId); + + return ResponseEntity.ok().body(transaction.stream().map(Transaction::toRestFindResponse).collect(Collectors.toList())); + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/Transaction.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/Transaction.java new file mode 100644 index 0000000..faebf10 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/Transaction.java @@ -0,0 +1,64 @@ +package com.yape.transaction.manager.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.yape.transaction.manager.application.response.FindTransactionResponse; +import com.yape.transaction.manager.application.response.TransactionStatus; +import com.yape.transaction.manager.application.response.TransactionType; +import com.yape.transaction.manager.domain.contants.TransactionTypeEnum; +import lombok.Getter; + +import java.util.Date; + +@Getter +public class Transaction { + + private String internalId; + private String transactionExternalId; + private int transferTypeId; + private String status; + private double value; + private Date createdAt; + + @JsonCreator + public Transaction(@JsonProperty("accountExternalIdDebit") final String accountExternalIdDebit, + @JsonProperty("accountExternalIdCredit") final String accountExternalIdCredit, + @JsonProperty("tranferTypeId") final int tranferTypeId, + @JsonProperty("value") double value) { + + if (accountExternalIdDebit != null) { + this.transactionExternalId = accountExternalIdDebit; + } else if (accountExternalIdCredit != null) { + this.transactionExternalId = accountExternalIdCredit; + } + + this.transferTypeId = tranferTypeId; + this.value = value; + this.status = "PENDING"; + this.createdAt = new Date(); + } + public Transaction(String internalId, + String transactionExternalId, + int transferTypeId, + String status, + double value, + Date createdAt) { + this.internalId = internalId; + this.transactionExternalId = transactionExternalId; + this.transferTypeId = transferTypeId; + this.status = status; + this.value = value; + this.createdAt = createdAt; + } + + public FindTransactionResponse toRestFindResponse() { + + FindTransactionResponse response = new FindTransactionResponse(); + response.setTransactionExternalId(transactionExternalId); + response.setTransactionStatus(new TransactionStatus(status)); + response.setTransactionType(new TransactionType(TransactionTypeEnum.valueOf(transferTypeId).description)); + response.setValue(value); + response.setCreateAt(createdAt); + return response; + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/contants/TransactionTypeEnum.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/contants/TransactionTypeEnum.java new file mode 100644 index 0000000..b7525f5 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/contants/TransactionTypeEnum.java @@ -0,0 +1,24 @@ +package com.yape.transaction.manager.domain.contants; + +public enum TransactionTypeEnum { + PAYMENT(1, "PAYMENT"), + TRANSACTION(2, "TRANSACTION"); + + public final int id; + public final String description; + + TransactionTypeEnum(int id, String description) { + this.id = id; + this.description = description; + } + + public static TransactionTypeEnum valueOf (int id){ + for(TransactionTypeEnum e : values()) { + if(e.id == id) { + return e; + } + } + + return null; + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/event/CreateTransactionEventPort.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/event/CreateTransactionEventPort.java new file mode 100644 index 0000000..082d18a --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/event/CreateTransactionEventPort.java @@ -0,0 +1,9 @@ +package com.yape.transaction.manager.domain.event; + +import com.yape.transaction.manager.domain.Transaction; + +public interface CreateTransactionEventPort { + + void sendCreateTransactionEvent (Transaction transaction); + +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/repository/TransactionRepository.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/repository/TransactionRepository.java new file mode 100644 index 0000000..ba7ed3e --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/repository/TransactionRepository.java @@ -0,0 +1,15 @@ +package com.yape.transaction.manager.domain.repository; + +import com.yape.transaction.manager.domain.Transaction; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface TransactionRepository { + + List findByExternalId(UUID id); + Iterable findAll(); + Transaction save(Transaction transaction); + +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/service/DomainTransactionService.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/service/DomainTransactionService.java new file mode 100644 index 0000000..1dbfe0e --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/service/DomainTransactionService.java @@ -0,0 +1,36 @@ +package com.yape.transaction.manager.domain.service; + +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.event.CreateTransactionEventPort; +import com.yape.transaction.manager.domain.repository.TransactionRepository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class DomainTransactionService implements TransactionService { + + private final TransactionRepository repository; + private final CreateTransactionEventPort port; + + public DomainTransactionService(TransactionRepository repository, CreateTransactionEventPort port) { + this.repository = repository; + this.port = port; + } + + @Override + public Transaction createTransaction(Transaction transaction) { + + Transaction registeredTransaction = repository.save(transaction); + + port.sendCreateTransactionEvent(registeredTransaction); + + return registeredTransaction; + } + + @Override + public List findTransactionsByExternalId(String externalId) { + return repository.findByExternalId(UUID.fromString(externalId)); + } + +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/service/TransactionService.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/service/TransactionService.java new file mode 100644 index 0000000..1942d78 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/domain/service/TransactionService.java @@ -0,0 +1,12 @@ +package com.yape.transaction.manager.domain.service; + +import com.yape.transaction.manager.domain.Transaction; + +import java.util.List; +import java.util.Optional; + +public interface TransactionService { + + Transaction createTransaction (Transaction transaction); + List findTransactionsByExternalId (String externalId); +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/BeanConfig.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/BeanConfig.java new file mode 100644 index 0000000..fcbbcde --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/BeanConfig.java @@ -0,0 +1,17 @@ +package com.yape.transaction.manager.infrastructure.config; + +import com.yape.transaction.manager.domain.event.CreateTransactionEventPort; +import com.yape.transaction.manager.domain.repository.TransactionRepository; +import com.yape.transaction.manager.domain.service.DomainTransactionService; +import com.yape.transaction.manager.domain.service.TransactionService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class BeanConfig { + + @Bean + TransactionService DomainTransactionService(TransactionRepository repository, CreateTransactionEventPort port) { + return new DomainTransactionService(repository, port); + } +} \ No newline at end of file diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/DataStaxAstraProperties.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/DataStaxAstraProperties.java new file mode 100644 index 0000000..3673bb4 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/DataStaxAstraProperties.java @@ -0,0 +1,16 @@ +package com.yape.transaction.manager.infrastructure.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.io.File; + +@Getter +@Setter +@ConfigurationProperties("datastax.astra") +public class DataStaxAstraProperties { + + private File secureConnectBundle; + +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/KafkaTopicConfig.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/KafkaTopicConfig.java new file mode 100644 index 0000000..450c621 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/config/KafkaTopicConfig.java @@ -0,0 +1,20 @@ +package com.yape.transaction.manager.infrastructure.config; + +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.TopicBuilder; + +@Configuration +public class KafkaTopicConfig { + + @Bean + public NewTopic createdTransactionTopic() { + return TopicBuilder.name("createdTransactionTopic").build(); + } + + @Bean + public NewTopic validatedTransactionTopic() { + return TopicBuilder.name("validatedTransactionTopic").build(); + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/event/CreatedTransactionProducer.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/event/CreatedTransactionProducer.java new file mode 100644 index 0000000..11c7efa --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/event/CreatedTransactionProducer.java @@ -0,0 +1,31 @@ +package com.yape.transaction.manager.infrastructure.event; + +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.event.CreateTransactionEventPort; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Service; + +@Service +public class CreatedTransactionProducer implements CreateTransactionEventPort { + + private KafkaTemplate kafkaTemplate; + + public CreatedTransactionProducer(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + @Override + public void sendCreateTransactionEvent(Transaction transaction) { + + Message transactionMessage = MessageBuilder + .withPayload(transaction) + .setHeader(KafkaHeaders.TOPIC, "createdTransactionTopic") + .build(); + + kafkaTemplate.send(transactionMessage); + + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/event/ValidatedTransactionConsumer.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/event/ValidatedTransactionConsumer.java new file mode 100644 index 0000000..f2a32a2 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/event/ValidatedTransactionConsumer.java @@ -0,0 +1,21 @@ +package com.yape.transaction.manager.infrastructure.event; + +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.repository.TransactionRepository; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; + +@Service +public class ValidatedTransactionConsumer { + + private final TransactionRepository repository; + + public ValidatedTransactionConsumer(TransactionRepository repository) { + this.repository = repository; + } + + @KafkaListener(topics = "validatedTransactionTopic", groupId = "managerConsumerGroup") + public void consume(Transaction event) { + repository.save(event); + } +} \ No newline at end of file diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/CassandraTransactionRepository.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/CassandraTransactionRepository.java new file mode 100644 index 0000000..61556a7 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/CassandraTransactionRepository.java @@ -0,0 +1,40 @@ +package com.yape.transaction.manager.infrastructure.repository; + +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.repository.TransactionRepository; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Component +public class CassandraTransactionRepository implements TransactionRepository { + + private final SpringDataCassandraTransactionRepository repository; + + public CassandraTransactionRepository(SpringDataCassandraTransactionRepository repository) { + this.repository = repository; + } + + @Override + public List findByExternalId(UUID id) { + return repository.findByExternalId(id) + .stream() + .map(TransactionEntity::toDomainTransaction) + .collect(Collectors.toList()); + } + + @Override + public Iterable findAll() { + + List transactions = repository.findAll(); + + return transactions.stream().map(TransactionEntity::toDomainTransaction).collect(Collectors.toList()); + } + + @Override + public Transaction save(Transaction transaction) { + return repository.save(new TransactionEntity(transaction)).toDomainTransaction(); + } +} diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/SpringDataCassandraTransactionRepository.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/SpringDataCassandraTransactionRepository.java new file mode 100644 index 0000000..6865ce2 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/SpringDataCassandraTransactionRepository.java @@ -0,0 +1,15 @@ +package com.yape.transaction.manager.infrastructure.repository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import com.yape.transaction.manager.domain.Transaction; +import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SpringDataCassandraTransactionRepository extends CassandraRepository { + + List findByExternalId(UUID externalId); +} \ No newline at end of file diff --git a/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/TransactionEntity.java b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/TransactionEntity.java new file mode 100644 index 0000000..f454d62 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/java/com/yape/transaction/manager/infrastructure/repository/TransactionEntity.java @@ -0,0 +1,68 @@ +package com.yape.transaction.manager.infrastructure.repository; + +import com.yape.transaction.manager.application.response.FindTransactionResponse; +import com.yape.transaction.manager.application.response.TransactionStatus; +import com.yape.transaction.manager.application.response.TransactionType; +import com.yape.transaction.manager.domain.Transaction; +import com.yape.transaction.manager.domain.contants.TransactionTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.cassandra.core.cql.PrimaryKeyType; +import org.springframework.data.cassandra.core.mapping.*; + +import java.util.Date; +import java.util.UUID; + +@Data +@NoArgsConstructor +@Table(value = "transaction") +public class TransactionEntity { + + @Id + @PrimaryKeyColumn(name = "transaction_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED) + @CassandraType(type = CassandraType.Name.UUID) + private UUID id; + + @Indexed + @Column("external_id") + @CassandraType(type = CassandraType.Name.UUID) + private UUID externalId; + + @Column("type") + @CassandraType(type = CassandraType.Name.TEXT) + private int transferTypeId; + + @Column("status") + @CassandraType(type = CassandraType.Name.TEXT) + private String status; + + @Column("value") + @CassandraType(type = CassandraType.Name.DOUBLE) + private double value; + + @Column("created_date") + @CassandraType(type = CassandraType.Name.TIMESTAMP) + private Date createdAt; + + public TransactionEntity(Transaction transaction){ + + if(transaction.getInternalId() != null){ + this.id = UUID.fromString(transaction.getInternalId()); + } + else { + this.id = UUID.randomUUID(); + } + + this.externalId = UUID.fromString(transaction.getTransactionExternalId()); + this.transferTypeId = transaction.getTransferTypeId(); + this.status = transaction.getStatus(); + this.value = transaction.getValue(); + this.createdAt = transaction.getCreatedAt(); + } + + Transaction toDomainTransaction() { + return new Transaction(id.toString(), externalId.toString(), transferTypeId, status, value, createdAt); + } +} \ No newline at end of file diff --git a/yape-challenge/yape-transaction-manager/src/main/resources/application.properties b/yape-challenge/yape-transaction-manager/src/main/resources/application.properties new file mode 100644 index 0000000..633b17f --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/resources/application.properties @@ -0,0 +1,32 @@ +spring.application.name=yape-transaction-manager +server.port=8081 + +spring.kafka.consumer.bootstrap-servers=localhost:9092 +spring.kafka.consumer.group-id=managerConsumerGroup +spring.kafka.consumer.auto-offset-reset=earliest +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer +spring.kafka.consumer.properties.spring.json.trusted.packages=* +spring.kafka.consumer.properties.spring.json.type.mapping=com.yape.transaction.validator.domain.Transaction:com.yape.transaction.manager.domain.Transaction + +spring.kafka.producer.bootstrap-servers=localhost:9092 +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +spring.cassandra.keyspace-name=yape +spring.cassandra.username=ftkvUskglmcIysGsdFwNOYJj +spring.cassandra.password=XKyy4bGi427Isdvt3WLG4cj5I.6,knwmy,76Ir+fDvl2M+crDGApAImur_1fBp7virPynK-NoMMlDw_-CFpZJ1f24qzKlBuxvoDcfwxK10SK-02,fc3jMSYqgUjzb08A + +spring.cassandra.schema-action=create_if_not_exists +spring.cassandra.request.timeout=10s +spring.cassandra.connection.connect-timeout=10s +spring.cassandra.connection.init-query-timeout=10s + +datastax.astra.secure-connect-bundle=classpath:secure-connect-yape-transaction.zip + +astra.db.id=67f3333b-d996-4bf6-921a-9dc6c79baa96 +astra.db.region=us-east-2 +astra.db.keyspace=yape +astra.db.application.token=AstraCS:ftkvUskglmcIysGsdFwNOYJj:3ee75b7df70cb6cc9e7b3e404c7753db97530a6da13d43613debf4f111a3f9eb + +spring.graphql.graphiql.enabled=true \ No newline at end of file diff --git a/yape-challenge/yape-transaction-manager/src/main/resources/graphql/schema.graphqls b/yape-challenge/yape-transaction-manager/src/main/resources/graphql/schema.graphqls new file mode 100644 index 0000000..ef42e16 --- /dev/null +++ b/yape-challenge/yape-transaction-manager/src/main/resources/graphql/schema.graphqls @@ -0,0 +1,12 @@ +type Query{ + transactions: [Transaction] +} + +type Transaction { + + internalId: ID!, + transferTypeId: Int!, + status: String!, + value: Float! + +} \ No newline at end of file diff --git a/yape-challenge/yape-transaction-manager/src/main/resources/secure-connect-yape-transaction.zip b/yape-challenge/yape-transaction-manager/src/main/resources/secure-connect-yape-transaction.zip new file mode 100644 index 0000000..aee2b93 Binary files /dev/null and b/yape-challenge/yape-transaction-manager/src/main/resources/secure-connect-yape-transaction.zip differ diff --git a/yape-challenge/yape-transaction-validator/.gitignore b/yape-challenge/yape-transaction-validator/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/yape-challenge/yape-transaction-validator/.gitignore @@ -0,0 +1,37 @@ +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 +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/yape-challenge/yape-transaction-validator/build.gradle b/yape-challenge/yape-transaction-validator/build.gradle new file mode 100644 index 0000000..563e637 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.0' + id 'io.spring.dependency-management' version '1.1.5' +} + +group = 'com.yape' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '21' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-cassandra' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.kafka:spring-kafka' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.kafka:spring-kafka-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/yape-challenge/yape-transaction-validator/gradle/wrapper/gradle-wrapper.jar b/yape-challenge/yape-transaction-validator/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e644113 Binary files /dev/null and b/yape-challenge/yape-transaction-validator/gradle/wrapper/gradle-wrapper.jar differ diff --git a/yape-challenge/yape-transaction-validator/gradle/wrapper/gradle-wrapper.properties b/yape-challenge/yape-transaction-validator/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b82aa23 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/yape-challenge/yape-transaction-validator/gradlew b/yape-challenge/yape-transaction-validator/gradlew new file mode 100644 index 0000000..1aa94a4 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/yape-challenge/yape-transaction-validator/gradlew.bat b/yape-challenge/yape-transaction-validator/gradlew.bat new file mode 100644 index 0000000..25da30d --- /dev/null +++ b/yape-challenge/yape-transaction-validator/gradlew.bat @@ -0,0 +1,92 @@ +@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=. +@rem This is normally unused +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% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +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% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/yape-challenge/yape-transaction-validator/settings.gradle b/yape-challenge/yape-transaction-validator/settings.gradle new file mode 100644 index 0000000..609914d --- /dev/null +++ b/yape-challenge/yape-transaction-validator/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'yape-transaction-validator' diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/YapeTransactionValidatorApplication.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/YapeTransactionValidatorApplication.java new file mode 100644 index 0000000..77e5c97 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/YapeTransactionValidatorApplication.java @@ -0,0 +1,13 @@ +package com.yape.transaction.validator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class YapeTransactionValidatorApplication { + + public static void main(String[] args) { + SpringApplication.run(YapeTransactionValidatorApplication.class, args); + } + +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/Transaction.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/Transaction.java new file mode 100644 index 0000000..0be3956 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/Transaction.java @@ -0,0 +1,19 @@ +package com.yape.transaction.validator.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.Getter; + +import java.util.Date; + +@Data +public class Transaction { + + private String internalId; + private String transactionExternalId; + private int transferTypeId; + private String status; + private double value; + private Date createdAt; +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/event/ValidatedTransactionEventPort.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/event/ValidatedTransactionEventPort.java new file mode 100644 index 0000000..2e5328d --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/event/ValidatedTransactionEventPort.java @@ -0,0 +1,8 @@ +package com.yape.transaction.validator.domain.event; + +import com.yape.transaction.validator.domain.Transaction; + +public interface ValidatedTransactionEventPort { + + void sendValidatedTransactionEvent (Transaction transaction); +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/service/DomainValidatorService.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/service/DomainValidatorService.java new file mode 100644 index 0000000..548f226 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/service/DomainValidatorService.java @@ -0,0 +1,25 @@ +package com.yape.transaction.validator.domain.service; + +import com.yape.transaction.validator.domain.Transaction; +import com.yape.transaction.validator.domain.event.ValidatedTransactionEventPort; + +public class DomainValidatorService implements ValidatorService { + + private final ValidatedTransactionEventPort eventPort; + + public DomainValidatorService(ValidatedTransactionEventPort eventPort) { + this.eventPort = eventPort; + } + + @Override + public void validateTransaction(Transaction transaction) { + + if(transaction.getValue() > 1000) { + transaction.setStatus("REJECTED"); + } else { + transaction.setStatus("APPROVED"); + } + + eventPort.sendValidatedTransactionEvent(transaction); + } +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/service/ValidatorService.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/service/ValidatorService.java new file mode 100644 index 0000000..ed5ac09 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/domain/service/ValidatorService.java @@ -0,0 +1,9 @@ +package com.yape.transaction.validator.domain.service; + +import com.yape.transaction.validator.domain.Transaction; + +public interface ValidatorService { + + void validateTransaction(Transaction transaction); + +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/config/BeanConfig.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/config/BeanConfig.java new file mode 100644 index 0000000..3dcb344 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/config/BeanConfig.java @@ -0,0 +1,16 @@ +package com.yape.transaction.validator.infrastructure.config; + +import com.yape.transaction.validator.domain.event.ValidatedTransactionEventPort; +import com.yape.transaction.validator.domain.service.DomainValidatorService; +import com.yape.transaction.validator.domain.service.ValidatorService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class BeanConfig { + + @Bean + ValidatorService DomainValidatorService(ValidatedTransactionEventPort port) { + return new DomainValidatorService(port); + } +} \ No newline at end of file diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/config/KafkaTopicConfig.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/config/KafkaTopicConfig.java new file mode 100644 index 0000000..65bfdd5 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/config/KafkaTopicConfig.java @@ -0,0 +1,20 @@ +package com.yape.transaction.validator.infrastructure.config; + +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.TopicBuilder; + +@Configuration +public class KafkaTopicConfig { + + @Bean + public NewTopic createdTransactionTopic() { + return TopicBuilder.name("createdTransactionTopic").build(); + } + + @Bean + public NewTopic validatedTransactionTopic() { + return TopicBuilder.name("validatedTransactionTopic").build(); + } +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/event/CreatedTransactionConsumer.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/event/CreatedTransactionConsumer.java new file mode 100644 index 0000000..325e2f7 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/event/CreatedTransactionConsumer.java @@ -0,0 +1,22 @@ +package com.yape.transaction.validator.infrastructure.event; + +import com.yape.transaction.validator.domain.Transaction; +import com.yape.transaction.validator.domain.service.ValidatorService; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; + +@Service +public class CreatedTransactionConsumer { + + private final ValidatorService service; + + public CreatedTransactionConsumer(ValidatorService service) { + this.service = service; + } + + @KafkaListener(topics = "createdTransactionTopic", groupId = "validatorConsumerGroup") + public void consume(Transaction transaction) { + service.validateTransaction(transaction); + } + +} diff --git a/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/event/ValidatedTransactionProducer.java b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/event/ValidatedTransactionProducer.java new file mode 100644 index 0000000..64457f4 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/java/com/yape/transaction/validator/infrastructure/event/ValidatedTransactionProducer.java @@ -0,0 +1,30 @@ +package com.yape.transaction.validator.infrastructure.event; + +import com.yape.transaction.validator.domain.Transaction; +import com.yape.transaction.validator.domain.event.ValidatedTransactionEventPort; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Service; + +@Service +public class ValidatedTransactionProducer implements ValidatedTransactionEventPort { + + private KafkaTemplate kafkaTemplate; + + public ValidatedTransactionProducer(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + @Override + public void sendValidatedTransactionEvent(Transaction transaction) { + + Message transactionMessage = MessageBuilder + .withPayload(transaction) + .setHeader(KafkaHeaders.TOPIC, "validatedTransactionTopic") + .build(); + + kafkaTemplate.send(transactionMessage); + } +} diff --git a/yape-challenge/yape-transaction-validator/src/main/resources/application.properties b/yape-challenge/yape-transaction-validator/src/main/resources/application.properties new file mode 100644 index 0000000..729db07 --- /dev/null +++ b/yape-challenge/yape-transaction-validator/src/main/resources/application.properties @@ -0,0 +1,15 @@ +spring.application.name=yape-transaction-validator +server.port=8082 + +spring.kafka.consumer.bootstrap-servers=localhost:9092 +spring.kafka.consumer.group-id=validatorConsumerGroup +spring.kafka.consumer.auto-offset-reset=earliest +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer +spring.kafka.consumer.properties.spring.json.trusted.packages=* +spring.kafka.consumer.properties.spring.json.type.mapping=com.yape.transaction.manager.domain.Transaction:com.yape.transaction.validator.domain.Transaction + +spring.kafka.producer.bootstrap-servers=localhost:9092 +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +