From bec7093889743b45862657d739b801ab87047dc8 Mon Sep 17 00:00:00 2001 From: NewUsername Date: Fri, 10 Oct 2025 12:56:49 +0300 Subject: [PATCH] Initial commit --- .gradle/8.14.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .gradle/8.14.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .gradle/8.14.3/fileHashes/fileHashes.bin | Bin 0 -> 18947 bytes .gradle/8.14.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .gradle/8.14.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 + .gradle/vcs-1/gc.properties | 0 .idea/.gitignore | 5 + .idea/.name | 1 + .idea/compiler.xml | 18 + .idea/gradle.xml | 15 + .idea/misc.xml | 5 + .idea/modules.xml | 8 + .idea/modules/payment.main.iml | 8 + .idea/vcs.xml | 6 + HELP.md | 14 + build.gradle | 50 ++ build/reports/problems/problems-report.html | 663 ++++++++++++++++++ build/resources/main/application.yml | 40 ++ .../compileJava/previous-compilation-data.bin | Bin 0 -> 93696 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 251 +++++++ gradlew.bat | 94 +++ settings.gradle | 1 + .../com/test/payment/PaymentApplication.java | 15 + .../payment/configurations/RedisConfig.java | 22 + .../configurations/ResilienceConfig.java | 45 ++ .../configurations/WebClientConfig.java | 16 + .../payment/controller/MpesaController.java | 28 + .../exceptions/MpesaPermanentException.java | 8 + .../exceptions/MpesaTransientException.java | 7 + .../payment/jobs/MpesaTransactionJob.java | 23 + .../test/payment/models/MpesaResponse.java | 13 + .../test/payment/models/PaymentRequest.java | 12 + .../com/test/payment/models/Transaction.java | 21 + .../payment/repository/MpesaRepository.java | 31 + .../test/payment/service/MpesaService.java | 65 ++ .../payment/service/MpesaTokenService.java | 27 + src/main/resources/application.yml | 40 ++ .../test/payment/PaymentApplicationTests.java | 13 + 42 files changed, 1574 insertions(+) create mode 100644 .gradle/8.14.3/checksums/checksums.lock create mode 100644 .gradle/8.14.3/executionHistory/executionHistory.lock create mode 100644 .gradle/8.14.3/fileChanges/last-build.bin create mode 100644 .gradle/8.14.3/fileHashes/fileHashes.bin create mode 100644 .gradle/8.14.3/fileHashes/fileHashes.lock create mode 100644 .gradle/8.14.3/gc.properties create mode 100644 .gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 .gradle/buildOutputCleanup/cache.properties create mode 100644 .gradle/vcs-1/gc.properties create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/modules/payment.main.iml create mode 100644 .idea/vcs.xml create mode 100644 HELP.md create mode 100644 build.gradle create mode 100644 build/reports/problems/problems-report.html create mode 100644 build/resources/main/application.yml create mode 100644 build/tmp/compileJava/previous-compilation-data.bin create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/com/test/payment/PaymentApplication.java create mode 100644 src/main/java/com/test/payment/configurations/RedisConfig.java create mode 100644 src/main/java/com/test/payment/configurations/ResilienceConfig.java create mode 100644 src/main/java/com/test/payment/configurations/WebClientConfig.java create mode 100644 src/main/java/com/test/payment/controller/MpesaController.java create mode 100644 src/main/java/com/test/payment/exceptions/MpesaPermanentException.java create mode 100644 src/main/java/com/test/payment/exceptions/MpesaTransientException.java create mode 100644 src/main/java/com/test/payment/jobs/MpesaTransactionJob.java create mode 100644 src/main/java/com/test/payment/models/MpesaResponse.java create mode 100644 src/main/java/com/test/payment/models/PaymentRequest.java create mode 100644 src/main/java/com/test/payment/models/Transaction.java create mode 100644 src/main/java/com/test/payment/repository/MpesaRepository.java create mode 100644 src/main/java/com/test/payment/service/MpesaService.java create mode 100644 src/main/java/com/test/payment/service/MpesaTokenService.java create mode 100644 src/main/resources/application.yml create mode 100644 src/test/java/com/test/payment/PaymentApplicationTests.java diff --git a/.gradle/8.14.3/checksums/checksums.lock b/.gradle/8.14.3/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..083f4f11e5f81a604b2d3099b34fe0dae91f559f GIT binary patch literal 17 TcmZRsIeswuP+gQg0~7!NHx~pv literal 0 HcmV?d00001 diff --git a/.gradle/8.14.3/executionHistory/executionHistory.lock b/.gradle/8.14.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..73c42514db7ca9fb4521d729065c2d8b26faf671 GIT binary patch literal 17 TcmZRc8N2NI)pZV03{U_7I%Wiv literal 0 HcmV?d00001 diff --git a/.gradle/8.14.3/fileChanges/last-build.bin b/.gradle/8.14.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/.gradle/8.14.3/fileHashes/fileHashes.bin b/.gradle/8.14.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..04d0d25edb4caf025067527aa23ce129ca1f05bb GIT binary patch literal 18947 zcmeI(?@JSL0LSsK+MumP;)qRH(I6^i*p=A|6O?|ig%Gt|7(rQ5AsCgSJ&7o?7}6sR zMo(6OS>!B>q;zqh`6vTL#Ui4}e6T?ggpm=m8@n&=xc@-jU%0z3pYMH+`@WtYw?_z9 z{(?Tl;#j>nWrhF(2q1s}0tg_000IagfB*srAb-4-z=AQ?8){g8t zt3M}Tm3cz7t!XG5O}~OR0#TVK``b#DdmpFuyj=J8grOlOM$8TW{3lfeAN3ag zbhr4f)H)0e%koZhWA@sPuU&D=nK$k3Vl~%3V`w;AyUmS@2Oh?v2fg-vmFRlj|F+*wrrYIn$=+M3<4DX~zx@gIfb B?(hHr literal 0 HcmV?d00001 diff --git a/.gradle/8.14.3/fileHashes/fileHashes.lock b/.gradle/8.14.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..668f7515d622c5060e05bd6089c75cfeb73755c0 GIT binary patch literal 17 UcmZRseY~f2VY0#&1_ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..f9163b4 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4ba5914 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d28af19 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/payment.main.iml b/.idea/modules/payment.main.iml new file mode 100644 index 0000000..afc1871 --- /dev/null +++ b/.idea/modules/payment.main.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..a544ba6 --- /dev/null +++ b/HELP.md @@ -0,0 +1,14 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Gradle documentation](https://docs.gradle.org) +* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/3.5.6/gradle-plugin) +* [Create an OCI image](https://docs.spring.io/spring-boot/3.5.6/gradle-plugin/packaging-oci-image.html) + +### Additional Links +These additional references should also help you: + +* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle) + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..a474213 --- /dev/null +++ b/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.5.6' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'com.test' +version = '0.0.1-SNAPSHOT' +description = 'Demo project for Spring Boot' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")/* + implementation("io.r2dbc:r2dbc-postgresql")*/ + + implementation("org.springframework.boot:spring-boot-starter-data-redis-reactive") + implementation("io.lettuce:lettuce-core:6.2.2.RELEASE") + + implementation 'com.h2database:h2' + + implementation("io.github.resilience4j:resilience4j-reactor:2.0.2") + implementation("io.github.resilience4j:resilience4j-ratelimiter:2.0.2") + implementation("io.github.resilience4j:resilience4j-circuitbreaker:2.0.2") + implementation("io.github.resilience4j:resilience4j-retry:2.0.2") + implementation("io.github.resilience4j:resilience4j-spring-boot3:2.0.2") + + implementation("org.springframework.boot:spring-boot-starter") + + implementation 'org.projectlombok:lombok:1.18.32' // Use the latest stable version + annotationProcessor 'org.projectlombok:lombok:1.18.32' // For annotation processing + + testImplementation("org.springframework.boot:spring-boot-starter-test") +} + + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html new file mode 100644 index 0000000..f6cb495 --- /dev/null +++ b/build/reports/problems/problems-report.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/build/resources/main/application.yml b/build/resources/main/application.yml new file mode 100644 index 0000000..c09bf79 --- /dev/null +++ b/build/resources/main/application.yml @@ -0,0 +1,40 @@ +#spring: + # redis: + # host: localhost + # port: 6379 + +resilience4j: + ratelimiter: + instances: + mpesaLimiter: + limit-for-period: 10 + limit-refresh-period: 1s + timeout-duration: 0s + + retry: + instances: + mpesaRetry: + max-attempts: 3 + wait-duration: 2s + retry-exceptions: + - org.springframework.web.reactive.function.client.WebClientRequestException + - java.io.IOException + ignore-exceptions: + - com.test.payment.exceptions.MpesaPermanentException + + circuitbreaker: + instances: + mpesaCircuitBreaker: + sliding-window-size: 10 + permitted-number-of-calls-in-half-open-state: 3 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + +spring: + datasource: + url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + driverClassName: org.h2.Driver + username: sa + password: password + platform: h2 + diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin new file mode 100644 index 0000000000000000000000000000000000000000..3bd3e6119be7803a2f0f74f1eae2deeca0cbe91b GIT binary patch literal 93696 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d4081da --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..23d15a9 --- /dev/null +++ b/gradlew @@ -0,0 +1,251 @@ +#!/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. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# 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/platforms/jvm/plugins-application/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 -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || 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="\\\"\\\"" + + +# 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, 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" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# 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/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..5eed7ee --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@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 +@rem SPDX-License-Identifier: Apache-2.0 +@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= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +: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/settings.gradle b/settings.gradle new file mode 100644 index 0000000..bd3755d --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'payment' diff --git a/src/main/java/com/test/payment/PaymentApplication.java b/src/main/java/com/test/payment/PaymentApplication.java new file mode 100644 index 0000000..f02a856 --- /dev/null +++ b/src/main/java/com/test/payment/PaymentApplication.java @@ -0,0 +1,15 @@ +package com.test.payment; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +public class PaymentApplication { + + public static void main(String[] args) { + SpringApplication.run(PaymentApplication.class, args); + } + +} diff --git a/src/main/java/com/test/payment/configurations/RedisConfig.java b/src/main/java/com/test/payment/configurations/RedisConfig.java new file mode 100644 index 0000000..9c7a9d9 --- /dev/null +++ b/src/main/java/com/test/payment/configurations/RedisConfig.java @@ -0,0 +1,22 @@ +package com.test.payment.configurations; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +@Configuration +public class RedisConfig { + + @Bean + public LettuceConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(); + } + + @Bean + public RedisTemplate redisTemplate(LettuceConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + return template; + } +} diff --git a/src/main/java/com/test/payment/configurations/ResilienceConfig.java b/src/main/java/com/test/payment/configurations/ResilienceConfig.java new file mode 100644 index 0000000..d4b9f43 --- /dev/null +++ b/src/main/java/com/test/payment/configurations/ResilienceConfig.java @@ -0,0 +1,45 @@ +package com.test.payment.configurations; + +import com.test.payment.exceptions.MpesaPermanentException; +import io.github.resilience4j.circuitbreaker.*; +import io.github.resilience4j.ratelimiter.*; +import io.github.resilience4j.retry.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClientRequestException; + +import java.io.IOException; +import java.time.Duration; + +@Configuration +public class ResilienceConfig { + + @Bean + public RateLimiter rateLimiter() { + return RateLimiter.of("mpesaLimiter", RateLimiterConfig.custom() + .limitForPeriod(10) + .limitRefreshPeriod(Duration.ofSeconds(1)) + .timeoutDuration(Duration.ZERO) + .build()); + } + + @Bean + public Retry retry() { + return Retry.of("mpesaRetry", RetryConfig.custom() + .maxAttempts(3) + .waitDuration(Duration.ofSeconds(2)) + .retryExceptions(WebClientRequestException.class, IOException.class) + .ignoreExceptions(MpesaPermanentException.class) + .build()); + } + + @Bean + public CircuitBreaker circuitBreaker() { + return CircuitBreaker.of("mpesaCircuitBreaker", CircuitBreakerConfig.custom() + .failureRateThreshold(50) + .waitDurationInOpenState(Duration.ofSeconds(10)) + .permittedNumberOfCallsInHalfOpenState(3) + .slidingWindowSize(10) + .build()); + } +} diff --git a/src/main/java/com/test/payment/configurations/WebClientConfig.java b/src/main/java/com/test/payment/configurations/WebClientConfig.java new file mode 100644 index 0000000..db8a9c8 --- /dev/null +++ b/src/main/java/com/test/payment/configurations/WebClientConfig.java @@ -0,0 +1,16 @@ +package com.test.payment.configurations; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + public WebClient mpesaWebClient(WebClient.Builder builder) { + return builder + .baseUrl("https://sandbox.safaricom.co.ke") + .build(); + } +} diff --git a/src/main/java/com/test/payment/controller/MpesaController.java b/src/main/java/com/test/payment/controller/MpesaController.java new file mode 100644 index 0000000..a7bda73 --- /dev/null +++ b/src/main/java/com/test/payment/controller/MpesaController.java @@ -0,0 +1,28 @@ +package com.test.payment.controller; + + +import com.test.payment.models.*; +import com.test.payment.models.MpesaResponse; +import com.test.payment.models.PaymentRequest; +import com.test.payment.service.MpesaService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/api/mpesa") +@RequiredArgsConstructor +public class MpesaController { + + private final MpesaService mpesaService; + + @PostMapping("/pay") + public Mono> pay(@RequestBody PaymentRequest request) { + return mpesaService.initiatePayment(request) + .map(ResponseEntity::ok) + .onErrorResume(ex -> Mono.just(ResponseEntity.badRequest() + .body(new MpesaResponse("FAILED", ex.getMessage())))); + } +} + diff --git a/src/main/java/com/test/payment/exceptions/MpesaPermanentException.java b/src/main/java/com/test/payment/exceptions/MpesaPermanentException.java new file mode 100644 index 0000000..527c550 --- /dev/null +++ b/src/main/java/com/test/payment/exceptions/MpesaPermanentException.java @@ -0,0 +1,8 @@ +package com.test.payment.exceptions; + + +public class MpesaPermanentException extends RuntimeException { + public MpesaPermanentException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/test/payment/exceptions/MpesaTransientException.java b/src/main/java/com/test/payment/exceptions/MpesaTransientException.java new file mode 100644 index 0000000..cc7d46a --- /dev/null +++ b/src/main/java/com/test/payment/exceptions/MpesaTransientException.java @@ -0,0 +1,7 @@ +package com.test.payment.exceptions; + +public class MpesaTransientException extends RuntimeException { + public MpesaTransientException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/src/main/java/com/test/payment/jobs/MpesaTransactionJob.java b/src/main/java/com/test/payment/jobs/MpesaTransactionJob.java new file mode 100644 index 0000000..b94fa60 --- /dev/null +++ b/src/main/java/com/test/payment/jobs/MpesaTransactionJob.java @@ -0,0 +1,23 @@ +package com.test.payment.jobs; + + +import com.test.payment.repository.MpesaRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class MpesaTransactionJob { + + private final MpesaRepository mpesaRepository; + + @Scheduled(fixedDelay = 60000) + public void pullTransactions() { + mpesaRepository.findAllTransactions() + .doOnNext(tx -> log.info("Checking transaction: {}", tx)) + .subscribe(); + } +} diff --git a/src/main/java/com/test/payment/models/MpesaResponse.java b/src/main/java/com/test/payment/models/MpesaResponse.java new file mode 100644 index 0000000..60d80ed --- /dev/null +++ b/src/main/java/com/test/payment/models/MpesaResponse.java @@ -0,0 +1,13 @@ +package com.test.payment.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MpesaResponse { + private String status; + private String message; +} diff --git a/src/main/java/com/test/payment/models/PaymentRequest.java b/src/main/java/com/test/payment/models/PaymentRequest.java new file mode 100644 index 0000000..888f464 --- /dev/null +++ b/src/main/java/com/test/payment/models/PaymentRequest.java @@ -0,0 +1,12 @@ +package com.test.payment.models; + + +import lombok.Data; + +@Data +public class PaymentRequest { + private String phoneNumber; + private double amount; + private String accountReference; + private String transactionDesc; +} diff --git a/src/main/java/com/test/payment/models/Transaction.java b/src/main/java/com/test/payment/models/Transaction.java new file mode 100644 index 0000000..7c7c3d9 --- /dev/null +++ b/src/main/java/com/test/payment/models/Transaction.java @@ -0,0 +1,21 @@ +package com.test.payment.models; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Transaction { + + @Id + private String id; + private String phoneNumber; + private double amount; + private String status; +} + diff --git a/src/main/java/com/test/payment/repository/MpesaRepository.java b/src/main/java/com/test/payment/repository/MpesaRepository.java new file mode 100644 index 0000000..18298ae --- /dev/null +++ b/src/main/java/com/test/payment/repository/MpesaRepository.java @@ -0,0 +1,31 @@ +package com.test.payment.repository; + + +import com.test.payment.models.Transaction; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Repository +public class MpesaRepository { + + private final RedisTemplate redisTemplate; + + public MpesaRepository(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + public Mono saveTransaction(Transaction transaction) { + return Mono.fromRunnable(() -> + redisTemplate.opsForHash().put("mpesa:transactions", transaction.getId(), transaction.getStatus()) + ).then(); + } + + public Flux findAllTransactions() { + List values = redisTemplate.opsForHash().values("mpesa:transactions"); + return Flux.fromIterable(values).cast(Transaction.class); + } +} diff --git a/src/main/java/com/test/payment/service/MpesaService.java b/src/main/java/com/test/payment/service/MpesaService.java new file mode 100644 index 0000000..ba3d913 --- /dev/null +++ b/src/main/java/com/test/payment/service/MpesaService.java @@ -0,0 +1,65 @@ +package com.test.payment.service; + + +import com.test.payment.exceptions.MpesaPermanentException; +import com.test.payment.exceptions.MpesaTransientException; +import com.test.payment.models.*; +import com.test.payment.repository.MpesaRepository; +import io.github.resilience4j.circuitbreaker.*; +import io.github.resilience4j.ratelimiter.*; +import io.github.resilience4j.retry.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.UUID; +import java.util.function.Supplier; + +@Service +@RequiredArgsConstructor +@Slf4j +public class MpesaService { + + private final WebClient mpesaWebClient; + private final MpesaRepository mpesaRepository; + private final MpesaTokenService tokenService; + private final RateLimiter rateLimiter; + private final Retry retry; + private final CircuitBreaker circuitBreaker; + + public Mono initiatePayment(PaymentRequest request) { + Supplier> decoratedSupplier = + CircuitBreaker.decorateSupplier(circuitBreaker, + RateLimiter.decorateSupplier(rateLimiter, + Retry.decorateSupplier(retry, () -> callMpesa(request)) + ) + ); + + return Mono.defer(decoratedSupplier) + .flatMap(response -> { + Transaction tx = new Transaction(UUID.randomUUID().toString(), + request.getPhoneNumber(), request.getAmount(), response.getStatus()); + return mpesaRepository.saveTransaction(tx).thenReturn(response); + }) + .doOnError(e -> log.error("M-Pesa API failed: {}", e.getMessage())); + } + + private Mono callMpesa(PaymentRequest request) { + return tokenService.getToken() + .flatMap(token -> + mpesaWebClient.post() + .uri("/mpesa/stkpush/v1/processrequest") + .header("Authorization", "Bearer " + token) + .bodyValue(request) + .retrieve() + .bodyToMono(MpesaResponse.class) + .timeout(java.time.Duration.ofSeconds(20)) + .onErrorResume(ex -> { + log.error("Error calling M-Pesa: {}", ex.getMessage()); + return Mono.error(new MpesaTransientException("Temporary M-Pesa issue", ex)); + }) + ); + } +} diff --git a/src/main/java/com/test/payment/service/MpesaTokenService.java b/src/main/java/com/test/payment/service/MpesaTokenService.java new file mode 100644 index 0000000..2d10bc5 --- /dev/null +++ b/src/main/java/com/test/payment/service/MpesaTokenService.java @@ -0,0 +1,27 @@ +package com.test.payment.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +@Service +@RequiredArgsConstructor +public class MpesaTokenService { + + private final RedisTemplate redisTemplate; + + public Mono getToken() { + String cachedToken = redisTemplate.opsForValue().get("mpesa:token"); + if (cachedToken != null) { + return Mono.just(cachedToken); + } + // Simulate token fetch from M-Pesa auth endpoint + String newToken = "access_token_" + System.currentTimeMillis(); + redisTemplate.opsForValue().set("mpesa:token", newToken, Duration.ofMinutes(50)); + return Mono.just(newToken); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..c09bf79 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,40 @@ +#spring: + # redis: + # host: localhost + # port: 6379 + +resilience4j: + ratelimiter: + instances: + mpesaLimiter: + limit-for-period: 10 + limit-refresh-period: 1s + timeout-duration: 0s + + retry: + instances: + mpesaRetry: + max-attempts: 3 + wait-duration: 2s + retry-exceptions: + - org.springframework.web.reactive.function.client.WebClientRequestException + - java.io.IOException + ignore-exceptions: + - com.test.payment.exceptions.MpesaPermanentException + + circuitbreaker: + instances: + mpesaCircuitBreaker: + sliding-window-size: 10 + permitted-number-of-calls-in-half-open-state: 3 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + +spring: + datasource: + url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + driverClassName: org.h2.Driver + username: sa + password: password + platform: h2 + diff --git a/src/test/java/com/test/payment/PaymentApplicationTests.java b/src/test/java/com/test/payment/PaymentApplicationTests.java new file mode 100644 index 0000000..0b1ed91 --- /dev/null +++ b/src/test/java/com/test/payment/PaymentApplicationTests.java @@ -0,0 +1,13 @@ +package com.test.payment; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PaymentApplicationTests { + + @Test + void contextLoads() { + } + +}